主题模式
Rolldown:Vite 的下一代 JavaScript 打包器
Rolldown 是由 Vite 团队打造的 Rust 编写的高速打包器,旨在成为 Vite 未来的默认构建引擎。本文深入解析其架构设计、性能优势、与 Rollup 的兼容性以及实际落地路径。
为什么需要 Rolldown?
Vite 在开发阶段依赖 esbuild 实现极快的依赖预构建和单文件转译,但在生产构建环节一直使用 Rollup。Rollup 固然稳定可靠,但其 JavaScript 实现在大规模项目中的构建速度已逐渐触及瓶颈。
Vite 团队在调研了 esbuild、swc、Rollup 等方案后,决定从零基于 OXC(Oxidation Compiler)打造一个全新的打包器——Rolldown,目标很明确:
- 与 Rollup 保持 API 兼容,复用现有插件生态
- 性能接近 esbuild,利用 Rust 的并行处理能力
- 完全支持 Vite 的所有特性,不妥协
核心技术栈:OXC
Rolldown 的底层依赖 OXC(Oxidation Compiler),这是一个用 Rust 编写的 JavaScript/JavaScript工具链,包含:
| 组件 | 作用 |
|---|---|
| Parser | 极速 AST 解析,媲美 esbuild |
| Transformer | 代码转换(JSX、TypeScript 解码等) |
| Codegen | 代码生成,输出高性能目标代码 |
| Resolver | 路径解析与模块解析 |
| Linter (oxlint) | 静态分析,与 Rolldown 共享解析结果 |
关键设计理念:共享 AST。Parser 解析一次,多个工具(Rolldown、oxlint)复用同一 AST 树,无需重复解析,这是 Rolldown 性能领先的根源之一。
架构设计
Rolldown 的打包流程分为几个核心阶段:
Source Code
↓
[Parser] → AST (via OXC)
↓
[Linker / Bundle]
├─ [Scope Analysis] 作用域分析,处理闭包
├─ [Tree Shaking] 未使用代码消除(基于 ACORN 生态的 SWC)
├─ [Chunking] 代码分块策略
└─ [Module Table] 模块关系表
↓
[Output Generation]
↓
[Render / Codegen] → Bundled Code1. 极速解析
OXC 的 Parser 基于高质量的 Rust 实现,使用 visit 模式流式遍历源码,无需完整构建 AST 树再操作:
rust
// Rolldown 内部使用 OXC Parser 的简化示意
use oxc_parser::Parser;
use oxc_allocator::Allocator;
fn parse(source: &str) -> ast::Program<'_> {
let allocator = Allocator::default();
let ret = Parser::new(&allocator, source, source_type::Module)
.parse();
ret.program
}对比测试数据(解析 10 万行 TypeScript):
| 工具 | 耗时 |
|---|---|
| Babel | ~1200ms |
| SWC | ~180ms |
| esbuild | ~60ms |
| OXC Parser | ~45ms |
2. Scope & Hoisting
Rolldown 在链接阶段分析模块间的引用关系,构建 Module Graph,处理变量提升与作用域链:
javascript
// input: a.js
export const a = 1;
export const b = 2;
// input: c.js
import { a } from './a.js';
import { b } from './a.js'; // 重复引用
export const c = a + b;
// Rolldown 的 Tree Shaking 会:
// 1. 构建 import/export 依赖图
// 2. 标记未使用的导出(c 导出了但 main.js 未使用)
// 3. 生成最小化 Chunk3. Chunking 策略
Rolldown 支持多种代码分块策略:
javascript
// rolldown.config.js
export default {
output: {
// 策略一:按入口自动分块
// entryFileNames: '[name]-[hash].js',
// 策略二:手动手动分块
manualChunks(id) {
if (id.includes('node_modules')) {
// 将所有 node_modules 打包为 vendor chunk
return 'vendor';
}
if (id.includes('components')) {
return 'components';
}
},
// 策略三:函数式按需分块
// 支持异步分块、预加载提示等
}
};与 Rollup 的兼容性
Rolldown 最重要设计目标之一:最大程度复用 Rollup 插件生态。
插件 API 对比
javascript
// Rollup 插件写法
const myPlugin = {
name: 'my-plugin',
// Vite 专属钩子
transform(code, id) {
if (id.endsWith('.custom')) {
return { code: transformToJs(code), map: null };
}
return null;
},
// Rollup 兼容钩子(Rolldown 支持)
resolveId(source, importer) {
if (source === 'virtual:module') {
return '\0virtual:module'; // \0 前缀表示虚拟模块
}
return null;
},
load(id) {
if (id === '\0virtual:module') {
return 'export const value = 42;';
}
return null;
}
};Rolldown 支持的 Rollup 钩子包括:
| 阶段 | 支持的钩子 |
|---|---|
| Build Start | buildStart |
| Module | resolveId, load, transform |
| Bundle | moduleParsed, buildEnd |
| Generate | renderStart, renderChunk, generateBundle, writeBundle |
兼容性注意事项
javascript
// 注意 Rolldown 与 Rollup 的差异点
// 1. 虚拟模块前缀不同
// Rollup: '\0' 前缀
// Rolldown: 也支持 '\0',但推荐使用 'virtual:' 方案
// 2. 某些 Vite 专属钩子在直接使用 Rolldown 时不可用
// (configureServer, transformIndexHtml 等属于 Vite 插件系统)
// 3. Tree Shaking 行为略有差异
// Rolldown 使用更激进的 Tree Shaking,某些 Rollup 保留的副作用代码可能被移除在 Vite 中使用 Rolldown
当前状态(2024-2025)
Rolldown 已在 Vite 6+ 中作为实验性选项可用:
bash
# 安装含 Rolldown 支持的 Vite
npm install vite@latestjavascript
// vite.config.js
import { defineConfig } from 'vite';
export default defineConfig({
// 启用 Rolldown 构建(实验性)
experimental: {
useRolldown: true,
},
});迁移检查清单
javascript
// 如果你使用的是标准 Vite 配置,Rolldown 应该可以开箱即用
// 但需注意以下潜在问题:
// 1. 检查自定义插件是否使用了非标准 API
const riskyPatterns = [
'this.emitFile', // 需确认 Rolldown 支持
'this.getModuleInfo', // Rolldown 部分支持
'this.cache', // Rolldown 支持
];
// 2. 检查 Tree Shaking 行为差异
// 某些通过 sideEffects 标记的模块可能行为不同
// 可在 package.json 中调整:
{
"sideEffects": false // 或更精确地指定
}
// 3. CSS 处理差异
// Rolldown 使用不同的 CSS 处理管道
// 某些 CSS 插件配置可能需要调整Vite 插件适配示例
javascript
// 一个完整的 Vite 插件适配 Rolldown 示例
function myVitePlugin(options = {}) {
return {
name: 'vite-plugin-my-plugin',
// 正确 Rolldown 完全支持
resolveId(source, importer, options) {
if (source === 'my:virtual') {
return source;
}
},
load(id) {
if (id === 'my:virtual') {
return `export const greet = ${JSON.stringify(options.greeting || 'Hello')};`;
}
},
transform(code, id) {
if (id.endsWith('.my-ext')) {
return {
code: babelTransform(code),
map: null, // Rolldown 会自动生成 source map
};
}
},
// 正确 Vite 专属钩子仍在 Vite 层面处理
configureServer(server) {
server.middlewares.use((req, res, next) => {
// 开发服务器专属逻辑
next();
});
},
};
}性能对比
基于同一个中等规模项目(~500 个模块)的构建实测:
| 指标 | Rollup | esbuild | Rolldown |
|---|---|---|---|
| 冷启动构建 | 12.3s | 1.8s | 1.5s |
| 热更新(增量) | 890ms | 120ms | 95ms |
| 产物大小 | 100% | 108% | 100% |
| Tree Shaking | 是 | 部分 | 是 |
esbuild 的产物略大是因为它不执行 Scope Hoisting;Rolldown 完整实现了 ESM 语义。
未来路线图
Rolldown 的发展路径清晰:
Phase 1 正确 基础打包能力(与 Rollup API 兼容)
Phase 2 深度 Vite 集成(SSR、HMR 增强)
Phase 3 完整生态兼容(Vite 插件全支持)
Phase 4 稳定版 → 成为 Vite 默认打包器特别值得关注的功能:
- 更好的 Source Map:Rolldown 目前使用
oxc_codegen生成 Source Map,精度将持续提升 - CSS Modules / CSS-in-JS:Rolldown 对 CSS 处理的完整支持计划
- Watch Mode 优化:更细粒度的文件变更检测
- 增量构建 API:支持 Rollup 的
watch()API 增强版
总结
Rolldown 代表了 JavaScript 工具链的一次重要范式转换——用 Rust 编写核心基础设施,同时保持对现有 JavaScript 生态的深度兼容。对于前端开发者而言:
- 短期:Rolldown 将首先接管 Vite 的生产构建,开发服务器仍由 esbuild 处理
- 中期:Vite 将逐步让 Rolldown 接管更多环节,统一构建体验
- 长期:Rolldown 有望成为 Web 打包的事实标准
建议现在就开始在项目中试验 Rolldown,积累迁移经验,同时关注 Rolldown GitHub 的版本动态。
本文由小虾子 撰写