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,154 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import enquirer from 'enquirer'
|
||||
import pc from 'picocolors'
|
||||
|
||||
const manifestPath = path.resolve(process.cwd(), 'manifest.config.ts')
|
||||
// 获取是否只是测试运行
|
||||
const dryRun = process.argv.includes('--dry-run')
|
||||
|
||||
/**
|
||||
* 将语义化版本号根据传递的类型进行递增
|
||||
* @param {string} version 当前版本号,如 '1.1.0'
|
||||
* @param {string} type 升级类型: 'patch' | 'minor' | 'major' | 'none'
|
||||
* @returns {string} 新的版本号
|
||||
*/
|
||||
function bumpVersionName(version, type) {
|
||||
if (type === 'none') return version
|
||||
|
||||
const parts = version.split('.')
|
||||
let major = Number.parseInt(parts[0] || '0', 10)
|
||||
let minor = Number.parseInt(parts[1] || '0', 10)
|
||||
let patch = Number.parseInt(parts[2] || '0', 10)
|
||||
|
||||
switch (type) {
|
||||
case 'major':
|
||||
major += 1; minor = 0; patch = 0;
|
||||
break;
|
||||
case 'minor':
|
||||
minor += 1; patch = 0;
|
||||
break;
|
||||
case 'patch':
|
||||
patch += 1;
|
||||
break;
|
||||
}
|
||||
return `${major}.${minor}.${patch}`
|
||||
}
|
||||
|
||||
async function run() {
|
||||
const source = fs.readFileSync(manifestPath, 'utf8')
|
||||
|
||||
// 匹配 versionCode 和 versionName 的正则表达式,支持键名带有引号的情况,例如 'versionCode': '100'
|
||||
const versionCodeRegex = /((?:['"])?versionCode(?:['"])?\s*:\s*)(['"])(\d+)\2/
|
||||
const versionNameRegex = /((?:['"])?versionName(?:['"])?\s*:\s*)(['"])([\d\.]+)\2/
|
||||
|
||||
const codeMatch = source.match(versionCodeRegex)
|
||||
const nameMatch = source.match(versionNameRegex)
|
||||
|
||||
if (!codeMatch || !nameMatch) {
|
||||
console.error(pc.red('✖ [bump-version] 未在 manifest.config.ts 中找到合法的 versionCode 或 versionName'))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const currentVersionCode = Number.parseInt(codeMatch[3], 10)
|
||||
const currentVersionName = nameMatch[3]
|
||||
const nextVersionCode = String(currentVersionCode + 1)
|
||||
|
||||
// 1. 检查命令行参数是否有 --type
|
||||
const typeArgMatch = process.argv.find(arg => arg.startsWith('--type='))
|
||||
let bumpType = typeArgMatch ? typeArgMatch.split('=')[1] : null
|
||||
|
||||
// 2. 环境判定:如果不在交互终端或者是CI环境,但是没有指定类型,则默认只升级 versionCode
|
||||
const isInteractive = process.stdout.isTTY && !process.env.CI
|
||||
|
||||
if (!bumpType) {
|
||||
if (!isInteractive) {
|
||||
console.log(pc.yellow('⚠ [bump-version] 非交互环境且未指定参数,默认不修改 versionName'))
|
||||
bumpType = 'none'
|
||||
} else {
|
||||
// 3. 在终端交互式询问用户怎么处理 versionName
|
||||
console.log('')
|
||||
console.log(pc.cyan('📦 准备发布新版本'))
|
||||
console.log(`${pc.gray('当前版本:')} ${pc.bold(currentVersionName)} ${pc.gray(`(v${currentVersionCode})`)}`)
|
||||
console.log('')
|
||||
|
||||
const response = await enquirer.prompt({
|
||||
type: 'select',
|
||||
name: 'selectedType',
|
||||
message: '请选择如何升级版本名称 (versionName)?',
|
||||
pointer: pc.cyan('❯'),
|
||||
choices: [
|
||||
{
|
||||
message: `${pc.bold('修复')} (Patch) ${pc.gray(currentVersionName)} → ${pc.green(bumpVersionName(currentVersionName, 'patch'))}`,
|
||||
name: 'patch',
|
||||
hint: pc.gray('修复Bug、极小的代码安全变动')
|
||||
},
|
||||
{
|
||||
message: `${pc.bold('特性')} (Minor) ${pc.gray(currentVersionName)} → ${pc.cyan(bumpVersionName(currentVersionName, 'minor'))}`,
|
||||
name: 'minor',
|
||||
hint: pc.gray('新增功能、向下兼容的API更新')
|
||||
},
|
||||
{
|
||||
message: `${pc.bold('重大')} (Major) ${pc.gray(currentVersionName)} → ${pc.magenta(bumpVersionName(currentVersionName, 'major'))}`,
|
||||
name: 'major',
|
||||
hint: pc.gray('重大重构、不兼容的API修改')
|
||||
},
|
||||
{
|
||||
message: `${pc.bold('仅Code')} (None) ${pc.gray('保持 ' + currentVersionName)}`,
|
||||
name: 'none',
|
||||
hint: pc.gray('保持名称不变,仅升级构建号(versionCode)')
|
||||
},
|
||||
{
|
||||
message: `${pc.bold('取消')} (Cancel) ${pc.gray('完全不升级版本')}`,
|
||||
name: 'cancel',
|
||||
hint: pc.gray('跳过版本修改,直接进入后续打包流程')
|
||||
},
|
||||
],
|
||||
// 如果用户按 ctrl+c 退出
|
||||
onCancel: () => {
|
||||
console.log(pc.red('✖ 取消操作并退出编译'))
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
bumpType = response.selectedType
|
||||
|
||||
// 用户选择了完全不升级
|
||||
if (bumpType === 'cancel') {
|
||||
console.log('')
|
||||
console.log(pc.green('✔ 已跳过版本升级操作'))
|
||||
console.log('')
|
||||
process.exit(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 根据类型计算下一代版本并进行替换计算
|
||||
const nextVersionName = bumpVersionName(currentVersionName, bumpType)
|
||||
|
||||
let updated = source.replace(versionCodeRegex, `${codeMatch[1]}${codeMatch[2]}${nextVersionCode}${codeMatch[2]}`)
|
||||
updated = updated.replace(versionNameRegex, `${nameMatch[1]}${nameMatch[2]}${nextVersionName}${nameMatch[2]}`)
|
||||
|
||||
// 5. 回填文件内容
|
||||
if (!dryRun) {
|
||||
fs.writeFileSync(manifestPath, updated, 'utf8')
|
||||
}
|
||||
|
||||
// 美化成功提示输出
|
||||
console.log('')
|
||||
console.log(pc.green(`✔ ${dryRun ? '(模拟运行) ' : ''}版本更新成功!`))
|
||||
|
||||
if (bumpType !== 'none') {
|
||||
console.log(` ${pc.gray('versionName:')} ${pc.strikethrough(pc.gray(currentVersionName))} → ${pc.bold(pc.green(nextVersionName))}`)
|
||||
} else {
|
||||
console.log(` ${pc.gray('versionName:')} ${pc.dim(currentVersionName)} (未更改)`)
|
||||
}
|
||||
|
||||
console.log(` ${pc.gray('versionCode:')} ${pc.strikethrough(pc.gray(currentVersionCode))} → ${pc.bold(pc.green(nextVersionCode))}`)
|
||||
console.log('')
|
||||
}
|
||||
|
||||
run().catch(err => {
|
||||
console.error(pc.red('✖ [bump-version] 发生错误:'), err)
|
||||
process.exit(1)
|
||||
})
|
||||
@@ -0,0 +1,55 @@
|
||||
// 基础配置文件生成脚本
|
||||
// 此脚本用于生成 src/manifest.json 和 src/pages.json 基础文件
|
||||
// 由于这两个配置文件会被添加到 .gitignore 中,因此需要通过此脚本确保项目能正常运行
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
// 获取当前文件的目录路径(替代 CommonJS 中的 __dirname)
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
|
||||
// 最简可运行配置
|
||||
const manifest = { }
|
||||
const pages = {
|
||||
pages: [
|
||||
{
|
||||
path: 'pages/index/index',
|
||||
type: 'home',
|
||||
style: {
|
||||
navigationStyle: 'custom',
|
||||
navigationBarTitleText: '首页',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'pages/me/me',
|
||||
type: 'page',
|
||||
style: {
|
||||
navigationBarTitleText: '我的',
|
||||
},
|
||||
},
|
||||
],
|
||||
subPackages: [],
|
||||
}
|
||||
|
||||
// 使用修复后的 __dirname 来解析文件路径
|
||||
const manifestPath = path.resolve(__dirname, '../src/manifest.json')
|
||||
const pagesPath = path.resolve(__dirname, '../src/pages.json')
|
||||
|
||||
// 确保 src 目录存在
|
||||
const srcDir = path.resolve(__dirname, '../src')
|
||||
if (!fs.existsSync(srcDir)) {
|
||||
fs.mkdirSync(srcDir, { recursive: true })
|
||||
}
|
||||
|
||||
const MIN_SIZE = `{ }`.length // 如果只有一个空对象,必定是不对的,需要重新生成
|
||||
|
||||
// 如果 src/manifest.json 不存在,就创建它;或者如果文件大小小于等于 MIN_SIZE,也重新创建
|
||||
if (!fs.existsSync(manifestPath) || fs.statSync(manifestPath).size <= MIN_SIZE) {
|
||||
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2))
|
||||
}
|
||||
|
||||
// 如果 src/pages.json 不存在,就创建它;或者如果文件大小小于等于 MIN_SIZE,也重新创建
|
||||
if (!fs.existsSync(pagesPath) || fs.statSync(pagesPath).size <= MIN_SIZE) {
|
||||
fs.writeFileSync(pagesPath, JSON.stringify(pages, null, 2))
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import { exec } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
|
||||
/**
|
||||
* 打开开发者工具
|
||||
* @param {string} env - 环境,'dev' 或 'build'
|
||||
* @param {object} options - 配置选项
|
||||
* @param {string} options.wechatDevtoolsCliPath - 微信开发者工具 CLI 路径
|
||||
*/
|
||||
function _openDevTools(env = 'dev', options = {}) {
|
||||
const { wechatDevtoolsCliPath } = options
|
||||
const platform = process.platform // darwin, win32, linux
|
||||
const { UNI_PLATFORM } = process.env // mp-weixin, mp-alipay, mp-lark
|
||||
|
||||
const uniPlatformText = UNI_PLATFORM === 'mp-weixin' ? '微信小程序' : UNI_PLATFORM === 'mp-alipay' ? '支付宝小程序' : UNI_PLATFORM === 'mp-lark' ? '抖音小程序' : '小程序'
|
||||
|
||||
// 项目路径(构建输出目录),根据环境选择不同目录
|
||||
const outputDir = env === 'build' ? `dist/build/${UNI_PLATFORM}` : `dist/dev/${UNI_PLATFORM}`
|
||||
const projectPath = path.resolve(process.cwd(), outputDir)
|
||||
|
||||
// 检查构建输出目录是否存在
|
||||
if (!fs.existsSync(projectPath)) {
|
||||
console.log(`❌ ${uniPlatformText}构建目录不存在:`, projectPath)
|
||||
return
|
||||
}
|
||||
|
||||
console.log(`🚀 正在打开${uniPlatformText}开发者工具...`)
|
||||
|
||||
// 根据不同操作系统执行不同命令
|
||||
let command = ''
|
||||
|
||||
if (platform === 'darwin') {
|
||||
// macOS
|
||||
if (UNI_PLATFORM === 'mp-weixin') {
|
||||
const cliPath = wechatDevtoolsCliPath || '/Applications/wechatwebdevtools.app/Contents/MacOS/cli'
|
||||
command = `"${cliPath}" -o "${projectPath}"`
|
||||
}
|
||||
else if (UNI_PLATFORM === 'mp-alipay') {
|
||||
command = `/Applications/小程序开发者工具.app/Contents/MacOS/小程序开发者工具 --p "${projectPath}"`
|
||||
}
|
||||
else if (UNI_PLATFORM === 'mp-lark') {
|
||||
command = `/Applications/抖音开发者工具.app/Contents/MacOS/抖音开发者工具 --p "${projectPath}"`
|
||||
}
|
||||
}
|
||||
else if (platform === 'win32' || platform === 'win64') {
|
||||
// Windows
|
||||
if (UNI_PLATFORM === 'mp-weixin') {
|
||||
const cliPath = wechatDevtoolsCliPath || 'C:\\Program Files (x86)\\Tencent\\微信web开发者工具\\cli.bat'
|
||||
command = `"${cliPath}" -o "${projectPath}"`
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Linux 或其他系统
|
||||
console.log('❌ 当前系统不支持自动打开微信开发者工具')
|
||||
return
|
||||
}
|
||||
|
||||
exec(command, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.log(`❌ 打开${uniPlatformText}开发者工具失败:`, error.message)
|
||||
if (UNI_PLATFORM === 'mp-weixin') {
|
||||
console.log('💡 当前使用的微信开发者工具 CLI 命令:', command)
|
||||
console.log('💡 如果安装位置不同,可以在 env/.env 配置 WECHAT_DEVTOOLS_CLI_PATH 为本机实际 CLI 路径')
|
||||
}
|
||||
console.log(`💡 请确保${uniPlatformText}开发者工具服务端口已启用`)
|
||||
console.log(`💡 可以手动打开${uniPlatformText}开发者工具并导入项目:`, projectPath)
|
||||
return
|
||||
}
|
||||
|
||||
if (stderr) {
|
||||
console.log('⚠️ 警告:', stderr)
|
||||
}
|
||||
|
||||
console.log(`✅ ${uniPlatformText}开发者工具已打开`)
|
||||
|
||||
if (stdout) {
|
||||
console.log(stdout)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 Vite 插件,用于自动打开开发者工具
|
||||
* @param {object} options - 配置选项
|
||||
* @param {string} options.mode - 构建模式,'development' 或 'production'
|
||||
* @param {string} options.wechatDevtoolsCliPath - 微信开发者工具 CLI 路径
|
||||
*/
|
||||
export default function openDevTools(options = {}) {
|
||||
const { mode = 'development', wechatDevtoolsCliPath } = options
|
||||
// 根据 mode 确定环境:development -> dev, production -> build
|
||||
const env = mode === 'production' ? 'build' : 'dev'
|
||||
|
||||
// 首次构建标记
|
||||
let isFirstBuild = true
|
||||
|
||||
return {
|
||||
name: 'uni-devtools',
|
||||
writeBundle() {
|
||||
if (isFirstBuild && process.env.UNI_PLATFORM?.includes('mp')) {
|
||||
isFirstBuild = false
|
||||
_openDevTools(env, { wechatDevtoolsCliPath })
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// # 执行 `pnpm upgrade` 后会升级 `uniapp` 相关依赖
|
||||
// # 在升级完后,会自动添加很多无用依赖,这需要删除以减小依赖包体积
|
||||
// # 只需要执行下面的命令即可
|
||||
|
||||
import { exec } from 'node:child_process'
|
||||
import { promisify } from 'node:util'
|
||||
|
||||
// 日志控制开关,设置为 true 可以启用所有日志输出
|
||||
const FG_LOG_ENABLE = true
|
||||
|
||||
// 将 exec 转换为返回 Promise 的函数
|
||||
const execPromise = promisify(exec)
|
||||
|
||||
// 定义要执行的命令
|
||||
const dependencies = [
|
||||
// TODO: 如果不需要某个平台的小程序,请手动删除或注释掉
|
||||
'@dcloudio/uni-mp-baidu',
|
||||
'@dcloudio/uni-mp-jd',
|
||||
'@dcloudio/uni-mp-kuaishou',
|
||||
'@dcloudio/uni-mp-qq',
|
||||
'@dcloudio/uni-mp-xhs',
|
||||
'@dcloudio/uni-quickapp-webview',
|
||||
]
|
||||
|
||||
/**
|
||||
* 带开关的日志输出函数
|
||||
* @param {string} message 日志消息
|
||||
* @param {string} type 日志类型 (log, error)
|
||||
*/
|
||||
function log(message, type = 'log') {
|
||||
if (FG_LOG_ENABLE) {
|
||||
if (type === 'error') {
|
||||
console.error(message)
|
||||
}
|
||||
else {
|
||||
console.log(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 卸载单个依赖包
|
||||
* @param {string} dep 依赖包名
|
||||
* @returns {Promise<boolean>} 是否成功卸载
|
||||
*/
|
||||
async function uninstallDependency(dep) {
|
||||
try {
|
||||
log(`开始卸载依赖: ${dep}`)
|
||||
const { stdout, stderr } = await execPromise(`pnpm un ${dep}`)
|
||||
if (stdout) {
|
||||
log(`stdout [${dep}]: ${stdout}`)
|
||||
}
|
||||
if (stderr) {
|
||||
log(`stderr [${dep}]: ${stderr}`, 'error')
|
||||
}
|
||||
log(`成功卸载依赖: ${dep}`)
|
||||
return true
|
||||
}
|
||||
catch (error) {
|
||||
// 单个依赖卸载失败不影响其他依赖
|
||||
log(`卸载依赖 ${dep} 失败: ${error.message}`, 'error')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 串行卸载所有依赖包
|
||||
*/
|
||||
async function uninstallAllDependencies() {
|
||||
log(`开始串行卸载 ${dependencies.length} 个依赖包...`)
|
||||
|
||||
let successCount = 0
|
||||
let failedCount = 0
|
||||
|
||||
// 串行执行所有卸载命令
|
||||
for (const dep of dependencies) {
|
||||
const success = await uninstallDependency(dep)
|
||||
if (success) {
|
||||
successCount++
|
||||
}
|
||||
else {
|
||||
failedCount++
|
||||
}
|
||||
|
||||
// 为了避免命令执行过快导致的问题,添加短暂延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 100))
|
||||
}
|
||||
|
||||
log(`卸载操作完成: 成功 ${successCount} 个, 失败 ${failedCount} 个`)
|
||||
}
|
||||
|
||||
// 执行串行卸载
|
||||
uninstallAllDependencies().catch((err) => {
|
||||
log(`串行卸载过程中出现未捕获的错误: ${err}`, 'error')
|
||||
})
|
||||
@@ -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)
|
||||
})
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @description 通过 vite 自定义条件动态导入 eruda
|
||||
* @description Eruda 配置参考 https://eruda.liriliri.io/zh/docs/
|
||||
* @param {object} options
|
||||
* @param {boolean} [options.open] - 是否开启 eruda
|
||||
* @param {object} [options.erudaOptions] - eruda 配置
|
||||
* @param {string} [options.erudaUrl] - eruda 地址
|
||||
*/
|
||||
export default function vitePluginEruda(options = {}) {
|
||||
const { open = true, erudaOptions = {}, erudaUrl = 'https://cdn.jsdelivr.net/npm/eruda' } = options
|
||||
|
||||
return {
|
||||
name: 'vite-plugin-eruda',
|
||||
|
||||
transformIndexHtml(html) {
|
||||
const tags = [
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: {
|
||||
src: erudaUrl,
|
||||
},
|
||||
injectTo: 'head',
|
||||
},
|
||||
{
|
||||
tag: 'script',
|
||||
children: `eruda.init(${JSON.stringify(erudaOptions)});`,
|
||||
injectTo: 'head',
|
||||
},
|
||||
]
|
||||
|
||||
if (!open) {
|
||||
return html
|
||||
}
|
||||
return { html, tags }
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user