Rspack / Rsbuild Rust 系的崛起

Rspack / Rsbuild Rust 系的崛起

写在前面

上一篇讲了 Vite 的双引擎设计。本篇讲 Rspack——字节跳动开源的 Rust 写的 webpack 兼容方案,以及它的封装 Rsbuild。Rspack 解决了 Vite 解决不了的问题:存量 webpack 项目的无痛迁移。

一、为什么需要 Rspack

1.1 字节的痛点

字节跳动内部有几千个 webpack 项目,每个项目都要等 30 秒冷启动、5 秒 HMR。

他们试过:

需要一个既能保留 webpack 配置,又能跑得和 Vite 一样快的方案。

1.2 Rspack 的目标

和 webpack 100% 配置兼容,但用 Rust 重写核心,速度提升 5-10 倍。

二、Rspack 的架构

2.1 核心组件

┌─────────────────────────────────────┐
│  Rspack (Rust)                       │
│  ├─ Compiler (Rust)                  │  ← 核心编译逻辑
│  ├─ Module Federation (Rust)         │  ← 内置模块联邦
│  ├─ SWC Transform (Rust)             │  ← TS/JSX 转译
│  ├─ Loader Runner (Rust+JS)          │  ← 运行 JS loader
│  └─ Plugin System                    │  ← 兼容 webpack 插件
└─────────────────────────────────────┘

2.2 关键模块

Rust 核心

// Rspack 的 Rust 代码示意
pub struct Compiler {
    pub options: CompilerOptions,
    pub plugins: Vec<Box<dyn Plugin>>,
    pub resolvers: HashMap<ResolverKind, Resolver>,
}

impl Compiler {
    pub fn run(&mut self) -> Result<()> {
        // 1. 解析入口
        // 2. 并行处理所有模块
        // 3. 构建依赖图
        // 4. 优化 chunk
        // 5. 输出文件
    }
}

用 Rayon 做并行处理,多核 CPU 充分利用。

SWC 转译

Rspack 用 swc(也是 Rust 写的)做 TS/JSX 转译,比 Babel 快 5-20 倍。

// 用 swc 转译 TS
let fm = swc::SourceFile::new(...);
let lexer = Lexer::new(...);
let mut parser = Parser::new_from(lexer);
let module = parser.parse_module().unwrap();
let transformed = Transform::new().transform(module);

Loader Runner

Rspack 用 Rust 调用 JS loader(兼容 webpack loader):

// Rust 调用 JS loader
let result = node_runtime.call(
    loader_path,
    source_code,
    loader_options,
)?;

大部分 webpack loader 可以直接用,但调用开销比 webpack 小(Rust 直接处理)。

2.3 性能对比

字节官方 benchmark:

项目 webpack 5 Rspack 提升
Modern.js(中等) 12.5s 1.8s 7x
ant-design-pro(大型) 28s 4.2s 6.7x
Next.js 13(超大) 65s 9.8s 6.6x

典型提升 5-10 倍。

三、Rspack 的使用

3.1 配置文件

// rspack.config.js
module.exports = {
    entry: './src/index.js',
    output: {
        path: __dirname + '/dist',
        filename: '[name].[contenthash].js',
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                loader: 'builtin:swc-loader',
                options: {
                    jsc: {
                        parser: { syntax: 'typescript', tsx: true },
                        target: 'es2020',
                    },
                },
            },
            {
                test: /\.css$/,
                use: ['css-loader', 'postcss-loader'],
            },
        ],
    },
    plugins: [
        new rspack.HtmlRspackPlugin({  // 替代 HtmlWebpackPlugin
            template: './public/index.html',
        }),
    ],
};

几乎和 webpack 一模一样,只是部分内置 loader/plugin 用 builtin: 前缀。

3.2 启动

# 安装
npm install -D @rspack/core @rspack/cli

# 启动 dev server
npx rspack serve

# 构建
npx rspack build

四、Rsbuild:Rspack 的封装

4.1 Rsbuild 是什么

Rsbuild 是字节在 Rspack 之上的封装——提供开箱即用的开发体验。

// rsbuild.config.ts
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';

export default defineConfig({
    plugins: [pluginReact()],
    html: {
        template: './index.html',
    },
    source: {
        entry: { index: './src/index.ts' },
    },
});

4.2 Rsbuild 内置能力

能力 默认支持
TypeScript ✅(swc 转译)
JSX ✅
CSS / Sass / Less ✅
CSS Modules ✅
PostCSS(autoprefixer) ✅
图片 / 字体 / SVG ✅
HTML 处理 ✅
静态资源处理 ✅
代码分割 ✅
Tree Shaking ✅
Source Map ✅
HMR ✅
TypeScript 类型检查(独立) ⚙️(可选插件)

对比 webpack:这些都需要手动配置 loader/plugin。

4.3 Rsbuild 的命令

# 开发
npx rsbuild dev

# 构建
npx rsbuild build

# 预览构建产物
npx rsbuild preview

4.4 Rsbuild 生态

字节围绕 Rsbuild 建了一整套工具:

五、webpack 兼容性实测

5.1 Loader 兼容性

Loader 兼容情况
babel-loader ✅ 完全兼容
css-loader / style-loader ✅ 完全兼容
postcss-loader ✅ 完全兼容
sass-loader / less-loader ✅ 完全兼容
file-loader / url-loader ⚙️ Rspack 有内置,无需 loader
ts-loader ⚙️ 用 swc-loader 替代,更快
vue-loader ⚙️ 需要 vue-loader 16+
自定义 loader ✅ 99% 兼容

5.2 Plugin 兼容性

Plugin 兼容情况
HtmlWebpackPlugin ⚙️ 用 HtmlRspackPlugin 替代
MiniCssExtractPlugin ⚙️ 用 CssExtractRspackPlugin 替代
CopyWebpackPlugin ✅ 兼容
DefinePlugin ✅ 完全兼容
ProvidePlugin ✅ 完全兼容
webpack-bundle-analyzer ⚙️ 用 Rsbuild 的 bundle-analyzer
自定义 plugin ⚠️ 大部分兼容

5.3 配置兼容性

// webpack.config.js 改几个名字就能用
const config = {
    entry: './src/index.js',
    output: { path: './dist', filename: '[name].js' },
    module: {
        rules: [{ test: /\.css$/, use: 'css-loader' }],
    },
    // ... 其他都一样
};

module.exports = config;

90% 的 webpack 项目可以直接跑 Rspack。

5.4 真实迁移案例

公司项目 from-webpack-to-rspack:

- const path = require('path');
- const HtmlWebpackPlugin = require('html-webpack-plugin');
- const MiniCssExtractPlugin = require('mini-css-extract-plugin');
- const { DefinePlugin } = require('webpack');
+ const path = require('path');
+ const rspack = require('@rspack/core');

module.exports = {
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[contenthash:8].js',
        clean: true,
    },
    module: {
        rules: [
-           { test: /\.tsx?$/, use: 'ts-loader' },
+           { test: /\.tsx?$/, loader: 'builtin:swc-loader' },
            {
                test: /\.css$/,
-               use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
+               use: [rspack.CssExtractRspackPlugin.loader, 'css-loader', 'postcss-loader'],
            },
        ],
    },
    plugins: [
-       new HtmlWebpackPlugin({ template: './public/index.html' }),
+       new rspack.HtmlRspackPlugin({ template: './public/index.html' }),
-       new MiniCssExtractPlugin({ filename: '[name].[contenthash:8].css' }),
+       new rspack.CssExtractRspackPlugin({ filename: '[name].[contenthash:8].css' }),
        new rspack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify('production'),
        }),
    ],
};

改动 < 50 行,迁移后冷启动从 60 秒降到 8 秒。

六、Rspack 的优势场景

6.1 存量 webpack 迁移

这是 Rspack 最大的优势——大部分公司都有存量 webpack 项目。

迁移成本: < 1 周(主要是改 plugin)
性能提升: 5-10 倍

6.2 大型 monorepo

字节内部的 monorepo 用 Rspack + Turborepo 远程缓存,构建时间从 30 分钟降到 5 分钟。

6.3 自定义 loader 多

webpack 的 JS loader 灵活,Rspack 完全兼容——很多公司有自定义 loader,Rspack 不用重写。

七、Rspack 的局限

7.1 还在快速发展

7.2 生产构建产物偶尔有差异

webpack 5.x 的某些 advanced optimization,Rspack 还在追赶。

7.3 swc-loader 不能完全替代 babel-loader

某些特殊 babel 插件(自定义语法),swc-loader 不支持。

八、Rspack vs Vite vs Turbopack

8.1 对比表

维度 Rspack Vite Turbopack
配置兼容 webpack ✅ ❌ ❌
开发体验 ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
生产产物 ⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐
启动速度 ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
框架绑定 无 无 Next.js
生态 早期 成熟 早期

8.2 选型建议

存量 webpack     → Rspack / Rsbuild(无痛迁移)
新项目+体验优先   → Vite
Next.js 项目      → Turbopack(默认)
存量 Vite         → 继续用 Vite

九、Rsbuild 实战案例

9.1 项目结构

.
├── rsbuild.config.ts
├── src/
│   ├── index.ts
│   ├── App.tsx
│   └── components/
├── public/
└── tsconfig.json

9.2 完整配置

// rsbuild.config.ts
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';
import { pluginTypeCheck } from '@rsbuild/plugin-type-check';

export default defineConfig({
    plugins: [
        pluginReact(),
        pluginTypeCheck(),  // 独立类型检查
    ],

    source: {
        entry: {
            index: './src/index.tsx',
        },
        alias: {
            '@': './src',
        },
        define: {
            'process.env.APP_VERSION': JSON.stringify(process.env.npm_package_version),
        },
    },

    html: {
        template: './public/index.html',
        title: 'My App',
        meta: {
            description: 'My React App',
        },
    },

    output: {
        distPath: {
            root: 'dist',
        },
        polyfill: 'usage',       // 按需 polyfill
        cleanDistPath: true,
    },

    server: {
        port: 3000,
        open: true,
        historyApiFallback: true,
        proxy: {
            '/api': {
                target: 'http://localhost:8080',
                changeOrigin: true,
            },
        },
    },

    performance: {
        chunkSplit: {
            strategy: 'split-by-experience',
        },
        removeConsole: ['log', 'info'],  // 生产环境去掉 console
    },

    tools: {
        swc: {
            jsc: {
                transform: {
                    react: {
                        runtime: 'automatic',  // React 17+ JSX runtime
                    },
                },
            },
        },
    },
});

9.3 性能对比

指标 webpack 5 Rsbuild 提升
冷启动 45s 6s 7.5x
HMR 5s 300ms 16x
生产构建 60s 18s 3.3x
内存占用 3.5GB 1.8GB 1.9x

十、Module Federation 2.0

Rspack 把 Module Federation 做到了生产可用:

// 应用 A - 暴露组件
new rspack.container.ModuleFederationPlugin({
    name: 'appA',
    filename: 'remoteEntry.js',
    exposes: {
        './Button': './src/components/Button',
        './Modal': './src/components/Modal',
    },
    shared: {
        react: { singleton: true },
        'react-dom': { singleton: true },
    },
});

// 应用 B - 消费组件
new rspack.container.ModuleFederationPlugin({
    name: 'appB',
    remotes: {
        appA: 'appA@https://cdn.company.com/appA/remoteEntry.js',
    },
    shared: {
        react: { singleton: true },
    },
});

字节内部大量微前端都用 MF——Rspack 让 MF 真正可用了。

十一、本篇小结

主题 关键点
Rspack Rust 写的 webpack 兼容方案
Rsbuild Rspack 之上的开箱即用封装
性能 比 webpack 5-10 倍
兼容性 90% webpack 项目可直接迁移
适用 存量 webpack 项目
关键决策 推荐
存量 webpack Rspack
新项目 Vite / Rsbuild
库代码 Rollup

下一篇讲 从 webpack 迁移到 Rspack 实战——rsbuild 那篇文章的完整展开。

参考资料