持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
参考
使用
可以使用@tarojs/plugin-mini-ci进行微信、字节、支付宝、百度各种小程序的ci,也就是打包上传。
- config/index.js
// 如果你使用 VSCode 作为开发工具, 你还可以使用注释的语法引入插件包含的声明文件,可获得类似于 Typescript 的友好提示
/**
* @typedef { import("@tarojs/plugin-mini-ci").CIOptions } CIOptions
* @type {CIOptions}
*/
const CIPluginOpt = {
// 微信小程序
weapp: {
appid: "微信小程序appid",
privateKeyPath: "密钥文件相对项目根目录的相对路径,例如 key/private.appid.key"
},
// 字节跳动小程序
tt: {
email: "字节小程序邮箱",
password: "字节小程序密码"
},
// 支付宝小程序
alipay: {
appId: "支付宝小程序appId",
toolId: "工具id",
privateKeyPath: "密钥文件相对项目根目录的相对路径,例如 key/pkcs8-private-pem"
},
// 百度小程序
swan: {
token: "鉴权需要的token令牌"
},
// 版本号
version: "1.0.0",
// 版本发布描述
desc: "版本描述"
}
const config = {
plugins: [
["@tarojs/plugin-mini-ci", CIPluginOpt]
]
}
- package.json
{
"scripts": {
// 构建完后自动 “打开开发者工具”
"build:weapp": "taro build --type weapp --open",
// 构建完后自动“上传代码作为体验版”
"build:weapp:upload": "taro build --type weapp --upload",
源码
学艺不精,上面的小程序配置代码没看懂,ctx,joi什么的,挑能看懂的说,把weapp流程讲一遍
# index.ts
// 打包的时候命令行输入 taro build --type weapp --open
//那么可以提取出 weapp 和 open ,很容易得出是 weapp,
onBuildDone(async () => {
const args = minimist(process.argv.slice(2), {
boolean: ['open', 'upload', 'preview']
})
const { printLog, processTypeEnum } = ctx.helper
const platform = ctx.runOpts.options.platform
let ci
switch (platform) {
// 这里去实例化ci
case 'weapp':
ci = new WeappCI(ctx, pluginOpts)
break
。。。其他平台
}
// 再判断有其他的什么参数,有open,走open,这里很牛逼,我第一次看到这种switch (true),我个人是习惯用if判断的,但是如果并行判断的话,那么用这种,确实更有范儿。
switch (true) {
case args.open:
ci.open()
break
case args.upload:
ci.upload()
break
case args.preview:
ci.preview()
break
default:
break
}
})
实例weapp
先要了解miniprogram-ci, developers.weixin.qq.com/miniprogram…
这里面的预览和上传都主要靠它。
- \packages\taro-plugin-mini-ci\src\WeappCI.ts
/* eslint-disable no-console */
import * as ci from 'miniprogram-ci'
import * as path from 'path'
import * as os from 'os'
import * as cp from 'child_process'
import { Project } from 'miniprogram-ci'
import BaseCI from './BaseCi'
export default class WeappCI extends BaseCI {
private instance: Project
/** 微信开发者安装路径 */
private devToolsInstallPath: string
// 配置信息有个devToolsInstallPath是填微信开发工具的安装路径的,没填就认为是默认路径,再判断秘钥privateKeyPath有没有填
// 封装 ci ,方便调用 预览体验和上传
_init () {
const { outputPath, appPath } = this.ctx.paths
const { fs } = this.ctx.helper
if (this.pluginOpts.weapp == null) {
throw new Error('请为"@tarojs/plugin-mini-ci"插件配置 "weapp" 选项')
}
this.devToolsInstallPath = this.pluginOpts.weapp.devToolsInstallPath || (process.platform === 'darwin' ? '/Applications/wechatwebdevtools.app' : 'C:\\Program Files (x86)\\Tencent\\微信web开发者工具')
delete this.pluginOpts.weapp.devToolsInstallPath
const weappConfig: any = {
type: 'miniProgram',
projectPath: outputPath,
ignores: ['node_modules/**/*'],
...this.pluginOpts.weapp!
}
const privateKeyPath = path.isAbsolute(weappConfig.privateKeyPath) ? weappConfig.privateKeyPath : path.join(appPath, weappConfig.privateKeyPath)
if (!fs.pathExistsSync(privateKeyPath)) {
throw new Error(`"weapp.privateKeyPath"选项配置的路径不存在,本次上传终止:${privateKeyPath}`)
}
this.instance = new ci.Project(weappConfig)
}
// 这里就是用child_process去执行命令行 微信开发者安命令行工具路径 open --project 项目路径
//其中有不少平台兼容代码,检查安装路径是否存在,判断命令行工具是否开启了命令行,
async open () {
const { fs, printLog, processTypeEnum, getUserHomeDir } = this.ctx.helper
const { appPath } = this.ctx.paths
// 检查安装路径是否存在
if (!(await fs.pathExists(this.devToolsInstallPath))) {
printLog(processTypeEnum.ERROR, '微信开发者工具安装路径不存在', this.devToolsInstallPath)
return
}
/** 命令行工具所在路径 */
const cliPath = path.join(this.devToolsInstallPath, os.platform() === 'win32' ? '/cli.bat' : '/Contents/MacOS/cli')
const isWindows = os.platform() === 'win32'
// 检查是否开启了命令行
const errMesg = '工具的服务端口已关闭。要使用命令行调用工具,请打开工具 -> 设置 -> 安全设置,将服务端口开启。详细信息: https://developers.weixin.qq.com/miniprogram/dev/devtools/cli.html'
const installPath = isWindows ? this.devToolsInstallPath : `${this.devToolsInstallPath}/Contents/MacOS`
const md5 = require('crypto').createHash('md5').update(installPath).digest('hex')
const ideStatusFile = path.join(
//ide-status这种东西只能说特别硬核了
getUserHomeDir(),
isWindows
? `/AppData/Local/微信开发者工具/User Data/${md5}/Default/.ide-status`
: `/Library/Application Support/微信开发者工具/${md5}/Default/.ide-status`
)
if (!(await fs.pathExists(ideStatusFile))) {
printLog(processTypeEnum.ERROR, errMesg)
return
}
const ideStatus = await fs.readFile(ideStatusFile, 'utf-8')
if (ideStatus === 'Off') {
printLog(processTypeEnum.ERROR, errMesg)
return
}
if (!(await fs.pathExists(cliPath))) {
printLog(processTypeEnum.ERROR, '命令行工具路径不存在', cliPath)
}
printLog(processTypeEnum.START, '微信开发者工具...')
cp.exec(`${cliPath} open --project ${appPath}`, (err) => {
if (err) {
printLog(processTypeEnum.ERROR, err.message)
}
})
}
// 体验版 用了其他库 miniprogram-ci 传参就行了 ,以及成功和失败的打印。
async preview () {
const { chalk, printLog, processTypeEnum } = this.ctx.helper
try {
printLog(processTypeEnum.START, '上传开发版代码到微信后台并预览')
//
const uploadResult = await ci.preview({
project: this.instance,
version: this.version,
desc: this.desc,
onProgressUpdate: undefined
})
if (uploadResult.subPackageInfo) {
const allPackageInfo = uploadResult.subPackageInfo.find((item) => item.name === '__FULL__')
const mainPackageInfo = uploadResult.subPackageInfo.find((item) => item.name === '__APP__')
const extInfo = `本次上传${allPackageInfo!.size / 1024}kb ${mainPackageInfo ? ',其中主包' + mainPackageInfo.size + 'kb' : ''}`
console.log(chalk.green(`上传成功 ${new Date().toLocaleString()} ${extInfo}`))
}
} catch (error) {
console.log(chalk.red(`上传失败 ${new Date().toLocaleString()} \n${error.message}`))
}
}
// 上传,同体验,没什么好说的。上传,以及成功和失败的打印。
async upload () {
const { chalk, printLog, processTypeEnum } = this.ctx.helper
try {
printLog(processTypeEnum.START, '上传体验版代码到微信后台')
printLog(processTypeEnum.REMIND, `本次上传版本号为:"${this.version}",上传描述为:“${this.desc}”`)
const uploadResult = await ci.upload({
project: this.instance,
version: this.version,
desc: this.desc,
onProgressUpdate: undefined
})
if (uploadResult.subPackageInfo) {
const allPackageInfo = uploadResult.subPackageInfo.find((item) => item.name === '__FULL__')
const mainPackageInfo = uploadResult.subPackageInfo.find((item) => item.name === '__APP__')
const extInfo = `本次上传${allPackageInfo!.size / 1024}kb ${mainPackageInfo ? ',其中主包' + mainPackageInfo.size + 'kb' : ''}`
console.log(chalk.green(`上传成功 ${new Date().toLocaleString()} ${extInfo}`))
}
} catch (error) {
console.log(chalk.red(`上传失败 ${new Date().toLocaleString()} \n${error.message}`))
}
}
}
瞄了一眼其他平台的,大同小异,不多说了
其他
多亏了川哥的一些源码解读文章,我也搞出了公司自用的cicd库,也是推给了同事用了
总结
上传和体验版主要是靠miniprogram-ci,一些流程、文件判断和平台差异还是可以学习的。
小疑问
taro build --type weapp --open"是怎么指定用@tarojs/plugin-mini-ci执行的,我观察到taro的package.json没看到有什么相关的,为什么里面没有bin去设置taro,那么taro是怎么跑的