Vite 预构建
开发阶段 Vite 会对项目中使用的第三方依赖如 lodash-es 等做预构建操作。
之所有要做预构建,是因为Vite是居于浏览器原生的ESM规范来实现的,这就要求整个项目的代码必须符合ESM规范。
而我们在开发中无法保证第三方依赖依赖会严格按照ESM规范来做,所以这就需要我们通过预构建功能将非ESM规范转为符合ESM规范的代码。
另外,就算有些第三方依赖已经符合ESM规范,但它可能由多个子文件组成,如lodash-es,如果不做处理直接使用,那么就会引发请求瀑布流(如果对lodash-es进行处理, 那么浏览器会发起几百次请求),这将会非常影响页面性能,因此,通过Vite的预构建功能,将第三方依赖内部的多个文件合并为一个,来减少http请求的数量,从而优化页面加载速度。
综上所述,预构建主要做了两件事:
1. 将非ESM规范的代码转成符合ESM规范的代码
2. 将第三方依赖内部的多个文件合并为一个,减少http请求数量
示例:
在vite.config.ts配置文件中,我们将optimizeDeps.exclude的值设置为['lodash-es'],也就是说我们将不对lodash-es进行预构建
export default defineConfig({
plugins: [vue()],
optimizeDeps: {
exclude: ['lodash-es']
},
})
发送请求如下:
如果我们将optimizeDeps去掉,Vite默认会对第三方依赖进行预构建,发送请求次数如下:
对比可发现,进行预构建的效果是非常显著的。
默认情况下,预构建结果会保存到 node_modules 的 .vite/deps 目录下。
当我们重复启动项目时,那么 Vite 会复用上一次预构建的结果。如果不想让 Vite 复用上一次预构建的结构,我们可以配置 optimizeDeps.force 为 true,使得 dev server 每次启动的时候都强制进行预构建。
Vite是怎么做到快速识别项目中的第三方依赖呢?
预构建,最关键的一步就是找到项目中所有的第三方依赖。 那 Vite 是怎么做到快速获取项目中所有的第三方依赖呢?
Vite 借助 ESbuild 快速打包的能力,对整个项目进行一个全量打包,打包的时候通过分析 依赖关系,得到项目中所有源文件的URL,然后分离出第三方依赖,流程大致如下:
- 找到入口文件
entry对应的url, 这个url一般为相对路径; - 将
url解析为绝对路径,找到源文件在本地磁盘的位置,并构建一个module对象; - 读取源文件的内容;
- 将源文件内容解析为
AST对象,分析AST对象,找到源文件中的静态依赖(import xxx from 'xxx') 和动态依赖(import('xx'))对应的url, 并收集到module对象中; - 遍历第 4 步收集到的
静态依赖、动态依赖对应的url,重复 2 - 5 步骤,直到项目中所有的源文件都遍历完成。
这样,Vite 就可以对找到的第三方依赖做转化、合并操作了。
预构建功能非常棒,但在实际的项目中,并不能保证所有的第三方依赖都可以被找到。如果出现下面的这两种情况, Esbuild 也无能为力:
plugin在运行过程中,动态给源码注入了新的第三方依赖;动态依赖在代码运行时,才可以确定最终的url;
当出现这两种情况时,Vite 会触发二次预构建:
plugin在运行过程中,动态给源码注入了新的第三方依赖;动态依赖在代码运行时,才可以确定最终的url;
作者:百应前端团队
链接:juejin.cn/post/712821…
来源:稀土掘金