作者:来自 vivo 互联网大前端团队- Wei Xing
在研发小型项目时,传统的 Vue、React 显得太"笨重"。本文主要针对开发小型项目的场景,谈谈 Vite+Svelte 是如何让项目变得"小巧灵动",并横向对比 Svelte 和 Vue 的性能表现,对二者的加载流程做详细分析。
一、背景
为了统一技术标准、提升协作效率,通常在前端团队内部只会保留一套通用的研发框架。尤其是在团队初创时期,团队成员会考虑易用性、社区活跃程度、学习成本等因素,选择一个合适的研发框架并一直推行和使用下去。
国内的前端团队比较青睐 Vue和 React,我们团队内部的主要研发框架也是 Vue,包括组件库、工具库、脚手架等等,都是围绕 Vue 展开来做研发。
坚持使用一个技术栈虽然让团队协作变得高效,也不用重复"造轮子",同时提升了人员"流通性",有它不可忽略的优势。但没有任何一款框架是"银弹",例如 Vue,它的通用性很好,但在某些特殊场景下,我们会有更好的选择。
例如,当我们在开发一些小型项目时,会发现至少有两个明显的问题:
框架太"重"了:通常一个小型项目只由少数几个简单页面构成,如果使用 Vue 或者 React 这些框架来研发的话,有点"大材小用"了。构建的产物中包含了不少框架运行时代码(虚拟 DOM、响应式、状态管理等),这些代码对于小型项目而言是冗余的,它们影响了包体大小,进而影响页面的启动速度和执行性能。
打包太慢了:以 Vue CLI 为例,它的底层基于 Webpack,虽然 Webpack 具备更强大的功能和灵活性,但相比于 Vite、Esbuild 这些以速度为标杆的构建工具来说,它的速度确实慢了一些,影响了研发效率。
面对这两个问题,我们似乎有更好的技术方案可选:使用更轻量的 Vite + Svelte 。本文就是针对开发小型项目的场景,谈谈 Vite+Svelte 是如何让项目变得"小巧灵动"。
注意 :本篇所有针对 Svelte 的性能观点,都是基于小型项目这个前提下提出。事实上,随着项目规模的增长, Svelte 的性能、包体大小优势会逐渐减小,甚至不如 Vue 或 React,详情可参考尤雨溪尤大本人针对 Svelte 和 Vue3的包体大小问题的分析。
理论上在普通 CSR 项目中,组件数量超过19个时, Svelte 就失去了它的包体大小优势。
二、Vite 和 Svelte 简介
先了解下 Vite 和 Svelte。
2.1 Vite
Vite 是尤雨溪尤大写的一款高效的前端构建工具,相比于 Webpack,它最大的优势就是"快"。
在开发环境下,Vite 使用高性能的 Esbuild 来进行预构建,并利用现代浏览器对 ESM 的支持,直接将预构建好的ES模块丢给浏览器进行解析执行,无需在每次变更代码时都重新编译代码,具有更快的冷启动速度和热更新效率。
在生产环境下,Vite 基于 Rollup 进行打包,Rollup 同样支持 ESM 语法,并且具有更快速高效的 Treeshaking,一般情况下,Rollup 具有更小的包体大小和更快的构建速度。
参考 github 上的构建工具横向对比 benchmark。
可以看到无论是冷启动、热更新还是生产环境打包,Vite 都是优于 Webpack 的。尤其是在开发过程中的热更新很快,大大优化了开发体验。
2.2 Svelte
Svelte 是由 Rollup 的作者 Rich Harris(前端轮子哥) 写的一款前端框架。在语法上,Svelte 和 Vue 类似。它和传统框架(如 Vue、React)的最大差异就在于:在构建阶段,Svelte 就将代码编译为"纯粹"的 JavaScript 代码,几乎没有运行时。
这意味着在小型项目中,它打出来的包更小,在运行时,它也不需要复杂的状态管理和虚拟 DOM,在性能上的表现也更好。
在前端大佬 Jacek Schae 的前端框架横向测评中(测评简述:使用各个前端框架来编写同一个标准 App - RealWorld,并横向对比它们的表现),可以看到,Svelte 无论是在首屏渲染速度、包体大小还是代码行数上都展现了较大的优势,全部跻身前三。
首屏渲染速度:
包体大小:
代码行数:
三、搭建 Vite+Svelte 项目
在基本了解了 Vite 和 Svelte 之后,来看看如何着手去搭建一个 Vite+Svelte 的项目。
3.1 全局安装 Vite
通过 npm 全局安装 Vite:
npm install vite -g
3.2 创建 Svelte 项目
Vite 原生支持直接通过脚手架创建 Svelte 项目,执行以下命令:
npm create vite@latest
命令行中会出现引导,按照提示输入项目的名称并直接选择 Svelte 框架即可。
✔ Project name: vite-svelte-demo
? Select a framework: › - Use arrow-keys. Return to submit.
Vanilla
Vue
React
Preact
Lit
❯ Svelte
Solid
Qwik
Others
? Select a variant: › - Use arrow-keys. Return to submit.
TypeScript
❯ JavaScript
SvelteKit ↗
3.3 运行项目
通过以下命令运行项目:
cd vite-svelte-demo
npm install
npm run dev
这样一来,整个 Vite + Svelte 的项目结构就搭建好了,开箱即用。整个项目的目录结构如下:
|-node_modules -- 项目依赖
|-public -- 公共文件
|--vite.svg
|-src -- 源文件
|-assets
|-lib
|--App.svelte -- 项目根组件
|--app.css -- 项目根样式
|--main.js -- 项目入口文件
|--.gitignore
|-- index.html -- 首页index.html
|-- package-lock.json
|-- package.json
|-- tsconfig.json
|-- svelte.config.js -- svelte配置文件
|-- vite.config.js -- vite配置文件
可以看到,整个项目结构基本和 Vue 类似,只是组件的后缀名改为了.svelte,新增了 vite.config.js 和 svelte.config.js 两个配置文件。
3.4 配置
Vite+Svelte 支持开箱即用,项目的初始配置也很简单,没有任何额外配置。
vite.config.js:用于配置 Vite 构建工具的行为,例如入口文件、输出目录、插件、devServer 等。
// vite.config.js
import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'
export default defineConfig({
plugins: [svelte()],
})
svelte.config.js:用于配置 Svelte 项目的各种选项,例如别名、预处理器、插件等。
// svelte.config.js
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
export default {
preprocess: vitePreprocess(),
}
在工程配置这里,唯一需要注意的是,Vite 默认情况打出的包体仅支持现代浏览器(支持 ESM ),如果要兼容低版本浏览器,可以使用官方提供的 @vitejs/plugin-legacy插件:
// vite.config.js
import { defineConfig } from "vite";
import { svelte } from "@sveltejs/vite-plugin-svelte";
import legacy from "@vitejs/plugin-legacy";
export default defineConfig({
plugins: [
svelte(),
legacy({
// 设置需要兼容的目标浏览器版本
targets: [
"Android >= 4.4",
"iOS >= 9",
"ie >= 11",
"not Android < 4.4",
"not iOS < 9",
"not ie < 11",
],
additionalLegacyPolyfills: ["regenerator-runtime/runtime"],
renderLegacyChunks: true,
}),
});
更多配置项可参考官网的 Vite 配置文档和 Svelte 配置文档。
四、开发体验优化
项目搭建完成后,后续就是根据业务需求来开发 Svelte 组件和完善业务逻辑。整个开发过程中,体验感还是不错的。
详细的开发流程不再赘述,想要了解更多关于 Vite 和 Svelte 内容,可以参考 Vite 官方文档和 Svelte 官方文档。这里我们主要来看看 Vite 和 Svelte 分别在开发体验上带来的一些优化。
4.1 Vite 的开发体验太棒了
首先,Vite 的开发体验太棒了。它的构建速度极快,对开发效率有很明显的提升。
在开发环境下,Webpack 每次都需要对改动的部分进行重新编译打包,耗时几秒钟,而 Vite 则不需要重新打包,只需要把更新后的 ESM 代码交付给浏览器就ok,几乎是即时更新。
同时在构建生产环境包时,也明显比原先的 Vue 项目要快了近50%。别小看这一点速度的提升,让整个开发体验好了不少。
4.2 Svelte 的语法更优雅?
如果你跟随上面步骤搭建了项目,那你可以打开项目中的 Counter.svelte 文件看看,会发现 Svelte 组件的基本结构和 Vue 几乎一致,也是由 script、template 和 style 三部分组成,唯一的差异在于 Svelte 中不需要像 Vue 一样额外使用来作为 DOM 结构的根标签。
<script>
let count = 0
const increment = () => {
count += 1
}
</script>
<button on:click={increment}>
count is {count}
</button>
<style>
...
</style>
在语法上,Svelte 和 Vue 也非常相似,但个人更喜欢 Svelte 的一些简洁的语法设计,举一些例子:
插值表达式:Svelte 的插值表达式只需要单个{},而 Vue 则需要两层{{}},并且 Svelte 还有一些简写语法,例如 src={src} 可以简写为 {src}。
// Svelte的插值表达式
<div {src}>
count is {count}
</<div>
// Vue的插值表达式
<template>
<div :src="src">
count is {{ count }}
</div>
</template>
响应式:Svelte 声明的变量直接支持响应式,而在 Vue 中则需要使用 ref 来声明。
// Svelte
let message = 'Svelte';
// Vue
import { ref } from 'vue';
const message = ref('Vue');
computed 计算属性 / watch 监听:Svelte 的$: 代码块类似于 Vue 的 computed 计算属性和 watch 状态监听的结合体。
// Svelte的计算属性
$: info = name + age
// Svelte的监听
let val
$: {
console.log(`你输入的内容是: ${val}`);
}
// Vue的计算属性
import { computed } from 'vue';
const info = computed(() => {
return name + age
});
// Vue的监听
import { watch } from 'vue';
let val = ref('');
watch(val, (newValue, oldValue) => {
console.log(`你输入的内容是: ${val}`);
});
虽然差异没有很大,但这些简洁的语法,至少让我个人感觉写项目时更流畅,体验感很不错。
这些就是 Vite 和 Svelte 带来的开发体验上的一些优化。
五、Svelte 和 Vue 性能对比
上面我们了解了如何搭建 Vite+Svelte 项目,并感受到 Vite 和 Svelte 带来的开发体验优化。那接下来看看这套方案在实际项目中的性能表现。
为了对比 Svelte 和 Vue 之间的性能差异,我特地找了一个小型项目进行改造,用 Svelte 对它重写,并通过 ABTest 进行线上的性能数据对比。
5.1 首先,来看打包之后的 bundle 大小对比
Vue 的包体:
Svelte 的包体:
可以看到 Svelte 相比于 Vue,在包体大小上确实优化了不少,基本在40%左右,效果很明显。
5.2 其次,看看本地的启动速度(FCP)对比
在本地进行10次平均性能测试,发现 Svelte 的 FCP 指标比 Vue 要快了约46%,说明 Svelte 的首屏渲染速度比 Vue 快了不少,提升很明显。
下面这个录屏是对比两个页面首次打开时的效果,左侧为 Svelte,右侧为 Vue。
5.3 最后,看看线上的启动速度数据对比
我们通过 ABTest 进行线上的启动速度数据对比,在投放了1周后,数据结论如下:
以看到 Svelte 在线上的启动速度表现也比 Vue 要快一些,优化程度约为14.5%。
注意:这里的平均启动速度指标是我们团队内部定义的页面启动速度指标,计算方式:业务启动速度 = 页面加载完成时间 - 页面入口点击时间。由于我们是在客户端 App 中进行测试,因此该时间包含了客户端 webview 的启动时间。所以实际上 Svelte 对前端部分的启动速度优化程度可能会更高,参考前面的 FCP 指标的本地测试结果。
总之,对于小型项目,Svelte 在包体大小和启动速度上还是有不少提升的,如果你的项目对启动速度有强要求,也可以尝试使用 Svelte 来开发或改造,应该会有不错的效果。
六、Svelte 比 Vue 快在哪?
通过上面的数据分析,虽然我们了解到 Svelte 在构建小型项目时确实有更快的页面启动速度,但具体快在哪,还需要进一步深入分析。
我们可以通过 Chrome 的 devtool 来观察 Svelte 和 Vue 两者打包后的页面在加载流程上的差异。
Vue 页面加载流程:
Svelte 页面加载流程:
对比二者的加载流程,可以看到耗时上有两个主要的差异点:
因此,在小型项目中,Svelte 相比于 Vue,有两个明显的优势:
-
资源加载更快:由于包体较小,所以加载首屏 JS Bundle 时网络耗时更短。
-
Html/JS解析执行更快:由于 Svelte 几乎无运行时,因此在执行相同业务逻辑时,解析执行耗时更短。并且在解析执行过程中,没有二次加载更多的首屏 JS、CSS 资源,因此整体的解析执行速度更快。
七、总结
总之,对于小型项目而言,Vite + Svelte 这对组合还是很不错的,既提升了开发效率,又优化了页面性能,更加"小巧灵动"。而且这两者的学习曲线都比较缓和,基本在2-3天内就可以完成学习加一个简单项目的改造。
一点题外话,很多时候大家会低估"技术尝新"的重要性,我们被困在团队圈定的"技术穹顶"中,永远用一个"套路"去实现所有业务,这会让我们感到疲乏、缺乏价值感和动力,甚至影响工作的投入程度,久而久之,整个团队也会在技术上变得迟滞。
所以在有机会时,要尽量合理地发掘和尝试新的技术方案,一方面是让自己保持技术活力,另一方面也是在加强团队的技术沉淀。