综合对比
webpack项目整体上可以无痛迁移到rsbuild,其中rspack对标webpack,swc对标babel和terser,这些对标不仅是从能力上对标,更是参考了目标的大量配置api设计,因此绝大多数重要能力的配置api都可以沿用webpack的,迁移过程中几乎不需要关注能力/特性丢失问题,体验极佳。
编译
js(x)/ts(x)编译
webapck大多基于babel,rsbuild基于swc,swc的配置也对标了babel常用的preset和plugin,如@babel/preset-react,不过也缺失了一些细节优化插件,如@babel/plugin-proposal-class-properties。
rsbuild提供了常用的配置插件,默认值的设置也比较贴近实践,使用更为简单,比如对react的编译:
javascript
import { pluginReact } from '@rsbuild/plugin-react';
export default {
plugins: [pluginReact()],
};
如果确实需要使用部分babel插件,比如项目中可能有自定义的ast处理脚本,rsbuild也提供了接入方式:
javascript
import { pluginBabel } from '@rsbuild/plugin-babel';
export default {
plugins: [pluginBabel()],
};
需要注意的是,该插件并不是将swc切换为babel,而是在swc的基础上额外执行babel转义,因此会增加编译时间。
ts装饰器
Rsbuild 不会读取 tsconfig.json 中的 experimentalDecorators 选项,而是提供了 decorators.version 配置项来指定装饰器版本
css
export default {
source: {
decorators: {
version: 'legacy',
},
},
};
另外swc明确支持ts的decoratorMetadata,迁移的时候可以不用担心装饰器被破坏。
样式
less/sass
webpack的less-loader,sass-loader对应@rsbuild/plugin-less和@rsbuild/plugin-sass,配置的不同点在于webpack通过module.rules[].test匹配,而rsbuild通过插件本身的include和exclude
css modules
不管是规范还是多数实践,项目中一般都会对css module文件名中增加module标记,比如*.module.less。rsbuild也是根据该规范判断样式文件是否启用css modules。但webpack更灵活,可以任意设置该文件是否启用css modules:
javascript
{
test: /\.module\.css$/,
use: [
'style-loader', // 或 mini-css-extract-plugin.loader
{
loader: 'css-loader',
options: {
modules: {
mode: 'local', // 局部作用域(默认)
localIdentName: '[name]__[local]--[hash:base64:5]', // 类名生成规则
exportLocalsConvention: 'camelCase', // 导出驼峰命名(如 .btn-primary → btnPrimary)
},
},
},
],
},
因此如果迁移rsbuild,建议对不符合css modules命名规范的文件重新命名。 当然rsbuild也可以对任意文件设置是否启用css modules 在默认情况下,只有 *.module.css 结尾的文件才被视为 CSS Modules 模块。
如果你想将其他 CSS 文件也当做 CSS Modules 模块进行处理,可以通过配置 output.cssModules.auto 来实现。
比如:
javascript
export default {
output: {
cssModules: {
auto: (resource) => {
return resource.includes('.module.') || resource.includes('shared/');
},
},
},
};
设置后,以下两个文件都会被视为 CSS Modules:
javascript
import styles1 from './foo.module.css';
import styles2 from './shared/bar.css';
但个人并不推荐该方式。
postcss和tailwind
rsbuild的tools.postcss对标webpack的postcss-loader,对tailwind的配置也通过postcss。不过其内置的Lightning CSS覆盖了postcss一些插件,比如autoprefixer。
压缩
SWC vs Terser
SWC的压缩配置对标Terser,Terser有的SWC几乎都有,可以无脑切换。
css-minimizer-webpack-plugin和Lightning CSS的压缩
css-minimizer-webpack-plugin可以设置压缩工具为cssnano(默认)、Lightning CSS、csso,rsbuild仅支持Lightning CSS(当前主流)。Lightning CSS相当于cssnano(压缩)+ autoprefixer(前缀)+ postcss-preset-env(语法降级)
其他重要插件
svgr
| webpack | rsbuild | 重要区别 | |
|---|---|---|---|
| 插件 | @svgr/webpack | @rsbuild/plugin-svgr | 混合导入 |
webpack支持混合导入,svg可以当成path或一个React组件
javascript
import starUrl, { ReactComponent as Star } from './star.svg'
const App = () => (
<div>
<img src={starUrl} alt="star" />
<Star />
</div>
)
@rsbuild/plugin-svgr开启具名导入后,需要额外开启混合导入,否则无法当成path处理。虽然该插件支持混合导入,但推荐的写法如下
javascript
import Logo from './logo.svg?react';
export const App = () => <Logo />;
建议优先使用
?react来将 SVG 转换为 React 组件,而不是使用混合导入。因为混合导入有如下局限性:
- 包体积增加:混合导入会导致单个 SVG 模块被编译为两种代码(即使部分导出没有被使用),这会增加产物的包体积。
- 编译速度下降:混合导入会产生额外的编译开销。即使代码中未使用到 ReactComponent 导出,SVG 文件仍然会被 SVGR 编译。而 SVGR 是基于 Babel 实现的,性能开销较大。
code-inspector-plugin
| webpack | rsbuild | 重要区别 | |
|---|---|---|---|
| 插件 | code-inspector-plugin | code-inspector-plugin | 配置方式 |
webpack和rspack的配置方式类似
javascript
// webpack.config.js
const { codeInspectorPlugin } = require('code-inspector-plugin');
module.exports = () => ({
plugins: [
codeInspectorPlugin({
bundler: 'webpack',
}),
],
});
// rspack.config.js
const { codeInspectorPlugin } = require('code-inspector-plugin');
module.exports = {
// other config...
plugins: [
codeInspectorPlugin({
bundler: 'rspack',
}),
// other plugins...
],
};
但rsbuild的配置略有不同------rsbuild的plugin并不是rspack的plugin
javascript
// rsbuild.config.js
import { defineConfig } from '@rsbuild/core';
import { codeInspectorPlugin } from 'code-inspector-plugin';
export default defineConfig({
// ...other config
tools: {
rspack: {
plugins: [
codeInspectorPlugin({
bundler: 'rspack',
}),
],
},
},
});
rsbuild vs vite 重要特性横向对比
按需编译
vite的按需编译依赖浏览器的esm加载机制,而rsbuild的按需编译(Lazy compilation),依赖于拆包,即只编译入口,动态import引入文件按需编译。如果问开发服务器启动时间,那肯定是vite更快,但要问开发环境页面加载时间,大型项目可能rsbuild更快。
热更新
rsbuild的热更新还是chunk粒度,而vite是文件粒度,速度上来说vite更快,但实际体验差距不大。
兼容性
如果都是从webpack升级,相比vite,显然rsbuild更安全,除了插件的兼容,更关键的是编译兼容。
swc的语法降级,对标babel的@babel/preset-env,支持按需引入polyfill(类似useBuiltIns: 'usage');同时swc也可以安全地编译ts的元数据和装饰器;压缩上对标Terser,几乎可以无缝迁移相关配置。这三点超越了esbuild。
webpack特性丢失问题
rsbuild几乎没有特性丢失的问题,比如模块联邦,splitChuks均能与webpack保持一致,而vite由于内置打包是rollup,这两个特性支持并不好。
结论
纯个人意见,充满主观判断:rsbuild相比webpack全面超越,相比vite,无论是兼容性还是开发/配置体验都更好。