Vite、Webpack 与现代构建链路
📦 构建工具负责把源码、依赖和静态资源转换为浏览器可高效加载、适合部署并便于调试的产物。
现代构建链路
典型阶段:
- 读取配置与环境变量
- 解析模块入口和依赖图
- 转译 TypeScript / JSX / 新语法
- 处理 CSS、图片和其他资源
- Tree Shaking、代码分割与压缩
- 生成 sourcemap、hash 文件名和资源清单
- 开发服务器提供 HMR
Vite 的核心思路
开发环境利用浏览器原生 ESM,按需转换源码;依赖通常预构建以减少请求数量和兼容 CommonJS。生产构建使用 Rollup 生态完成打包与优化。
优势:
- 冷启动快
- 按需编译
- HMR 粒度细
- 配置简洁,适合现代浏览器项目
Webpack 的核心思路
Webpack 从入口构建完整依赖图,通过 loader 转换不同模块,通过 plugin 介入编译生命周期,再生成 bundle 和 chunk。
适合场景:
- 大型遗留工程
- 高度定制的资源处理链
- 已沉淀丰富 loader / plugin 的项目
- 需要精细控制模块联邦等复杂架构
关键概念对照
| 概念 | Vite / Rollup | Webpack |
|---|---|---|
| 转换 | Plugin transform | Loader |
| 生命周期扩展 | Plugin hooks | Plugin + compiler hooks |
| 开发模式 | 原生 ESM 按需转换 | 通常先构建依赖图 |
| 生产打包 | Rollup | Webpack 自身 |
| 代码分割 | 动态 import / manualChunks | 动态 import / splitChunks |
Tree Shaking
Tree Shaking 依赖静态 ESM 结构。要点:
- 使用
import/export。 - 避免顶层不可分析副作用。
- 库通过
sideEffects标注副作用文件。 - Babel / TypeScript 不应过早把 ESM 转为 CommonJS。
const Editor = () => import('./Editor')
动态 import() 会形成异步 chunk,但拆得过细也会增加请求和调度成本。
缓存策略
- 文件名使用内容 hash。
- HTML 通常短缓存或协商缓存。
- 带 hash 的静态资源使用长期不可变缓存。
- 运行时环境配置不要错误地固化进需要跨环境复用的 bundle。
环境变量与安全
前端环境变量最终可能进入客户端代码,不得保存密钥。Vite 的 import.meta.env 与 Webpack 的 DefinePlugin 本质上都是构建期替换。
常见问题
- 包中混合 ESM / CJS 导致默认导入差异。
- monorepo 中重复依赖或 symlink 解析不一致。
- sourcemap 泄露源码或未正确上传监控平台。
- chunk 拆分策略导致首屏 waterfall。
- HMR 正常但生产构建路径、base URL 或动态资源失败。
优化步骤
- 用可视化分析工具查看产物组成。
- 找出重复依赖和超大模块。
- 对重型、低频功能做路由或组件级懒加载。
- 验证压缩、缓存和 CDN 配置。
- 比较真实页面指标,而不仅是 bundle 大小。
工程检查清单
- 开发、测试、生产配置边界清晰
- 构建产物可复现
- sourcemap 策略与错误监控一致
- 长期缓存与版本回滚可用
- CI 中执行类型检查、测试和构建验证