Rspack 与 Webpack 迁移实践
Rspack 的价值不在「比 Vite 快」,而在「能直接吃 webpack 配置」。存量项目的迁移成本被压到一两天。
一、能直接吃 webpack 配置
一句话:用 Rust 重写的、兼容 webpack 的打包器。
它兼容的是 webpack 的配置格式、loader 接口与插件接口,所以现有的 webpack.config.js、自定义 loader、大部分插件都能继续用。这决定了它的目标场景非常明确:
- 有大型 webpack 配置、短期不可能重写的老项目;
- 重度依赖 webpack 生态(自定义 compiler hooks、特定 loader)的项目;
- 用了模块联邦、需要保留这套机制的项目。
它不是「更快的新框架」,而是低成本替换。这个定位要记牢——如果你的项目可以重写,答案很可能是 Vite 而不是 Rspack。
截至 2026 年 10 月:Rspack 2.0 于 2026 年 4 月发布(现代默认值、更干净的 API、优化产物,从 1.x 升级是破坏性变更),2.1 于同年 6 月发布(新增 Rust 版 React Compiler 支持、
import.meta.glob、持久化缓存清理等)。
二、增量替换的路径
分阶段推进,跳过任何一步都会让问题变难查:
① 先在开发环境切。 验证 HMR、代理、静态资源这些基础功能。这一阶段的目标是「能跑起来」,不是「产物一致」。
② 生产环境双构建对比。 同时跑 webpack 和 Rspack 的生产构建,比对产物体积、sourcemap、核心功能回归。这一步不能省——构建成功不等于产物正确。
③ 逐步全量。 确认无差异后,再把 CI 流水线切过去。
# 双构建对比的思路:产出到不同目录,逐项比对
webpack build --output-path dist-webpack
rspack build --output-path dist-rspack
# 比对产物体积与文件清单,再跑一遍冒烟
配置文件本身的迁移通常很小,主要是:安装 Rspack、把配置指过去、替换少数不兼容的插件。Rspack 的配置格式与 webpack 几乎一致,多数情况下只是换包名:
// rspack.config.js —— 配置格式与 webpack 兼容
module.exports = {
entry: './src/index.js',
resolve: { extensions: ['.tsx', '.ts', '.js'] },
module: {
rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader'] }],
},
}
三、插件与 loader 的缺口
问题基本都出在插件层,而不是 loader 层:
- 依赖 webpack 内部钩子的自定义插件 —— Rspack 的插件接口覆盖了常用部分,但内部实现不同,深度定制的插件需要改写;
- 小众 loader —— 主流 loader(postcss-loader、svg-loader 一类)通常直接可用,冷门的要先查兼容列表;
- 配置字段差异 —— 大版本升级时会改名或调整默认值,按官方迁移指南过一遍;
- 模块联邦 —— Rspack 支持模块联邦,但相关运行时包在新版本里变成了可选依赖,用了联邦的项目要手动装上它(否则运行时会报「找不到联邦运行时」)。
判断方法很朴素:先跑一遍,看报什么错。多数不兼容会在第一步就明确暴露,反而是「构建成功但产物行为不同」这类需要靠第②步的对比来发现。
四、产物体积与行为对比
四件事,缺一件都可能漏问题:
- 产物内容对比 —— 哈希、文件清单、关键 chunk 的内容是否一致;
- 构建耗时对比 —— 记录前后数字,作为收益的依据;
# 记录迁移前后构建耗时,作为收益依据
time rspack build
# 与 webpack 时期的基线数字对比
- 运行时冒烟 —— 重点验证路由、懒加载、样式这三类最容易受影响的地方;
- 线上错误率监控对齐 —— 灰度期间盯住错误率,它比任何本地验证都真实。
只看「构建成功」是不够的。插件行为的差异往往在运行时才暴露——比如某个插件在 webpack 下注入了特定代码,在 Rspack 下行为略有不同,构建照样成功,功能却变了。
动手改配置之前,先把用到的插件列出来对照兼容清单,能省掉大半返工:
# 列出配置里实际用到的插件与 loader
node -e "const c=require('./webpack.config.js');
console.log((c.plugins||[]).map(p=>p.constructor.name).join('\n'));
console.log('--loaders--');
(c.module?.rules||[]).forEach(r=>console.log(r.test, r.use))"
# 再逐个对照官方兼容表,有缺口的先找替代再谈迁移
五、什么项目选哪个
按现状决定,而不是按喜好:
| 现状 | 选择 | 理由 |
|---|---|---|
| 大型 webpack 配置、无法重写 | Rspack | 迁移成本一两天,保住既有生态投入 |
| 新项目 / 可以重构 | Vite | 生态最大,无需背 webpack 包袱 |
| Next.js 项目 | Turbopack | 框架内置,别无选择也更省心 |
| 库打包 | Rollup / Rolldown | 干净的 ESM 产物 |
一句话总结:Rspack 是「从 webpack 来」的路径,Vite 是「从零开始或可以重来」的路径。 它们不冲突,因为它们的出发点不同。
双跑对比的关键是把两次产物拉到同一标准下比,别只比耗:
# 同一份入口,两套构建分别产出到不同目录
webpack --config webpack.config.js --output-path dist-wp
rspack build --output-path dist-rs
# 逐项比对:体积、文件数、首屏 chunk 数
du -sh dist-wp dist-rs
ls dist-wp/static/js | wc -l; ls dist-rs/static/js | wc -l
六、两条迁移路径的取舍
Rspack 并不兼容所有 webpack 插件。主流插件可用,但深度依赖内部钩子的那些需要改写。
迁移也不等于换个包:配置有差异、插件要逐个验证、产物必须回归。
它和 Vite 也不是二选一的关系,按现状选就行——一个面向 webpack 迁移,一个面向新项目。
构建成功更不等于迁移完成,必须做产物对比、运行时冒烟、错误率监控这三段验收。
迁移是否成功不看构建有没有跑通,而看产物与线上错误率有没有变。
loader 与插件的兼容清单在 rspack.dev 持续更新,迁移评估前先看目标插件是否在列。