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

相关推荐
范文杰3 分钟前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪11 分钟前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪20 分钟前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy1 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom2 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom2 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom2 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom2 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom2 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试
LaoZhangAI3 小时前
2025最全GPT-4o图像生成API指南:官方接口配置+15个实用提示词【保姆级教程】
前端