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

相关推荐
前端小小王7 分钟前
React Hooks
前端·javascript·react.js
迷途小码农零零发16 分钟前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀39 分钟前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪1 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef3 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6413 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻3 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云3 小时前
npm淘宝镜像
前端·npm·node.js
dz88i83 小时前
修改npm镜像源
前端·npm·node.js
Jiaberrr4 小时前
解锁 GitBook 的奥秘:从入门到精通之旅
前端·gitbook