概述

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

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

密钥及 IP 白名单配置

使用 miniprogram-ci 前应访问”微信公众平台-开发-开发设置”后下载代码上传密钥,并配置 IP 白名单 开发者可选择打开 IP 白名单,打开后只有白名单中的 IP 才能调用相关接口。我们建议所有开发者默认开启这个选项,降低风险 代码上传密钥拥有预览、上传代码的权限,密钥不会明文存储在微信公众平台上,一旦遗失必须重置,请开发者妥善保管

入口

功能

miniprogram-ci 目前提供以下能力:

  1. 上传代码,对应小程序开发者工具的上传
  2. 预览代码,对应小程序开发者工具的预览
  3. 构建 npm,对应小程序开发者工具的: 菜单-工具-构建npm
  4. 上传云开发云函数代码,对应小程序开发者工具的上传云函数能力
  5. 代理,配置 miniprogram-ci 的网络请求代理方式
  6. 支持获取最近上传版本的 sourceMap
  7. 支持 node 脚本调用方式和 命令行 调用方式

脚本调用

  1. npm install miniprogram-ci --save

项目对象

项目对象是本模块主要的入参,可以依据下边的定义自行实现

项目对象的定义:

  1. interface IProject {
  2. appid: string
  3. type: string
  4. projectPath: string
  5. privateKey: string
  6. attr(): Promise<IProjectAttr>
  7. stat(prefix: string, filePath: string): IStat | undefined
  8. getFile(prefix: string, filePath: string): Promise<Buffer>
  9. getFileList(prefix: string, extName: string): string[]
  10. updateFiles: () => void
  11. }
类型说明
appid属性小程序/小游戏项目的 appid
type属性项目的类型,有效值 miniProgram/miniProgramPlugin/miniGame/miniGamePlugin
projectPath属性项目的路径,即 project.config.json 所在的目录
privateKey属性私钥,在获取项目属性和上传时用于鉴权使用,在 微信公众平台 上登录后下载
attr异步方法项目的属性,如指定了 privateKey 则会使用真实的项目属性
stat同步方法特定目录下前缀下(prefix)文件路径 (filePath) 的 stat, 如果不存在则返回 undefined
getFile异步方法特定目录下前缀下(prefix)文件路径 (filePath) 的 Buffer
getFileList同步方法特定目录下前缀下(prefix)文件路径 (filePath) 下的文件列表
updateFile同步方法更新项目文件

也可以通过指定项目路径来创建该对象

  1. const ci = require('miniprogram-ci')
  2. const project = new ci.Project({
  3. appid: 'wxsomeappid',
  4. type: 'miniProgram',
  5. projectPath: 'the/project/path',
  6. privateKeyPath: 'the/privatekey/path',
  7. ignores: ['node_modules/**/*'],
  8. })
类型必填说明
appidstring合法的小程序/小游戏 appid
projectPathstring项目路径
privateKeyPathstring私钥的路径
typestring显示指明当前的项目类型, 默认为 miniProgram,有效值 miniProgram/miniProgramPlugin/miniGame/miniGamePlugin
ignoresstring[]指定需要排除的规则

上传

  1. const ci = require('miniprogram-ci')
  2. ;(async () => {
  3. const project = new ci.Project({
  4. appid: 'wxsomeappid',
  5. type: 'miniProgram',
  6. projectPath: 'the/project/path',
  7. privateKeyPath: 'the/path/to/privatekey',
  8. ignores: ['node_modules/**/*'],
  9. })
  10. const uploadResult = await ci.upload({
  11. project,
  12. version: '1.1.1',
  13. desc: 'hello',
  14. setting: {
  15. es6: true,
  16. },
  17. onProgressUpdate: console.log,
  18. })
  19. console.log(uploadResult)
  20. })()

参数

类型必填说明
projectIProject#项目对象
versionstring自定义版本号
descstring自定义备注
settingobject#编译设置
onProgressUpdatefunction进度更新监听函数
robotnumber指定使用哪一个 ci 机器人,可选值:1 ~ 30

返回

类型必填说明
subPackageInfoArray<{name:string, size:number}>小程序包信息, nameFULL 时表示整个小程序包, nameAPP 时表示小程序主包,其他情况都表示分包
pluginInfoArray<{pluginProviderAppid:string, version: string, size:number}>小程序插件信息
devPluginIdstring插件开发模式下,上传版本的插件 id

预览

  1. const ci = require('miniprogram-ci')
  2. ;(async () => {
  3. const project = new ci.Project({
  4. appid: 'wxsomeappid',
  5. type: 'miniProgram',
  6. projectPath: 'the/project/path',
  7. privateKeyPath: 'the/path/to/privatekey',
  8. ignores: ['node_modules/**/*'],
  9. })
  10. const previewResult = await ci.preview({
  11. project,
  12. desc: 'hello', // 此备注将显示在“小程序助手”开发版列表中
  13. setting: {
  14. es6: true,
  15. },
  16. qrcodeFormat: 'image',
  17. qrcodeOutputDest: '/path/to/qrcode/file/destination.jpg',
  18. onProgressUpdate: console.log,
  19. // pagePath: 'pages/index/index', // 预览页面
  20. // searchQuery: 'a=1&b=2', // 预览参数 [注意!]这里的`&`字符在命令行中应写成转义字符`\&`
  21. })
  22. console.log(previewResult)
  23. })()

参数

类型必填说明
projectIProject#项目对象
descstring自定义备注,将显示在“小程序助手”开发版列表中
settingobject#编译设置
onProgressUpdatefunction进度更新监听函数
robotnumber指定使用哪一个 ci 机器人,可选值:1 ~ 30
qrcodeFormatstring返回二维码文件的格式 “image”“base64”, 默认值 “terminal” 供调试用
qrcodeOutputDeststring二维码文件保存路径
pagePath:string预览页面路径
searchQuery:string预览页面路径启动参数
scenenumber默认值 1011,具体含义见场景值列表

返回

类型必填说明
subPackageInfoArray<{name:string, size:number}>小程序包信息, nameFULL 时表示整个小程序包, nameAPP 时表示小程序主包,其他情况都表示分包
pluginInfoArray<{pluginProviderAppid:string, version: string, size:number}>小程序插件信息

构建npm

对应开发者工具构建npm功能。

  1. const ci = require('miniprogram-ci')
  2. ;(async () => {
  3. const project = new ci.Project({
  4. appid: 'wxsomeappid',
  5. type: 'miniProgram',
  6. projectPath: 'the/project/path',
  7. privateKeyPath: 'the/path/to/privatekey',
  8. ignores: ['node_modules/**/*'],
  9. })
  10. // 在有需要的时候构建npm
  11. const warning = await ci.packNpm(project, {
  12. ignores: ['pack_npm_ignore_list'],
  13. reporter: (infos) => { console.log(infos) }
  14. })
  15. console.warn(warning)
  16. // 可对warning进行格式化
  17. /*
  18. warning.map((it, index) => {
  19. return `${index + 1}. ${it.msg}
  20. \t> code: ${it.code}
  21. \t@ ${it.jsPath}:${it.startLine}-${it.endLine}`
  22. }).join('---------------\n')
  23. */
  24. // 完成构建npm之后,可用ci.preview或者ci.upload
  25. })()
参数类型必填说明
projectIProject项目对象
options.ignoresstring[]指定构建npm需要排除的规则
options.reporterfunction构建回调信息

拉取最近上传版本的sourceMap

  1. const ci = require('miniprogram-ci')
  2. ;(async () => {
  3. const project = new ci.Project({
  4. appid: 'wxsomeappid',
  5. type: 'miniProgram',
  6. projectPath: 'the/project/path',
  7. privateKeyPath: 'the/path/to/privatekey',
  8. ignores: ['node_modules/**/*'],
  9. })
  10. await ci.getDevSourceMap({
  11. project,
  12. robot: 1,
  13. sourceMapSavePath: './sm.zip'
  14. })
  15. })()

参数

类型必填说明
projectIProject#项目对象
robotnumber指定使用哪一个 ci 机器人,可选值:1 ~ 30
sourceMapSavePathstring保存的路径

自定义 node_modules 位置的构建 npm

有的时候,需要被构建模块对应的 node_modules 可能并不在小程序项目内,所以提供了一个新的接口来支持这个需求。 例如有如下项目结构

  1. ├── lib # lib目录存放要被构建的 node_modules
  2. ├── node_modules
  3. └── is-object
  4. └── package.json
  5. └── miniprogram-project # 这里是小程序项目路径
  6. ├── miniprogram # 我们希望最终把 miniprogram_npm 构建在 miniprogram/ 目录之下
  7. ├── app.js
  8. ├── app.json
  9. ├── app.wxss
  10. ├── pages
  11. ├── index
  12. └── logs
  13. └── sitemap.json
  14. └── project.config.json

于是可以这样调用

  1. let packResult = await ci.packNpmManually({
  2. packageJsonPath: './lib/package.json',
  3. miniprogramNpmDistDir: './miniprogram-project/miniprogram/',
  4. })
  5. console.log('pack done, packResult:', packResult)
  6. // 输出 pack done, packResult: { miniProgramPackNum: 0, otherNpmPackNum: 1, warnList: [] }

得到的最终项目

  1. .
  2. ├── lib
  3. ├── node_modules
  4. └── is-object
  5. └── package.json
  6. └── miniprogram-project
  7. ├── miniprogram
  8. ├── app.js
  9. ├── app.json
  10. ├── app.wxss
  11. ├── miniprogram_npm # <--- 这就是构建出来的由 lib/node_modules 里 miniprogram_npm 了
  12. ├── pages
  13. └── sitemap.json
  14. └── project.config.json
参数类型必填说明
options.packageJsonPathstring希望被构建的node_modules 对应的 package.json 的路径
options.miniprogramNpmDistDirstring被构建 miniprogram_npm 的目标位置目标位置
options.ignoresstring[]指定需要排除的规则

上传云开发云函数

对应开发者工具云开发云函数上传能力。

  1. const ci = require('miniprogram-ci')
  2. ;(async () => {
  3. const project = new ci.Project({
  4. appid: 'wxsomeappid',
  5. type: 'miniProgram',
  6. projectPath: 'the/project/path',
  7. privateKeyPath: 'the/path/to/privatekey',
  8. ignores: ['node_modules/**/*'],
  9. })
  10. const result = await ci.cloud.uploadFunction({
  11. project,
  12. env: '云环境 ID',
  13. name: '云函数名称',
  14. path: '云函数代码目录',
  15. remoteNpmInstall: true, // 是否云端安装依赖
  16. })
  17. console.warn(result)
  18. })()
参数类型必填说明
projectIProject项目对象
envstring云环境 ID
namestring云函数名称
pathstring云函数代码目录
remoteNpmInstallboolean是否云端安装依赖,默认 false

remoteNpmInstall 额外说明:true 时云端安装依赖,不会上传本地 node_modules,false 时全量上传,包括上传 node_modules

代理

miniprogram-ci 使用了 get-proxy 模块来自动获取代理地址。 如果不适用ci.proxy()方法或者--proxy参数来指定代理,那么 miniprogram-ci 将会按照以下顺序去获取 https 代理地址

  1. 获取环境变量中的 HTTPS_PROXY
  2. 获取环境变量中的 https_proxy
  3. 获取环境变量中的 HTTP_PROXY
  4. 获取环境变量中的 http_proxy
  5. 获取npm配置的 https-proxy
  6. 获取npm配置的 http-proxy
  7. 获取npm配置的 proxy
  8. servicewechat.com 加入到环境变量中的 no_proxy,miniprogram-ci 将不通过代理发送网络请求
  1. const ci = require('miniprogram-ci')
  2. ci.proxy('YOUR_PROXY_URL')

命令行调用

  1. npm install -g miniprogram-ci
  1. #help
  2. miniprogram-ci --help
  3. #preview
  4. miniprogram-ci \
  5. preview \
  6. --pp ./demo-proj/ \
  7. --pkp ./private.YOUR_APPID.key \
  8. --appid YOUR_APPID \
  9. --uv PACKAGE_VERSION \
  10. -r 1 \
  11. --enable-es6 true \
  12. --proxy YOUR_PROXY \
  13. --qrcode-format image \
  14. --qrcode-output-dest '/tmp/x.jpg' \
  15. #upload
  16. miniprogram-ci \
  17. upload \
  18. --pp ./demo-proj/ \
  19. --pkp ./private.YOUR_APPID.key \
  20. --appid YOUR_APPID \
  21. --uv PACKAGE_VERSION \
  22. -r 1 \
  23. --enable-es6 true \
  24. #pack-npm
  25. miniprogram-ci \
  26. pack-npm \
  27. --pp ./YOUR_PROJECT/ \
  28. --pkp ./private.YOUR_APPID.key \
  29. --appid YOUR_APPID \
  30. #pack-npm-manually
  31. miniprogram-ci \
  32. pack-npm-manually \
  33. --pack-npm-manually-package-json-path PACKAGE_JSON_PATH \
  34. --pack-npm-manually-miniprogram-npm-dist-dir DISTPATH
  35. #cloudbase upload cloudfunction
  36. miniprogram-ci cloud functions upload \
  37. --pp ./YOUR_PROJECT/ \
  38. --appid YOUR_APPID \
  39. --pkp ./private.YOUR_APPID.key \
  40. --env YOUR_CLOUD_ENV_ID \
  41. --name YOUR_CLOUD_FUNCTION_NAME \
  42. --path ./YOUR_CLOUD_FUNCTION_FOLDER_PATH/ \
  43. --remote-npm-install true
  44. #proxy
  45. export HTTPS_PROXY = YOUR_PROXY_URL # 可以在shell脚本里声明临时proxy
  46. miniprogram-ci \
  47. upload \
  48. --pp ./demo-proj/ \
  49. --pkp ./private.YOUR_APPID.key \
  50. --appid YOUR_APPID \
  51. --uv PACKAGE_VERSION \
  52. -r 1 \
  53. --enable-es6 true \
  54. --proxy YOUR_PROXY_URL # 也可以使用这个参数声明proxy
  55. #get dev source map
  56. miniprogram-ci \
  57. get-dev-source-map \
  58. --pp ./demo-proj/ \
  59. --pkp ./private.YOUR_APPID.key \
  60. --appid YOUR_APPID \
  61. -r 1 \ # 获取具体哪个robot最近上传的版本的sourceMap
  62. --source-map-save-path ./sourcemap.zip #保存路径,推荐zip结尾,最后得到的是一个zip包

编译设置

类型说明
es6boolean对应小程序开发者工具的 “es6 转 es5”
es7boolean对应小程序开发者工具的 “增强编译”
minifyJSboolean压缩 JS 代码
minifyWXMLboolean压缩 WXML 代码
minifyWXSSboolean压缩 WXSS 代码
minifyboolean压缩所有代码,对应小程序开发者工具的 “压缩代码”
codeProtectboolean对应小程序开发者工具的 “代码保护”
autoPrefixWXSSboolean对应小程序开发者工具的 “样式自动补全”

关于小程序开发者工具代码编译选项

Tips

miniprogram-ci1.0.28 开始支持第三方平台开发的上传和预览,调用方式与普通开发模式无异。 使用第三方平台开发模式时,应注意:

  • 请确保项目中存在正确的 ext.json
  • 密钥文件是第三方平台绑定的开发小程序 appid 的密钥文件
  • ip白名单是第三方平台绑定的开发小程序 appid 的 ip 白名单
  • 调用传入的 appid 是第三方平台绑定的开发小程序 appid 关于第三方平台开发模式,请参考这里