主打一个“小巧灵动”:Vite + Svelte

作者:来自 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

(图片来源:https://github.com)

可以看到无论是冷启动、热更新还是生产环境打包,Vite 都是优于 Webpack 的。尤其是在开发过程中的热更新很快,大大优化了开发体验。

2.2 Svelte

Svelte 是由 Rollup 的作者 Rich Harris(前端轮子哥) 写的一款前端框架。在语法上,Svelte 和 Vue 类似。它和传统框架(如 Vue、React)的最大差异就在于:在构建阶段,Svelte 就将代码编译为"纯粹"的 JavaScript 代码,几乎没有运行时。

这意味着在小型项目中,它打出来的包更小,在运行时,它也不需要复杂的状态管理和虚拟 DOM,在性能上的表现也更好。

在前端大佬 Jacek Schae 的前端框架横向测评中(测评简述:使用各个前端框架来编写同一个标准 App - RealWorld,并横向对比它们的表现),可以看到,Svelte 无论是在首屏渲染速度、包体大小还是代码行数上都展现了较大的优势,全部跻身前三。

首屏渲染速度

(图片来源:https://medium.com)

包体大小:

(图片来源:https://medium.com)

代码行数:

(图片来源:https://medium.com)

三、搭建 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天内就可以完成学习加一个简单项目的改造。

一点题外话,很多时候大家会低估"技术尝新"的重要性,我们被困在团队圈定的"技术穹顶"中,永远用一个"套路"去实现所有业务,这会让我们感到疲乏、缺乏价值感和动力,甚至影响工作的投入程度,久而久之,整个团队也会在技术上变得迟滞。

所以在有机会时,要尽量合理地发掘和尝试新的技术方案,一方面是让自己保持技术活力,另一方面也是在加强团队的技术沉淀。

相关推荐
蟾宫曲3 小时前
在 Vue3 项目中实现计时器组件的使用(Vite+Vue3+Node+npm+Element-plus,附测试代码)
前端·npm·vue3·vite·element-plus·计时器
正小安3 天前
Vite系列课程 | 11. Vite 配置文件中 CSS 配置(Modules 模块化篇)
前端·vite
学前端的小朱4 天前
Echarts实现大屏可视化
websocket·echarts·nodejs·vue3·vite·koa·cors
正小安6 天前
Vite 系列课程|1课程道路,2什么是构建工具
前端·vite
三天不学习8 天前
Vue3+Vite 环境变量和模式配置详解
前端·javascript·vue.js·vite·vue环境变量
潜心专研的小张同学9 天前
解决 Vite 项目启动时端口重复问题的总结
前端·vue.js·vite
沐晨爸爸10 天前
pinia和pinia-plugin-persistedstate的配置和用法
vue.js·vite