Vite 预构建
1. 面试题
Q: 如果 Vite 不需要打包,那它如何处理 node_modules?为什么需要预构建?
2. 核心解答
预构建 (Pre-bundling) 是 Vite 启动开发服务器的第一步。
(1) 背景
- CommonJS 问题:很多旧的第三方库 (React, Lodash) 都是使用 CommonJS 规范编写的。而浏览器只认识 ESM。
- 性能问题:有些库 (lodash-es) 包含数百个小文件。如果没有预构建,浏览器为了加载这些模块,会发起数百次 HTTP 请求,导致严重的网络拥塞。虽然 HTTP/2 解决了队头阻塞,但大量请求的往返时间 (RTT) 依然很慢。
(2) 实现原理
Vite 使用 Esbuild (Go 编写的打包器) 来执行预构建。
- 扫描:Vite 会自动扫描入口文件中所引用的所有依赖 (
import 'react')。
- 构建:Esbuild 将这些依赖打成一个个单独的大文件 (ESM 格式)。
my-component -> node_modules/.vite/deps/my-component.js.
- CommonJS 代码会自动转换为 ESM。
- 多依赖合并为一个请求。
- 缓存:构建结果将被强缓存 (Header:
Cache-Control: public, max-age=31536000, immutable)。
(3) 如果依赖的代码更新了怎么办?
- Lockfile 校验:Vite 会生成
package-lock.json 或 yarn.lock 的 hash 值。只要 lock 文件没变,预构建结果就不会变。
- force:如果手动删除了
node_modules/.vite 目录,或者启动时加上 --force (例如 vite --force),Vite 就会强制重新预构建。
3. 面试加分项
Q: 为什么不用 Rollup 做预构建?
Rollup 处理大型依赖很慢。而 Esbuild 的预构建速度比 Rollup 快 10-100 倍。这对于冷启动体验至关重要。
4. 总结
- Reason: Format conversion (CJS -> ESM) & Performance (Request merge).
- Tool: Esbuild (Fast).
- Optimization: Strong caching, immutable.
- Trigger: Lock file change or force flag.