Skip to content

Vite 核心原理

开发环境:基于原生 ESM

Webpack 在开发时需要抓取整个应用的依赖图并进行打包,而 Vite 跳过了此步骤。

  • 利用原生 ESM:现代浏览器支持 importexport 语法。Vite 启动时,只启动一个简单的 HTTP 服务器,不进行打包。
  • 按需请求:当你打开页面时,浏览器请求哪个文件,Vite 就会实时转换并返回哪个文件。
    • 例如:你请求 App.vueVite 会在后台调用 Vue 编译器把它转换为 JS,然后丢给浏览器。
  • 依赖预构建:为了解决 CommonJS 兼容性和上百个小文件请求过慢的问题,Vite 会在初始启动时使用 esbuildnode_modules 中的第三方库(如 Reactlodash)预先打包成一个大的 ESM 包。

💡 提示esbuild 是使用 Go 语言编写的,速度比传统 JS 编写的打包工具快很多。

生产环境:基于 Rollup

虽然开发环境不打包,但是为了生产环境的性能(减少 HTTP 请求、代码压缩、Tree Shaking),Vite 在执行 vite build 时依然会进行打包。

  • 核心引擎Vite 在生产环境使用 Rollup 进行打包。
  • 为什么用 RollupRollup 在处理 ESM 模块、Tree Shaking 和生成小体积包方面非常成熟且高效。
  • 插件兼容Vite 设计了一套兼容 Rollup 的插件接口,这意味着很多 Rollup 的插件可以直接在 Vite 中使用。

热更新(HMR)的底层差异

WebpackVite 在热更新(HMR)的底层实现上存在显著差异:

  • Webpack:当你修改一个文件时,Webpack 需要重新计算依赖图。即使有缓存,随着项目增大,速度也会变慢。
  • Vite:由于基于原生 ESMVite 只需要让浏览器重新请求那个改变的文件即可。无论项目多大,热更新速度几乎是恒定延迟

为什么预构建要用 esbuild

  • 编译语言优势:传统的打包工具如 WebpackRollup 都是用 JavaScript 编写的。JS 作为解释性语言,存在垃圾回收和 JIT 编译的开销。而 esbuild 是用 Go 语言编写的,直接编译成机器码,能够充分利用多核 CPU 的并行能力。
  • 性能优势:在处理大型依赖库时,esbuild 的速度通常是 WebpackRollup 的 10 到 100 倍。

依赖预构建的目的

  1. CommonJS 转 ESM: 很多旧的 npm 包依然是 CommonJS 规范的,而浏览器不支持 CommonJS 规范,因此需要将 CommonJS 规范的代码转换为 ESM 规范的代码。
  2. 减少网络请求(Bundle 瘦身): 有些库内部由几百个小文件组成,如果直接请求,会触发几百个 HTTP 请求,导致网页加载较慢。esbuild 会把这些小文件打包成一个大文件,显著减少 HTTP 请求次数。

为什么生产环境不用 esbuild

生产环境并不在乎打包花多少时间,而是更在乎最终生成的代码体积有多小

  • Rollup:它是 Tree Shaking 的鼻祖,能够精准地分析哪些是没用的代码。在 CSS 拆分、代码分割和公共提取方面非常成熟。
  • esbuild:虽然也有这些功能,但相对来说还不够成熟,生成的代码质量和体积不如 Rollup 优化得极致。

Rollup 拥有一个庞大且稳定的插件生态系统,而 esbuild 还在完善中。对于很多复杂的构建场景,Rollup 的插件系统能够灵活地满足需求。