Vite(法语意为“快”)是一个基于浏览器原生 ES Modules(ESM)的下一代前端构建工具,它的核心设计理念可以用一句话概括:开发环境直接利用浏览器支持 ESM 的能力,无需打包即可启动;生产环境交给 Rollup 进行最优打包。这种“开发用原生、构建用打包”的架构,彻底改变了传统打包工具(如 Webpack)先打包后服务的模式,从而获得极致的启动速度和热更新体验。
21.3.1 基于 ESM 的开发服务器
在 Vite 的开发模式下,它启动一个本地服务器,不会先对整个项目进行打包。当浏览器解析到 <script type="module"> 时,会按照 ESM 规范去请求对应的模块文件。
Vite 服务器会做两件事:
- 拦截浏览器发出的模块请求,找到对应的源文件,然后按需编译并返回。浏览器的每一次模块请求都只触发单个文件的实时编译(通常通过 esbuild 完成,esbuild 是用 Go 语言编写的极快编译器),整个应用不会因为依赖了上百个文件就全部打包一次。
- 将非 JS 模块转换为 ESM,比如对
.ts、.jsx、.vue等文件进行即时转译,对 CSS 文件包装成 JS 模块注入,确保每个文件都以标准 ESM 格式返回。
由于不需要构建整个依赖图,开发服务器几乎是秒级启动。一个包含数百个组件的项目,Vite 的冷启动时间通常不超过一秒,而 Webpack 可能需要几十秒甚至更长。
21.3.2 预构建机制
虽然 Vite 在开发时对源码采用按需编译,但第三方依赖(node_modules)通常包含大量文件且格式复杂(可能是 CommonJS、UMD 或大量 ESM 子模块)。直接让浏览器逐个请求,会产生过多的 HTTP 请求并且容易遇到兼容性问题。
Vite 的解决方案是预构建:
- 在首次启动时,使用 esbuild 将
node_modules中的依赖打包成单个 ESM 文件,并缓存到node_modules/.vite目录下。 - 后续浏览器只需要请求这一个(或少数几个)经过优化打包的模块,极大减少网络请求。同时,预构建也解决了 CommonJS 转 ESM 的问题,让浏览器可以正常加载。
预构建过程非常快,因为 esbuild 的打包速度比传统工具快 10-100 倍。Vite 还会对构建结果做强缓存(通过 HTTP 缓存头),除非依赖版本变化,否则不会重新执行预构建。
21.3.3 热模块替换(HMR)
Vite 的 HMR 同样建立在 ESM 基础之上。当一个文件被修改时,Vite 只会关闭与该模块相关的部分请求,向浏览器推送一个精准的更新指令。浏览器收到后,按需重新请求相关模块并替换,不需要刷新整个页面。
由于依赖图是浏览器通过 ESM 边请求边构建的,Vite 能够精确定位受影响的最小模块链,并且不需要像 Webpack 那样维护一套 HMR Runtime 和跨模块的依赖映射关系,因此 HMR 速度基本不受项目规模影响,通常毫秒级即可完成更新。
21.3.4 生产构建:Rollup
到了生产环境,浏览器原生 ESM 请求的方案不再适用——大量未打包的模块会带来数百甚至数千个 HTTP 请求,严重影响加载性能。所以 Vite 的生产构建使用 Rollup 进行打包优化。
Rollup 基于 ESM 静态分析,具备极佳的 Tree Shaking 能力和灵活的插件生态,能够输出高度优化的产物。Vite 为生产构建预设了一套合适的多入口、代码分割、资源处理等逻辑,开发者通常无需额外配置即可得到最佳产物体积。
为什么要开发用 esbuild,构建用 Rollup?
- esbuild 虽然编译、转译极快,但它是为速度而非优化产物体积设计的,其代码分割能力和对部分高级语法(如 CSS Module 的某些场景)的支持不如 Rollup 完善。
- Rollup 经过多年迭代,在生产环境下可以做到极致的体积优化,并且 Vite 基于 Rollup 的插件体系可以复用大量生态插件。
因此,Vite 做了一次清晰的“各取所长”:开发阶段用 esbuild 保证速度,生产阶段用 Rollup 保证质量。
21.3.5 与 Webpack 的核心差异
| 对比维度 | Vite | Webpack(及同类打包器) |
|---------|------|------------------------|
| 开发启动 | 秒级,不对源码打包,利用浏览器 ESM 按需请求 | 需要先打包整个应用,冷启动时间长,项目庞大后尤为明显 |
| 热更新 | 极快,与项目大小关系不大,基于原生 ESM 精准更新 | 随着项目增长,需要重新构建变更模块的依赖图,速度可能变慢 |
| 依赖处理 | 用 esbuild 预构建 node_modules 为 ESM,快速且缓存 | 将所有依赖一起打包进 bundle,可能重复处理未变更的依赖 |
| 底层语言 | 关键部分用 Go (esbuild) 和 Rust 编写,性能极高 | 核心用 JavaScript 编写,虽然做了大量优化,但速度存在天花板 |
| 生产构建 | 使用 Rollup,产物体积优秀,配置高度封装 | 自建打包引擎,功能全面但配置复杂,插件与 loader 繁多 |
| 学习成本 | 开箱即用,配置文件简洁,隐藏了大量 Rollup 复杂性 | 灵活但概念多(entry、loader、plugin、chunk、module federation),容易让新手迷失 |
简单来说,如果你追求开发体验的流畅性,Vite 是当下最前沿的选择;如果你的项目已经深度依赖 Webpack 生态,迁移需要评估成本。
21.3.6 实际使用中的注意事项
- 浏览器兼容性:Vite 开发环境要求浏览器支持原生 ESM,现代浏览器均已支持,但仍需在生产构建中通过
@vitejs/plugin-legacy等方案产出兼容旧浏览器的产物。 - CommonJS 依赖:虽然 Vite 会预构建,但少数纯 CommonJS 模块的依赖可能无法被 esbuild 正确处理,需要手动配置优化。
- 环境差异:开发环境和生产环境底层机制不同(一个靠 esbuild,一个靠 Rollup),极少数情况下可能会导致行为不一致,比如对某些导入的处理,这时需要检查插件兼容性。
- Vite 适用场景:绝大多数新项目(尤其 Vue/React 项目)都强烈推荐使用 Vite;对于需要高度自定义构建流程的大型工程,Vite 插件生态也已足够丰富。
21.3.7 小结
Vite 不是另一种“打包器”,而是一个开发-构建一体化的前端工具平台。它用两套引擎解决了“开发快”和“构建好”的矛盾,让开发者可以享受到即时启动、即时生效的开发体验,同时在生产环境获得高质量的优化输出。理解这一原理,你就掌握了现代前端工程化的一个重要演进方向。