30多个小程序一键发布——miniprogram-ci

news2024/11/14 3:11:58

概述

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

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

miniprogram-ci 从 1.0.28 开始支持第三方平台开发的上传和预览,调用方式与普通开发模式无异。查看详情

密钥及 IP 白名单配置

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

入口

功能

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

  1. 上传代码,对应小程序开发者工具的上传
  2. 预览代码,对应小程序开发者工具的预览
  3. 构建 npm,对应小程序开发者工具的: 菜单-工具-构建npm
  4. 上传云开发云函数代码,对应小程序开发者工具的上传云函数能力
  5. 上传云托管代码,对应小程序开发者工具的上传云托管能力
  6. 上传云存储/静态托管文件,对应小程序开发者工具-云开发-云存储和静态托管文件管理
  7. 代理,配置 miniprogram-ci 的网络请求代理方式
  8. 支持获取最近上传版本的 sourceMap
  9. 支持 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中的所有小程序打包提交体验版)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/713523.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[DBT-05509] Failed to connect to the specified database (orcl).

同事在arm上测试19c部署时&#xff0c;发截图给我说dbca建库有告警&#xff0c;无法进行&#xff0c; Cause- OS Authentication might be disabled for this database (orcl). Action Specify a valid sysdba user name and password to connect to the database. 查找到的…

Windows安装ciphey编码工具,编码工具战神,cry简单题绝对克星!

TA是什么 一款智能化的编码分析解码工具&#xff0c;对于CTF中复杂性编码类题目可以快速攻破。 编码自动分析解码的神器。 如何安装 Windows环境 Python 3.8 64位&#xff08;最新的版本不兼容&#xff0c;32位的也不行&#xff09; 方便起见&#xff0c;我直接给一个3.8.…

【花雕】全国青少年机器人技术一级考试备考实操搭建手册2

目录 1、秋千 2、跷跷板 3、搅拌器 4、奇怪的钟 5、起重机 6、烤肉架 7、手摇风扇 8、履带车 9、直升机 10、后轮驱动车 游乐场里的跷跷板 跷跷板&#xff08;又作翘翘板&#xff09;&#xff0c;又称为摇摇板&#xff0c;是指以某些东西作为支点&#xff0c;支撑著很长但十分…

MongoDB 获取数组中匹配到的第一个元素对象

例如当前test库中的grade集合中有两条文档数据,如下图所示: 相关的两个实体映射类如下: import lombok.Data; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb…

Python中Self的详解及使用

大家学Python面向对象的时候&#xff0c;总会遇到一个让人难以理解的存在&#xff1a;self 这个self到底是谁啊&#xff0c;为什么每个类实例方法都有一个参数self&#xff0c;它到底有什么作用呢&#xff1f; 「先下结论&#xff1a;类实例化后&#xff0c;self即代表着实例&…

[SSM]在WEB中应用MyBtis

目录 MyBatis基础 5.1需求描述 5.2数据库表的设计和准备数据 5.3实现步骤 第一步&#xff1a;引入相关依赖 第二步&#xff1a;引入相关配置文件&#xff0c;放到resources目录下&#xff08;全部放到类的根路径下&#xff09; 第三步&#xff1a;前端页面index.html 第…

Istio 深入理解数据平面组件 Envoy

ingress control承载了控制面和数据面的一个职责&#xff0c;在control里面有一个process&#xff0c;这个进程就承担了反向代理的能力&#xff0c;当有任何请求发过来的时候&#xff0c;会被nginx接收到这个请求并且被转发&#xff0c;基于的规则由ingress control动态配置的&…

2023年7月1日【青书学堂】考试 计算机应用基础(高起专)

2023年7月1日【青书学堂】考试 计算机应用基础(高起专) 注意:答案仅供参考 成绩:88.8 分 第1题 单选题 在Word的编辑状态,按先后顺序依次打开了d1.doC、d2.doC、d3.doC、d4.doc 4个文档,当前的活动窗口的文档名为____。 A:d1.doc B:d2.doc C:d4.doc D:d3.doc 答案:C 第…

php代码还原工具,解决goto语句混淆,php goto解密还原

在编写php代码时&#xff0c;使用goto语句是一种常见的加密技巧。为了解决goto解码无法阅读这个问题&#xff0c;今天我要向大家介绍一款强大的php goto解密工具。 这款工具的主要功能之一就是php代码的还原。通过对代码进行解析和分析&#xff0c;它能够轻松还原被混淆的goto…

vim多文件切换快捷键设置

1、基本切换指令 vim中在打开多个文件时&#xff0c;会有多个文件进行切换的需求。按:bn切换到下一个文件&#xff0c;按:bp切换到上一个文件。 2、快捷键设置 为了便捷操作&#xff0c;将切换命令设置成快捷键。 进入/home/yys个人目录下&#xff0c;vim .vimrc进入vimrc文…

Spring Boot 中的 @EnableDiscoveryClient 注解

Spring Boot 中的 EnableDiscoveryClient 注解 Spring Boot 是一个快速开发 Spring 应用程序的框架&#xff0c;它提供了一些基础设施&#xff0c;使得我们可以快速地开发出高效、可靠的应用程序。其中&#xff0c;EnableDiscoveryClient 注解是 Spring Boot 中一个非常重要的…

C++刷题第四天 链表 24. 两两交换链表中的节点 ● 19.删除链表的倒数第N个节点 ● 160. 链表相交 ● 142.环形链表II

24. 两两交换链表中的节点 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例&#xff1a; 原列表为&#xff1a;1-2-3-4-…

【Mysql】Explain深入分析(三)

Explain工具介绍 使用EXPLAIN关键字可以模拟优化器执行SQL语句&#xff0c;分析你的查询语句或是结构的性能瓶颈 在 select 语句之前增加 explain 关键字&#xff0c;MySQL 会在查询上设置一个标记&#xff0c;执行查询会返回执行计划的信息&#xff0c;而不是执行这条SQL 注意…

node ffmpeg jsmpeg 拉流 展示笔记

拉流参考上一篇 基础&#xff1a;FFmpeg安装过 拉流完成之后转换成可播放的方式 1、下载jsmpeghttps://github.com/phoboslab/jsmpeg 下载完 用vscode 打开jsmpeg-master目录 2、在根目录下安装 node-media-server npm install node-media-server 新建app.js并运行 const…

8 图像去噪 滤波 锐化 边缘检测案例(matlab程序)

1.简述 学习目标&#xff1a;一个图像处理的经典综合案例 一、图像锐化的原理   图像锐化的目的是凸显物体的细节轮廓&#xff0c;通常可以用梯度、Laplace算子和高通滤波来实现&#xff0c;下面一一说明&#xff1a; 1、梯度法 梯度计算可以参考 小白学习图像处理——cann…

数据可视化01_t-SNE

1. t-SNE的定义 t-SNE stands for t-distributed Stochastic Neighbor Embedding. 代表 t 分布随机邻域嵌入。 t-SNE 获取高维数据并将其降低到较低维空间&#xff0c;同时保持数据点之间的关系尽可能接近其原始排列。 它是一种无监督机器学习算法&#xff0c;由 Laurens va…

8年测试经验总结,性能测试流程与性能测试学习路线,卷起来...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试流程 1、…

运输层概述、端口号、复用与分用

1.运输层概述、端口号、复用与分用 笔记来源&#xff1a; 湖科大教书匠&#xff1a;运输层概述 湖科大教书匠&#xff1a;运输层端口号、复用与分用的概念 声明&#xff1a;该学习笔记来自湖科大教书匠&#xff0c;笔记仅做学习参考 1.1 运输层概述 计算机网络体系结构中的物…

交流220v转12v给单片机供电芯片

客户的应用需求&#xff1a;AD220V转DC12V 体积要非常小&#xff0c;单片机使用&#xff0c;单片机设备12V 电流很小不会超过100mA&#xff1f; 【AD220V转DC12V体积小的问题】 问题&#xff1a;我需要将交流电&#xff08;220V&#xff09;转换为直流电&#xff08;12V&…

fastadmin后台 点击开关 弹出 你没有权限访问 角色组里面添加了,除了超级管理员其他的只要用状态开关就,没权限 解决办法

首发地址&#xff1a;https://ask.fastadmin.net/question/22863.html 然后再对应的后台控制器里面 加入 protected $multiFields 你设计数据库的开关字段; //注意是字段&#xff0c;不是填写: multi 示例&#xff1a; protected $multiFields show_switch; 也可以多个 p…