前端项目(vue)自动化打包部署--qiankun

2,465 阅读2分钟

本文针对qiankun微前端多项目的自动打包部署,手动打包部署可以参考我上一篇文章。单项目同样可以使用。

话不多说我们直接开始。

1. 明确目标

项目目录如下,将打包好的main文件夹放在dist文件夹下

image-20220514142553521.png

最终打包main文件夹成品如下

  • main:主应用(main文件夹我放在根路径下)例如:http://localhost:8080/mian
    • children:子应用文件夹
      • boy:子应用1
      • girl:子应用2

image-20220507150112051.png

vue项目打包路径配置,可以在vue.config.js文件中配置outputDir的参数(以main项目为例)

const path = require("path") 

// main
// 将打包文件放在项目外dist/main目录下
outputDir: path.resolve(path.resolve(__dirname, "../dist/main"))

2. 项目自动打包

涉及到多项目同时的打包,这肯定就不能使用同一个进程了,通过子进程(child_process)异步开启打包,节省打包时间

同时也要兼顾项目打包完成时间,输出项目打包完成情况,兼顾多异步时,一般采取promise.all方法,监听完成情况。 但是需要更具异步之间的依赖性考虑使用 all方法 还是 allSettled 方法了

  • all方法: 等待所有都完成(或第一个失败)

  • allSettled方法: 指定的 promises 集合中每一个 promise 已经完成,无论是成功的达成或被拒绝 具体实现代码如下:(同理,多项目同时启动也可以使用子进程的spawn函数)

// 子进程
const childProcess = require('child_process')
const path = require('path')

// 获取到所有项目的绝对路径
const filePath = {
  'boy': { path: path.join(__dirname, '../boy'), isMain: false },
  'girl': { path: path.join(__dirname, '../girl'), isMain: false },
  'main': { path: path.join(__dirname, '../main'), isMain: true }
}

// cd 子应用的目录 npm run build 打包项目
function buildProject () {
  const flags = []
  // Promise数组
  const promiseList = []
  Object.keys(filePath).forEach(key => {
    // 创建一个新的promise,放在Promise数组中
    promiseList.push(
      new Promise((resolve, reject) => {
        // 开启一个子进程,执行项目打包命令
        const cp = childProcess.spawn(`cd ${filePath[key].path} && npm run build`, 
        { stdio: 'inherit', shell: true})
        // 监听子进程退出事件,code !== null 子进程自己退出
        cp.on('exit', (code) => {
          flags.push({ name: key, code })
          if(flags.length === Object.keys(filePath).length) {
            console.log("👏👏👏👏👏👏👏👏👏👏👏👏")
            flags.forEach(flag => {
              if (flag.code !== null && flag.code === 0) {
                console.log(flag.name + " rebuild successfully!")
              } else {
                console.log("\033[1;31;40m"+flag.name+" rebuild failed!\033[0m")
              }
            })
          }
          if(code === null) reject()
          // 子进程退出,更改promise的状态,并返回退出码
          resolve(code)
        })
      })
    )
    
  })
  
  // 待所有的进程都完成
  // return Promise.all(promiseList)
  // allSettled 更适合相互独立的promise,且只要发生状态改变都会进入
  // 由于子进程打包失败并不会影响主进程的流程,因此allSettled更合适
  return Promise.allSettled(promiseList)
}

// buildProject()

module.exports = {
  filePath,
  buildProject
}

3. 项目部署

项目部署需要连接服务器然后上传项目包;因此需要引导使用者操作输入信息,这时需要用到

因为命令行返回操作指令文件压缩文件上传shell命令 等存在异步过程,使用 Promise +async awiat控制异步过程和代码逻辑清晰,实现代码执行顺序的控制。

image-20220516101901531.png

image-20220516135717468.png

逐步进行,实现如图的效果:

image-20220516101643650.png

其他的通过promise返回inquirer的answers中的数据,按顺序执行即可,

函数都是拿的对应插件的模板示例对应修改即可

也可以点击可以查看实现代码,拿到代码自己动手试一下。

## 下载依赖
npm install
## 执行打包发布
npm run deploy

主要在于多项目版本信息输入的异步问题。

因为使用的是build中存储的数据源数组,所以使用循环的时候需采取异步循环+promise的方式进行解决forEach函数迭代的不按数组顺序问题(当然也可以使用for循环就不存在这个问题了)

const versionInfoQuiz = () => {
  const psList = []
  let flag = Promise.resolve()
  Object.keys(filePath).forEach(key => {
      flag = new Promise(async resolve => {
        await flag
        inquirer.prompt([
          {
            type: 'input',
            name: 'version',
            message: `Please enter the versionInfo of ${key}:`
          }
        ]).then(answers => {
          resolve({
            key,
            version: answers.version
          })
        })
      })
      psList.push(flag)
  })
  return Promise.all(psList)
}