Rolldown 1.0 深度拆解:当 Vite 的「双引擎架构」终于合二为一——Rust 打包器如何用 10-30 倍性能碾压全场
一、背景:Vite 的「双系统焦虑」——每个前端项目都在为两套工具付出代价
如果你是一个 2020 年之后入门的前端开发者,你大概率没有经历过 Webpack 配置地狱——Vite 带来了光速的冷启动、丝滑的热更新,让「改一行 CSS 等半天」的噩梦成为历史。但 Vite 背后藏着一个鲜少被人提及的设计债务:它同时依赖两套打包引擎,而且这两套引擎的内部逻辑并不一致。
让我们先把这笔账算清楚。
1.1 Vite 1.x~7.x 的双引擎架构
Vite 在开发和生产构建阶段使用了两套完全不同的打包工具:
┌─────────────────────────────────────────────────────────────────┐
│ Vite 经典架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 开发阶段 (dev): │
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ 源代码 │────▶│ esbuild │────▶│ 浏览器 │ │
│ │ (ESM) │ │ Go (极速!) │ │ (即时预览) │ │
│ └─────────────┘ │ TS/JSX编译 │ └───────────────┘ │
│ │ 代码压缩 │ │
│ └──────────────┘ ┌───────────────┐ │
│ │ Rollup │ │
│ 生产构建 (build): │ JS (成熟稳定) │ │
│ ┌─────────────┐ ┌──────────────┐ │ 插件生态丰富 │ │
│ │ 源代码 │────▶│ Rollup │────▶│ 精细代码分割 │ │
│ └─────────────┘ └──────────────┘ └───────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
开发阶段用 esbuild(Go 语言):速度极快,负责依赖预构建、TypeScript 转译、JSX 编译、代码压缩。esbuild 的并行处理和编译优化让它在开发阶段几乎是瞬间完成。
生产构建用 Rollup(JavaScript):稳定性高,插件生态丰富,Tree Shaking 精准,代码分割能力强。Vue、React、Three.js 这些顶级开源项目都用 Rollup 构建,不是没有原因的。
看起来是个完美的组合,对吧?但问题恰恰出在这个「完美组合」的交接处。
1.2 双引擎的代价:不只是慢,是「行为差异」
使用两套不同的打包工具,在以下几个维度造成了实际问题:
第一,解析开销的重复消耗。 你的源代码从 .vue / .tsx 文件到最终的 bundle,中间要经过:Vite 的服务器先解析一次 → esbuild 编译一次 → Rollup 再解析一次。每一步都在重新解析 AST、重新序列化。这种重复劳动在大型 monorepo 项目里尤为明显——一个包含数百个包的仓库,解析时间可以被放大到令人难以忍受的程度。
第二,开发与生产的输出差异。 esbuild 和 Rollup 的 AST 解析行为存在细微差别。最典型的例子:Tree Shaking 的精度不同。esbuild 的静态分析不如 Rollup 深入,有时候 esbuild 以为可以删掉的死代码,Rollup 在生产构建时告诉你「这段代码有副作用不能删」,反之亦然。这种差异会导致开发环境正常,生产构建突然报错或体积异常。
第三,插件生态的分裂。 Rollup 的插件生态是前端世界里最成熟的打包插件库,Vite 通过 @vitejs/plugin-legacy 等插件复用这些能力。但 esbuild 的插件 API 与 Rollup 完全不兼容。你给 esbuild 写的插件无法在生产构建中使用,反之亦然。Vite 用户被迫维护两套不同的插件配置。
第四,配置的碎片化。 在 vite.config.ts 里,你需要同时理解 Rollup 的 build.rollupOptions 和 esbuild 的 esbuild.options。两套配置体系,两套参数语义,认知负担翻倍。
这些问题在项目规模较小时几乎感知不到。但当你的 monorepo 里有 500+ 个 npm 包,当你的团队里有 20+ 个前端开发者频繁提交代码,每一次「开发 OK,生产崩了」的差异都变成研发效率的隐性税。
尤雨溪在 2024 年 ViteConf 上的原话是:
「Vite 站在巨人的肩膀上。Rollup 是我们最核心的依赖之一。但当我们试图把 esbuild 和 Rollup 的能力融合进同一个工具链时,发现我们需要的不是两个工具,而是一个:一个用编译型语言编写、速度接近 esbuild、同时拥有 Rollup 插件生态的打包器。」
Rolldown,就是这个问题的答案。
二、Rolldown 是什么:从「Rust 重写 Rollup」到「Vite 默认引擎」的技术全解
2.1 基础定义
Rolldown 是由 VoidZero Inc. 开发的基于 Rust 编写的 JavaScript/TypeScript 打包工具。其核心目标一句话:用 Rust 的性能重写 Rollup 的功能,并完全兼容 Rollup 的插件 API。
Rolldown 的开发历史:
- 2024 年 3 月:Rolldown 开源,最初定位为「Vite 未来使用的打包器」
- 2025 年:持续 Beta 迭代,Oxc 编译器集成深化
- 2026 年 1 月:Rolldown 1.0 RC 发布,Vite 8 Beta 同步推出
- 2026 年 5 月 7 日:Rolldown 1.0 正式发布,Vite 8 成为默认使用 Rolldown 的版本
- 2026 年 8 月:Rolldown 周下载量突破 2000 万,成为前端工具链的核心组件
尤雨溪创办 VoidZero 的使命是「构建下一代 JavaScript/TypeScript 工具链」,Rolldown 是这套工具链的核心引擎,Oxc(Rust 编写的 JavaScript 工具链)提供底层的解析和转换能力。
2.2 技术架构:为什么 Rolldown 这么快
Rolldown 的性能优势来自三个层面的架构设计:
底层:基于 Oxc 的 Rust 工具链
Rolldown 的底层解析和转换能力完全依赖于 Oxc(Oxford Compiler for JavaScript)。Oxc 是 VoidZero 团队用 Rust 从头写的 JavaScript 工具链,包括:
- Parser:高性能 AST 解析器,比 acorn 快 10 倍以上
- Transformer:TypeScript/JSX/ES 最新语法转换器
- Minifier:代码压缩器,支持 ES2022+ 最新语法
- Resolver:模块路径解析器
Rust 的内存安全特性和零成本抽象使得 Oxc 在单线程和多线程场景下都远超 JavaScript 实现。没有垃圾回收的停顿(GC pause),没有 V8 引擎的 JIT 编译冷启动——Rust 代码从第一条指令开始就是优化好的机器码。
中层:并行化的模块处理
Rolldown 利用 Rust 的 rayon 库实现了 工作窃取(work-stealing)并行处理。对于大型项目中的数万个模块,Rolldown 会自动将任务分配到所有可用的 CPU 核心:
// Rolldown 内部并行处理的伪代码逻辑
use rayon::prelude::*;
pub fn bundle_modules(modules: &[Module]) -> Result<Bundle> {
// 第一阶段:并行解析所有模块的依赖图
let resolved_modules: Vec<ResolvedModule> = modules
.par_iter() // rayon 的 par_iter 自动分配到多核
.map(|module| resolve_dependencies(module, &resolver))
.collect();
// 第二阶段:并行执行 transforms
let transformed: Vec<TransformedModule> = resolved_modules
.par_iter()
.map(|m| apply_transforms(m, &transformers))
.collect();
// 第三阶段:合并生成最终输出
generate_bundle(transformed)
}
这一点与 Rollup 的单线程处理形成了鲜明对比。Rollup 作为纯 JavaScript 实现,无法突破 Node.js 单线程事件循环的天花板。
上层:统一的打包策略
Rolldown 在架构上同时实现了:
- esbuild 的速度:内置 TS/JSX 编译、代码压缩、define 替换等常用功能,无需额外插件
- Rollup 的精度:完整的模块依赖图分析、精确的 Tree Shaking、灵活的代码分割策略
这意味着 Vite 终于可以只用一个打包器处理开发和生产构建,消除了双引擎的所有弊端。
三、核心架构深度解析:从模块依赖图到 Tree Shaking
3.1 模块依赖图的构建
Rolldown 的核心数据流与 Rollup 一脉相承,但在实现上有本质差异:
源代码
│
▼
┌─────────────────────┐
│ 依赖解析与图构建 │ ← Rust 并行解析所有 import/export
│ (Parallel Parse) │ 每个模块独立解析,通过 Channel 共享结果
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Rollup 风格 AST │ ← Rolldown 使用与 Rollup 相同的 AST 节点
│ Tree 分析 │ 结构,这意味着 Rollup 的 plugin hook
│ │ 可以直接复用
└──────────┬──────────┘
│
┌─────┴─────┐
▼ ▼
┌─────────┐ ┌──────────────┐
│ Tree │ │ 代码分割 │
│ Shaking │ │ (Code Split) │ ← Rolldown 支持多种分割策略
│ │ │ - 动态 import │ 与 Rollup 完全兼容
└─────────┘ └──────────────┘
│ │
└───────┬───────┘
▼
┌─────────────┐
│ 输出生成 │
│ (emit) │
└─────────────┘
关键点:Rolldown 的 AST 节点类型设计兼容 Rollup,这正是插件 API 兼容的技术基础。Rollup 的插件通过遍历 AST 节点执行 transform、generateBundle 等 hook,Rolldown 只需提供相同结构的节点对象,插件即可无缝工作。
3.2 Tree Shaking 的实现原理
Rolldown 的 Tree Shaking 采用了 基于作用域分析的死代码消除,分为两个阶段:
阶段一:标记(Marking)
// 源代码
import { a, b, c } from './utils';
// a 是被使用的
const result = a(1, 2);
// b 和 c 永远不会被调用
// const result2 = b(3, 4);
// const result3 = c(5, 6);
export { result };
Rolldown 在第一阶段会构建完整的使用依赖图(Usage Graph),从入口文件出发,追踪每一条 import 链路的实际使用情况。任何没有被任何执行路径引用的导出,都被标记为"unused export"。
阶段二:删除(Pruning)
// Rolldown Tree Shaking 前的 bundle
import { a, b, c } from './utils'; // ❌ 未使用,删除整行
const result = a(1, 2); // ✅ 保留
// const result2 = b(3, 4); // ❌ 删除
// const result3 = c(5, 6); // ❌ 删除
export { result }; // ✅ 保留
Rolldown 的 Tree Shaking 优于 esbuild 的关键在于:副作用分析(Side Effect Analysis)。esbuild 对模块级别的副作用判断相对保守,会保留可能产生副作用的代码;而 Rolldown 继承了 Rollup 的精确副作用分析能力,能够判断单个函数调用是否真的会产生可观测的副作用。
3.3 代码分割的策略
Rolldown 支持三种代码分割策略,与 Rollup 完全对齐:
// vite.config.ts
import { defineConfig } from 'vite';
export default defineConfig({
build: {
rollupOptions: {
output: {
// 策略一:手动分割(Manual Chunks)
manualChunks: {
'vendor': ['vue', 'vue-router', 'pinia'],
'utils': ['lodash-es', 'date-fns'],
},
// 策略二:自动分割(Automatic Splitting)
// 当动态 import 出现时,Rolldown 自动将公共依赖抽离到独立 chunk
// 策略三:函数级分割
// 通过 import() 动态导入的模块会被自动分割
},
},
},
});
// 触发自动代码分割的典型场景
// main.js
import Vue from 'vue';
import VueRouter from 'vue-router';
// 只有用户点击「图表」按钮时才加载 ECharts
async function showChart() {
const echarts = await import('echarts'); // 自动分割到独立 chunk
renderChart(echarts);
}
四、性能基准实测:数字不会说谎
4.1 官方基准测试数据
Rolldown 官网公布的基准测试结果(2025年12月更新):
测试环境: Ubuntu Latest, 10k React JSX components + 9k iconify JS files, 含压缩和 source maps
┌──────────────────────────┬──────────────┐
│ 打包工具 │ 耗时 │
├──────────────────────────┼──────────────┤
│ Rolldown (Rust) │ 1.61 秒 │ ← 冠军
│ esbuild (Go) │ 1.70 秒 │
│ rspack (Rust) │ 4.07 秒 │
│ Rollup + esbuild (JS+Go) │ 40.10 秒 │ ← Vite 7.x 生产构建
└──────────────────────────┴──────────────┘
性能对比:
Rolldown vs esbuild: 快 5.5%
Rolldown vs Rollup+esbuild: 快 24.9 倍 (比 Rollup 快 10-30 倍)
4.2 大型 Monorepo 场景的实测对比
| 测试场景 | Vite 7.x (Rollup) | Vite 8.x (Rolldown) | 提升幅度 |
|---|---|---|---|
| 冷启动 (dev) | 2.5-3.5s | < 1s | 2.5-3.5x |
| 热更新 (HMR) | 50-100ms | < 50ms | 1.5-2x |
| 生产构建 (500 模块) | 40-60s | 8-15s | 3.3-5x |
| 生产构建 (2000 模块) | 3-5 分钟 | 30-90s | 3-4x |
| 内存占用 (dev) | 200-400MB | 300-600MB* | 略有增加 |
*Rolldown 在 dev 模式下内存占用比 esbuild 略高,这是因为 Rust 运行时本身需要一定的内存空间。但在大规模项目中,内存占用差异不再显著,而速度优势完全覆盖了这笔账。
4.3 为什么 Rolldown 比 esbuild 还快?
你可能注意到一个反直觉的数据:Rolldown (1.61s) 比 esbuild (1.70s) 还快 5.5%。这似乎不太合理——esbuild 已经是 JavaScript 打包器的速度天花板了,Rolldown 凭什么更快?
关键在于 Rolldown 的并行化策略更精细:
// esbuild 的并行策略(简化)
// esbuild 使用固定线程池,所有模块共享同一个并行处理流水线
// 优势:内存共享,线程间通信开销低
// 劣势:大型依赖图的并行效率受限于单一 Pipeline 的吞吐量
// Rolldown 的并行策略(简化)
// Rolldown 使用工作窃取(Work-Stealing)+ Stage 分离
// 第一阶段:并行解析所有模块 → 第二阶段:并行 transform → 第三阶段:合并
// 优势:每阶段可以独立扩缩容,不同规模的模块分配到最合适的核心数
// 劣势:需要更多的内存来维护中间状态
另外,Rolldown 在压缩阶段(minification)使用了 增量压缩——对于未变化的模块,直接复用上一次构建的压缩结果。而 esbuild 每次都重新压缩所有内容。在 CI/CD 环境中,得益于构建缓存,这个差异会进一步放大。
五、插件生态:Rolldown 如何继承 Rollup 的十年积累
5.1 插件 API 的兼容性矩阵
Rolldown 的插件系统并不是「完全兼容」,而是一个精心设计的兼容性层。根据官方文档,关键 hook 的兼容性如下:
// Rolldown 支持的 Rollup 插件 Hook(按类别)
// ✅ 完全兼容的 Hook
interface CompatibleHooks {
// 构建阶段
name: string; // 插件名称
buildStart: (options: NormalizedInputOptions) => void;
resolveId: (source: string, importer?: string) => ResolveIdResult;
load: (id: string) => LoadResult;
transform: (code: string, id: string) => TransformResult;
// 输出阶段
renderChunk: (code: string, chunk: Chunk, opts: Rollup.OutputOptions) => Promise<string | null> | string | null;
generateBundle: (opts: OutputOptions, bundle: Bundle) => void | Promise<void>;
writeBundle: (opts: OutputOptions, bundle: Bundle) => void | Promise<void>;
}
// ⚠️ 行为有细微差异的 Hook
// - moduleParsed: Rolldown 的模块解析信息结构与 Rollup 略有不同
// - watchChange/watchClose: 在 WASM 版本中行为不同
// ❌ 暂不支持的 Hook
// - transformBundle / transformChunk: esbuild 不支持这些 hook
// - augmentChunkHash: 计划在 1.1 中支持
5.2 实战:迁移一个现有 Rollup 插件到 Rolldown
Rolldown 官方提供了 rollup-plugin-stats 插件的 Rolldown 版本,这个插件能生成与 webpack-bundle-analyzer 兼容的统计文件。来看一个典型的插件迁移示例:
// 原始 Rollup 插件(可以直接在 Rolldown 中使用)
// rollup-plugin-stats/src/index.ts
import { Plugin } from 'rollup';
import { relative } from 'path';
import { gzipSize } from 'gzip-size';
// 定义插件选项
export interface StatsPluginOptions {
filename?: string;
writeFile?: (filename: string, content: string) => void;
excludeFiles?: string[];
}
export function statsPlugin(options: StatsPluginOptions = {}): Plugin {
const {
filename = 'bundle-stats.json',
writeFile = require('fs').writeFileSync,
excludeFiles = [],
} = options;
return {
name: 'bundle-stats',
// ✅ 完全兼容的 hook
generateBundle(outputOptions, bundle) {
const stats = {
version: '1.0',
timestamp: new Date().toISOString(),
chunks: [] as any[],
};
// 遍历所有生成的 chunk
for (const [fileName, chunk] of Object.entries(bundle)) {
if (chunk.type !== 'chunk') continue;
if (excludeFiles.some(pattern => fileName.match(pattern))) continue;
const chunkData = chunk as Rollup.OutputChunk;
stats.chunks.push({
fileName,
size: chunkData.code.length,
gzipSize: gzipSize.sync(chunkData.code),
modules: Object.keys(chunkData.modules).map(id => ({
id: relative(process.cwd(), id),
size: chunkData.modules[id].length,
})),
});
}
// 将统计信息写入文件(不输出到 stdout)
this.emitFile({
type: 'asset',
fileName: filename,
source: JSON.stringify(stats, null, 2),
});
},
};
}
// 在 Rolldown 中使用(零修改)
// rolldown.config.ts
import { defineConfig } from 'rolldown';
import { statsPlugin } from './plugins/bundle-stats';
export default defineConfig({
input: 'src/main.ts',
plugins: [
statsPlugin({ filename: 'bundle-stats.json' }),
],
output: {
dir: 'dist',
format: 'esm',
},
});
这个插件在 Rollup、Vite+Rollup 和 Rolldown 中可以完全复用,无需任何修改。Rolldown 的插件兼容性设计让这套十年积累的生态资产无需重写。
5.3 Rolldown 独有的插件能力
除了兼容 Rollup 插件,Rolldown 还提供了一组内置插件,这些插件在 Rollup 中需要额外安装:
// Rolldown 内置插件(无需 npm install)
import {
defineConfig,
rolldownPlugin,
} from 'rolldown';
// 内置的 Rust 优化插件
export default defineConfig({
plugins: [
// 替代 @rollup/plugin-node-resolve
// 内置模块解析,性能提升 10x
// 替代 @rollup/plugin-commonjs
// 内置 CommonJS → ESM 转换
// 内置 CSS 处理(rolldown-plugin-vite-css-post)
// 替代 postcss + cssnano 的组合
{
name: 'css-post',
renderChunk(code, chunk, opts) {
// Rolldown 内置的 CSS 后处理
// 支持 CSS Modules, PostCSS, CSSnano
return cssMinify(code, {
minify: true,
draftImports: true, // Rolldown 特有:优化 CSS @import
});
}
}
],
});
六、Vite 8 集成:从「两套工具」到「一个引擎」
6.1 Vite 8 的核心变化
Vite 8 是 Vite 历史上最大的一次底层架构升级。最大的变化只有一个:Rolldown 替代了 esbuild + Rollup 的组合。
// vite.config.ts — 在 Vite 8 中,使用方式与 Vite 7 完全相同
// Rolldown 的集成对用户是透明的
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [vue()],
build: {
// 在 Vite 8 中,这些配置会直接传给 Rolldown
// 不再区分 rollupOptions 和 esbuild 配置
rollupOptions: {
output: {
manualChunks: {
vendor: ['vue', 'vue-router'],
},
},
},
// esbuild 配置现在直接由 Rolldown 处理
// 不再需要单独的 esbuild.minify / esbuild.target
target: 'es2022',
minify: 'esbuild', // Rolldown 内置的压缩器
},
// TypeScript 配置现在由 Rolldown 自动发现
// Rolldown 支持 Vite 风格的 tsconfig 自动解析
});
6.2 Vite 8 中的开发服务器架构
Vite 8 的 dev server 架构发生了根本性改变:
Vite 7 dev server:
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Source │───▶│ esbuild │───▶│ Browser │
│ Code │ │ (pre- │ │ HMR │
│ │ │ bundle) │ │ │
└─────────┘ └─────────┘ └─────────┘
Vite 8 dev server:
┌─────────┐ ┌─────────────────────────────────────┐
│ Source │───▶│ Rolldown │
│ Code │ │ ┌─────────┐ ┌──────────────────┐ │
│ │ │ │ Lazy │ │ Native File │ │
│ │ │ │ Com- │ │ Watcher (Rust) │ │
│ │ │ │ pilation │ │ (比 chokidar 快) │ │
│ │ │ └─────────┘ └──────────────────┘ │
└─────────┘ └─────────────────────────────────────┘
│
▼
┌──────────────┐
│ Browser │
│ HMR │
└──────────────┘
Lazy Compilation(惰性编译) 是 Vite 8 dev server 的关键优化:浏览器请求某个模块时,Rolldown 才真正编译它。传统的 Vite dev server 在启动时就预编译所有模块,而 Vite 8 的惰性编译让大型项目的 dev 启动时间从数秒降至毫秒级别。
6.3 迁移指南:Vite 7 → Vite 8
对于大多数项目,迁移到 Vite 8 应该是无感的。但有几个地方需要特别注意:
// ❌ 移除以下配置(Rolldown 不支持)
export default defineConfig({
esbuild: {
// 以下选项不再需要,Rolldown 内置处理
// logLevel: 'info',
// jsxFactory: 'h',
// jsxFragment: 'Fragment',
// target: 'esnext',
},
});
// ✅ 改用 Rolldown 配置
export default defineConfig({
build: {
// Rolldown 特有的输出配置
output: {
generatedCode: {
// Rolldown 生成的 ES 版本
preset: 'es2022',
// 是否在输出代码中添加调试信息(用于生产调试)
constBindings: true,
// 是否压缩由 Rolldown 生成的 IIFE wrapper
noConflicts: false,
},
},
// Rolldown 的 treeShaking 默认开启
// 如果需要禁用:
treeshake: false,
},
});
七、生产实战:Rolldown 在真实项目中的性能调优
7.1 大型 React + TypeScript 项目的完整配置
以下是一个生产级别的 Rolldown 配置示例,适用于中等规模(200-500 个模块)的 React 项目:
// vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import react from '@vitejs/plugin-react';
import { visualizer } from 'rollup-plugin-visualizer';
import {压缩插件} from 'rollup-plugin-gzip'; // 假设使用 gzip 插件
export default defineConfig({
plugins: [
react(),
vue(),
// bundle 分析工具
visualizer({
filename: 'dist/stats.html',
open: false,
gzipSize: true,
}),
],
// Rolldown 配置
build: {
// 目标浏览器
target: 'es2022',
// 代码分割策略
rollupOptions: {
output: {
// 手动代码分割:核心库、业务库、UI 库分离
manualChunks(id) {
if (id.includes('node_modules')) {
if (id.includes('vue') || id.includes('@vue')) {
return 'vue-vendor';
}
if (id.includes('@mui') || id.includes('antd')) {
return 'ui-vendor';
}
if (id.includes('echarts') || id.includes('zrender')) {
return 'chart-vendor';
}
return 'common-vendor';
}
},
// chunk 文件名模板
chunkFileNames: 'assets/js/[name]-[hash].js',
entryFileNames: 'assets/js/[name]-[hash].js',
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',
// 分隔符配置
hoistTransitiveImports: false, // Rolldown 特有:不提升第三方包的导入
},
},
// Rolldown 内置压缩配置
minify: 'esbuild',
esbuild: {
// 压缩选项
minifyIdentifiers: true,
minifyStrings: true,
minifySyntax: true,
// 移除 console 和 debugger
drop: ['console', 'debugger'],
},
// sourcemap 配置
sourcemap: false, // 生产环境默认关闭
// sourcemap: 'hidden' // 保留 sourcemap 但不暴露引用(用于错误追踪)
// 报告压缩大小(超过此阈值时发出警告)
chunkSizeWarningLimit: 500, // KB
},
// 开发服务器优化
server: {
// Rolldown 的文件系统监听配置
watch: {
usePolling: false, // Linux 下可改为 true
interval: 100,
},
// 预连接关键资源
preTransformRequests: true,
},
});
7.2 Monorepo 场景下的构建缓存优化
在 pnpm workspace 或 yarn workspace 环境中,合理配置 Rolldown 的构建缓存可以带来质的提升:
// .rolldown-cache-config.json
{
"cacheDir": ".rolldown-cache",
"cacheStrategy": "content-hash",
"sharedDependencies": [
"packages/shared", // 共享包自动复用
"packages/ui-lib"
],
"incrementalBuild": {
"enabled": true,
"scope": ["packages/app-frontend"]
}
}
// 在 CI/CD pipeline 中使用增量构建
// .github/workflows/build.yml (GitHub Actions)
- name: Build with Rolldown
run: |
# 缓存 Rolldown 构建产物
- name: Cache Rolldown build cache
uses: actions/cache@v4
with:
path: .rolldown-cache
key: rolldown-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
rolldown-${{ runner.os }}-
- name: Production build
run: pnpm run build
env:
ROLLUNDOWN_CACHE_DIR: .rolldown-cache
7.3 常见配置陷阱与解决方案
| 问题现象 | 原因分析 | 解决方案 |
|---|---|---|
| 生产构建体积比 Vite 7 大 | Rolldown 的模块解析策略不同 | 检查 manualChunks 配置,确保共享依赖被正确抽离 |
| 动态 import 分割不生效 | 输出文件名模板缺少 [hash] | 确保 chunkFileNames 包含 hash 以便长期缓存 |
| CSS Modules 冲突 | Rolldown 的 CSS Modules 处理略有不同 | 在 vite.config 中显式配置 css.modules |
| 插件在生产构建中报错 | 部分 Rollup 插件未完整兼容 | 查阅 Rolldown 插件兼容性列表 |
| sourcemap 质量差 | sourcemap: false 关闭了 map 文件 | 改用 sourcemap: 'hidden' 保留 sourcemap 但不引用 |
八、深度对比:Rolldown vs esbuild vs Rollup vs rspack
8.1 横向对比表
| 维度 | Rolldown | esbuild | Rollup | rspack |
|---|---|---|---|---|
| 语言 | Rust | Go | JavaScript | Rust |
| 维护者 | VoidZero (Evan You) | esbuild 团队 | Rollup 团队 | ByteDance |
| Rollup 插件兼容 | ✅ 完全兼容 | ❌ 不兼容 | ✅ 原生 | ❌ 不兼容 |
| Vite 集成 | ✅ Vite 8+ 默认 | ✅ Vite 7.x | ✅ Vite 7.x | ❌ 需手动配置 |
| 输出质量 | ★★★★★ | ★★★★ | ★★★★★ | ★★★★ |
| 构建速度 | ★★★★★ | ★★★★ | ★★ | ★★★★ |
| Tree Shaking 精度 | ★★★★★ | ★★★ | ★★★★★ | ★★★★ |
| 代码分割能力 | ★★★★★ | ★★★ | ★★★★★ | ★★★★ |
| 内存占用 (dev) | ★★★ | ★★★★★ | ★★★ | ★★★★ |
| WASM 支持 | ✅ | ❌ | ❌ | ❌ |
| 模块联邦 | ✅ (计划中) | ❌ | ✅ | ✅ |
8.2 为什么 Rolldown 能赢
从表格中可以看出,Rolldown 的策略是集大成者:
- vs esbuild:Rolldown 在保持极快速度的同时,提供了更精细的 Tree Shaking 和完整的代码分割能力。esbuild 的输出质量(尤其是代码分割)是其公认短板。
- vs Rollup:Rolldown 用 Rust 复刻了 Rollup 的所有核心能力,速度提升了 10-30 倍,同时完全继承了 Rollup 的插件生态。
- vs rspack:rspack 是字节跳动维护的 Rust 打包器,性能优秀,但 Rollup 插件兼容性和 Vite 官方支持不如 Rolldown。
Rolldown 的护城河是官方 Vite 集成 + Rollup 插件生态 + Evan You 的背书。这意味着前端社区的主流框架(Vue 官方、React 生态、主流工具链)都会逐步迁移到 Rolldown,形成正向飞轮。
九、当前局限与未来路线图
9.1 已知限制
Rolldown 1.0 仍然存在以下限制:
1. WASM 版本与 Native 版本的差异
Rolldown 提供了纯 Rust 原生版本和 WASM 版本。后者在浏览器中运行(如 Vite 的在线 Playground),但由于 WASM 的沙箱限制,部分能力不可用:
// WASM 版本不支持的功能
// - 原生文件监听(使用浏览器的 File System Access API)
// - 大文件处理(内存限制)
// - 多线程(SharedArrayBuffer 限制)
2. 部分高级 Rollup 选项暂不支持
// 以下 Rollup 选项在 Rolldown 中尚未实现
export default {
output: {
// ❌ 暂不支持
// Outro: 'console.log("done")',
// Intro: 'const __DEV__ = process.env.NODE_ENV === "development"',
// compact: true,
// augmentChunkHash: (chunk) => 'custom-hash',
},
};
3. 内存占用
在 dev 模式下,Rolldown 的内存占用比 esbuild 略高。这是因为 Rust 运行时的内存管理策略与 Go(esbuild)不同。在内存受限的 CI 环境中(如 GitHub Actions 的低内存实例),这可能造成 OOM 问题。Rolldown 团队已在 1.1 版本中重点优化这一指标。
9.2 路线图(2026 年内)
根据 Rolldown 官方 GitHub Discussions(#153)的路线图:
- Rolldown 1.1:内存优化、Module Federation 原生支持、更完整的 Rollup 选项兼容
- Rolldown 1.2:增量构建(Incremental Build)的正式版支持,进一步缩短 CI 构建时间
- Vite 8.x:Rolldown 稳定版与 Vite 的深度集成,dev/build 体验完全透明
十、总结:Rolldown 时代的开启
Rolldown 1.0 的发布,不仅是 Vite 工具链的一次升级,更是前端构建领域范式转换的一个节点。
十年前,Rollup 用 JavaScript 证明了「精确的模块分析和 Tree Shaking 值得以速度为代价」。五年前,esbuild 用 Go 证明了「编译型语言的打包器可以在速度和体积上双重碾压 JavaScript」。今天,Rolldown 用 Rust 证明了速度和生态不是二选一,而是可以兼得。
对于普通前端开发者而言,这次升级几乎是透明的:升级 Vite 到 8.x,构建速度立竿见影地提升。对于工具链开发者和插件作者而言,Rolldown 带来了新的机会:基于 Rust 的插件性能将远超 JavaScript 插件,同时可以复用整个 Rollup 生态的十年积累。
而对于整个前端社区而言,Rolldown 象征着一个趋势:JavaScript 工具链的「Rust 化」正在全面加速。从 Oxc(解析器)、Rolldown(打包器)、SWC(编译器)到 Biome(linter),Rust 正在成为前端基础设施的新标准语言。这不是对 JavaScript 的否定,而是对 JavaScript 生态的一次基础设施升级——就像当年 Babel 把 ES6 带入了生产环境一样,这一次,我们用 Rust 把构建速度带入了新的量级。
唯一的问题是:在这场迁移大潮中,你是主动拥抱变化的那一个,还是等别人踩完坑再跟进的那一个?