去年年底我们做了一件拖了两年的事:把团队 30 个中后台项目从 webpack 4 迁到 Vite 5。不是新项目试点,是存量项目全量换底座。三个月里我踩的坑,大概够写一篇长文,这里挑最值钱的部分记下来。
先说结论:收益是真的,但收益不在「构建更快」,而在「改一行代码到看到结果只要 200ms」这件事改变了写代码的手感。 至于迁移成本,跟项目的「野」程度强相关,跟你项目大小关系不大。
一、先量一量,别凭感觉迁
动手前我写了个脚本,把 30 个项目按四个维度打了分:
| 维度 | 判断方式 | 风险 |
|---|---|---|
| 依赖体积 | node_modules 里 CJS 包占比 |
高 |
| 动态引用 | require( 变量 ) 出现次数 |
高 |
| 自定义 loader | 自研 loader / 特殊 webpack 插件 | 高 |
| 环境判定 | process.env.* 出现次数 |
中 |
最后只有 9 个项目是「低风险」,可以直接换。剩下 21 个,得先做改造再迁移。这一步花了两周,但它决定了后面不会出现「迁到一半发现某个包根本跑不起来」的尴尬。
二、冷启动从 42s 到 3.4s,代价是首屏多了一次请求
webpack 时代,最大的项目冷启动 42s,改一个文件 HMR 1.8s。Vite 下分别是 3.4s 和 200ms 左右。
但 Vite 的「快」是把编译推迟到了浏览器请求时。开发环境里,首屏会看到一大堆 module 请求瀑布。项目里有 200+ 路由懒加载时,这个瀑布会很明显。我们的做法是:
ts
// vite.config.ts
export default defineConfig({
server: {
warmup: {
// 预热首页和登录后必到的几个页面
clientFiles: ['./src/pages/home/index.tsx', './src/pages/login/index.tsx'],
},
},
})
配合 optimizeDeps.include 把高频依赖预构建,首屏瀑布能压掉一半左右。
三、CJS 依赖:最烦的不是报错,是报错很晚
webpack 对 CJS 的兼容是「顺手就做了」,Rollup 不是。表现是:构建能过,运行时报 Cannot read properties of undefined。
三个必须提前处理的点:
- Node 内置模块 。老代码里
import path from 'path'、process.cwd()到处都是,浏览器里没有。要么 polyfill,要么在define里塞进去:
ts
define: {
'process.env': JSON.stringify({}),
__dirname: JSON.stringify('/'),
}
- 动态 require 。
require('./locales/' + lang)这种,Rollup 静态分析不出来。改成import.meta.glob:
ts
const modules = import.meta.glob('./locales/*.json', { eager: true })
const dict = modules[`./locales/${lang}.json`].default
- default 互操作 。
import _ from 'lodash'在某些 CJS 包里拿到的是 module 对象而不是函数。@rollup/plugin-commonjs的requireReturnsDefault: 'auto'能救一部分,剩下的只能一个个改。
四、真正难的是灰度,不是编译
30 个项目不可能一次性全切。我们的方案是双构建并行 + 入口分流:
- webpack 构建产物仍然发布,Vite 产物发布到独立的静态目录;
- 网关按
用户 ID hash % 100决定这次请求返回哪份index.html; - 灰度比例 1% → 5% → 20% → 50% → 100%,每档观察 24 小时的 JS 错误率和首屏 P75。
关键是回滚要能在 1 分钟内完成。因为只是改网关的分流规则,回滚就是改一个比例数字,比回滚代码发布快得多。这条比任何优化都重要------它让我们敢在白天灰度。
五、几个事后才明白的事
- 别在迁移期间顺手升级依赖。两个变量一起动,出问题定位成本翻倍。
vite build和vite dev是两套行为。dev 下能跑不代表 build 后能跑,CI 里必须跑一次完整构建 + 冒烟。- 产物体积不一定会变小 。Rollup 的 tree-shaking 更彻底,但 chunk 切分策略不同,某些项目产物反而大了 5%。需要重新调
manualChunks。 - 团队心智成本被低估了 。
public/与src/assets的引用规则、index.html变成入口,这些小事每个人都会问一遍。我们写了一页「Vite 速查」贴在群里,省了大量重复答疑。
写在最后
迁完之后,最直观的变化不是构建时间,是「保存即刷新」带来的一种心理上的轻松:改样式不用等,改逻辑不用猜。这种手感上的收益,是很难用数字汇报、但每个人都能感知到的。
如果你们也在评估,我的建议是:先挑一个最野的项目做,把它做成模板;剩下的项目迁移就是复制粘贴加改配置。 反过来先拿最简单的项目试点,会得到一个「看起来很顺利」的假象。