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

相关推荐
大怪v12 分钟前
【Virtual World 04】我们的目标,无限宇宙!!
前端·javascript·代码规范
狂炫冰美式34 分钟前
不谈技术,搞点文化 🧀 —— 从复活一句明代残诗破局产品迭代
前端·人工智能·后端
xw51 小时前
npm几个实用命令
前端·npm
!win !1 小时前
npm几个实用命令
前端·npm
代码狂想家1 小时前
使用openEuler从零构建用户管理系统Web应用平台
前端
dorisrv3 小时前
优雅的React表单状态管理
前端
蓝瑟3 小时前
告别重复造轮子!业务组件多场景复用实战指南
前端·javascript·设计模式
dorisrv3 小时前
高性能的懒加载与无限滚动实现
前端
韭菜炒大葱4 小时前
别等了!用 Vue 3 让 AI 边想边说,字字蹦到你脸上
前端·vue.js·aigc
StarkCoder4 小时前
求求你,别在 Swift 协程开头写 guard let self = self 了!
前端