最近工作中遇到一个问题,我们的项目是一个saas项目,目前有60多个客户,当我们修复了一些问题后,需要重新构建发布,但是手动替换更新内容以及重新打包需要耗费很多的精力,所以探索了下如何自动化构建HBuilder项目。
开发环境为mac,windows上的差异会进行标注。以下代码描述如何构建wgt包,至于h5包、app包原理一致,请参考官方描述。
由于我们的项目安卓app和ios用的appid不一样,所以每个包都需要打俩个不同appid的wgt来做热更新。
1.配置环境变量
mac:
bash:
vim ~/.bash_profile
zsh:
vim ~/.zprofile
按i键,输入如下变量
export HX_HOME=/Applications/HBuilderX.app/Contents/MacOS/
export PATH=$HX_HOME:$PATH:.
按esc,:wq退出。
别忘了source一下,不然环境变量不生效。
source ~/.bash_profile // zsh换成 ~/.zprofile
2.编写脚本
这里我们使用node来编写脚本,实现思路就是读取项目,然后构建,构建后放置到指定位置。
项目结构:
- config // 配置文件
- handler // 脚本
- source // 项目源
- wgt // 构建产物存放目录
source
如果存在A、B、C三个项目,我们放入到source文件夹内
source
- A
- B
- C
config
const projects = ['A', 'B', 'C'] //定义要构建的项目
const appids = ['uni_ios1', 'uni_android1'] // 定义appids
module.exports = {
projects,
appids
}
handler
handler.js
const { projects, appids } = require('../config')
const { readFile, saveFile } = require('fs').promises
const { execFile, execSync } = require('child_process');
const getRootPath = () => {
return path.join(__dirname, '../')
}
// 构建wgt包
const BuildWgtHandler = async () => {
for (let i = 0; i < projects.length; i++) {
const project = projects[i]
const p_path = 'source/' + project
try {
for (let j = 0; j < appids.length; j++) {
const appid = appids[j]
await handleManifestAppidPath(p_path, appid)
await runShell(getRootPath() + p_path, provider, appid)
}
} catch (e) {
console.log('e', e)
break;
}
}
}
// 替换appid
const handleManifestAppidPath = async (p_path, appid) => {
const filePath = p_path + '/manifest.json'
const { file_content } = await readFile(filePath)
const regexp = /"appid"\s?:\s?"([\w_\d]+)"/g
const matchs = file_content.match(regexp)
let c = file_content
if (matchs) {
matchs.forEach((match) => {
c = c.replaceAll(match, `"appid" : "${appid}"`)
})
} else {
throw new Error('未匹配到manifest中对appid')
}
await saveFile(filePath, c)
return true
}
// 调用脚本
const runShell = (project_path, project, appid) => {
return new Promise((resolve) => {
// process.env会默认传递给被调用脚本
process.env.projectPath = project_path // 要打开的项目路径
process.env.projectDir = project // 项目名称
process.env.wgt_outputDir = getRootPath() + 'wgt/' + appid
process.env.wgtFileName = project.toLowerCase().replace(/ /, '') + '.wgt'
// 对sh脚本文件赋予权限,防止每次运行前都需要进行赋予权限操作
execSync('chmod +x ' + getRootPath() + 'handler/build.sh')
execFile(getRootPath() + 'handler/build.sh', (error, stdout, stderr) => {
if (error) {
console.error('error:', error);
resolve()
return;
}
console.log('stdout: ' + stdout); // stdout: 执行 test2.sh test1 输出...
console.log('stderr: ' + stderr);
resolve()
})
})
}
module.exports = BuildWgtHandler
build.sh
#!/bin/bash
cli project open --path $projectPath
cli publish --platform APP --type wgt --project $projectDir --path $wgt_outputDir --name $wgtFileName
脚本的含义就是
- 打开指定路径($projectPath)的项目
- 对项目名称为wgt_outputDir,wgt包文件名为$wgtFileName
run.js
const BuildWgtHandler = require('./handler')
const run = async () => {
await BuildWgtHandler()
console.log('run finished.')
}
run()
运行
mac:直接在终端中进入到handler目录中
Windows: 在git bash中运行,没有的话下一个
node run.js
注意事项:
项目名称最好不要包含空格。