Vite 核心原理
开发环境:基于原生 ESM
Webpack 在开发时需要抓取整个应用的依赖图并进行打包,而 Vite 跳过了此步骤。
- 利用原生 ESM:现代浏览器支持
import和export语法。Vite启动时,只启动一个简单的 HTTP 服务器,不进行打包。 - 按需请求:当你打开页面时,浏览器请求哪个文件,
Vite就会实时转换并返回哪个文件。- 例如:你请求
App.vue,Vite会在后台调用Vue编译器把它转换为JS,然后丢给浏览器。
- 例如:你请求
- 依赖预构建:为了解决
CommonJS兼容性和上百个小文件请求过慢的问题,Vite会在初始启动时使用esbuild将node_modules中的第三方库(如React、lodash)预先打包成一个大的ESM包。
💡 提示
esbuild是使用Go语言编写的,速度比传统JS编写的打包工具快很多。
生产环境:基于 Rollup
虽然开发环境不打包,但是为了生产环境的性能(减少 HTTP 请求、代码压缩、Tree Shaking),Vite 在执行 vite build 时依然会进行打包。
- 核心引擎:
Vite在生产环境使用Rollup进行打包。 - 为什么用
Rollup:Rollup在处理ESM模块、Tree Shaking和生成小体积包方面非常成熟且高效。 - 插件兼容:
Vite设计了一套兼容Rollup的插件接口,这意味着很多Rollup的插件可以直接在Vite中使用。
热更新(HMR)的底层差异
Webpack 和 Vite 在热更新(HMR)的底层实现上存在显著差异:
- Webpack:当你修改一个文件时,
Webpack需要重新计算依赖图。即使有缓存,随着项目增大,速度也会变慢。 - Vite:由于基于原生
ESM,Vite只需要让浏览器重新请求那个改变的文件即可。无论项目多大,热更新速度几乎是恒定延迟
为什么预构建要用 esbuild
- 编译语言优势:传统的打包工具如
Webpack、Rollup都是用JavaScript编写的。JS作为解释性语言,存在垃圾回收和JIT编译的开销。而esbuild是用Go语言编写的,直接编译成机器码,能够充分利用多核CPU的并行能力。 - 性能优势:在处理大型依赖库时,
esbuild的速度通常是Webpack或Rollup的 10 到 100 倍。
依赖预构建的目的
- CommonJS 转 ESM: 很多旧的
npm包依然是CommonJS规范的,而浏览器不支持CommonJS规范,因此需要将CommonJS规范的代码转换为ESM规范的代码。 - 减少网络请求(Bundle 瘦身): 有些库内部由几百个小文件组成,如果直接请求,会触发几百个
HTTP请求,导致网页加载较慢。esbuild会把这些小文件打包成一个大文件,显著减少HTTP请求次数。
为什么生产环境不用 esbuild
生产环境并不在乎打包花多少时间,而是更在乎最终生成的代码体积有多小。
- Rollup:它是
Tree Shaking的鼻祖,能够精准地分析哪些是没用的代码。在CSS拆分、代码分割和公共提取方面非常成熟。 - esbuild:虽然也有这些功能,但相对来说还不够成熟,生成的代码质量和体积不如
Rollup优化得极致。
Rollup 拥有一个庞大且稳定的插件生态系统,而 esbuild 还在完善中。对于很多复杂的构建场景,Rollup 的插件系统能够灵活地满足需求。