我们那个写了五年的老旧 React 项目,开发启动时间已经飙升到了 3 分钟,每次修改代码热更新(HMR)都要等上 15 到 20 秒。开发体验差到极致,天天都在“改行代码去接杯水”的节奏里度过。之前尝试过转到 Vite,但在转换大量 CommonJS 依赖和各种非标准的 webpack 魔法语法时,直接被排查不完的运行时报错劝退。最终,我们把目光投向了近来大热的 Rust 构建工具——Rspack。
迁移过程并不是一键搞定的爽剧,而是充满了跟各种遗留 Webpack 插件斗智斗勇的踩坑史。虽然官方宣传 Rspack 拥有极高的 Webpack 兼容度,但如果你的项目里塞满了自定义 Loader、特定版本的 Less 配置,或者依赖了某些冷门的 Webpack 内部钩子,那迁移过程依然是个心智负担极大的重体力活。
我们遇到的第一个大坑是 less-loader 与 CSS Modules 的配合问题。旧项目里大量使用了 CSS Modules 进行样式隔离,同时在 Less 中定义了许多全局混入(mixin)。Rspack 内置了极其高效的 CSS 处理器,但默认的 CSS Modules 处理逻辑和原本 Webpack 配合 less-loader 有细微区别。如果不做硬编码级别的兼容,编译出来的类名哈希值就会错乱,导致整个后台管理界面的样式直接崩溃。
下面是我们耗费了两天时间,反复调整并最终稳定跑在生产环境的 rspack.config.js 配置:
const path = require('path');
const rspack = require('@rspack/core');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
entry: {
main: './src/index.tsx',
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
module: {
rules: [
{
test: /\.(j|t)sx?$/,
use: [
{
loader: 'builtin:swc-loader',
options: {
jsc: {
parser: {
syntax: 'typescript',
tsx: true,
},
transform: {
react: {
runtime: 'automatic',
development: true,
refresh: true,
},
},
},
},
},
],
},
{
test: /\.module\.less$/,
type: 'css/module',
use: [
{
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true,
modifyVars: {
'@primary-color': '#1890ff',
},
},
},
},
],
},
{
test: /\.less$/,
exclude: /\.module\.less$/,
type: 'css',
use: [
{
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true,
},
},
},
],
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
}),
new rspack.ReactRefreshPlugin(),
new rspack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
}),
],
devServer: {
port: 8080,
hot: true,
historyApiFallback: true,
headers: {
'Access-Control-Allow-Origin': '*',
},
},
};
这里要吐槽一下 Rspack 的内置 builtin:swc-loader。它的编译速度确实无可挑剔,但如果你的 React 代码里用到了旧版的装饰器(Legacy Decorators)或者特定的 TS 元数据反射(Metadata Reflection),就必须在 swc-loader 的配置里显式开启对应的编译器开关,否则直接在词法解析阶段就会报错。
其次就是旧的打包插件生态。像 copy-webpack-plugin 这种工具,在 Rspack 中应该干脆替换为 Rspack 内置的 rspack.CopyRspackPlugin,以榨干 Rust 级别的执行性能。直接混用 Webpack 的旧 JS 插件往往会导致 Rust 核心与 Node.js 之间频繁进行序列化通信,极大地拖慢编译进程,甚至引发神秘的内存泄漏。
目前,迁移到 Rspack 后的开发首屏启动直接从 3 分钟缩短到了 12 秒,热更新几乎是秒级完成,体验提升非常显著。至于生产构建,我们暂时保留了原有的 Webpack 打包分支,做双引擎并跑,观察一段时间看看 Rspack 输出的代码在老旧浏览器上是否会有潜在的兼容性问题。