vue-cli3+qiankun迁移至rsbuild

背景

因为我们的项目是基于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好像出来也没多久,但是用起来确实很丝滑,老项目焕发生机了属于是,文档写的也都还可以,不过估计用的人少踩坑的问题不多,构建和打包速度都很快,打包体积也小了很多。我这个是最简单的版本,后续还有很多地方需要改善,水平比较差,有问题多指正

相关推荐
zhanghaisong_201517 分钟前
Caused by: org.attoparser.ParseException:
前端·javascript·html·thymeleaf
Eric_见嘉20 分钟前
真的能无限试(白)用(嫖)cursor 吗?
前端·visual studio code
DK七七1 小时前
多端校园圈子论坛小程序,多个学校同时代理,校园小程序分展示后台管理源码
开发语言·前端·微信小程序·小程序·php
老赵的博客1 小时前
QSS 设置bug
前端·bug·音视频
Chikaoya1 小时前
项目中用户数据获取遇到bug
前端·typescript·vue·bug
南城夏季1 小时前
蓝领招聘二期笔记
前端·javascript·笔记
Huazie1 小时前
来花个几分钟,轻松掌握 Hexo Diversity 主题配置内容
前端·javascript·hexo
NoloveisGod1 小时前
Vue的基础使用
前端·javascript·vue.js
GISer_Jing1 小时前
前端系统设计面试题(二)Javascript\Vue
前端·javascript·vue.js
海上彼尚2 小时前
实现3D热力图
前端·javascript·3d