我把公司项目从 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. [ ] 对比构建速度和产物体积

评论区

0 条评论

登录后可评论。

查看完整榜单
查看完整榜单
查看完整榜单