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 编写的打包器) 来执行预构建。

  1. 扫描:Vite 会自动扫描入口文件中所引用的所有依赖 (import 'react')。
  2. 构建:Esbuild 将这些依赖打成一个个单独的大文件 (ESM 格式)。
    • my-component -> node_modules/.vite/deps/my-component.js.
    • CommonJS 代码会自动转换为 ESM。
    • 多依赖合并为一个请求。
  3. 缓存:构建结果将被强缓存 (Header: Cache-Control: public, max-age=31536000, immutable)。

(3) 如果依赖的代码更新了怎么办?

  • Lockfile 校验:Vite 会生成 package-lock.jsonyarn.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.