背景
因为我们的项目是基于vue-elemen-admin开发的,所以vue,vuex,element-ui版本都比较老,这次刚好一次性升级到支持的最新版本
去年整个项目做了微服务拆分,把一整个项目拆成好几个板块,使用的是阿里的qiankun微服务,因为技术上比较成熟点,网上的示例也很多,不过听字节的朋友说字节也出了一个叫garfish的微服务,不知道怎么样,以后有机会试试,这次先使用qiankun。
替换原因
首先是项目开发很久了,有一个诟病大家应该都知道的,就是vue-cli实在是太慢了,因为是基于webpack4版本的,所以构建速度慢很正常,其次打出来的包也很体积也很大,因为各个开发水平不一,所以开发出来的代码无法保证精简以及质量,所以很难保证打包出来的项目体积,因为不少次被上面要求优化用户体验,所以这次就想着不如升级一下。然后为什么不用rspack呢,因为在掘金上搜索迁移的时候刚好看到几个大佬发的rsbuild迁移,就直接抄过来了。rsbuild应该是rspack的集成版本我猜,反正除了踩了一些坑确实简单很多。
开始迁移工作
juejin.cn/post/732821... juejin.cn/post/739512... 这里主要参考这两位大佬的迁移方案,里面都有详细的哪些文件需要删除需要修改,我就不一一概括了。第一步创建一个rsbuild.config.js的文件,和原来的vue.config.js是一样的功能。然后安装rsbuild需要的所有node包
完整代码
jsimport
import { pluginLess } from '@rsbuild/plugin-less'
import { pluginSass } from '@rsbuild/plugin-sass'
import { pluginVue2 } from '@rsbuild/plugin-vue2'
const { pluginVue2Jsx } = require('@rsbuild/plugin-vue2-jsx')
import { pluginBabel } from '@rsbuild/plugin-babel'
import { pluginNodePolyfill } from '@rsbuild/plugin-node-polyfill'
const path = require('path')
const { publicVars } = loadEnv({ prefixes: ['VUE_APP_'] })
const defaultSettings = require('./src/settings.js')
function resolve(dir) {
return path.join(__dirname, dir)
}
const name = defaultSettings.title || 'vue Element Admin' // page title
const port = process.env.port || process.env.npm_config_port || 8800 // dev port
// 微前端子项目配置注入
const packageName = require('./package.json').name
const Timestamp = new Date().getTime()
// const Timestamp = new Date().getTime()
export default defineConfig({
output: {
assetPrefix: '/abc', // 生产环境下的publicpath,但是有一个问题,只有生产环境才会生效,所以这里配置在沙箱环境下是无效的,会导致静态资源加载失败,所以需要配置下面的server.base
polyfill: 'usage',
sourceMap: false, // 是否生成sourceMap
clean: true, // 是否清理dist目录
filename: 'js/[name].js',
cssFilename: 'css/[name].css',
assetModuleFilename: 'assets/[hash][ext]'
},
performance: {
chunkSplit: {
strategy: 'split-by-experience'
},
removeConsole: true,
removeMomentLocale: true
},
plugins: [
pluginVue2(),
pluginVue2Jsx(), // 支持jsx,只要在vue文件中需要用到jsx写法就需要引入这个插件,在脚本中还要需要加入lang="jsx",否则不会生效
pluginLess(),
pluginSass({
sassLoaderOptions: {
sassOptions: {
silenceDeprecations: ['import'] // 允许使用import引入
}
}
}),
pluginNodePolyfill(),
pluginBabel({
include: /\.(?:jsx|tsx)$/
})
],
source: {
entry: {
index: './src/main.js' // 指定入口文件
},
define: publicVars
},
html: {
template: './public/index.html'
},
dev: {
assetPrefix: '/abc' // 这个是用作开发环境下的publicpath
},
tools: {
rspack: {
resolve: {
name: name,
extensions: ['.vue', '.js', '.jsx', '.tsx', '.ts', '.json'],
alias: {
'@': path.resolve(__dirname, 'src')
}
},
output: {
library: `${packageName}-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${packageName}`,
filename: `js/[name].${Timestamp}.js`,
chunkFilename: `js/[name].${Timestamp}.js`
}
},
bundlerChain: (chain, { CHAIN_ID }) => {
chain.module.rule(CHAIN_ID.RULE.SVG).oneOfs.clear()
chain.module
.rule(CHAIN_ID.RULE.SVG)
.use('vue-svg-loader')
.loader('vue-svg-loader')
chain.module
.rule('svg')
.exclude.add(resolve('src/icons'))
.end()
chain.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end()
}
},
server: {
port: port,
open: true,
compress: true,
base: '/abc', // 这里是子项目的基础路径,配置在主项目中的,作为主项目访问子项目静态资源的路径,由于没有rsbuild没有publicpath,所以这里一定要配
headers: {
// 由于qiankun内部请求都是fetch来请求资源,因此子应用必须容许跨域
'Access-Control-Allow-Origin': '*'
},
proxy: {
[process.env.VUE_APP_BASE_API]: {
target: `http://xxxxx`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
}
}
}
})
先贴下完整的代码,基本上配置就是如上图然后几个要注意的点后面也都加了注释,主要说下几个地方
- 51行的这个import一定要加上,否则项目中用到所有的引入都会报错
- assetPrefix相当于是publicpath,这个东西output里的这个只有在生产模式下才会生效,一定要注意,和webpack的publicpath不一样,所以一定要在server里的base再添加一个,才能保证项目正常运行,否则读取资源会出问题
- pluginVue2Jsx这个插件引入了以后就可以在vue2里面写jsx了,但是有一点要记住,写的时候需要在外层的脚本上加上
<script lang="jsx">
这个,否则还是会报错 - pluginVue2这个如果是vue3项目就引入pluginVue就好了
- qiankun的子项目入口需要从这里抛出,要写在tools的output里面,这个相当于webpack的chainwebpack,写法就是我这样就好了
修改packjson
package.json
"dev": "rsbuild dev",
"build:prod": "rsbuild build --env-mode production",
"build:stage": "rsbuild build --env-mode staging",
需要把原来的运行指令改成rsbuild的,然后因为rsbuild只支持读取三种环境,develop,production和none,所以这里如果有额外的测试环境等需要用 --env-mode production这种写法来读取就好了
删除的配置
因为完整的替换了vue-cli,所有项目里基本上跟vue-cli相关的都可以删掉了,这里可以参考我上面发的第一个链接里面大佬的建议,对了,还有就是vue-element-admin里面postcss.config.js也可以删掉,不然会报错的
qiankun配置
qiankun的子项目的配置就不详细说了,主要说一下这边的坑。我在顺利把子项目构建起来以后,在主服务中一直报错,提示子服务没起起来,我找了很多文档都没发现问题,但是我知道大概率是在子服务的publicpath上出问题了
js
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__ + '/abc/'
}
其实就是这里的问题,前后的/一定不能去掉,一旦去掉就会有问题,虽然是个很小的问题,但是坑是真的大,找了两天无意中才解决
总结
写文档主要是为了记录一下,虽然坑都是小问题,但是确实处理起来都挺麻烦的,然后rsbuild好像出来也没多久,但是用起来确实很丝滑,老项目焕发生机了属于是,文档写的也都还可以,不过估计用的人少踩坑的问题不多,构建和打包速度都很快,打包体积也小了很多。我这个是最简单的版本,后续还有很多地方需要改善,水平比较差,有问题多指正