本文针对qiankun微前端多项目的自动打包部署,手动打包部署可以参考我上一篇文章。单项目同样可以使用。
话不多说我们直接开始。
1. 明确目标
项目目录如下,将打包好的main文件夹放在dist文件夹下
最终打包main文件夹成品如下
- main:主应用(main文件夹我放在根路径下)例如:http://localhost:8080/mian
- children:子应用文件夹
- boy:子应用1
- girl:子应用2
- children:子应用文件夹
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. 项目部署
项目部署需要连接服务器然后上传项目包;因此需要引导使用者操作输入信息,这时需要用到
- 命令行交互插件——inquirer
- 压缩文件插件—— compressing
- 部署脚本插件——node-ssh
因为命令行返回操作指令、 文件压缩 、文件上传 、 shell命令 等存在异步过程,使用 Promise +async awiat控制异步过程和代码逻辑清晰,实现代码执行顺序的控制。
逐步进行,实现如图的效果:
其他的通过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)
}