Rspack是最近出来的基于 Rust 的高性能 Web 构建工具,它的API及配置方式、插件等基本对齐webpack(v5)生态,具有如下的主要特性(取自官方文档):
- 启动速度极快
- 闪电般的 HMR
- 兼容 webpack
- 内置常见构建能力
- 默认生产优化
- 框架无关
很多公司或团队应该还有很多庞大而臃肿的老项目都是基于vue 2,经常本地开发以及发布时的打包时间都要好几分钟甚至十几分钟,大大影响了开发及发布效率,所以今天我们主要介绍基于vue 2(vue-cli或者webpack配置)的老项目如何迁移至Rspack以此来提升打包部署的速度。
升级@vue/cli v4 -> v5(可选)
如果你的vue项目是基于@vue/cli v4的,可以先升级到v5(升级文档),升级的原因是v4是基于webpack4的,而rspack只支持webpack5,如果你本身直接依赖了webpack4的一些插件loader啥的,需要自己删掉重装webpack5相关的依赖,当然这是可选的,你可以直接无视,正常来说无脑升级就可以搞定:
@vue/cli的各种插件、ESLint配置
如果你之前用的是@vue/cli的各种插件来配置eslint的,很多都得去掉,直接用eslint对应vue的插件,主要就是@vue/xxx
开头的这些库,如@vue/cli-plugin-babel
,@vue/cli-plugin-eslint
, @vue/eslint-config-prettier
等,以及删除babel相关的库;
对于ESLint来说,保留eslint-plugin-xxx
相关的即可,如eslint-plugin-vue
,之前用vue-cli-service lint
的后面直接用eslint --ext .ts,.js,.vue --fix
这种命令;
对于TypeScript来说,eslint里parserOptions.parser
直接使用@typescript-eslint/parser
,extends
里使用plugin:@typescript-eslint/recommended
,去掉@vue/typescript
(如果有用的话);
对于Prettier来说,去掉@vue/prettier
(如果有的话),直接使用plugin:prettier/recommended
;
对于Githooks来说,@vue/cli自带了pre-commit
能力,通过package.json里gitHooks
配置,当迁移完之后就没有了,需要自己安装husky
库添加hook。
json
// 这个得去掉
{
"gitHooks": {
"pre-commit": "lint-staged"
},
}
安装Rspack及基本配置
接下来先安装rspack库:
bash
npm i @rspack/cli -D
# 安装html plugin,可选,也可以用自带的
npm i @rspack/plugin-html -D
安装完创建rspack.config.js
,配置方式跟webpack雷同,entry
,output
,resolve.alias
, devServer
, devtool
等这些常规项目基本可以无脑copy过来。
builtins 选项
builtins
选项里是rspack自带的一些配置能力,无需额外插件(可能在后续的更新中为了对齐webpack又把一些配置以单独的插件来处理),常用的如下,更多的请查看builtins文档:
js
{
// ...
builtins: {
// 压缩的一些配置,比如去掉console
minifyOptions: {
dropConsole: true
},
// 设置一些环境变量在app里使用
define: {
'process.env.APP_VERSION': JSON.stringify('1.0.0')
},
// 类似copy-webpack-plugin的作用,直接复制相关文件
copy: {
patterns: [
{
from: './public'
}
]
}
}
}
添加vue支持
Rspack从v0.2开始支持vue,vue3的话需要vue-loader >= 17.2.2
,而要支持vue2的话需要vue-loader@15
,我们先来看下配置,在rspack.config.js
:
js
const isProd = process.env.NODE_ENV === 'production'
module.exports = {
//...
modules: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
compilerOptions: {
// 替换老的compilerOptions.preserveWhitespace=false
whitespace: 'condense'
}
}
},
{
// 处理使用ts的vue文件
resourceQuery: /lang=ts/,
type: 'typescript'
},
{
// 处理vue文件里使用less的style标签
resourceQuery: /lang=less/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
// dev下使用sourceMap
sourceMap: !isProd
}
},
{
loader: 'less-loader',
options: {
sourceMap: !isProd,
lessOptions: {
// 一些第三方ui库需要这个为true
javascriptEnabled: true
}
}
}
],
type: 'javascript/auto'
},
{
resourceQuery: /lang=css/,
use: ['vue-style-loader', 'css-loader'],
type: 'javascript/auto'
},
{
// 单纯的less文件
test: /\.less$/,
loader: 'less-loader',
options: {
sourceMap: !isProd,
lessOptions: {
javascriptEnabled: true
}
},
type: 'css'
},
{
// 单纯的css文件
test: /\.css$/,
type: 'css'
},
{
// 静态资源
test: /\.(svg|png|jpe?g|gif|webp|woff2?|eot|ttf)$/i,
type: 'asset'
}
]
}
}
上面一堆loader配下来,如果运气好的话就大功告成了,接下来我们再来看下还有哪些需要注意的(如果在自己项目中有用到的话):
样式文件里的:export
使用webpack时我们比如可以在less文件里export变量出去,这样在js里也可以统一引用样式变量:
less
@primary-color: #0a8afa;
@primary-pink-color: #ff6699;
:export {
primaryColor: @primary-color;
pinkPrimaryColor: @primary-pink-color;
}
然后在js里:
js
import { primaryColor } from 'path/to/theme.less'
迁移后还是用其他解决方案吧,这个似乎已经不生效了。
expertments.css
的问题
官方文档在vue2支持那边说了:
请确保在配置 Vue2 项目时关闭
experiments.css
或在 CSS 相关的规则中使用Rule.type = "javascript/auto"
在v0.2.11
之后的版本不能把experiments.css=false
,会直接编译失败,直接把这个配置去掉,用type=javascript/auto
。
unplugin及unplugin-auto-import的问题
越来越多的vue项目开始使用unplugin-auto-import
及其他unplugin插件,特别是在使用composition api的时候,避免来回重复的各种import,插件会在编译时自动加上对应的macro,unplugin本身已支持Rspack,只是还是处于实验阶段,官方不建议使用到线上,可能导致的问题如笔者提到的这个issue:
但是其实我们很多项目已经使用了,而且感觉回不去了,不然得修改很多代码,不太现实,这种情况下我们有2条路选择:
- 等官方更新修复
- 修改插件代码,使用自己修改过的plugin
第一个不着急的话可以慢慢等,如果急需提升线上打包速度的话就可能需要自己修改了,我们先来看下笔者在迁移时发现上面issue里的问题的根源是什么:
从上面unplugin的rspack插件的代码里看出当做转化的时候include
无脑包含了所有的文件例如静态资源,导致打包出来的静态资源跟源文件不一样了,而且这里的include
也不接收外面参数,导致外面使用的插件也无法修改,那我们要在哪里改呢,直接改这个include么,还是说让他接收外面参数,还是说有hook在外面用的地方可以再次修改compiler里面的数据?
我们再看下unplugin的readme的framework-specific-logic这块,它本身提供了rspack(compiler)
的回调hook,也就是在这个回调里你还可以直接把compiler里面的东西给改掉,这看起来就是我们需要的。
那我们就试下,在使用unplugin-auto-import
的时候加上,发现还是不行🥺
,加上console看连hook都没执行,难道是个假hook?笔者再去看了下auto-import的代码,发现它压根没加rspack的hook回调支持(可能由于上层rspack支持还处于实验阶段),也就是你传了等于没传,真的是太难了😭。
最后笔者的临时方案还是改node_modules里unplugin-auto-import的相关代码使其能够接受用户options里的rspack hook,
注意这里的
unplugin
,unplugin-auto-import
及其他使用的unplugin插件都需要固定版本,它打包出来的文件都是带hash的,如果没固定,自己修改过的代码引用的文件可能会不存在!
以unplugin-auto-import为例,修改里面的代码:
然后在rspack.config.js
里使用修改过的版本:
js
function unpluginRspackHook(compiler) {
if (!compiler.options.module?.rules?.length) return
for (const rule of compiler.options.module.rules) {
if (rule.use?.loader?.includes('rspack/loaders/')) {
if (!rule.include || String(rule.include).includes('.*')) {
// 把这里改成只处理vue,js,ts相关文件
rule.include = [/\.vue$/, /\.vue\?vue/, /\.tsx?$/, /\.jsx?$/]
}
}
}
}
module.exports = {
plugins: [
// ...
{
AutoImport({
imports: ['vue', 'vue-router'],
rspack: unpluginRspackHook
})
}
]
}
这样搞完顺利编译通过,而且静态资源也正常了✅
总结
本文主要介绍了vue老项目迁移到Rspack的过程、遇到的一些坑及对应的一些解决思路,有遇到过其他坑的大佬们可以交流下;总的来说迁移后生产打包速度基本可以提升80%左右,本地开发也有大幅提升(跟vite的秒开可能还差点,毕竟实现思路不一样🤔),让屎山老项目再次焕发生机🍏。
希望能对已在迁移或准备迁移的项目有所帮助,少走些弯路!