From dee2887026a8b7b18c7691fda4099e5da056edac Mon Sep 17 00:00:00 2001 From: ZF sun <34314687@qq.com> Date: Mon, 11 May 2026 11:56:37 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=20readme=20=E5=8F=8D?= =?UTF-8?q?=E6=98=A0=20H5=20=E8=87=AA=E5=8A=A8=20ZIP=20=E6=89=93=E5=8C=85?= =?UTF-8?q?=E5=92=8C=E7=BB=9F=E4=B8=80=E9=85=8D=E7=BD=AE=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme.md | 69 +++++++++++++++++--------------- vue.config.js | 106 +++++++++++++++++++++++++++++++++++--------------- 2 files changed, 111 insertions(+), 64 deletions(-) diff --git a/readme.md b/readme.md index 4075865..2add22e 100644 --- a/readme.md +++ b/readme.md @@ -83,37 +83,24 @@ 📌 **测试版**保留原有 `/hwappx/test/` 💡 **个性化定制示例**:`/hwappx/2811/`,其中 2811 为定制化版客户编号 -3. 选择菜单栏「发行」 → 「自定义发行」 →(「H5-xcx.aigc-quickapp.com」查看.local.config.js中站点的网址前缀,站点的网址前缀是什么就选自定义发行中相同的格式) - 例如:网址是5g.aigc-quickapp.com,自定义发行就选H5-5g.aigc-quickapp.com - 网址是dev.aigc-quickapp.com,自定义发行就选H5-xcx.aigc-quickapp.com +3. 选择菜单栏「发行」 → 「自定义发行」 → 选择对应的站点脚本 + 💡 例如:网址是 `5g.aigc-quickapp.com` 选 `H5-5g.aigc-quickapp.com` 4. 修改以下配置: 1. **网站标题**:快应用 - 2. **网站域名**:当前客户域名(示例:xcx.aigc-quickapp.com或者5g.aigc-quickapp.com) + 2. **网站域名**:当前客户域名 3. 确认后点击「发行」等待构建完成 - ⚠️ **注意**:底部控制台弹出“项目 lucky_shop 导出Web成功,路径为:D:\项目文件\项目根目录\unpackage\dist\build\web”后再执行下一步 - 💡 **示例**:`项目 lucky_shop 导出Web成功,路径为:D:\0.项目源码\lucky_shop\unpackage\dist\build\web` -5. 按控制台提示的路径找到 `web` 目录,将该目录下所有文件手动打包成一个 `.zip` 压缩包 - *仅打包文件,不包含外层 web 目录* + ⚠️ **注意**:构建完成后自动输出到 `unpackage/dist/build/h5/`,格式为 `{域名}-{base路径}.zip` + 💡 **示例**:`xcx.aigc-quickapp.com-hwappx.common-3bff91e-20260511_1058.zip` -##### 4.2.1.2 【重命名】 -1. 按版本类型规范重命名压缩包: - - **通用版**:`hwappx-common-域名-时间.zip` - 💡 **示例**:`hwappx-common-xcx.aigc-quickapp.com-2026-01-24.zip` - - - **定制化版**:`客户名称-定制化---hwappx-客户编号-域名-时间.zip` - 💡 **示例**:`POCT检测分析平台-定制化---hwappx-2811-xcx.aigc-quickapp.com-2026-01-24.zip` - - 🚫 **禁止**:压缩包命名禁止包含 `/ \ : * ? " < > |` 等特殊字符 - -##### 4.2.1.3 【交付与最终发布】🔍 - -1. 将重命名后的压缩包发送给运维人员 +##### 4.2.1.2 【交付与最终发布】🔍 +1. 将生成的 `.zip` 文件发送给运维人员 2. **运维人员操作流程**: 1. 解压压缩包 2. 打开快应用开发者工具,导入解压后的代码目录 3. 验证代码无报错后,执行上传发布操作 -##### 4.2.1.3 【测试流程】 + +##### 4.2.1.3 【测试流程】 H5:打开自己的浏览器输入网址(https://5g.aigc-quickapp.com/hwappx/common/?uniacid=75)改站点 如果是test就把hwappx/common/改为hwappx/test/----------改站点 @@ -134,22 +121,40 @@ H5:打开自己的浏览器输入网址(https://5g.aigc-quickapp.com/hwappx/co - **commitId**:当前构建的 Git 短提交 ID - **buildTime**:构建时间 -> **开发模式**:HMR 热更新时自动跳过重复注入,不影响开发体验。 +> **开发模式**:HMR 热更新时由 webpack emit 钩子自动处理,不影响开发体验。 -### 5.2 可用的 npm 脚本命令 +### 5.2 自动 ZIP 打包 -| 命令 | 说明 | +**H5 自定义发行**构建完成后自动执行: + +| 步骤 | 说明 | |------|------| -| `npm run mp-weixin` | 拷贝 site.js + config 文件 + 创建 ZIP 压缩包(用于手动触发) | +| 重命名输出目录 | `{域名}-{base路径用.连接}`(如 `xcx.aigc-quickapp.com-hwappx.common`) | +| 创建 ZIP 文件 | 文件名格式:`{目录名}-{Git提交ID}-{上海时区时间戳}.zip` | +| 清理 | ZIP 创建完成后自动删除源目录 | -> 生产构建时,ZIP 打包由构建插件自动触发,通常无需手动执行此命令。 +💡 **示例 ZIP**:`xcx.aigc-quickapp.com-hwappx.common-3bff91e-20260511_1058.zip` -### 5.3 构建后处理功能(mp-weixin.patch.js) +**微信小程序**生产构建时自动执行: +- 拷贝 `site.js` / `project.config.json` / `project.private.config.json` 到构建目录 +- 创建 ZIP 包(文件名包含 Git 提交 ID) -- 复制 `project.config.json` 和 `project.private.config.json` 到构建目录 -- 复制 `site.js` 到构建目录 -- 创建 ZIP 压缩包(文件名包含 Git 提交 ID) -- 自动打开 ZIP 文件所在目录 +### 5.3 环境配置 + +域名配置统一通过 `package.json` 中各脚本的 `env.UNI_APP_DOMAIN` 传入: + +```json +"h5-xcx.aigc-quickapp.com": { + "title": "...", + "env": { + "UNI_PLATFORM": "h5", + "UNI_APP_DOMAIN": "https://xcx.aigc-quickapp.com/" + }, + "define": { "PRODUCTION": true } +} +``` + +`config.js` 和 `vue.config.js` 均通过 `process.env.UNI_APP_DOMAIN` 读取,**新增/删除脚本无需改动代码**。 --- diff --git a/vue.config.js b/vue.config.js index 1c8a1ab..ad9dbf7 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,4 +1,5 @@ const path = require('path'); +const fs = require('fs'); const { execSync } = require('child_process'); const { zionUniMpLoadPackagePlugin } = require('zion-uniapp-mp-load-package/webpack'); @@ -25,11 +26,8 @@ try { // 从 manifest.json 读取 h5.router.base,拼接到输出路径 let baseSuffix = ''; try { - const manifest = require('./manifest.json'); - if (manifest?.h5?.router?.base) { - // 将 /hwappx/common/ 转换为 hwappx.common - baseSuffix = manifest.h5.router.base.replace(/^\/+|\/+$/g, '').replace(/\//g, '.'); - } + const manifestPath = path.join(__dirname, 'manifest.json'); + baseSuffix = _readManifestBase(manifestPath); } catch (e) {} // 从脚本 env 中获取域名(优先使用 UNI_APP_DOMAIN,否则从 UNI_SCRIPT 提取) let domain = ''; @@ -52,6 +50,25 @@ try { console.log('NODE_ENV 环境变量未设置,默认使用开发模式'); } +/** + * 读取 manifest.json 中的 h5.router.base,去掉注释后解析 + * 返回 base 路径的 . 连接形式(如 /hwappx/common/ → hwappx.common) + */ +function _readManifestBase(manifestPath) { + try { + const raw = fs.readFileSync(manifestPath, 'utf8'); + // 去掉 /* */ 和 // 注释(HBuilder 生成的 JSON 允许注释) + const clean = raw.replace(/\/\*[\s\S]*?\*\//g, '').replace(/\/\/.*$/gm, ''); + const manifest = JSON.parse(clean); + if (manifest?.h5?.router?.base) { + return manifest.h5.router.base.replace(/^\/+|\/+$/g, '').replace(/\//g, '.'); + } + } catch (e) { + console.warn('[manifest] 读取 h5.router.base 失败:', e.message); + } + return ''; +} + /** * 自定义 webpack 插件:在通用产物(vendor.js)中内联注入版本数据 * 利用 emit 钩子在资源写入磁盘前处理,支持 HMR(每次重编译都会自动注入) @@ -148,8 +165,8 @@ class VersionInjectPlugin { } catch (e) { console.error('补丁脚本执行失败:', e.message); } - } else if (platform === 'h5' && UNI_SCRIPT && this._cachedCommitId) { - this._zipH5Build(UNI_SCRIPT, this._cachedCommitId); + } else if (platform === 'h5' && UNI_SCRIPT) { + this._zipH5Build(compilation); } callback(); @@ -157,15 +174,9 @@ class VersionInjectPlugin { } } - _zipH5Build(UNI_SCRIPT, commitId) { - // 计算输出目录名(与 UNI_OUTPUT_DIR 逻辑一致) - let baseSuffix = ''; - try { - const manifest = require('./manifest.json'); - if (manifest?.h5?.router?.base) { - baseSuffix = manifest.h5.router.base.replace(/^\/+|\/+$/g, '').replace(/\//g, '.'); - } - } catch (e) {} + _computeH5OutputName() { + // 计算输出目录名: {域名}-{base用.连接} + let baseSuffix = _readManifestBase(path.join(__dirname, 'manifest.json')); let domain = ''; if (process.env.UNI_APP_DOMAIN) { try { @@ -174,45 +185,76 @@ class VersionInjectPlugin { domain = process.env.UNI_APP_DOMAIN.replace(/^https?:\/\//, '').replace(/\/.*$/, ''); } } else { - domain = UNI_SCRIPT.replace(/^h5-/, ''); + domain = (process.env.UNI_SCRIPT || '').replace(/^h5-/, ''); } - const outputDirName = baseSuffix ? `${domain}-${baseSuffix}` : domain; + const result = baseSuffix ? `${domain}-${baseSuffix}` : domain; + console.log('[H5Zip] 输出目录名:', result); + return result; + } - // 上海时区时间(UTC+8) + _zipH5Build(compilation) { + const outputDirName = this._computeH5OutputName(); + const buildDir = process.env.NODE_ENV === 'production' ? 'build' : 'dev'; + const h5Dir = path.join(__dirname, 'unpackage', 'dist', buildDir, 'h5'); + + // 实际构建输出目录(由 webpack 决定) + const actualOutput = compilation.compiler.outputPath; + const targetDir = path.join(h5Dir, outputDirName); + + // 如果路径一致,跳过重命名 + if (actualOutput !== targetDir) { + try { + if (fs.existsSync(targetDir)) { + fs.rmSync(targetDir, { recursive: true }); + } + fs.renameSync(actualOutput, targetDir); + console.log(`[H5Zip] 输出目录已重命名为: ${outputDirName}`); + } catch (e) { + console.error('[H5Zip] 目录重命名失败:', e.message); + return; + } + } else { + console.log(`[H5Zip] 输出目录名正确: ${outputDirName}`); + } + + // 上海时区时间戳格式: 20260511_1058 const now = new Date(); const shanghaiOffset = 8 * 60; const shanghaiTime = new Date(now.getTime() + shanghaiOffset * 60 * 1000); - const ts = shanghaiTime.toISOString().replace(/[^0-9]/g, '').slice(0, 14); + const y = shanghaiTime.getFullYear(); + const M = String(shanghaiTime.getMonth() + 1).padStart(2, '0'); + const d = String(shanghaiTime.getDate()).padStart(2, '0'); + const h = String(shanghaiTime.getHours()).padStart(2, '0'); + const m = String(shanghaiTime.getMinutes()).padStart(2, '0'); + const ts = `${y}${M}${d}_${h}${m}`; - const buildDir = process.env.NODE_ENV === 'production' ? 'build' : 'dev'; - const sourceDir = path.join(__dirname, 'unpackage', 'dist', buildDir, 'h5', outputDirName); - const destDir = path.join(__dirname, 'unpackage', 'dist', buildDir, 'h5'); - const zipFileName = `${outputDirName}-${commitId}-${ts}.zip`; - const zipFilePath = path.join(destDir, zipFileName); + const zipFileName = `${outputDirName}-${this._cachedCommitId}-${ts}.zip`; + const zipFilePath = path.join(h5Dir, zipFileName); - console.log(`\n📦 H5 构建完成,打包 ZIP: ${zipFileName}...`); + console.log(`\n📦 H5 ZIP: ${zipFileName}...`); let command; - const sourcePath = sourceDir.replace(/'/g, "''"); + const sourcePath = targetDir.replace(/'/g, "''"); const destPath = zipFilePath.replace(/'/g, "''"); if (process.platform === 'win32') { command = `powershell -Command "Compress-Archive -Path '${sourcePath}\\*' -DestinationPath '${destPath}' -Force"`; } else { - const sourceBase = path.dirname(sourceDir); - const sourceName = path.basename(sourceDir); + const sourceBase = path.dirname(targetDir); + const sourceName = path.basename(targetDir); command = `cd '${sourceBase}' && zip -r '${zipFilePath}' '${sourceName}' -x '*/node_modules/*' '*.git/*' '*.DS_Store'`; } try { execSync(command, { stdio: 'inherit' }); - console.log(`✅ H5 ZIP 文件已创建: ${zipFileName}`); + console.log(`✅ H5 ZIP: ${zipFileName}`); + // 删除已打包的源目录 + fs.rmSync(targetDir, { recursive: true, force: true }); + console.log(`[H5Zip] 已删除源目录: ${outputDirName}`); } catch (e) { console.error('H5 ZIP 打包失败:', e.message); } } } - } -} // 导出配置 module.exports = {