Skip to main content

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'] }],
},
}
① dev 先切 Rspack② 生产双构建对比产物③ 全量切换验收:热更新、loader 行为验收:产物体积与运行时行为验收:CI 与缓存命中关键是第二步——只要两套产物能并行对比,切换就不是一次不可回退的赌博。跳过这一步直接全量换,等于把「构建能过」当成了「行为一致」。
图:迁移的三步与各自的验收点——每一步都可以单独回退

三、插件与 loader 的缺口​

问题基本都出在插件层,而不是 loader 层:

  • 依赖 webpack 内部钩子的自定义插件 —— Rspack 的插件接口覆盖了常用部分,但内部实现不同,深度定制的插件需要改写;
  • 小众 loader —— 主流 loader(postcss-loader、svg-loader 一类)通常直接可用,冷门的要先查兼容列表;
  • 配置字段差异 —— 大版本升级时会改名或调整默认值,按官方迁移指南过一遍;
  • 模块联邦 —— Rspack 支持模块联邦,但相关运行时包在新版本里变成了可选依赖,用了联邦的项目要手动装上它(否则运行时会报「找不到联邦运行时」)。

判断方法很朴素:先跑一遍,看报什么错。多数不兼容会在第一步就明确暴露,反而是「构建成功但产物行为不同」这类需要靠第②步的对比来发现。

四、产物体积与行为对比​

四件事,缺一件都可能漏问题:

  1. 产物内容对比 —— 哈希、文件清单、关键 chunk 的内容是否一致;
  2. 构建耗时对比 —— 记录前后数字,作为收益的依据;
# 记录迁移前后构建耗时,作为收益依据
time rspack build
# 与 webpack 时期的基线数字对比
  1. 运行时冒烟 —— 重点验证路由、懒加载、样式这三类最容易受影响的地方;
  2. 线上错误率监控对齐 —— 灰度期间盯住错误率,它比任何本地验证都真实。

只看「构建成功」是不够的。插件行为的差异往往在运行时才暴露——比如某个插件在 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 持续更新,迁移评估前先看目标插件是否在列。