小程序 | 小程序持续集成与部署

为什么需要进行小程序持续化集成与部署

小程序开发有别于web开发,我们开发好的代码,需要通过小程序开发工具上传到腾讯的服务器。预览我们开发好的小程序,也需要通过小程序开发者工具进行构建。
如果是一个人开发,这种通过在开发者本机并经过小程序开发者工具构建上传的方式不会有什么问题,但是,一旦同一个小程序开发的人员多了,就很容易因为开发环境不一致而出现种种问题。
而通过持续化集成,提供统一的构建环境,则可以避免这一问题。

实现原理

实际上,我们是在一台局域网mac上安装并注册了一个GitLab Runner(可以理解为一个用来执行软件集成脚本的容器,Runner可以分布在不同的主机上,同一个主机上也可以有多个Runner。),当GitLab-CI(一套配合GitLab使用的持续集成系统)检测到了变化,例如有新的push,会通知这台runner拉取新的代码,然后进行构建以及后续的操作。

代码编译完成后,我们使用小程序开发者工具提供的命令行工具进行代码上传。

当然,不一定要用mac, 只要能安装小程序开发者工具的设备,均可以。但是目前微信只提供了mac 和 windows版本的开发者工具,所以只能在基于mac 或者 windows系统上进行构建。

步骤

安装小程序开发工具

下载微信官方小程序开发者工具,并安装到GitLab Runner对应的设备上。

安装并配置 GitLab Runner

我们以mac系统为例:

安装GitLab Runner
1
2
sudo curl --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64
sudo chmod +x /usr/local/bin/gitlab-runner
注册GitLab Runner

首先,需要到GitLab管理界面中的Runners页面去找注册需要使用的token。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
gitlab-runner register

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://xxx.com/ (这里填写你gitlab的地址)
Please enter the gitlab-ci token for this runner:
xxxxxx (刚刚获取到的token)
Please enter the gitlab-ci description for this runner:
xxxxxx (随便填)
Please enter the gitlab-ci tags for this runner (comma separated):
wxapplet (这个我很重要,识别这个runner的标志)
Whether to run untagged builds [true/false]:
[false]: false
Whether to lock the Runner to current project [true/false]:
[true]: false
Registering runner... succeeded runner=xxxx
Please enter the executor: docker-ssh, virtualbox, docker+machine, docker-ssh+machine, docker, parallels, shell, ssh, kubernetes:
shell
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
运行刚刚注册过的GitLab Runner
1
2
3
cd ~
gitlab-runner install
gitlab-runner start

此时,如果在GitLab管理页面中的Runner页面,你可以看到一个Tags名称为wxapplet的runner,说明注册成功。

编写 .gitlab-ci.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
image: node:latest

before_script:
- npm install

after_script:
- rm -r ./dist

cache:
paths:
- node_modules/

stages:
- build

build-package:
stage: build
tags:
- wxapplet
only:
- tags
script:
- regex="^prod-.*$"; if [[ $CI_COMMIT_TAG =~ $regex ]]; then npm run build; fi
- regex="^freeze-.*$"; if [[ $CI_COMMIT_TAG =~ $regex ]]; then npm run freeze; fi
- npm run deploy -- --tag ${CI_COMMIT_TAG}'

上面的文件表示,在build阶段,当push中带了tag时,将会启动build-package这个任务。GitLab Runner将会依次执行以上的script。前两个script表示,当以prod-或者freeze-开头时,才会执行当前的命令。

我们可以根据tag的不同,去执行不同的脚本。

因为我们使用了小程序开发的第三方框架,所以上面的npm run build或者npm run freeze,均是生成小程序所需代码到dist目录中。如果你没有使用框架开发小程序,可忽略这两部,直接npm run deploy

npm run deploy实际上执行了在package.json中定义的脚本"node ./deploy/index.js",并且将CI_COMMIT_TAG作为参数传入。

deploy/index.js

核心(伪)代码如下;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// tag 取传入的CI_COMMIT_TAG

let cmd = '';

// 同构tag中的login,可以控制小程序开发者工具进行登录。因为只有登录了才能上传代码。在对应项目的CI中,我们可以看到输出的二维码。

if (/^login.*$/.test(tag)) {
cmd = '/Applications/wechatwebdevtools.app/Contents/Resources/app.nw/bin/cli -l --login-qr-output';
} else {
cmd = `/Applications/wechatwebdevtools.app/Contents/Resources/app.nw/bin/cli --upload ${小程序版本}@${小程序dist所在目}/ --upload-desc ${这个版本的描述}`;
}

// 根据不同环境,将不同的project.config.json copy 到dist目录下。
if (/^prod-.*$/.test(tag)) {
execSync('cp ./deploy/prod/project.config.json ./dist/project.config.json');
}

if (/^freeze-.*$/.test(tag)) {
execSync('cp ./deploy/freeze/project.config.json ./dist/project.config.json');
}

const child = exec(
cmd,
(error) => {
if (error) {
throw error;
}
},
);

child.stdout.on('data', (data) => {
process.stdout.write(data);
});

child.stderr.on('data', (data) => {
process.stdout.write(data);
throw new Error('构建失败');
});

对于 project.config.json 的说明

v2-341399507f35a8a1a896761fd02f1d6b_r


参考: