自动化构建Hbuilder项目

503 阅读2分钟

最近工作中遇到一个问题,我们的项目是一个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

windows参考官方文档

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

脚本的含义就是

  1. 打开指定路径($projectPath)的项目
  2. 对项目名称为projectDir进行构建wgt包,构建完成后存放目录为projectDir进行构建wgt包,构建完成后存放目录为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

注意事项:

项目名称最好不要包含空格。