mirror of
https://github.com/ialley-workshop-open/uni-halo.git
synced 2026-07-27 04:20:43 +08:00
chore: 清理旧文件并重构项目基础结构
- 删除大量废弃的旧代码、依赖和配置文件 - 新增基础项目配置、工具函数、页面模板和请求库 - 重构目录结构,统一项目规范 - 添加commitlint、husky等代码规范工具
This commit is contained in:
@@ -0,0 +1,270 @@
|
||||
/**
|
||||
* 微信小程序 CLI 上传脚本
|
||||
*
|
||||
* 使用方法:
|
||||
* pnpm upload:mp # 版本号读取 package.json,描述使用最新 Git commit
|
||||
* pnpm upload:mp --version=1.0.1 # 指定版本号(覆盖 package.json)
|
||||
* pnpm upload:mp --desc="修复bug" # 指定版本描述(覆盖 Git commit)
|
||||
* pnpm upload:mp --robot=2 # 指定机器人编号(1-30)
|
||||
* pnpm upload:mp --version=2.0.0 --desc="重大更新" # 组合使用多个参数
|
||||
*
|
||||
* 版本号策略: 命令行参数 > package.json version
|
||||
* 描述策略: 命令行参数 > Git 最新 commit > 默认时间戳
|
||||
*
|
||||
* 注意事项:
|
||||
* 1. 确保已在微信公众平台开通 "小程序代码上传" 权限
|
||||
* 2. 确保私钥文件存在(private.${appid}.key),并且配置了上传IP白名单
|
||||
* 3. 上传前会自动执行 build:mp:prod 构建 并跳过打开开发者工具
|
||||
* 4. 秘钥文件的appid(VITE_WX_APPID)需要与微信公众平台的小程序appid一致
|
||||
*/
|
||||
|
||||
import { execSync } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import ci from 'miniprogram-ci'
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
const ROOT_DIR = path.resolve(__dirname, '..')
|
||||
|
||||
// 从 package.json 读取版本号
|
||||
function getPackageVersion() {
|
||||
try {
|
||||
const pkgPath = path.resolve(ROOT_DIR, 'package.json')
|
||||
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
|
||||
return pkg.version || '1.0.0'
|
||||
}
|
||||
catch {
|
||||
return '1.0.0'
|
||||
}
|
||||
}
|
||||
|
||||
// 获取最新的 Git commit 信息
|
||||
function getGitCommitMessage() {
|
||||
try {
|
||||
// 获取最新 commit 的作者和标题
|
||||
const message = execSync('git log -1 --pretty="%an: %s"', {
|
||||
cwd: ROOT_DIR,
|
||||
encoding: 'utf-8',
|
||||
}).trim()
|
||||
return message || null
|
||||
}
|
||||
catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// 生成默认描述
|
||||
function getDefaultDesc() {
|
||||
// 优先使用 Git commit 信息
|
||||
const gitMessage = getGitCommitMessage()
|
||||
if (gitMessage) {
|
||||
return gitMessage
|
||||
}
|
||||
// 回退到时间戳
|
||||
return `上传于 ${new Date().toLocaleString('zh-CN')}`
|
||||
}
|
||||
|
||||
// 解析命令行参数
|
||||
function parseArgs() {
|
||||
const args = process.argv.slice(2)
|
||||
const params = {
|
||||
version: null, // 稍后设置,优先级:命令行 > package.json
|
||||
desc: null, // 稍后设置,优先级:命令行 > Git commit > 默认
|
||||
robot: 1, // 机器人编号 1-30
|
||||
}
|
||||
|
||||
args.forEach((arg) => {
|
||||
if (arg.startsWith('--version=')) {
|
||||
params.version = arg.split('=')[1]
|
||||
}
|
||||
else if (arg.startsWith('--desc=')) {
|
||||
params.desc = arg.split('=')[1]
|
||||
}
|
||||
else if (arg.startsWith('--robot=')) {
|
||||
params.robot = Number.parseInt(arg.split('=')[1], 10)
|
||||
}
|
||||
})
|
||||
|
||||
// 如果命令行没有指定版本号,则读取 package.json
|
||||
if (!params.version) {
|
||||
params.version = getPackageVersion()
|
||||
}
|
||||
|
||||
// 如果命令行没有指定描述,则读取 Git commit 或使用默认
|
||||
if (!params.desc) {
|
||||
params.desc = getDefaultDesc()
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
// 读取环境变量
|
||||
function loadEnvFile(mode = 'production') {
|
||||
const envPath = path.resolve(ROOT_DIR, 'env', `.env.${mode}`)
|
||||
const defaultEnvPath = path.resolve(ROOT_DIR, 'env', '.env')
|
||||
|
||||
const envContent = {}
|
||||
|
||||
// 先读取默认 .env
|
||||
if (fs.existsSync(defaultEnvPath)) {
|
||||
const content = fs.readFileSync(defaultEnvPath, 'utf-8')
|
||||
content.split('\n').forEach((line) => {
|
||||
const trimmed = line.trim()
|
||||
if (trimmed && !trimmed.startsWith('#')) {
|
||||
const [key, ...valueParts] = trimmed.split('=')
|
||||
if (key) {
|
||||
envContent[key.trim()] = valueParts.join('=').trim().replace(/^['"]|['"]$/g, '')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 再读取对应模式的 .env 文件(会覆盖默认值)
|
||||
if (fs.existsSync(envPath)) {
|
||||
const content = fs.readFileSync(envPath, 'utf-8')
|
||||
content.split('\n').forEach((line) => {
|
||||
const trimmed = line.trim()
|
||||
if (trimmed && !trimmed.startsWith('#')) {
|
||||
const [key, ...valueParts] = trimmed.split('=')
|
||||
if (key) {
|
||||
envContent[key.trim()] = valueParts.join('=').trim().replace(/^['"]|['"]$/g, '')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return envContent
|
||||
}
|
||||
|
||||
// 获取私钥路径
|
||||
function getPrivateKeyPath(appid) {
|
||||
// 查找私钥文件
|
||||
const keyPatterns = [
|
||||
`private.${appid}.key`,
|
||||
'private.key',
|
||||
]
|
||||
|
||||
for (const pattern of keyPatterns) {
|
||||
const keyPath = path.resolve(ROOT_DIR, pattern)
|
||||
if (fs.existsSync(keyPath)) {
|
||||
return keyPath
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`未找到私钥文件,请确保项目根目录存在 private.${appid}.key 文件`)
|
||||
}
|
||||
|
||||
// 主函数
|
||||
async function main() {
|
||||
console.log('\n🚀 开始微信小程序上传流程...\n')
|
||||
|
||||
const params = parseArgs()
|
||||
const env = loadEnvFile('production')
|
||||
const appid = env.VITE_WX_APPID
|
||||
|
||||
if (!appid) {
|
||||
throw new Error('未找到 VITE_WX_APPID 环境变量,请检查 env/.env 文件')
|
||||
}
|
||||
|
||||
console.log(`📱 AppID: ${appid}`)
|
||||
console.log(`📌 版本号: ${params.version}`)
|
||||
console.log(`📝 版本描述: ${params.desc}`)
|
||||
console.log(`🤖 机器人编号: ${params.robot}`)
|
||||
|
||||
// 获取私钥路径
|
||||
const privateKeyPath = getPrivateKeyPath(appid)
|
||||
console.log(`🔑 私钥路径: ${privateKeyPath}`)
|
||||
|
||||
// 构建小程序(跳过自动打开开发者工具)
|
||||
console.log('\n📦 正在构建小程序...(跳过自动打开开发者工具)\n')
|
||||
try {
|
||||
execSync('pnpm build:mp:prod', {
|
||||
cwd: ROOT_DIR,
|
||||
stdio: 'inherit',
|
||||
env: {
|
||||
...process.env,
|
||||
SKIP_OPEN_DEVTOOLS: 'true', // 上传时跳过打开开发者工具
|
||||
},
|
||||
})
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ 构建失败:', error.message)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// 小程序代码目录
|
||||
const projectPath = path.resolve(ROOT_DIR, 'dist', 'build', 'mp-weixin')
|
||||
|
||||
if (!fs.existsSync(projectPath)) {
|
||||
throw new Error(`构建产物不存在: ${projectPath}`)
|
||||
}
|
||||
|
||||
console.log(`📂 项目路径: ${projectPath}`)
|
||||
console.log('\n⬆️ 正在上传到微信服务器...\n')
|
||||
|
||||
// 创建项目实例
|
||||
const project = new ci.Project({
|
||||
appid,
|
||||
type: 'miniProgram',
|
||||
projectPath,
|
||||
privateKeyPath,
|
||||
ignores: ['node_modules/**/*'],
|
||||
})
|
||||
|
||||
try {
|
||||
// 上传代码
|
||||
const uploadResult = await ci.upload({
|
||||
project,
|
||||
version: params.version,
|
||||
desc: params.desc,
|
||||
robot: params.robot,
|
||||
setting: {
|
||||
es6: true,
|
||||
es7: true,
|
||||
minify: true,
|
||||
autoPrefixWXSS: true,
|
||||
minifyWXML: true,
|
||||
minifyWXSS: true,
|
||||
minifyJS: true,
|
||||
},
|
||||
onProgressUpdate: (task) => {
|
||||
if (task._status === 'done') {
|
||||
console.log(` ✅ ${task._msg}`)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
console.log('\n✅ 上传成功!')
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
|
||||
console.log(` 📌 版本号: ${params.version}`)
|
||||
console.log(` 📝 描述: ${params.desc}`)
|
||||
console.log(` 🤖 机器人: ${params.robot}`)
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')
|
||||
console.log('\n📋 下一步操作:')
|
||||
console.log(' 1. 登录微信公众平台: https://mp.weixin.qq.com')
|
||||
console.log(' 2. 进入 "管理 -> 版本管理"')
|
||||
console.log(' 3. 在 "开发版本" 中找到刚上传的版本')
|
||||
console.log(' 4. 点击 "选为体验版" 按钮\n')
|
||||
|
||||
return uploadResult
|
||||
}
|
||||
catch (error) {
|
||||
console.error('\n❌ 上传失败:', error.message)
|
||||
if (error.message.includes('privateKeyPath')) {
|
||||
console.log('\n💡 提示: 请确保已在微信公众平台配置代码上传密钥')
|
||||
console.log(' 1. 登录微信公众平台')
|
||||
console.log(' 2. 进入 "开发 -> 开发设置"')
|
||||
console.log(' 3. 在 "小程序代码上传" 区域生成并下载密钥')
|
||||
console.log(' 4. 在 "小程序代码上传" 区域配置上传IP白名单')
|
||||
}
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error('❌ 执行出错:', error)
|
||||
process.exit(1)
|
||||
})
|
||||
Reference in New Issue
Block a user