Vite 3.0 核心盘点与分析

自2021 年2月,Vite 2.0版本发布以来,Vite项目在的用户量方面发生了非常迅速的增长,很快达到了每周 100 万的npm下载量,成为npm下载量最高的几个项目之一。同时,Vite 的社区也越来越活跃,目前已经形成非常庞大的社区生态,给整个前端领域带来了诸多的改变,如:

  • Nuxt 3、SvelteKit、Astro、StoryBook 等在内的各大前端框架已经将 Vite 作为内置的构建方案。
  • 基于 Vite 的测试工具 Vitest 诞生,成为替代 Jest 的新一代测试方案。

如今已经 2023 年 7 月,Vite 4.0 版本也推出了好几个月了,不过我们还是要给大家介绍一下 Vite 3.0 带来的一些改变。

1,全新的 VitePress 文档

对于用户侧来说,谈到框架的更新,文档自然是最重要的部分。现在你可以直接去 vitejs.dev 站点体验到 v3 版本的文档,目前文档同样是使用 VitePress 进行搭建。
在这里插入图片描述

不光是 Vite,也有 Vite 生态中其它的一些项目使用 VitePress 进行文档站点的搭建,比如 Vitest, vite-plugin-pwa 以及 VitePress 自身的文档,我也十分推荐大家使用 VitePress 作为自己的文档建站方案之一。

2,开发阶段的更新

2.1 CLI 的更新

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

2.2 开箱即用的 WebSocket 连接策略

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

2.3 服务冷启动性能提升

Vite 3.0 在服务冷启动方面做了非常多的工作,来最大程度提升项目启动的速度。首先我们来盘点一下 Vite 2.x 阶段服务冷启动的一些问题。

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

在这里插入图片描述

不过,这样带来了两个问题:

  • 依赖预构建会阻塞 Dev Server 启动,但其实不阻塞的情况下,Dev Server 也可以正常启动。
  • 当某些 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 将预构建的逻辑做了一次整体的重构,最后的效果如下:

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

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

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

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

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

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

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

  • 预构建不再阻塞 Dev Server 的启动,真正做到服务秒启动的效果;
  • 从根本上防止二次预构建的发生。

2.4 import.meta.glob 语法更新

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

  • 多种模式匹配
import.meta.glob(["./dir/*.js", "./another/*.js"]);
  • 否定模式(!)
import.meta.glob(["./dir/*.js", "!**/bar.js"]);
  • 命名导入,可以更好地做到 Tree Shaking
import.meta.glob("./dir/*.js", { import: "setup" });
  • 自定义 query 参数
import.meta.glob("./dir/*.js", { query: { custom: "data" } });
  • 指定 eager 模式,替换掉原来import.meta.globEager
import.meta.glob("./dir/*.js", { eager: true });

三、生产阶段的更新

3.1 SSR 产物默认使用 ESM 格式

在当下的社区生态中,众多 SSR 框架已经在使用 ESM 格式作为默认的产物格式。Vite 3.0 也积极拥抱社区,支持 SSR 构建默认打包出 ESM 格式的产物。

3.2 Relative Base 支持

Vite 3.0 正式支持 Relative Base(即配置base: ‘’),主要用于构建时无法确定 base 地址的场景。

总的来说,Vite 3.0 带来了一些比较大的架构变动,比如依赖预构建的重构、支持生产环境 Esbuild 预打包依赖以及全面支持 Pure ESM,当然也有一些比较小的 break change 在这个版本集中发布,比如 import.meta.glob 语法的变更。

猜你喜欢

转载自blog.csdn.net/xiangzhihong8/article/details/131764506