微信小程序自动化部署miniprogram-ci,一套代码一键上传多个小程序

2,542 阅读3分钟

背景

由于公司为合作伙伴推出定制小程序服务,而所有小程序都是一套代码实现,更新小程序时就需要实现一键将代码上传到所有小程序。

准备工作

miniprogram-ci概述

miniprogram-ci 是从微信开发者工具中抽离的关于小程序/小游戏项目代码的编译模块。

开发者可不打开小程序开发者工具,独立使用 miniprogram-ci 进行小程序代码的上传、预览等操作。

密钥及 IP 白名单配置

使用 miniprogram-ci 前应访问"微信公众平台-开发-开发设置"后下载代码上传密钥,并配置 IP 白名单

入口

安装

npm install miniprogram-ci --save

目录结构

新建ci目录,目录下新建存放小程序代码上传密钥文件夹,存放qrcode预览文件夹,新建预览,上传js文件;主要新增和更改文件如下

image.png

批量生成预览二维码

  • 读取小程序代码上传密钥文件夹
  • 获取所有密钥文件
  • 循环创建项目对象并以appId命名区分,输出预览二维码
const fs = require('fs');
const ci = require('miniprogram-ci')
const path = require('path')
let projectPath = path.resolve(__dirname, '..')
let privateList = fs.readdirSync(`${projectPath}/ci/privateKey`)
// 获取所有小程序
privateList.forEach(item => {
  let appId = item.split('.')[1]
  // 创建项目对象
  const project = new ci.Project({
    appid: appId,    // 小程序appid
    type: 'miniProgram',  // 类型,小程序或小游戏
    projectPath: projectPath, // 项目路径
    privateKeyPath: `${projectPath}/ci/privateKey/${item}`,  // 密钥路径
    ignores: ['node_modules/**/*']  // 忽略的文件
  })
  ci.preview({
    project,
    setting: {
      es6: true, // 对应小程序开发者工具的 "es6 转 es5"
      es7: true, // 对应小程序开发者工具的 "增强编译"
    },
    qrcodeFormat: 'image',
    qrcodeOutputDest: `${projectPath}/ci/qrcode/${appId}_qrcode.jpg`,
    onProgressUpdate: console.log,
  }).then(res => {
    console.log('执行成功', res)
  }).catch(error => {
    console.log('执行失败', error)
  })
})

批量上传微信小程序

  • 读取小程序代码上传密钥文件夹
  • 获取所有密钥文件
  • 循环创建项目对象并上传到小程序
// 使用ci脚本上传,需在小程序后台:开发管理 =》 小程序代码上传,生成小程序代码密钥放到privateKey文件夹;配置上传机器的IP白名单;上传前先预览再上传 npm run preview => npm run upload
const fs = require('fs');
const ci = require('miniprogram-ci')
const path = require('path')
const projectPath = path.resolve(__dirname, '..')
// 获取所有小程序上传密钥文件
const privateList = fs.readdirSync(`${projectPath}/ci/privateKey`)
const uploadInfo = {
  version: '5.0.9',
  desc: '功能优化与修复bug'
}
privateList.forEach(item => {
  let appId = item.split('.')[1] // item: private.appId.key
  // 创建项目对象
  const project = new ci.Project({
    appid: appId,    // 小程序appid
    type: 'miniProgram',  // 类型,小程序或小游戏
    projectPath: projectPath, // 项目路径
    privateKeyPath: `${projectPath}/ci/privateKey/${item}`,  // 密钥路径
    ignores: ['node_modules/**/*']  // 忽略的文件
  })
  // 调用上传方法
  ci.upload({
    project,
    ...uploadInfo,
    setting: {
      es6: true, // 对应小程序开发者工具的 "es6 转 es5"
      es7: true, // 对应小程序开发者工具的 "增强编译"
      minify: true  // 是否压缩代码
    },
  }).then(res => {
    console.log('执行成功', res)
  }).catch(error => {
    console.log('执行失败', error)
  })
})

运行

配置package.json

{
  "scripts": {
    "preview": "node ci/preview.js",
    "upload": "node ci/upload.js"
  },
  "dependencies": {
    "miniprogram-ci": "^1.9.15"
  }
}

运行命令

// 批量预览
npm run preview
// 批量上传
npm run upload

优化

由于预览和上传有大量重复代码,抽离一下,通过命令行读取参数来执行预览和上传;获取参数值的方法是使用 Node.js 中内置的 process 对象,它公开了 argv 属性,该属性是一个包含所有命令行调用参数的数组,参考文档: Node.js 从命令行接收参数

  • ci下新建ci.js文件
  • 通过process.argv获取传入命令
  • 根据命令进行预览/上传
// 使用ci脚本上传,需在小程序后台:开发管理 =》 小程序代码上传,生成小程序代码密钥放到privateKey文件夹;配置上传机器的IP白名单;上传前先预览再上传 npm run preview => npm run upload
const fs = require('fs');
const ci = require('miniprogram-ci')
const path = require('path')
const projectPath = path.resolve(__dirname, '..')
// 获取所有小程序上传密钥文件
const privateList = fs.readdirSync(`${projectPath}/ci/privateKey`)
const uploadInfo = {
  version: '5.0.9',
  desc: '功能优化与修复bug'
}
const command = process.argv.slice(2)[0]
privateList.forEach(item => {
  let appId = item.split('.')[1] // item: private.appId.key
  // 创建项目对象
  const project = new ci.Project({
    appid: appId,    // 小程序appid
    type: 'miniProgram',  // 类型,小程序或小游戏
    projectPath: projectPath, // 项目路径
    privateKeyPath: `${projectPath}/ci/privateKey/${item}`,  // 密钥路径
    ignores: ['node_modules/**/*']  // 忽略的文件
  })
  let ciFn = null
  if (command === 'upload') {
    ciFn = ci.upload({
      project,
      ...uploadInfo,
      setting: {
        es6: true, // 对应小程序开发者工具的 "es6 转 es5"
        es7: true, // 对应小程序开发者工具的 "增强编译"
        minify: true  // 是否压缩代码
      },
    })
  } else if (command === 'preview') {
    ciFn = ci.preview({
      project,
      setting: {
        es6: true, // 对应小程序开发者工具的 "es6 转 es5"
        es7: true, // 对应小程序开发者工具的 "增强编译"
      },
      qrcodeFormat: 'image',
      qrcodeOutputDest: `${projectPath}/ci/qrcode/${appId}_qrcode.jpg`,
      onProgressUpdate: console.log,
    })
  }
  // 调用
  ciFn.then(res => {
    console.log('执行成功', res)
  }).catch(error => {
    console.log('执行失败', error)
  })
})

配置最终package.json

{
  "scripts": {
    "preview": "node ci/ci.js preview",
    "upload": "node ci/ci.js upload"
  },
  "dependencies": {
    "miniprogram-ci": "^1.9.15"
  }
}

最终目录结构以及文件

image.png

官方文档

developers.weixin.qq.com/miniprogram…