跳到主要内容

版本

2024年01月09日
柏拉文
越努力,越幸运

一、Vite 1.x


二、Vite 2.x


三、Vite 3.x


3.1 CLI 的更新

在执行 vite 命令启动项目时,终端的界面和之前会有所不同,而更重要的是,为了避免 Vite 开发服务的端口和别的应用冲突,默认的端口号从之前的 3000 变成了 5173

Preview

3.2 开箱即用的 WebSocket 连接策略

Vite 2 中有存在一个痛点,即在存在代理的情况下(比如 Web IDE)需要我们手动配置 WebSocket 使 HMR 生效。目前 Vite 内置了一套更加完善的 WebSocket 连接策略,自动满足更多场景的 HMR 需求。

3.3 服务冷启动性能提升

Vite 3.0 在服务冷启动方面做了非常多的工作,来最大程度提升项目启动的速度。

首先我们来盘点一下 Vite 2.x 阶段服务冷启动的一些问题。

Vite 2.02.9 版本之前,Vite 会在服务启动之前进行依赖预构建,也就是使用 Esbuild 将项目中使用到的依赖扫描出来(Scan),然后分别进行一次打包(Optimize)。

Preview

这样会造成两个问题:

  1. 依赖预构建会阻塞 Dev Server 启动,但其实不阻塞的情况下,Dev Server 也可以正常启动。

  2. 当某些 Vite 插件手动注入了 import 语句,比如调用 babel-plugin-import 添加import Button from 'antd/lib/button',就会导致 Vite 的二次预构建,因为 antd/lib/button 的引入代码由 Vite 插件注入,属于 Dev Server 运行时发现的依赖,冷启动阶段无法扫描到。

所谓的二次预构建包含两个步骤,一是需要将所有的依赖全量预构建二是由于依赖更新,页面需要进行 reload,加载最新的依赖代码。这样会导致 Dev Server 性能明显下降,尤其是在新增依赖较多的场景下,很容易出现浏览器卡住的情况。因此二次预构建也是需要极力避免的。当时 vite-plugin-optimize-persist 就是为了解决二次预构建带来的问题,通过持久化的方式记录 Dev Server 运行时扫描到的依赖,从而让首次预构建便可以感知到,避免二次预构建的发生。

到了 2.9 版本,Vite 将预构建的逻辑做了一次整体的重构,最后的效果是下面这样的:

  1. Dev Server 启动后预构建(Optimize 阶段)在后台执行,也就是预构建不再阻塞 Dev Server 的启动,只需要等待 Scan 阶段完成,不过通常这个阶段的开销非常小。

    Preview
  2. 如果某些依赖是 Dev Server 运行时才发现的,那么 Vite 会尽可能地复用已有预构建产物,尽量不进行 page reload

那问题就完全解决了吗?其实并不是,在某些场景下,Vite 仍然不可避免地需要二次预构建。如下面的这个例子:

Preview

AB 都是项目的第三方依赖,它们也同时依赖 C。那么当 Vite 预构建 A 的时候,将会 AC 一起进行打包。但 Vite 在运行时发现了依赖 B,而 AB 需要共享 C 的代码,这样 C 的代码可能就会被抽离成一个公共的 chunk,因此之前 A 的预构建产物可能就发生变化了,那么此时 Vite 必须要强制刷新页面,让浏览器使用最新的预构建产物。这仍然是一个二次预构建(所有依赖再次打包 + page reload)的过程。

总体而言,2.9 版本解决了预构建阻塞服务启动的问题,但并没有完全解决二次预构建的问题。

但在 Vite 3.0,二次预构建的问题也得到了根本的解决。那 Vite 3.0 是如何做到的呢?

核心的解决思路在于延迟处理,即把预构建的行为延迟到页面加载的最后阶段进行,此时 Vite 已经编译完了所有的源文件,可以准确地记录下所有需要预构建的依赖(包括 Vite 插件添加的一些依赖),然后统一进行预构建,将预构建的产物响应给给浏览器即可。

因此,与 Vite 2.0 相比,Vite 3.0 在冷启动阶段所做的优化主要有两个方面:

  1. 预构建不再阻塞 Dev Server 的启动,真正做到服务秒启动的效果

  2. 从根本上防止二次预构建的发生

3.4 import.meta.glob 语法更新

Vite 3.0import.meta.glob 的实现进行了重写,支持了更加灵活的 glob 语法,增加了如下的一些特性:

  • 多种模式匹配

  • 否定模式(!)

  • 命名导入,可以更好地做到 Tree Shaking

  • 自定义 query 参数

  • 指定 eager 模式,替换掉原来import.meta.globEager

3.5 Esbuild 预构建用于生产环境

这应该是 Vite 架构上非常大的一个改动: 将原来仅仅用于开发阶段的依赖预构建功能应用在生产环境。在 Vite 2.x 中,开发阶段使用 Esbuild 来打包依赖,而在生产环境使用 Rollup 进行打包,用 @rollupjs/plugin-commonjs 来处理 cjs 的依赖,这样做会导致依赖处理的不一致问题,造成一些生产构建中的 bug

Vite 3.0 中支持通过配置将 Esbuild 预构建同时用于开发环境和生产环境,仅添加optimizeDeps.disabled: false 的配置即可。不过这个改动确实比较大,Vite 团队不打算将此作为 v3 的正式更新内容,而是一个实验性质的功能,不会默认开启。

四、Vite 4.x