
Taro 小程序 CI/CD 实战使用 tarojs/plugin-mini-ci 自动打开开发者工具、预览与上传体验版【免费下载链接】taro开放式跨端跨框架解决方案支持使用 React/Vue/Nerv 等框架来开发微信/京东/百度/支付宝/字节跳动/ QQ 小程序/H5/React Native 等应用。 https://taro.zone/项目地址: https://gitcode.com/NervJS/taro本指南基于 Taro 官方仓库中的 packages/taro-plugin-mini-ci/README.md系统讲解tarojs/plugin-mini-ci这一构建后 CI 插件的安装、配置、命令使用与 Hooks 扩展。读完本文你将掌握如何让 Taro 小程序在taro build构建完成后自动打开企业微信、字节、支付宝、钉钉、百度、京东等平台开发者工具自动上传代码作为开发版/体验版并生成预览二维码从而把「构建 → 预览 → 上传」这一繁琐链路完全交给脚本与 CI 流水线。一、插件是什么构建后自动化的 CI 能力tarojs/plugin-mini-ci是 Taro 官方提供的小程序端 CI持续集成插件核心定位是在 Taro 小程序构建完毕后自动执行三类动作自动打开对应平台的小程序开发者工具类似网页开发中自动打开浏览器上传代码作为「开发版」并生成预览二维码上传代码作为「体验版」。目前支持企业微信、京东、字节抖音、支付宝、钉钉、百度小程序。从仓库源码看插件按平台拆分了独立实现类src/WeappCI.ts、src/TTCI.ts、src/AlipayCI.ts、src/DingtalkCI.ts、src/SwanCI.ts、src/JdCI.ts它们统一继承自抽象基类 src/BaseCi.ts基类定义了init()、open()、upload()、preview()四个抽象方法以及版本号、描述、项目路径的公共处理逻辑。各平台底层依赖的 CI SDK 以 optional peerDependencies 形式声明在 package.json 中miniprogram-ci微信、tt-ide-cli字节、minidev支付宝、dingtalk-miniapp-opensdk钉钉、jd-miniprogram-ci京东使用时只需按需安装对应平台的 SDK 即可互不干扰。二、安装插件在 Taro 项目根目录执行npm i tarojs/plugin-mini-ci -D由于平台 SDK 是按需可选依赖还需要根据实际使用平台额外安装对应依赖例如微信平台npm i miniprogram-ci -D如果未安装对应平台依赖插件运行时会打印类似请安装依赖miniprogram-ci的错误提示并终止进程见 WeappCI.ts。三、在 config/index.js 中接入插件3.1 传入配置对象在 Taro 项目的 config/index.js 中声明插件及参数// 示例如果你使用 vs code 作为开发工具你还可以使用注释的语法引入插件包含的声明文件可获得类似于 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, }, dd: { appid: 钉钉小程序 appid即钉钉开放平台后台应用管理的 MiniAppId 选项, token: 令牌从钉钉后台获取, }, swan: { token: 鉴权需要的 token 令牌, }, jd: { privateKey: 京东小程序秘钥 } // 版本号 version: 1.0.0, // 版本发布描述 desc: 版本描述, } const config { plugins: [[tarojs/plugin-mini-ci, CIPluginOpt]], }3.2 传入异步函数动态获取配置除了对象插件还支持传入一个异步函数在编译时动态返回配置。这种写法适合从远程接口、环境变量或 CI 流水线注入的凭据中动态取得配置const CIPluginFn async () { // 可以在这里做一些异步事情比如请求接口获取配置 /** * typedef { import(tarojs/plugin-mini-ci).CIOptions } CIOptions * type {CIOptions} */ return { weapp: { appid: 微信小程序 appid, privateKeyPath: 密钥文件相对项目根目录的相对路径例如 key/private.appid.key }, tt: { email: 字节小程序邮箱, password: 字节小程序密码 }, alipay: { appid: 支付宝小程序 appid, toolId: 工具 id, privateKeyPath: 密钥文件相对项目根目录的相对路径例如 key/pkcs8-private-pem }, dd: { appid: 钉钉小程序 appid即钉钉开放平台后台应用管理的 MiniAppId 选项 token: 令牌从钉钉后台获取 }, swan: { token: 鉴权需要的 token 令牌 }, jd: { privateKey: 京东小程序秘钥 } // 版本号 version: 1.0.0, // 版本发布描述 desc: 版本描述 } } const config { plugins: [ [ tarojs/plugin-mini-ci, CIPluginFn ] ] }从源码 src/index.ts 可以看到插件在执行动作时会判断配置是函数还是对象const pluginOpts typeof _pluginOpts function ? await _pluginOpts() : _pluginOpts因此异步函数在动作执行前才会被调用每次构建可拿到最新配置。3.3 配置校验插件通过ctx.addPluginOptsSchema注册了 Joi 校验规则见 src/index.ts配置必须是一个「函数」或「包含合法字段的对象」否则会直接报错。例如weapp.appid、weapp.privateKeyPath、tt.email、tt.password、dd.token、dd.appid、swan.token、jd.privateKey均为必填项支付宝的clientType仅允许枚举值deleteVersion必须符合x.y.z的版本号格式。四、作为 build 命令选项使用构建后自动执行tarojs/plugin-mini-ci为taro build命令扩展了 4 个选项在package.json的scripts字段中组合使用{ scripts: { // 构建完后自动“打开开发者工具” build:weapp: taro build --type weapp --open, // 构建完后自动“上传代码作为开发版并生成预览二维码” build:weapp:preview: taro build --type weapp --preview, // 构建完后自动“上传代码作为体验版” build:weapp:upload: taro build --type weapp --upload, // 构建完后自动“上传 dist/xxx 目录的代码作为体验版”--projectPath 参数 适用于 taro 和 原生混合的场景 build:weapp:upload: taro build --type weapp --upload --projectPath dist/xxx }, taroConfig: { version: 1.0.0, desc: 上传描述 } }4.1 扩展的选项说明由上面的示例可知插件为 taro cli 命令扩展了 4 个选项选项作用--open打开开发者工具类似于网页开发中自动打开谷歌浏览器--preview上传代码作为开发版并生成预览二维码--upload上传代码作为体验版--projectPath指定要操作打开、预览、上传的目录路径默认情况下是操作构建后目录路径即outputRoot选项使用要点--open、--preview、--upload三个选项在一条命令里不能同时使用互斥。从源码 src/index.ts 可以看出插件在build命令的onBuildComplete兼容旧的onBuildFinish回调里用switch (true)依次匹配三个布尔参数只取第一个命中的动作执行--projectPath必须搭配上述三个选项之一一起使用--projectPath优先级为终端传入的--projectPath CI 配置的projectPath选项 outputRoot选项。对应源码 src/index.tsprojectPath projectPath || pluginOpts.projectPath || ctx.paths.outputPath相对路径会基于项目根目录appPath解析且会校验目录存在性不存在则报错退出。五、作为独立命令单独使用操作指定目录tarojs/plugin-mini-ci还额外注册了 3 个独立命令taro open、taro preview、taro upload见 src/index.ts让你可以不经过构建流程直接操作任意指定目录适用于把 taro 作为项目一部分例如 Taro 与原生小程序代码混合的场景{ scripts: { // 直接“打开开发者工具并载入项目” build:weapp: taro open --type weapp --projectPath dist/xxx, // 直接“上传代码作为开发版并生成预览二维码” build:weapp:preview: taro preview --type weapp, // 直接“上传代码作为体验版” build:weapp:upload: taro upload --type weapp, // 上传指定目录代码作为体验版 build:weapp:upload2: taro upload --type weapp --projectPath dist/xxx }, taroConfig: { version: 1.0.0, desc: 上传描述 } }当直接作为命令使用时有两个选项选项作用--type传入平台名称weapp/qywx/tt/alipay/iot/dd/swan/jd 等--projectPath传入路径。此选项优先级为终端传入的--projectPath CI 配置的projectPath选项 outputRoot选项独立命令同样遵循上述路径解析与校验逻辑。平台的类型映射同样见 src/index.tsweapp与qywx共用微信实现类alipay与iot共用支付宝实现类未支持平台会打印警告「插件暂时不支持 xx 平台」并返回。六、version 与 desc 的来源与优先级version上传版本号与desc上传描述无需在每个命令里重复传递插件会按以下优先级取值见 src/BaseCi.ts插件配置对象中的version/desc字段否则读取项目package.json下taroConfig字段中的version/descdesc仍未配置时默认生成CI构建自动构建于${当前时间}。因此上述示例中package.json里统一维护taroConfig即可{ taroConfig: { version: 1.0.0, desc: 上传描述 } }七、Hooks 扩展预览/上传完成后回调通知7.1 触发时机与事件在插件执行完「预览」「上传」操作后会触发 2 个钩子事件事件名传递参数对象说明onPreviewComplete详细见下文CI 执行预览后触发onUploadComplete详细见下文CI 执行上传后触发钩子由基类的triggerPreviewHooks/triggerUploadHooks通过ctx.applyPlugins触发见 src/BaseCi.ts事件名常量定义在 src/hooks.ts。钩子数据中会自动带上当前的version、desc、projectPath。需要留意当动作失败success: false时插件会调用process.exit(1)终止进程这可以保证 CI 流水线在预览/上传失败时立即失败避免误报成功。两个钩子被触发时传入的数据对象描述如下interface HooksData { /** 是否预览、构建成功 */ success: boolean data: { /** 当前构建的小程序平台 */ platform: string /** 预览码本地路径 */ qrCodeLocalPath: string /** 预览码内容 */ qrCodeContent: string /** 插件传递的预览版本号 */ version: string /** 插件传递的描述文本 */ desc: string /** 预览或上传的目录路径 */ projectPath: string } /** 错误对象 */ error?: Error }7.2 自定义插件接收事件你可以写一个自定义 Taro 插件通过ctx.register注册上述两个事件实现「预览/上传成功后自动发送钉钉或飞书消息」等扩展能力// config/test.js module.exports function (ctx) { ctx.register({ name: onPreviewComplete, fn: ({ success, data, error }) { console.log(接收预览后数据, success, data, error) // 你可以在这里发送钉钉或者飞书消息 }, }) ctx.register({ name: onUploadComplete, fn: ({ success, data, error }) { console.log(接收上传后数据, success, data, error) // 你可以在这里发送钉钉或者飞书消息 }, }) }然后把自己写的插件配置应用起来// config/index.js const config { plugins: [ [tarojs/plugin-mini-ci, CI插件参数], // 应用自己写的插件 require(path).join(__dirname, ./test), ], ...其他配置省略, } module.exports function (merge) { if (process.env.NODE_ENV development) { return merge({}, config, require(./dev)) } return merge({}, config, require(./prod)) }八、各平台功能支持情况对比平台/功能自动打开 IDE输出预览二维码输出体验二维码weapp✅✅✅qywx✅✅✅tt✅✅✅alipay✅✅✅dd✅✅❌swan✅✅✅jd❌✅✅ps: 各平台上传都是支持的只是不一定会输出二维码企业微信和微信的各项参数是一样的共用一个配置二维码的生成与读取机制插件使用 src/utils/qrcode.ts 中的工具函数统一处理二维码——readQrcodeImageContent用axiosJimpjsQR读取含网络图片二维码图片中的文本内容printQrcode2Terminal用qrcode库把内容直接打印成终端 ASCII 二维码generateQrcodeImageFile把内容生成为 PNG 图片文件。例如微信平台WeappCI.ts预览二维码保存在projectPath/preview.jpg体验版二维码按https://open.weixin.qq.com/sns/getexpappinfo?appidxxx#wechat-redirect规则生成并保存在projectPath/upload.png支付宝平台AlipayCI.ts预览二维码保存在projectPath/preview.png体验版二维码保存在projectPath/upload.png。九、插件完整配置 API9.1 顶层插件配置CIOptions参数类型说明weappObject企业微信小程序 CI 配置ttObject头条字节/抖音小程序配置alipayObject支付宝小程序配置ddObject钉钉小程序配置3.6.0 版本开始支持swanObject百度小程序配置jdObject京东小程序配置versionstring上传版本号不传时默认读取 package.json 下的 taroConfig 下的 version 字段descstring上传时的描述信息不传时默认读取 package.json 下的 taroConfig 下的 desc 字段projectPathstring目标项目目录对所有小程序生效不传默认取 outputRoot 字段3.6.0 版本开始支持9.2 企业微信小程序 CI 配置参数类型说明appidstring小程序/小游戏项目的 appidprivateKeyPathstring私钥文件在项目中的相对路径在获取项目属性和上传时用于鉴权使用devToolsInstallPathstring微信开发者工具安装路径如果你安装微信开发者工具时选的默认路径则不需要传入此参数 (选填)projectPathstring上传的小程序的路径默认取的 outputRoot3.6.0 版本已废弃ignoresstring[]上传需要排除的目录 (选填)robotnumber指定使用哪一个 ci 机器人可选值1 ~ 30(选填3.6.0 版本开始支持)settingObject预览和上传时的编译设置具体见下表 (选填3.6.2 版本开始支持)编译设置选项说明setting参数类型说明es6boolean对应于微信开发者工具的 es6 转 es5es7boolean对应于微信开发者工具的 增强编译disableUseStrictboolean增强编译 开启时是否禁用 JS 文件严格模式默认为 falseminifyJSboolean上传时压缩 JS 代码minifyWXMLboolean上传时压缩 WXML 代码minifyWXSSboolean上传时压缩 WXSS 代码minifyboolean上传时压缩所有代码对应于微信开发者工具的 上传时压缩代码codeProtectboolean对应于微信开发者工具的 上传时进行代码保护autoPrefixWXSSboolean对应于微信开发者工具的 上传时样式自动补全实现细节WeappCI.tsinit()阶段会校验weapp配置存在、动态加载miniprogram-ci、拼接并校验私钥路径privateKeyPath支持绝对路径相对路径会基于项目根目录解析路径不存在则直接抛错终止上传devToolsInstallPath默认取 macOS 的/Applications/wechatwebdevtools.app或 Windows 的C:\Program Files (x86)\Tencent\微信web开发者工具。open()动作会进一步检查开发者工具是否开启「服务端口」通过用户目录下 IDE 的.ide-status文件判断未开启时会提示前往「设置 → 安全设置」打开服务端口。上传成功后还会根据subPackageInfo打印主包/整包体积信息。9.3 头条字节/抖音小程序 CI 配置参数类型说明emailstring字节小程序邮箱passwordstring字节小程序密码从源码 TTCI.ts 看预览/上传前会先调用tt-ide-cli的loginByEmail完成邮箱登录dontSaveCookie: false会保存登录 Cookie上传时支持setting.skipDomainCheck跳过域名检查并默认needUploadSourcemap: true上传 SourceMap。9.4 支付宝小程序 CI 配置参数类型说明appidstring小程序 appid3.6.0之前参数名是appId3.6.0开始统一成appidtoolIdstring工具 idprivateKeyPathstring密钥文件相对项目根目录的相对路径私钥可通过支付宝开放平台开发助手生成privateKeystring私钥文本内容生成方式同上 (privateKeyPath 和 privateKey 之间必须要填写其中一个3.6.0 版本开始支持)devToolsInstallPathstring小程序开发者工具安装路径 (选填3.6.0 版本开始支持)clientTypestring上传的终端终端类型见下表选填默认值 alipaydeleteVersionstring在上传过程中删除指定的版本即使该版本正在构建中或不存在。记录已上传的版本并使用这个参数能有效避免上传版本无法超过 20 个的问题选填默认自动删除上一个版本。可设置0.0.0关闭自动删除终端类型值及其含义clientTypealipay: 支付宝 ampeAMPE amap高德 genie天猫精灵 aliosALIOS ucUC quark夸克 koubei口碑 alipayiotIoT cainiao菜鸟 alihealth阿里健康 health: 阿里医院实现细节AlipayCI.tsprivateKey与privateKeyPath二选一若只配置了privateKeyPath会读取该文件内容作为私钥并写入minidev的默认配置上传时会先查询最新已上传版本号若当前version不高于线上最新版本会报错终止SDK 要求版本号必须递增同时默认把上一个版本作为deleteVersion删除以规避支付宝平台上体验版本数量上限问题。9.5 钉钉小程序 CI 配置3.6.0 版本开始支持参数类型说明appidstring钉钉小程序 appid即钉钉开放平台后台应用管理的 MiniAppId 选项必填tokenstring令牌从钉钉后台获取必填devToolsInstallPathstring小程序开发者工具安装路径选填taro集成的钉钉 CI 使用了钉钉官方dingtalk-design-cli中的dingtalk-miniapp-opensdk包查阅源码封装而成。另外类型定义src/BaseCi.ts还提供了projectType字段默认dingtalk-biz企业内部应用可指定dingtalk-personal第三方个人应用、dingtalk-biz-isv第三方企业应用、dingtalk-biz-custom企业定制应用、dingtalk-biz-worktab-plugin工作台组件等应用类型。9.6 百度小程序 CI 配置参数类型说明tokenstring有该小程序发布权限的登录密钥minSwanVersionstring最低基础库版本不传默认为 3.350.6类型定义中百度配置还包含可选的devToolsInstallPath小程序开发者工具安装路径见 src/BaseCi.ts。9.7 京东小程序 CI 配置参数类型说明privateKeystring秘钥字符串robotnumber指定使用哪一个 ci 机器人可选值1 ~ 30ignoresstring[]指定需要排除的规则。无需配置以.开头的隐藏文件它们将默认被忽略如.git十、完整 TS 接口描述插件通过 src/BaseCi.ts 导出完整的 TypeScript 类型声明接入项目后在编辑器中可获得完整的类型提示export interface CIOptions { /** 发布版本号默认取 package.json 文件的 taroConfig.version 字段 */ version?: string /** 版本发布描述默认取 package.json 文件的 taroConfig.desc 字段 */ desc?: string /** 目标项目目录对所有小程序生效不传默认取 outputRoot 字段 */ projectPath?: string /** 微信小程序 CI 配置 */ weapp?: WeappConfig /** 头条小程序配置 */ tt?: TTConfig /** 支付宝系列小程序配置 */ alipay?: AlipayConfig /** 钉钉小程序配置 */ dd?: DingtalkConfig /** 百度小程序配置 */ swan?: SwanConfig /** 京东小程序配置 */ jd?: JdConfig } export type ProjectType miniProgram | miniGame | miniProgramPlugin | miniGamePlugin /** 微信小程序配置 */ export interface WeappConfig { /** 小程序/小游戏项目的 appid */ appid: string /** 私钥文件路径在获取项目属性和上传时用于鉴权使用 */ privateKeyPath: string /** 微信开发者工具安装路径 */ devToolsInstallPath?: string /** 类型默认 miniProgram 小程序 */ type?: ProjectType /** 上传需要排除的目录 */ ignores?: Arraystring /** 指定使用哪一个 ci 机器人可选值1 ~ 30 */ robot?: number /** 预览和上传时的编译设置 */ setting?: { /** 对应于微信开发者工具的 es6 转 es5 */ es6: boolean /** 对应于微信开发者工具的 增强编译 */ es7: boolean /** 增强编译 开启时是否禁用 JS 文件严格模式默认为 false */ disableUseStrict: boolean /** 上传时压缩 JS 代码 */ minifyJS: boolean /** 上传时压缩 WXML 代码 */ minifyWXML: boolean /** 上传时压缩 WXSS 代码 */ minifyWXSS: boolean /** 上传时压缩所有代码对应于微信开发者工具的 上传时压缩代码 */ minify: boolean /** 对应于微信开发者工具的 上传时进行代码保护 */ codeProtect: boolean /** 对应于微信开发者工具的 上传时样式自动补全 */ autoPrefixWXSS: boolean } } /** 头条小程序配置 */ export interface TTConfig { /** 绑定的邮箱账号 */ email: string /** 密码 */ password: string } /** 终端类型 */ export type AlipayClientType | alipay /** 支付宝 */ | ampe /** AMPE */ | amap /** 高德 */ | genie /** 天猫精灵 */ | alios /** ALIOS */ | uc /** UC */ | quark /** 夸克 */ | koubei /** 口碑 */ | alipayiot/** IoT */ | cainiao /** 菜鸟 */ | alihealth/** 阿里健康医蝶谷 */ | health /** 阿里医院 */ /** 支付宝系列小程序配置 */ export interface AlipayConfig { /** 小程序 appid */ appid: string /** 工具 id */ toolId: string /** 私钥文件路径在获取项目属性和上传时用于鉴权使用 (privateKeyPath 和 privateKey 之间必须要填写其中一个) */ privateKeyPath: string /** 私钥文本内容在获取项目属性和上传时用于鉴权使用 (privateKeyPath 和 privateKey 之间必须要填写其中一个) */ privateKey: string /** 小程序开发者工具安装路径 */ devToolsInstallPath?: string /** 上传的终端默认 alipay */ clientType?: AlipayClientType /** 上传时想要删除的一个版本 */ deleteVersion?: string } export type DingtalkProjectType /** 第三方个人应用 */ | dingtalk-personal /** 第三方企业应用 */ | dingtalk-biz-isv /** 企业内部应用 */ | dingtalk-biz /** 企业定制应用 */ | dingtalk-biz-custom /** 工作台组件 */ | dingtalk-biz-worktab-plugin export interface DingtalkConfig { /** 钉钉小程序 appid即钉钉开放平台后台应用管理的 MiniAppId 选项必填 */ appid: string /** 令牌从钉钉后台获取 */ token: string /** 小程序开发者工具安装路径 */ devToolsInstallPath?: string /** 钉钉应用类型默认为:dingtalk-biz (企业内部应用) */ projectType?: DingtalkProjectType } /** 百度小程序配置 */ export interface SwanConfig { /** 有该小程序发布权限的登录密钥 */ token: string /** 最低基础库版本不传默认为 3.350.6 */ minSwanVersion?: string } /** 京东小程序配置 */ export interface JdConfig { /** 秘钥信息 */ privateKey: string /** 指定使用哪一个 ci 机器人可选值1 ~ 30 */ robot?: number /** 指定需要排除的规则。无需配置以.开头的隐藏文件它们将默认被忽略如.git */ ignores?: string[] }十一、CI/CD 流水线中的典型用法将上述能力组合进流水线即可形成完整的「构建 → 上传 → 通知」链路例如本地/流水线构建执行taro build --type weapp产出dist目录上传体验版执行npx taro upload --type weapp或taro build --type weapp --upload版本号与描述由taroConfig统一提供结果通知通过自定义插件监听onUploadComplete/onPreviewComplete事件把data平台、二维码本地路径、二维码内容、版本号、描述、项目路径与success状态推送到钉钉/飞书/企微群机器人失败即中断预览/上传失败时插件会process.exit(1)确保流水线任务标记为失败。结语tarojs/plugin-mini-ci把小程序多平台「打开工具、预览、上传体验版」这些高频重复操作收敛为 3 个 CLI 选项与 3 个独立命令配合可选的 Hooks 事件足以覆盖日常开发与 CI 流水线的核心诉求。配置上只需在 config/index.js 声明平台参数并在package.json的taroConfig中维护版本号与描述实现层面每个平台都有独立的 CI 类src/WeappCI.ts、src/TTCI.ts、src/AlipayCI.ts 等与统一的二维码工具src/utils/qrcode.ts需要排查问题时可直接深入对应源码。【免费下载链接】taro开放式跨端跨框架解决方案支持使用 React/Vue/Nerv 等框架来开发微信/京东/百度/支付宝/字节跳动/ QQ 小程序/H5/React Native 等应用。 https://taro.zone/项目地址: https://gitcode.com/NervJS/taro创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考