我把公司项目从 Webpack 迁移到 Rspack 了,构建快了 10 倍,但这几个坑我先帮你踩了
我把公司项目从 Webpack 迁移到 Rspack 了,构建快了 10 倍,但这几个坑我先帮你踩了
先说结论:如果你们项目还在用 Webpack 构建,且每次冷启动要等 30 秒以上,直接上 Rspack 是当前性价比最高的方案,没有之一。
Rspack 是字节跳动开源的 Rust 打包工具,走的是兼容 Webpack 生态的路线,不像 Vite 那样需要你改一整套配置。如果你有现成的 Webpack 项目,Rspack 可以直接替换,迁移成本低到离谱。
迁移前后到底差多少?
先上数据,用我们实际项目跑的结果:
| 指标 | Webpack 5 | Rspack 1.x | 提升倍数 |
| 冷启动 (Dev) | 38s | 3.2s | 约 12x |
| HMR 热更新 | ~2s | ~80ms | 约 25x |
| 生产构建 | 125s | 14s | 约 9x |
| 内存占用 | 2.1GB | 780MB | 少 63% |
别觉得夸张,这数字基本是 Rspack 官方宣称的 5-10 倍提升的实际验证。我们项目大概 200+ 页面,30 万行代码的 Vue3 中后台系统,这个量级的项目提升最明显。
第一件事:搞清楚你的 Webpack 配置能不能兼容
Rspack 的口号是”兼容 Webpack”,但有条件的。它兼容的是 Webpack 5 的配置范式,不是百分百兼容所有 loader 和 plugin。
我列个对照表,你们可以先对着跑一遍:
/* js */
// webpack.config.js - 原始配置
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
entry: './src/main.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js'
},
resolve: {
alias: { '@': path.resolve(__dirname, 'src') },
extensions: ['.ts', '.js', '.vue', '.json']
},
module: {
rules: [
{ test: /.vue$/, use: 'vue-loader' },
{ test: /.ts$/, use: 'babel-loader' },
{ test: /.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'] }
]
},
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({ template: './index.html' }),
new MiniCssExtractPlugin()
]
}
改成 Rspack 配置:
/* js */
// rspack.config.js
const rspack = require('@rspack/core')
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
entry: './src/main.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js'
},
resolve: {
alias: { '@': path.resolve(__dirname, 'src') },
extensions: ['.ts', '.js', '.vue', '.json']
},
module: {
rules: [
{ test: /.vue$/, use: 'vue-loader' },
{ test: /.ts$/, use: 'builtin:swc-loader' }, // 🔥 关键变化
{ test: /.css$/, use: [rspack.CssExtractRspackPlugin.loader, 'css-loader'] }
]
},
plugins: [
new VueLoaderPlugin(),
new rspack.HtmlRspackPlugin({ template: './index.html' }),
new rspack.CssExtractRspackPlugin()
]
}
看出区别了吗?核心几点:
1. babel-loader → builtin:swc-loader
这是提速最关键的一步。Rspack 内置了 SWC 来做转译,以 Rust 运行,比 Babel 快两个数量级。如果你的项目用 TypeScript,builtin:swc-loader 可以直接替代 ts-loader + babel-loader。
2. html-webpack-plugin → HtmlRspackPlugin
Rspack 官方的替代品,接口类似但更简洁。
3. mini-css-extract-plugin → CssExtractRspackPlugin
同理,官方内置替代。
迁移中最容易踩的 5 个坑
坑一:postcss 和 autoprefixer 需要单独配置
Rspack 内置了 CSS 处理能力,但 默认不包含 autoprefixer。如果你项目依赖自动加浏览器前缀,需要在 rspack.config.js 里手动配:
/* js */
module.exports = {
module: {
rules: [
{
test: /.css$/,
use: [
rspack.CssExtractRspackPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [require('autoprefixer')]
}
}
}
]
}
]
}
}
坑二:CopyWebpackPlugin 的压缩行为不一样
如果你用了 copy-webpack-plugin 来复制静态资源,换成 Rspack 的 CopyRspackPlugin 后要注意一个细节——它的 minimized 参数含义是”源文件是否已被压缩过”,不是”是否要压缩”。这完全是反直觉的:
/* js */
// ❌ 以为是把压缩关掉
new rspack.CopyRspackPlugin({
patterns: [{ from: 'public', minimized: false }]
})
// ✅ 正确:告诉插件"源文件已经被压缩过了,不要重复处理"
new rspack.CopyRspackPlugin({
patterns: [{ from: 'public', minimized: true }]
})
我们团队有人在这上面卡了半天,iconfont 的 css 被错误压缩后 Unicode 编码乱了,字体图标全变成乱码。
坑三:某些 Webpack Loader 不兼容
Rspack 目前还在快速迭代中,一些冷门 loader 可能不支持。我们遇到的:
- svg-sprite-loader:Rspack 不支持,换成
@svgr/webpack+ 内联 SVG 组件方案 - thread-loader:不需要了,Rspack 本身就并行处理
- cache-loader:同样不需要,Rspack 自带增量编译
一个简单的判断方法:看 loader 是否在 rspack 的兼容列表里,不在的话先去 rspack 官方插件列表 找替代品。
坑四:Vue SFC 中样式穿透 /deep/ 失效
如果你用到 Vue2 的 /deep/ 选择器,迁移后可能会样式异常。虽然 Rspack 支持 css-loader 处理 scoped 样式,但在 Vue2 中 ::v-deep 是更好的选择。
/* css */
/* ❌ 不兼容 */
.parent /deep/ .child { color: red; }
/* ✅ 推荐 */
.parent :deep(.child) { color: red; }
坑五:DefinePlugin 的语法差异
Webpack 的 DefinePlugin 把值当代码直接注入,而 Rspack 的更严格,值必须是 JSON 可序列化的:
/* js */
// webpack - 这样也行
new webpack.DefinePlugin({
'process.env.API_URL': JSON.stringify('https://api.example.com')
})
// rspack - 更推荐用 rspack.DefinePlugin,参数结构略微不同
new rspack.DefinePlugin({
'process.env.API_URL': JSON.stringify('https://api.example.com')
})
渐进式迁移:不用一次性全改
如果项目太大了,Rspack 提供了 混合模式,你可以让部分模块继续走 Webpack:
/* js */
module.exports = {
// 大部分用 Rspack
experiments: {
rspackFuture: {
// 设置某些模块降级到 webpack
bundlerInfo: {
forceWebpack: [path.resolve(__dirname, 'src/legacy-module')]
}
}
}
}
不过说实话,这个功能我在实践中没用上。因为 Rspack 的覆盖率已经很高了,大部分常用的 loader 和 plugin 都有替代方案。
迁移后的收益不只是快
除了构建速度提升,我们还发现了几个隐性收益:
- CI 流水线从 12 分钟降到 4 分钟:生产构建快了,CI 自然也快了。团队每天的提交流程流畅很多。
- 开发者体验质变:热更新 80ms,基本改完代码一眨眼就看到了,不再有改一行等 2 秒的体验割裂。
- 内存占用降低 60% 多:以前 16GB 的 Mac 跑两个项目就卡,现在同时开三个没问题。
说两句实在的
Rspack 不是万能的。如果你项目依赖了一些很冷门的 Webpack 插件,可能会遇到兼容问题。建议先在分支上花一两天做 POC,跑一遍所有功能,确认没问题再全量切。
但如果你问我现在迁值不值——值。从 Webpack 到 Rspack,迁移成本大概是 Vite 的一半,性能提升几乎一样。对于还在用 Webpack 的中大型项目,这是 2026 年最值得做的基础设施升级之一。
最后送个 checklist,按这顺序来,不会漏:
1. [ ] 移除 webpack 及其相关依赖 (webpack-cli, webpack-dev-server)
2. [ ] 安装 @rspack/core, @rspack/cli
3. [ ] 创建 rspack.config.js
4. [ ] 替换 babel-loader → builtin:swc-loader
5. [ ] 替换 html-webpack-plugin → HtmlRspackPlugin
6. [ ] 替换 mini-css-extract-plugin → CssExtractRspackPlugin
7. [ ] 检查 postcss 配置是否生效
8. [ ] 检查所有 Copy 资源是否正确复制
9. [ ] 启动项目,跑一遍所有功能
10. [ ] 对比构建速度和产物体积
评论区
登录后可评论。












