charleyup

为自己吹过的🐮🍺奋斗终生.

微信小程序开发工程化实践之自动化部署

2019/09/23

如果你也是一名微信小程序开发者,并且小程序的部署还依赖于使用微信开发者工具手动上传,那你不妨花几分钟把这篇文章看完,或许会有一定的收获.

前言

作为一名微信小程序的开发者,你是否对这样的场景感到熟悉:当你正在编码当前迭代的新需求,测试小姐姐突然需要你部署测试环境时,你是怎么做的呢?

假如你是个和善的开发,你会把当前分支的改动暂存 --> 切换到测试分支 --> 上用微信开发者工具上传测试分支代码并设为体验版 --> 切回之前的开发分支继续编码.这一通操作下来,可能十五二十分钟过去了,并且还需要花几分钟找回之前的思路. 假如你是个暴躁老哥,那就是另一个故事了...

上述场景还只是部署测试环境,如果是部署正式环境,并且不止一个应用需要部署呢?

以我司为例,我们同一套代码,需要部署5个正式环境小程序和2个测试环境小程序,如果按照上述的部署方式,一是时间成本高,二是操作复杂,且全程人工操作,难以保证每次部署均准确无误(各个小程序/环境对应的配置、代码分支等),因此,我们需要一套自动化部署方案以支撑这类多应用、多环境的小程序部署场景.

下面,让我们进入正题,我们是如何实现微信小程序多应用、多环境自动化部署的呢?

miniprogram-ci

miniprogram-ci 是从微信开发者工具中抽离的关于小程序/小游戏项目代码的编译模块。 开发者可不打开小程序开发者工具,独立使用 miniprogram-ci 进行小程序代码的上传、预览等操作.

在微信小程序后台生成上传密钥(private.wxxxxxxx.key)并设置ip白名单

微信小程序后台截图

在小程序项目根目录下创建ci文件夹及以下文件

mkdir ci
cd ci
touch config.js # 小程序配置文件 
touch upload.js  # 小程序上传脚本
mkdir keys # 放置小程序代码上传密钥的文件夹

编写配置文件

// config.js
const path = require("path")
const resolve = path.resolve
const config = {
    app1: {
        appid: "wxxxxxxxxapp1", // 小程序appid
        type: "miniProgram", // 类型: 小程序或插件
        projectPath: resolve(__dirname, "../"), // 小程序代码所在目录
        privateKeyPath: resolve(__dirname, "./keys/private.wxxxxxxxxapp1.key"), // 小程序上传密钥
        // 其余各小程序差异化的配置也可写入其中
    },
    app2: {
        appid: "wxxxxxxxxapp2",
        type: "miniProgram",
        projectPath: resolve(__dirname, "../"),
        privateKeyPath: resolve(__dirname, "./keys/private.wxxxxxxxxapp2.key"),
    },
    app3: {
        appid: "wxxxxxxxxapp3",
        type: "miniProgram",
        projectPath: resolve(__dirname, "../"),
        privateKeyPath: resolve(__dirname, "./keys/private.wxxxxxxxxapp3.key"),
    },
}
module.exports = config

编写上传脚本

// upload.js
const ci = require("miniprogram-ci")
const config = require("./config")
const app = config[process.env.NODE_ENV]
const project = new ci.Project({
    appid: app.appid,
    type: app.type,
    projectPath: app.projectPath,
    privateKeyPath: app.privateKeyPath,
    ignores: ["node_modules/**/*"]
});
ci.upload({
    project,
    version: "1.0.0",
    desc: "这是一个自动上传的版本",
})

更新package.json文件

{
    "scripts": {
        "upload:app1": "NODE_ENV=app1 node ci/upload.js",
        "upload:app2": "NODE_ENV=app2 node ci/upload.js",
        "upload:app3": "NODE_ENV=app3 node ci/upload.js",
    }
}

如上,执行相应脚本上传对应小程序的代码已实现,例如执行npm run upload:app1可上传app1小程序.但我们希望能更自动一些,脚本的执行也应该是自动化的.因此,我们需要对代码分支做一些约定.

我们分别为app1、app2、app3创建各自的专属分支master-app1master-app2master-app3,我们希望当有代码推送到master-app1分支时,能自动化部署app1,我们需要引入CI工具来实现这个功能,这里我们以gitlab-ci为例,当然你也可以用jenkins、travis等其他CI工具.

编写ci配置文件,放置于项目根目录

# .gitlab-ci.yml
APP1:
  stage: deploy
  script:
    - npm install
    - npm run upload:app1
  only:
    - master-app1

APP2:
  stage: deploy
  script:
    - npm install
    - npm run upload:app2
  only:
    - master-app2

APP3:
  stage: deploy
  script:
    - npm install
    - npm run upload:app3
  only:
    - master-app3

至此,小程序自动化部署的配置、脚本均已完成.我们只需把通过测试准备上线的代码merge到具体分支即可触发自动上传脚本,部署对应的小程序,解放双手的同时大幅降低部署时间,同时防止人工误操作而引起的版本、配置不符的问题.

注意事项

  • 若想进一步提高安全性,小程序代码上传密钥可配置在ci工具的环境变量里,而不是直接放置在项目目录下.
  • 为防止错误的代码提交出发自动化部署,可加入自动化测试及各种lint.
  • 非原生小程序项目(如mpx、mpVue、taro等),执行上传脚本前需先执行构建脚本

写在最后

在我改造该项目之前,其实其他同事已经手动部署了一段时间了.但对于我来说,我有两个追求:

  1. DRY(Don’t Repeat Yourself)
  2. 自动化

坚持这两个原则,可以有效的提高开发效率及系统稳定性,也希望对各位看官有所帮助.