概述
miniprogram-ci 是从微信开发者工具中抽离的关于小程序/小游戏项目代码的编译模块。
开发者可不打开小程序开发者工具,独立使用 miniprogram-ci 进行小程序代码的上传、预览等操作。
miniprogram-ci 从 1.0.28 开始支持第三方平台开发的上传和预览,调用方式与普通开发模式无异。查看详情
密钥及 IP 白名单配置
使用 miniprogram-ci 前应访问"微信公众平台-开发-开发设置"后下载代码上传密钥,并配置 IP 白名单 开发者可选择打开 IP 白名单,打开后只有白名单中的 IP 才能调用相关接口。我们建议所有开发者默认开启这个选项,降低风险 代码上传密钥拥有预览、上传代码的权限,密钥不会明文存储在微信公众平台上,一旦遗失必须重置,请开发者妥善保管
功能
miniprogram-ci 目前提供以下能力:
- 上传代码,对应小程序开发者工具的上传
- 预览代码,对应小程序开发者工具的预览
- 构建 npm,对应小程序开发者工具的: 菜单-工具-构建npm
- 上传云开发云函数代码,对应小程序开发者工具的上传云函数能力
- 上传云托管代码,对应小程序开发者工具的上传云托管能力
- 上传云存储/静态托管文件,对应小程序开发者工具-云开发-云存储和静态托管文件管理
- 代理,配置 miniprogram-ci 的网络请求代理方式
- 支持获取最近上传版本的 sourceMap
- 支持 node 脚本调用方式和 命令行 调用方式
脚本调用
npm install miniprogram-ci --save
代码
preview.js
const ci = require('miniprogram-ci');
const fs = require('fs');
const path = require('path');
let config = {
xcxKey: [], //需要上传的小程序列表
version: "", //版本号
desc: "", //备注
appindex: 0 //当前执行到第几个
}
exports.start = async () => {
//先拿到需要上传的列表,也就是小程序的appid和名称等相关信息,还有上传的版本和备注
fs.readFile(
path.join(__dirname, '../xcxkey/xcxkey.json'),
'utf-8',
(err, data) => {
const fileJson = JSON.parse(data)
config.xcxKey = fileJson.xcxKey;
config.version = fileJson.version;
config.desc = fileJson.desc;
config.env = fileJson.env;
config.appindex = 0;
console.log(`本次提交--${config.xcxKey.map(item=> config.env + item.desc + config.desc)}`);
console.log(`版本--${config.version}`);
previewStart();
}
);
}
const previewStart = async () => {
if (!config.xcxKey[config.appindex]) {
console.log('上传完成')
return;
}
//开始上传,首先修改文件信息
await setProjectConfig();
await setMain();
console.log(`${config.xcxKey[config.appindex].desc}--${config.env}开始`);
const project = new ci.Project({
appid: config.xcxKey[config.appindex].appid,
type: 'miniProgram',
projectPath: path.resolve(__dirname, '../unpackage/dist/dev/mp-weixin'),
privateKeyPath: path.resolve(__dirname,
`../xcxkey/private.${config.xcxKey[config.appindex].appid}.key`),
ignores: ['node_modules/**/*'],
});
// 预览
const uploadResult = await ci.preview({
project,
version: config.xcxKey[config.appindex].version,
desc: `${config.env}——${config.desc}`,
setting: {
es6: true,
minifyJS: true,
minifyWXML: true,
minifyWXSS: true,
minify: true
},
qrcodeFormat: 'image',
qrcodeOutputDest: path.resolve(__dirname, `../ci/preview-images/${config.xcxKey[config.appindex].title}.jpg`),
onProgressUpdate: getstate,
pagePath: 'pages/home/index', // 预览页面
searchQuery: '' // 预览参数 [注意!]这里的`&`字符在命令行中应写成转义字符`\&`
});
//监听上传过程,如果上传完成延迟10秒再上传下一个
function getstate(e) {
console.log('eeee', e);
if (e._status === "done" && e._msg === "upload") {
console.log(`${config.xcxKey[config.appindex].desc}--${config.env}上传完成`)
setTimeout(() => {
config.appindex += 1;
previewStart();
}, 1000)
}
}
}
//修改 project.config.json 内容
const setProjectConfig = async () => {
// 要读取和替换的文件路径
const project_config = '../unpackage/dist/dev/mp-weixin/project.config.json';
const promise = new Promise((resolve, reject) => {
// 读取 project.config.json
fs.readFile(
path.join(__dirname, project_config),
'utf8',
(err, data) => {
if (err) throw err;
let json = JSON.parse(data);
// 替换 appid 和 projectname
json.appid = config.xcxKey[config.appindex].appid;
json.projectname = config.xcxKey[config.appindex].name;
// 改写 project.config.json 中 appid 和 projectname
fs.writeFile(
path.join(__dirname, project_config),
JSON.stringify(json, null, 4),
(err) => {
if (err) throw err;
resolve();
}
);
}
);
});
return promise;
}
//修改 main.js 内容
const setMain = async () => {
// 要读取和替换的文件路径
const app_main_file = '../unpackage/dist/dev/mp-weixin/common/main.js';
const promise = new Promise((resolve, reject) => {
// 读取 unpackage/dist/dev/mp-weixin/common/main.js
fs.readFile(
path.join(__dirname, app_main_file),
'utf8',
(err, data) => {
if (err) throw err;
let app_main = data;
const hotel_id = config.xcxKey[config.appindex].hotel_id;
// 替换 source_hotel_id
let re = /(?<=source_hotel_id:").*?(?=",source_hotel_id_end_ci:)/;
app_main = app_main.replace(re, hotel_id);
// 改写 unpackage/dist/dev/mp-weixin/common/main.js 中 source_hotel_id
fs.writeFile(
path.join(__dirname, app_main_file),
app_main,
(err) => {
if (err) throw err;
resolve();
}
);
}
);
});
return promise;
}
upload.js
const ci = require('miniprogram-ci');
const fs = require('fs');
const path = require('path');
let config = {
xcxKey: [], //需要上传的小程序列表
version: "", //版本号
desc: "", //备注
env: "",
appindex: 0 //当前执行到第几个
}
exports.start = async () => {
//先拿到需要上传的列表,也就是小程序的appid和名称等相关信息,还有上传的版本和备注
fs.readFile(
path.join(__dirname, '../xcxkey/xcxkey.json'),
'utf-8',
(err, data) => {
const fileJson = JSON.parse(data)
console.log(fileJson);
config.xcxKey = fileJson.xcxKey;
config.version = fileJson.version;
config.desc = fileJson.desc;
config.env = fileJson.env;
config.appindex = 0;
console.log(`本次提交--${config.xcxKey.map(item=> config.env + item.desc)} --- config.desc`);
console.log(`版本--${config.version}`);
uploadStart();
}
);
}
const uploadStart = async () => {
if (!config.xcxKey[config.appindex]) {
console.log('上传完成')
return;
}
//开始上传,首先修改文件信息
await setProjectConfig();
await setMain();
console.log(`${config.xcxKey[config.appindex].desc}--${config.env}开始`);
const project = new ci.Project({
appid: config.xcxKey[config.appindex].appid,
type: 'miniProgram',
projectPath: path.resolve(__dirname, '../unpackage/dist/dev/mp-weixin'),
privateKeyPath: path.resolve(__dirname,
`../xcxkey/private.${config.xcxKey[config.appindex].appid}.key`),
ignores: ['node_modules/**/*'],
});
// 上传
const uploadResult = await ci.upload({
project,
version: config.xcxKey[config.appindex].version,
desc: `${config.env}——${config.desc}`,
setting: {
es6: true,
minifyJS: true,
minifyWXML: true,
minifyWXSS: true,
minify: true
},
onProgressUpdate: getstate,
});
console.log(uploadResult)
//监听上传过程,如果上传完成延迟10秒再上传下一个
function getstate(e) {
if (e._status == "done" && e._msg == "upload") {
console.log(`${config.xcxKey[config.appindex].desc}--${config.env}上传完成`)
setTimeout(() => {
config.appindex += 1;
uploadStart();
}, 1000)
}
}
}
//修改 ext.json 内容
const setExtConfig = async () => {
// 要读取和替换的文件路径
const project_config = '../ext.json';
const promise = new Promise((resolve, reject) => {
// 读取 project.config.json
fs.readFile(
path.join(__dirname, project_config),
'utf8',
(err, data) => {
if (err) throw err;
let json = JSON.parse(data);
// 替换 appid 和 projectname
json.extAppid = config.xcxKey[config.appindex].appid;
// 改写 project.config.json 中 appid 和 projectname
fs.writeFile(
path.join(__dirname, project_config),
JSON.stringify(json, null, 4),
(err) => {
if (err) throw err;
resolve();
}
);
}
);
});
return promise;
}
//修改 project.config.json 内容
const setProjectConfig = async () => {
// 要读取和替换的文件路径
const project_config = '../unpackage/dist/dev/mp-weixin/project.config.json';
const promise = new Promise((resolve, reject) => {
// 读取 project.config.json
fs.readFile(
path.join(__dirname, project_config),
'utf8',
(err, data) => {
if (err) throw err;
let json = JSON.parse(data);
// 替换 appid 和 projectname
json.appid = config.xcxKey[config.appindex].appid;
json.projectname = config.xcxKey[config.appindex].name;
// 改写 project.config.json 中 appid 和 projectname
fs.writeFile(
path.join(__dirname, project_config),
JSON.stringify(json, null, 4),
(err) => {
if (err) throw err;
resolve();
}
);
}
);
});
return promise;
}
//修改 main.js 内容
const setMain = async () => {
// 要读取和替换的文件路径
const app_main_file = '../unpackage/dist/dev/mp-weixin/common/main.js';
const promise = new Promise((resolve, reject) => {
// 读取 unpackage/dist/dev/mp-weixin/common/main.js
fs.readFile(
path.join(__dirname, app_main_file),
'utf8',
(err, data) => {
if (err) throw err;
let app_main = data;
const hotel_id = config.xcxKey[config.appindex].hotel_id;
// 替换 source_hotel_id
let re = /(?<=source_hotel_id:").*?(?=",source_hotel_id_end_ci:)/;
app_main = app_main.replace(re, hotel_id);
// 改写 unpackage/dist/dev/mp-weixin/common/main.js 中 source_hotel_id
fs.writeFile(
path.join(__dirname, app_main_file),
app_main,
(err) => {
if (err) throw err;
resolve();
}
);
}
);
});
return promise;
}
package.json
{
"scripts": {
"upload": "node upload-ci.js",
"preview": "node preview-ci.js"
},
"dependencies": {
"gulp": "^4.0.2",
"miniprogram-ci": "^1.8.12"
}
}
preview-ci.js
const path = require('path');
const preview = require(path.join(__dirname, './ci/preview'));
;
(async () => {
preview.start();
})()
upload-ci.js
const path = require('path');
const upload = require(path.join(__dirname, './ci/upload'));
;
(async () => {
upload.start();
})()
{
"xcxKey": [
{
"name": "名称",
"title": "title",
"appid": "appid",
"version": "1.0.0",
"desc": "备注"
},
...
],
"env": "正式环境",
"desc": "备注",
"version": "1.0.0"
}
// npm run preview(会把xcxkey中的所有小程序打包预览)
// npm run upload(会把xcxkey中的所有小程序打包提交体验版)
请问下 这个只能发布到体验版吗?不能更进一步吗?
请问这个 ../unpackage/dist/dev/mp-weixin/ 路径怎么来的是提前打包操作了吗?还是说miniprogram-ci自动创建啊