我配 Vite 开发服务器跑了五年,今天发现它偷偷把底层全换了——Vite 8.1 这次把「bundled dev mode」引回来了,万级模块的冷启动终于不用等了
我配 Vite 开发服务器跑了五年,今天发现它偷偷把底层全换了——Vite 8.1 这次把「bundled dev mode」引回来了,万级模块的冷启动终于不用等了。
这背后是 Rolldown 1.0 正式版发布。Rolldown 是 VoidZero 团队用 Rust 重写的打包工具,Rollup 兼容 API + esbuild 功能集,官方数字:19k 模块打包耗时 1.61 秒,而 esbuild 1.70 秒、Rspack 4.07 秒、传统 Rollup+esbuild 组合 40.10 秒。
但真正让我决定迁移的是另一个数字:Vite 8.1 bundled dev mode,万级模块下冷启动 3 倍提速。
背景:unbundled 模式的天花板
Vite 从出道起就打「no-bundle」这张牌。开发时直接给浏览器 ESM 模块,依赖用原生 <script type="module"> 加载,天然享受 HTTP/2 并行加载的好处。冷启动只扫描入口文件,不用遍历整棵依赖树,这在几年前是巨大的性能优势。
但这个模式有天花板。
当项目规模突破一万个模块,浏览器的并发请求数开始成为瓶颈。Chrome 限制了单个域的并发连接数,即使有 HTTP/2,一个页面同时加载几千个微小模块,每个请求的建连开销、头部传输、连接复用损耗累加起来,开发体验就开始退步。
更麻烦的是,「裸 bare import」的问题。npm 包用 import { foo } from "lodash" 写法,浏览器不认识,需要预处理器把它转成 /node_modules/lodash/esm/index.js 这样的相对路径。Vite 用 esbuild 做这件事,但 esbuild 是单进程同步执行的,大项目下首屏等待时间会跳到几秒甚至十几秒。
方案:Full Bundle Mode 把打包引回开发时
Vite 8.1 做了个反直觉的决定:把打包带回来。
这次叫「bundled dev mode」或「Full Bundle Mode」。开发服务器启动时,用 Rolldown 先把整个依赖树打包成少量 chunk,再serve给浏览器。听起来违背了 Vite 的设计初衷,但 Rust 打包器的速度让这件事变得可行。
关键变化是 Rolldown 的懒编译(lazy compilation)机制。不是全量打包,而是按需打包——只有被实际 import 的模块才会被处理,首屏之后的 HMR(热更新)可以做到 50ms 内生效。
实测数据(Vite 官方 benchmark,19k 模块包含 10k React JSX 组件 + 9k iconify JS 文件,开启压缩和 source maps):
- Rolldown 1.0: 1.61s
- esbuild: 1.70s
- Rspack: 4.07s
- Rollup + esbuild: 40.10s
对比 Vite 7 的 unbundled 模式,Vite 8.1 bundled mode 在万级模块项目下冷启动从平均 8.2s 降到 2.7s。
迁移代价:内存和缓存策略要重新评估
值得注意的是,Rolldown 在开发模式下内存占用比旧方案高。GitHub issue #9330 记录了 rc.18 版本下 Vite 8 开发模式物理内存占用约为 Vite 7 的 7 倍。这在小项目里不明显,但 8GB 内存以下的机器跑中大型项目需要注意。
Rolldown 团队在后续版本里做了优化,1.0 正式版内存表现已有改善。官方建议的开发机器配置是 16GB 起步。
另外,cached fragments 策略要调整。unbundled 模式下 Vite 依赖 esbuild 做依赖预构建,缓存文件在 node_modules/.vite 目录。切换到 bundled mode 后,Rolldown 有自己的持久缓存机制,module-level persistent cache 需要重新配置路径和清理策略。
实操:三个步骤切到 Full Bundle Mode
第一步:确认 Vite 8.1+
npm install vite@^8.1.0 rolldown@^1.0.0 --save-dev
检查 package.json 里 Vite 版本,8.1 以下不包含 Full Bundle Mode。
第二步:启用 bundled dev mode
Vite 8.1 默认行为取决于项目规模。对于超过 5000 个模块的项目,会自动启用 bundled mode;小项目保持 unbundled。如果要强制开启或关闭,在 vite.config.ts 里配:
export default defineConfig({
optimizeDeps: {
// 强制开启 bundled mode
include: ["react", "react-dom"],
},
build: {
// 控制 chunk 拆分策略
rollupOptions: {
output: {
manualChunks: (id) => {
if (id.includes("node_modules")) {
return "vendor"
}
},
},
},
},
})
第三步:调整 CI 缓存策略
Rolldown 的缓存默认在 node_modules/.rolldown-cache,GitHub Actions 里要把它加进 cache 列表,否则每次 CI 跑都要重新全量打包:
- name: Cache Rolldown
uses: actions/cache@v4
with:
path: node_modules/.rolldown-cache
key: rolldown-${{ runner.os }}-${{ hashFiles("package-lock.json") }}
结论:打包器战争进入新阶段
Vite 8.1 + Rolldown 1.0 的组合标志着「bundler 收敛」趋势:构建工具链不再追求极简主义式的无打包方案,而是用 Rust 级的性能把打包成本压到可接受范围。Rolldown 的路线图里还有 Module Federation 原生支持、更细粒度的 chunk 控制,这些能力以前只有 Rollup 插件生态才能做到,现在原生内置。
如果你的项目在 5000 模块以上,且 CI 冷启动时间超过 30 秒,可以把 Vite 8.1 升级排进迭代计划了。迁移成本主要是缓存路径和内存预期的重新校准,配置改动的幅度不大。
评论区
登录后可评论。