🎉🎉🎉恭喜Rsbuild1.0版本发布!!!期望后续发展更好!!!
zepto兼容出现巨大翻车,详情请见下方zepto一节
原项目介绍
原项目是一个上古移动端Hybrid工程:
- 项目主要依赖:
vue@2.6.11+webpack@4.41.6 - CSS预处理器:
node-sass@4.14.1+sass-loader@8.0.2 - 前朝遗孽依赖:
zepto@1.2.0
Node版本切换
Node 18+
主要依赖安装
Rsbuild核心依赖:
// package.json
{
"@rsbuild/core": "^1.4.0",
"@rsbuild/plugin-vue2": "^1.4.0",
}
Rsbuild支持Vue最低版本为Vue@2.7,因此需要把旧项目从2.6升级到2.7
// package.json
{
"vue": "^2.7.14",
"vuex": "3.4.0"
}
项目根目录新增rsbuild.config.mjs
import { defineConfig } from '@rsbuild/core';
import { pluginVue2 } from '@rsbuild/plugin-vue2';
export default defineConfig({
plugins: [
pluginVue2()
],
});
npm命令替换:
// package.json
+ {
+ "dev": "rsbuild dev --open",
+ "build": "rsbuild build",
+ }
打包入口entry
原工程是一个MPA多页应用,因此需要配置多入口打包。根据官方文档使用source.entry来配置入口:
// rsbuild.config.mjs
export default defineConfig({
source: {
entry: {
home: './src/Home/index.js',
about: './src/About/index.js',
},
},
});
多页面dev的时候rsbuild默认输出所有页面的server URL地址,当页面很多的时候会占据一整屏shell空间,强迫症实在接受不了,因此参考官方自定义URL文档自定义输出:
import { logger } from "rslog"
import { defineConfig } from "@rsbuild/core";
export default defineConfig({
server: {
printUrls({ urls }) {
for(const url of urls) {
logger.greet(`${url}`)
}
},
},
});
原工程每个页面HTML都有一些个性化js引用,且使用#app节点进行Vue的挂载。而官方默认打包后的HTML文件使用#root进行挂载。因此需要配置入口HTML。根据官方文档使用html.template来配置:
// rsbuild.config.mjs
export default defineConfig({
html: {
template({ entryName }) {
const templates = {
home: './src/Home/index.html',
about: './src/About/index.html',
};
return templates[entryName]
}
},
});
VueRouter
按原工程依赖版本号固定版本号:
// package.json
{
"vue-router": "3.1.6",
}
原工程大量页面在路由守卫beforeRouteEnter的next方法中恢复路由的滚动高度:
export default {
beforeRouteEnter(to, from, next) {
next(vm => {
document.documentElement.scrollTop = document.body.scrollTop = vm.scrollTop
})
},
beforeRouteLeave(to, from, next) {
this.scrollTop = document.documentElement.scrollTop || document.body.scrollTop
next()
},
}
但是更新VueRouter小版本后发现此方法失效:vm.scrollTop有值,滚动条高度却为0。调试后发现可能失效的原因:新版本的next方法在Vue组件渲染前执行,页面还未产生滚动条,因此赋值滚动条高度失败。思虑再三按旧项目固定此依赖的版本号。
alias
根据官方文档使用resolve.alias配置路径别名
// rsbuild.config.mjs
export default defineConfig({
resolve: {
alias: {
'@styles': './assets/styles',
},
},
});
Sass
原工程node-sass仅支持Node 14,因此需要进行依赖更新以适配Node 18。去除原本的node-sass和sass-loader。Rsbuild内置了最新的sass处理,根据官方文档安装插件@rsbuild/plugin-sass即可
// package.json
{
"@rsbuild/plugin-sass": "^1.3.2",
}
// rsbuild.config.mjs
import { pluginSass } from '@rsbuild/plugin-sass';
export default defineConfig({
plugins: [
pluginSass(),
]
});
部分语法弃用警告
最新版本的rsbuild默认添加了配置来忽略
@import的警告
最新的sass 版本为1.80+,运行项目会出现一堆即将废弃的语法警告:
如果条件允许,建议根据sass官方指引针对性更改。
我们工程迁移不允许大面积更改代码,因此选择屏蔽掉这些警告。起初参考的是node-sass更换为dart-sass警告消除这篇文章。后来发现Rsbuild官网就有解决方法忽略 Sass 废弃提示。因此多看官网文档是一个好习惯。
样式覆盖
原工程node-sass使用/deep/来进行组件样式覆盖,而dart-sass使用::v-deep来进行组件样式覆盖,因此需要全局替换工程中的/deep/为::v-deep。
.test {
- /deep/ .van-radio__label {
+ ::v-deep ..van-radio__label {
color: red;
}
如果不想手动修改代码而通过构建工具统一替换,可以看我另一篇文章Rsbuild迁移之node-sass引发的血案
样式计算
dart-sass不支持 $padding / 2的写法,因此需要进行转换:
更新:是Dart Sass 2.0.0不支持此样式计算方法。使用Dart Sass 1版本依然可行,但Rsbuild会打印Warning日志,屏蔽即可。
$padding: 16px;
.test {
- padding: $padding / 2;
+ padding: calc($padding / 2);
}
不当语法修改
之前的工程有许多不当的Sass语句,编译没有问题,迁移到Rsbuild之后编译报错,需要修正过来:
.demo {
+ color: blue;
.child {
color: red'
}
- color: blue;
}
构建的时候如果有语法冲突,Rsbuild在终端中有修改提示,按照提示进行改造即可。为官方点赞👍
PostCSS
Rsbuild默认集成PostCSS。官方文档让使用tools.postcss进行配置。但经过测试,Rsbuild可以识别工程中postcss.config.js 原有的配置,因此删除旧工程中的相关依赖即可:
// package.json
- "postcss-loader": "3.0.0",
zepto
原工程有一个zepto编写的的JSBridge核心包,我实在不敢乱动,因此还是考虑进行兼容
原迁移方法使用commonjs-zepto包进行替换。但发现commonjs-zepto和html2canvas有重大兼容问题:使用commonjs-zepto后html2canvas生成的canvas中莫名出现很多normal字样,且样式布局错乱。因此使用zepto-webpack替换,目前测试没有问题
zepto是AMD格式的包,Webpack、Rsbuild直接使用会报错。旧项目通过exports-loader、script-loader 转换成CommonJS:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: require.resolve('zepto'),
loader: 'exports-loader?window.Zepto!script-loader'
}
]
}
}
然后在代码使用:
import $ from "zepto"
迁移Rsbuild时考虑去除多余的loader。因此转换思路使用commonjs-zepto zepto-webpack包替换,然后新建一个zepto的alias进行代码兼容。
// rsbuild.config.mjs
export default defineConfig({
source: {
alias: {
'zepto': 'zepto-webpack',
},
},
});
静态资源
Rsbuild内置对静态资源的处理,因此不需要进行额外的改造,把原项目中处理静态资源的相关loader删除即可。
Rsbuild构建的CSS产物中,静态资源路径是一个基于output.assetPrefix 的绝对路径。比如:
// css output
.test {
background: transparent url(prefix/static/image/a.24ae3b16.png) no-repeat;
}
我们项目的Hybrid App客户端将远端页面代码拉至本地,再通过file:// 加载。上述这种CSS文件通过绝对路径加载静态资源的方式会失效,找不到对应资源。
询问AI回答如下:
CSS 中的
url()路径解析则更 “静态”,它的基准路径是CSS 文件本身所在的位置,而不是页面路径,当assetPrefix设置的绝对路径(逻辑路径)和本地文件的物理路径不匹配时,就会加载失败。
因此需要将CSS中的静态资源访问改为相对路径。Webpack中通过配置mini-css-extract-plugin 的publicPath 来实现此功能。而在Rsbuild 中通过tools.cssExtract进行配置:
import { defineConfig } from "@rsbuild/core";
export default defineConfig({
tools: {
cssExtract: {
loaderOptions: {
publicPath: "../../"
}
}
},
});
由于Rsbuild 构建会将异步CSS单独放入static/css/async目录下,因此此文件夹中的CSS文件,配置../../ 的publicPath也不会生效。需要将异步CSS也放入一般CSS文件目录下:
import { defineConfig } from "@rsbuild/core";
export default defineConfig({
output: {
assetPrefix: "prefix",
distPath: {
cssAsync: 'static/css',
}
},
tools: {
cssExtract: {
loaderOptions: {
publicPath: "../../"
}
}
},
});
浏览器兼容性
语法降级和polyfill相关可以看这篇文章,要不要添加polyfill可以自行斟酌。我们项目算是上古项目,为保证迁移后的兼容性,还是加了polyfill。
旧项目通过引入@babel/polyfill ,兼容低版本浏览器。Rsbuild使用SWC 进行代码转换,转换@babel/polyfill时会报错,因此需要全量去掉项目中的引用:
- import '@babel/polyfill';
然后在项目根目录添加.browserslistrc 文件配置浏览器兼容范围:
下面的配置是我们项目的目标兼容范围,可以根据你们项目组的兼容范围自定义
>0.3%, last 2 versions, since 2018, not dead
然后在配置文件中根据官方文档配置适合自己项目的Polyfill方案:
import { defineConfig } from "@rsbuild/core";
export default defineConfig({
output: {
polyfill: "usage"
},
});
构建产物比较
webpack4.4构建

Rsbuild构建

结语
上面构建产物统计可以看出新工具的提升巨大,老旧项目可以尝试迁移。感谢社区的努力,让上古僵尸项目可以焕发新生。❤️❤️❤️