Vite 的运行流程
就像研究浏览器页面首屏性能,我们会先想到一个问题:从输入 url 到页面显示,这个过程发生了什么?
当我们研究 Vite 首屏性能,就不得不考虑一个问题:从输入 url 到页面显示,Vite 做了什么?
以下是 Vite3.x 的运行流程图:
- 运行 Vite 命令,启动 DevServer,输出端口
- 访问页面,页面会访问静态资源和依赖
- 请求静态资源时,Vite 会对资源进行转换,然后响应请求
- 请求依赖时,需要等待依赖预构建完成后,DevServer 才会响应请求。
- 当页面资源全部加载并执行完成后,显示首屏。
可以粗略的得出一个结论:
- 总时间 = Vite Server 启动时间 + 首屏时间
- 首屏时间 = Max(所有静态资源请求处理时间, 依赖预构建时间)
Vite Server 启动时间
严格来说,Server 启动时间,不算在首屏性能中,不过也值得我们拿出来研究一下。
DevServer 启动前,只做了少量的操作:
- 标准化用户传入的 config
- 初始化 DevServer 对象
- 热更新相关的逻辑
可以看出 Server 的启动时间,其实是不随项目的规模变大而显著增长的
注意这里说的是 Vite3.x
在 Vite2.x,Vite 会等待依赖预构建完成,才打印出 Server 端口,这时候才认为 Server 完全启动。
Vite3.x 则直接启动 Server,依赖预构建则异步执行。相当于将构建阶段往后挪了,这就会给人这样一种感觉:启动速度快了,但首屏反而更慢
静态资源处理时间
在浏览器打开页面,会请求 HTML 文件及其需要的静态资源文件
每当请求一个资源文件时,Vite 会对它们进行转换处理,例如:
- 给 HTML 注入热更新脚本
- 将 Vue 文件转换成 JS 代码,让浏览器能够正确运行
- 将 less 文件,转换成 CSS
Vite 并没有在 Server 启动期间进行代码转换,而是在浏览器请求模块时进行编译转换,这就能做到用到哪个模块就编译哪个模块。这也是 Vite Server 启动快的原因,但这同时也会带来更长的首屏时间。
项目规模的变大,对首屏时间的影响?
单个页面需要转换的资源越多,静态资源的转换时间就越长
一般来说,项目规模增大,往往是新增了更多的页面,单个页面使用的模块往往不会随项目规模增长。
如果是这种情况,其实对静态资源处理时间影响不会非常大,因为 Vite 只对使用到的模块进行转换,而其他页面的模块由于没有被使用到,因此也不会被转换。
如何减少获取静态资源的总时间?
- 使用 HTTP2。因为浏览器对 HTTP 1 的请求,会有并发上限,达到上限的请求,需要排队。而 HTTP 2 有多路复用的特性,则不会用并发上限的问题
- 使用缓存。Vite 其实已经内置了,第二次访问相同的资源时,Vite 会返回 304 状态码,使用浏览器缓存。但这个对首屏没有帮助,第一次仍然需要进行模块代码转换。如果需要提升首屏性能,则需要持久化缓存,但这个 Vite 只是有规划,但是仍然没有实现。
依赖预构建时间
依赖预构建的目的有两个:
- CommonJS 和 UMD 兼容性
- 提升性能
它的过程主要分为:
- 依赖扫描/依赖发现阶段
需要扫描所有项目文件,找到所有项目中使用到的依赖。更多细节可以查看《五千字深度解读 Vite 的依赖扫描》 - 预构建阶段
本质就是对项目中用到的依赖,提前进行构建打包,是一次使用 esbuild 的多入口构建,入口为所有项目依赖的入口脚本(各依赖 package.json 中定义的入口文件)。更多细节可以查看《快速理解 Vite 的依赖预构建》
从预构建过程可以看出:
- 依赖扫描的性能,与项目的文件数量有关,项目文件越多,需要扫描的文件就越多,时间就越长
- 预构建的性能,与项目使用的依赖的数量有关,使用的模块越多,需要构建的模块就越多,时间就越长
因此,项目规模越大,首屏时间就会越慢。当然这也是所有打包工具都会遇到的问题。
Vite 会优先使用本地的预构建产物。只有第一次启动 Vite 的时候,才会进行依赖预构建,第二次启动则会使用上次构建好的依赖。除非项目使用到的依赖 、配置文件发生了变化 ,则需要重新进行预构建。
于是可以分为以下两种情况:
- 首次执行 Vite,依赖预构建时间 > 所有静态资源请求处理时间。因此我们在开发者工具 Network 中,常常能看到,页面的所有静态资源请求都已经全部响应完成,但是部分依赖仍然在请求状态中。此时性能瓶颈在依赖预构建,直到依赖的请求全部响应,页面才展示。
- 非首次启动 Vite 时,由于有缓存,不需要依赖预构建,这时候首屏的主要耗时在静态资源的文件转换
总结
从整个 Vite 的运行流程可以看出,Vite 的启动速度,仅仅是把构建的过程,放到 DevServer 启动之后,构建的时间并没有减少,因此 Vite 也导致了 Vite 的首屏性能不好。
但 Vite 其实已经做了很多的努力了,使用了预构建缓存,运行时的模块转换的缓存,这一些列的措施,是我们在后续开发中的页面性能有了较大的提升。
如果这篇文章对您有所帮助,可以点赞加收藏👍,您的鼓励是我创作路上的最大的动力。也可以关注我的公众号订阅后续的文章:Candy 的修仙秘籍(点击可跳转)
关联阅读
更多内容可以查看我的专栏:《Vite 设计与实现》