ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Vite 8换芯实测:Rolldown取代esbuild+Rollup,构建提速3.19倍

2026/9/11 11:57:33 拓冰建站 浏览量
Vite 8换芯实测:Rolldown取代esbuild+Rollup,构建提速3.19倍 上个月我把团队里一个压了很久的 monorepo 项目从 Vite 7 升到了 Vite 8。坦白讲刚看到 release note 里“Rolldown 已正式取代 esbuild Rollup 双引擎”这句话时我下意识是嘀咕的——毕竟双引擎架构已经跑了好几年大家早就习惯了 dev 用 esbuild、build 用 Rollup 的分工。但升级完在真实项目上连续跑了三轮构建生产构建耗时从原来的 42.6 秒直接压到 13.35 秒整整快了 3.19 倍。这个数字让我意识到这次“换芯”不是挤牙膏式的优化而是把 Vite 的构建骨架整个换掉了。这篇文章我不会从“Vite 是什么”讲起直接说 Vite 8 这次换芯换的到底是什么、Rolldown 为什么能快这么多、换完之后对现有插件和配置有什么影响以及我在一个 260 多个路由、800 多个依赖的真实后台项目上跑出来的数据。如果你正打算升级或者还在纠结要不要升这篇完全可以当成一份踩坑笔记参考。1. 双引擎时代Vite 为什么曾经“一拆二”1.1 开发模式和生产模式的分工Vite 能火起来核心是它把“开发体验”和“生产构建”两条链路分开设计。开发服务器用原生 ESM浏览器按需加载模块启动时只做依赖预构建把 node_modules 里的 CommonJS 依赖提前转成 ESM再用 esbuild 的转译速度处理 TS、JSX 这类需要编译的源码文件。这样做的直接好处是项目再大冷启动也能控制在秒级因为不会在启动时真的去打包全部源码只需要编 node_modules 里被引用的那一批包。生产构建就不一样了。要输出最终上线的文件必须做全量依赖图分析、tree-shaking、代码分割、chunk 合并、资源指纹和压缩。Vite 这一层的选择是 Rollup。Rollup 是 JavaScript 生态里打包器的老牌选手插件生态极其丰富产物规则可控能生成非常干净、可预测的 ESM 产物。但它的硬伤也很明显纯 JavaScript 实现处理大项目依赖图时所有遍历都是单线程的 JS 对象操作性能天然处于劣势。于是 Vite 形成了大家熟悉的“双引擎”格局esbuild 管开发阶段和依赖预构建Rollup 管生产打包生产阶段再调 esbuild 来压缩 JS。这个组合在当地时间是平衡速度与生态的最优解至今很多 Build 工具教程里还会让你装 esbuild 和 rollup 两套依赖。1.2 双引擎的心智负担与行为不一致双引擎最大的问题就是“分裂”。同一段代码在 dev 模式下由 esbuild 编译在生产模式下由 Rollup 加一堆插件编译结果很可能不一样。典型症状包括ESM 和 CJS 互操作的细节差异、动态 import 的解析结果不同、CSS 注入顺序改变甚至插件在 transform 阶段拿到的 sourcemap 格式都不同。开发时一切正常一打包体积突然暴涨或者某个依赖没被正确 tree-shake这类问题排查起来极其痛苦。插件体系也因此变得很拧巴。Vite 插件名义上兼容 Rollup 插件接口但同一个 hook 在 dev 和 build 两个阶段执行路径并不完全一致很多冷门插件只会在 build 下被触发。社区里不少插件作者抱怨过自己写一个 Vite 插件等于同时维护两套行为还得定期在两个引擎上做回归测试。这就是为什么 Rolldown 的出现对整个前端工具链是一次“掀桌子”级别的变化——不是再优化 esbuild 和 Rollup 的配合而是索性用一个新的引擎把两个都替掉。2. Rolldown 是什么Rust 重写打包器的底牌2.1 从 rolldown-vite 实验包到 Vite 8 正式合入Rolldown 是 VoidZero 团队主导的项目目标是用 Rust 重写一个 Rollup 兼容的打包器。Vite 6 时代它就以rolldown-vite实验包的形式出现过当时需要在 npm 里单独安装才能体验很多人只是跑个 demo 就感受到差异了。到 Vite 8Rolldown 终于被正式合入主线esbuild 和 Rollup 在 Vite 内部的“双引擎”宣告退役。这里有个关键点必须解释清楚Rolldown 要做的是“替换”不是“推倒重写”。因为 Vite 的插件 API 几乎就是 Rollup 的插件 API只要 Rolldown 在 API 层面兼容 RollupVite 生态里成千上万的插件就能平移过来用户侧的迁移成本才能降到最低。现在你在 Vite 8 里配置build.rollupOptions依然有效就是这个策略落地的结果。2.2 Rust 到底快在哪些环节打包过程里最吃性能的几个环节源码解析、依赖解析、模块图构建、tree-shaking、代码生成、压缩。Rollup 用 JavaScript 在单线程里做每个模块经过插件 hook 时都会产生大量函数调用、对象分配和垃圾回收。Rolldown 把这些流程几乎全部换成了 Rust 实现并且用多线程并行处理没有依赖关系的模块。光换语言不够它还复用了 Oxc 生态。Oxc 是 Rust 写的 JS/TS 工具集合包含 parser、transformer、resolver、minifier 等组件这些组件直接内嵌到 Rolldown 里省去了像 esbuild 那样作为独立服务进程的通信开销。我习惯用一个比喻Rollup 像人工流水线每个工位都要停下记录、检查、交接Rolldown 是自动化并行流水线工件以更高效率通过而且多个工件同时处理。这也是为什么项目越大、依赖越多提升越明显。2.3 插件兼容并不是“零成本”Rolldown 保留了绝大多数 Rollup 和 Vite 插件 hook纯转换类插件基本都能直接跑。但有两种情况要特别小心一是依赖 Rollup 内部对象或非公开 API 的插件二是深度依赖renderChunk、augmentChunkHash这类输出阶段 hook 的插件。Rolldown 的执行上下文和传参对象结构跟 Rollup 存在差异这些插件可能要等作者跟进适配。在实际项目中如果你用的是vitejs/plugin-react、vitejs/plugin-vue、unplugin-auto-import、unplugin-vue-components这类主流插件升级后基本无感。但如果项目里躺着一两个几年前写的、只在公司内部用的私有插件那升级前就要把这些插件的适配情况列个清单。3. 实测记录真实项目从 Vite 7 升到 Vite 83.1 测试项目与硬件说明先说测试对象。这是一个企业后台 monorepo用 pnpm workspace 管理包含admin-web、shared-components、api-sdk三个包。技术栈是 React 18 TypeScript 5.6 antd 5 less页面路由 260 个左右依赖总数量 850 个。项目中用vite-plugin-svg-icons做 svg 图标自动注册这部分对构建阶段的资源处理有额外开销。硬件环境是 MacBook Pro 14 英寸M3 Pro 芯片32GB 内存Node 22.14 LTS。我特意把电脑重启后关掉多余进程再测每个环节跑三遍取中位数尽量排除系统状态带来的误差。3.2 三个关键环节的耗时对比指标Vite 7esbuild RollupVite 8Rolldown提升倍数冷启动 dev server含依赖预构建6.8s2.4s约 2.8 倍依赖预构建单独耗时4.2s1.1s约 3.8 倍首次热更新触发组件失效后重建2.1s0.8s约 2.6 倍生产构建总耗时42.6s13.35s约 3.19 倍构建产物 gzip 总体积4.18MB4.20MB基本持平3.3 3.19 倍是怎么算出来的标题里的 3.19 倍指的是生产构建耗时。Vite 7 下完整打包是 42.6 秒Vite 8 下是 13.35 秒两者一除就是约 3.19。生产构建提升最猛不难理解——这是全量重负载场景要遍历每个模块、执行完整的插件流水线、生成 chunk这些恰恰是 JavaScript 单线程最吃力的地方。Rolldown 全程走 Rust瓶颈直接被拿掉了。需要提醒的是这个倍数会随项目规模变化。小型 demo 项目提升可能只有 1.5 到 2 倍因为总耗时基数太小很多固定开销摊不掉超大项目比如 1000 个路由以上的中后台我看到社区里有人测出 4 倍以上的提升。大家看评测数据时最好结合自己的项目规模来判断。4. 迁移到 Vite 8配置与代码改动清单4.1 真正不用改的部分多数项目升级其实只做两件事换依赖重启。以我们的项目为例先执行pnpm up vite vitejs/plugin-react vitejs/plugin-react-swc pnpm install然后把 Node 版本确认到 Vite 8 要求的最低线以上。旧配置里build.rollupOptions只要不是用了特别冷门的 Rollup 内部 API基本可以原样保留。像manualChunks、external、output.chunkFileNames这些常用配置Rolldown 都做了兼容。我们迁移时最省心的是unplugin-auto-import和unplugin-vue-components如果用的是 Vue 项目这类插件它们在新引擎下表现稳定没有出现自动化注册失效的情况。4.2 需要重点检查的四个地方第一处是minify配置。Vite 旧版本默认用 esbuild 压缩 JS很多老项目会显式写成minify: terser追求更高压缩率。到 Vite 8默认压缩引擎换成了 Rust 生态里的 oxc minifier速度和压缩率都更平衡。如果你之前显式指定了 terser就要重新评估产物差异。terser 能做到的理论压缩率通常还是最高的但耗时会明显增加esbuild 快但产物略大oxc 压缩率接近 terser 且速度极快是大多数场景下的合理默认值。第二处是依赖预构建相关配置。以前的optimizeDeps.esbuildOptions是为 esbuild 预构建准备的换引擎后这一类配置基本失效该清理就清理。项目里如果有optimizeDeps.force这类为了修复缓存问题而加的配置建议先删掉跑一遍看是否还需要。第三处是 CSS 处理。Vite 8 里 CSS 压缩可以走cssMinify: lightningcss这是一条新路。如果你用了 PostCSS 插件比如autoprefixer我建议保留 PostCSS 链路把cssMinify设成lightningcss时要注意它和个别 PostCSS 插件会不会重复处理一些属性前缀。第四处是manualChunks的写法。Rolldown 对模块 ID 字符串的处理更严格有些旧的正则匹配可能需要微调。我们项目里有一个基于路径拆分 vendor 的逻辑升级后 vendor 命名多了一层目录前缀花了几分钟改正则才恢复正常。4.3 一个可直接参考的 Vite 8 配置示例import { defineConfig } from vite import react from vitejs/plugin-react import { fileURLToPath } from node:url export default defineConfig({ plugins: [react()], build: { minify: oxc, cssMinify: lightningcss, rollupOptions: { output: { manualChunks(id) { if (id.includes(node_modules)) { if (id.includes(react) || id.includes(scheduler)) { return react-vendor } if (id.includes(antd) || id.includes(ant-design)) { return antd-vendor } return vendor } } } } }, // rolldownOptions 在 Vite 8 下开放了部分引擎级配置 // 具体字段以你当前小版本的类型声明为准 rolldownOptions: { output: {} } })注意如果你的 CI 里长期缓存在旧版本 Vite 下生成的.vite缓存目录升级后第一次构建最好rm -rf node_modules/.vite清一次缓存避免 Rolldown 读取到旧引擎留下的中间产物。5. 常见问题排查与避坑实录5.1 插件在 Rolldown 下悄悄失效我们内部有一个 i18n 文案提取插件钩住 transform hook 收集中文文案。Vite 7 里跑得好好的升到 Vite 8 后文案死活收集不全。排查时先开启了调试日志命令是DEBUGrolldown* pnpm build看到日志后才发现这个插件依赖的模块在 Rolldown 的依赖图里被判定为“未被实际引用”在 transform 阶段之前就被裁剪了。解决方式是把信息收集逻辑从前置的 transform 挪到buildStart或moduleParsed钩子里才能拿到完整的模块列表。这类问题最隐蔽因为它不会报错只是数据少了。5.2 打包产物 chunk 数量和体积变化Rolldown 的 chunk 合并策略跟 Rollup 不完全一样默认的minChunkSize和合并粒度有差异。同一个项目Rollup 打出来 47 个 chunkRolldown 打出来 39 个体积基本持平。如果你的项目依赖强缓存策略并且文件名里不带 hash建议升级后在 CI 里重新固定一次基线。如果不需要固定文件名那 hash 变化反而是正常的。5.3 内存峰值上升与 CI 内存不足多线程并行带来的副作用是内存峰值升高。我们本地 32GB 内存几乎无感但 CI 的 8GB 容器在构建时出现了两次 OOM。这种情况优先考虑降低并发Vite 8 的rolldownOptions暴露了与并发 worker 相关的实验性字段不同小版本字段位置可能不一样直接查你当前安装版本的类型定义最准确。其次是给 Node 进程加大内存限制或者把 CI 构建机的内存规格往上提一档。5.4 CSS 样式覆盖顺序变化我们项目里有用 less 写主题变量的场景升级后出现了一个全局样式的覆盖顺序被改变的问题。原因是 CSS 注入阶段对模块遍历顺序的处理变了部分import和组件内样式之间的先后关系跟 Rollup 时代不同。排查方法是在首屏页面对比 Vite 7 和 Vite 8 生成的 style 标签顺序找到差异后用css.preprocessorOptions里的 additionalData 统一注入公共变量把顺序依赖降到最低。5.5 遇到疑似 Bug 怎么高效反馈Rolldown 还在快速迭代阶段遇到问题别急着降级。先在 GitHub 搜 issue如果没找到提 issue 时最少要带三样东西项目的vite.config.ts、DEBUGrolldown*的构建日志、一个可复现的最小仓库。只贴一段报错信息的话维护者很难定位最后大概率又是白等一趟。6. 写在最后的一些体会这次升级让我最感慨的其实不是快 3 倍这个数字而是整个前端工具链的整合趋势。Vite 早期靠 esbuild 解决“快”靠 Rollup 解决“全”本质上是在两个引擎之间反复横跳。Rolldown 把这两件事统一到一个引擎里从开发到构建、从转译到压缩行为和结果完全一致这种一致性带来的维护成本下降比单纯的构建提速更值钱。如果你现在问我“要不要升”我的建议是主流技术栈的常规项目升。你的收益非常直接构建快、配置简化、排查路径单一。但如果项目里压着大量私有插件或者长期依赖某些冷门的 Rollup 行为那就先拉一个分支跑一遍pnpm build把插件兼容清单过掉再合并。以我现在对这个生态的判断一年后再看Rolldown 只会更成熟而这个升级窗口会越来越平滑。