diff --git a/.local.config.js b/.local.config.js index ddeffdc..1902e69 100644 --- a/.local.config.js +++ b/.local.config.js @@ -62,5 +62,5 @@ const localDevConfig = ({ uniacid: 2075, domain: 'https://xcx.aigc-quickapp.com/', }, -})['47']; // 选择要使用的环境配置 +})['2811']; // 选择要使用的环境配置 export default localDevConfig; \ No newline at end of file diff --git a/pages/index/public/js/index.js b/pages/index/public/js/index.js index d7ba0cc..c30b5a4 100644 --- a/pages/index/public/js/index.js +++ b/pages/index/public/js/index.js @@ -111,49 +111,19 @@ export default { }, 2000); }, _showVersionInfo() { - // #ifdef MP-WEIXIN + let v = null; try { - const fs = uni.getFileSystemManager(); - fs.readFile({ - filePath: 'version.json', - encoding: 'utf-8', - success: (res) => { - try { - const v = JSON.parse(res.data); - if (v && v.commitId) { - uni.showModal({ - title: '构建版本信息', - content: `提交 ID: ${v.commitId}\n构建时间: ${v.buildTime}`, - showCancel: false - }); - return; - } - } catch (e) {} - uni.showModal({ title: '构建版本信息', content: '版本信息不可用', showCancel: false }); - }, - fail: () => this._showVersionFromGlobal() - }); - } catch (e) { - this._showVersionFromGlobal(); - } - // #endif - // #ifndef MP-WEIXIN - this._showVersionFromGlobal(); - // #endif - }, - _showVersionFromGlobal() { - try { - const v = typeof __app_version !== 'undefined' ? __app_version : null; - if (v && v.commitId) { - uni.showModal({ - title: '构建版本信息', - content: `提交 ID: ${v.commitId}\n构建时间: ${v.buildTime}`, - showCancel: false - }); - return; - } + v = typeof __app_version !== 'undefined' ? __app_version : null; } catch (e) {} - uni.showModal({ title: '构建版本信息', content: '版本信息不可用', showCancel: false }); + if (v && v.commitId) { + uni.showModal({ + title: '构建版本信息', + content: `提交 ID: ${v.commitId}\n构建时间: ${v.buildTime}`, + showCancel: false + }); + } else { + console.log('未获取到构建版本信息'); + } } } } \ No newline at end of file diff --git a/scripts/mp-weixin.patch.js b/scripts/mp-weixin.patch.js index 979baed..5f6399b 100644 --- a/scripts/mp-weixin.patch.js +++ b/scripts/mp-weixin.patch.js @@ -2,64 +2,38 @@ /** * fix-wechat-miniapp.js * - * 该脚本用于修复微信小程序的一些问题: - * 1. 将项目根目录下的 site.js 文件拷贝到 unpackage/dist/build/mp-weixin 目录下,如果文件存在则覆盖 - * 2. 将 project.config.json 及 project.private.config.json 拷贝到目标目录 - * 3. 生成 version.js(CommonJS 模块)和 version.json 到目标目录 - * 4. 将 `const site = require("../site");` 和 `const __app_version = require("../version");` - * 追加到 unpackage/dist/build/mp-weixin/common/vendor.js 文件内容开头部分, - * 如果文件开头已有则跳过 + * 该脚本用于微信小程序的构建后处理(仅在生产构建时由 vue.config.js 触发): + * 1. 将 project.config.json 及 project.private.config.json 拷贝到构建产物目录 + * 2. 将 site.js 拷贝到构建产物目录 + * 3. 创建 ZIP 压缩包 + * + * 注意:version.js 生成和 vendor.js 注入已由 webpack 插件 (VersionInjectPlugin) 在 emit 钩子中自动处理。 * * 使用: - * node fix-wechat-miniapp.js # 打补丁并创建 ZIP 文件(默认 mode=production) - * node fix-wechat-miniapp.js --no-zip # 只打补丁,不创建 ZIP 文件 - * node fix-wechat-miniapp.js --mode development # 使用 development 模式打补丁 - * node fix-wechat-miniapp.js --mode production # 使用 production 模式打补丁(默认) - * - * 注意: - * - 在 Windows 上路径使用反斜杠也是可以的;脚本使用 path.join 来兼容不同平台。 - * - 运行前请确认在项目根目录运行(site.js 在当前工作目录下)。 + * node fix-wechat-miniapp.js # 拷贝文件并创建 ZIP(默认 mode=production) + * node fix-wechat-miniapp.js --no-zip # 只拷贝文件,不创建 ZIP */ const fs = require('fs'); const fsp = fs.promises; const path = require('path'); -const { execSync } = require('child_process'); const { openFileDirectory } = require('./open-directory'); const { createZipWithSystemCommand } = require('./create-zip'); -async function commonPatch(mode = 'production') { +async function copyAssets(mode = 'production') { try { - - // 根据当前脚本所在目录(scripts),定位到项目根目录 const cwd = path.join(__dirname, '..'); - - const srcSitePath = path.join(cwd, 'site.js'); const destDir = path.join(cwd, 'unpackage', 'dist', mode === 'production' ? 'build' : 'dev', 'mp-weixin'); - const destSitePath = path.join(destDir, 'site.js'); - const vendorPath = path.join(destDir, 'common', 'vendor.js'); - // 1) 检查源文件是否存在 - const srcExists = await exists(srcSitePath); - if (!srcExists) { - console.error(`源文件不存在: ${srcSitePath}`); - process.exitCode = 2; - return; - } - - // 确保目标目录存在 await ensureDir(destDir); - // 复制 project.config.json 及 project.private.config.json 文件到 destDir 下面 + // 复制 project.config.json 和 project.private.config.json const configFiles = ['project.config.json', 'project.private.config.json']; for (const fileName of configFiles) { const srcPath = path.join(cwd, fileName); const destPath = path.join(destDir, fileName); - - // 检查源文件是否存在 - const fileExists = await exists(srcPath); - if (fileExists) { + if (await exists(srcPath)) { await fsp.copyFile(srcPath, destPath); console.log(`已拷贝: ${srcPath} -> ${destPath}`); } else { @@ -67,73 +41,15 @@ async function commonPatch(mode = 'production') { } } - // 复制 site.js 到目标目录(覆盖) - await fsp.copyFile(srcSitePath, destSitePath); - console.log(`已拷贝: ${srcSitePath} -> ${destSitePath}`); - - // 3) 生成 version.js(包含 Git 提交 ID 和构建时间,CommonJS 格式供 require 使用) - let commitId = 'unknown'; - try { - commitId = execSync('git rev-parse --short HEAD', { cwd }).toString().trim(); - } catch (e) { - console.warn('无法获取 Git 提交 ID,使用 unknown 代替'); + // 复制 site.js + const srcSitePath = path.join(cwd, 'site.js'); + if (await exists(srcSitePath)) { + await fsp.copyFile(srcSitePath, path.join(destDir, 'site.js')); + console.log(`已拷贝: ${srcSitePath} -> ${destDir}`); + } else { + console.error(`源文件不存在: ${srcSitePath}`); + process.exitCode = 2; } - const versionData = { - commitId, - buildTime: new Date().toISOString() - }; - // 同时生成 version.js(供 require)和 version.json(供文件系统读取) - const versionJsPath = path.join(destDir, 'version.js'); - await fsp.writeFile(versionJsPath, `module.exports = ${JSON.stringify(versionData, null, 2)};\n`); - console.log(`已生成: ${versionJsPath} (commitId: ${commitId})`); - - const versionJsonPath = path.join(destDir, 'version.json'); - await fsp.writeFile(versionJsonPath, JSON.stringify(versionData, null, 2)); - console.log(`已生成: ${versionJsonPath} (commitId: ${commitId})`); - - // 4) 处理 vendor.js:在开头追加 require 语句(如果还没有的话) - const vendorExists = await exists(vendorPath); - if (!vendorExists) { - console.warn(`⚠ 目标 vendor.js 不存在,跳过追加 require。路径: ${vendorPath}`); - console.warn(' → 请先执行 HBuilder 构建(uniapp 构建),产生 vendor.js 后再运行此脚本。'); - console.warn(' → version.json/version.js 已生成,可在首页连击 5 次标题查看版本信息。'); - return; - } - - let vendorContent = await fsp.readFile(vendorPath, 'utf8'); - - const requireLines = [ - 'const site = require("../site");', - 'const __app_version = require("../version");' - ]; - - // 清理已有的重复注入(兼容新旧格式:../version.json 和 ../version) - let cleaned = false; - const injectPatterns = [ - /^\s*const\s+site\s*=\s*require\s*\(['"]\.\.\/site(\.js)?['"]\);?\s*\r?\n/gm, - /^\s*const\s+__app_version\s*=\s*require\s*\(['"]\.\.\/version(\.json)?['"]\);?\s*\r?\n/gm, - ]; - for (const pattern of injectPatterns) { - if (pattern.test(vendorContent)) { - vendorContent = vendorContent.replace(pattern, ''); - cleaned = true; - } - } - - // 把 require 语句 + newline 插入文件最前面。 - // 保留原始换行风格(若可能) - const eol = vendorContent.includes('\r\n') ? '\r\n' : '\n'; - let prefix = ''; - - // 保留可能的 BOM - if (vendorContent.charCodeAt(0) === 0xfeff) { - prefix = '\uFEFF'; - vendorContent = vendorContent.slice(1); - } - - const newContent = prefix + requireLines.join(eol) + eol + vendorContent; - await fsp.writeFile(vendorPath, newContent, 'utf8'); - console.log(cleaned ? `已清理旧注入并重新注入: ${requireLines.join(', ')}` : `已在 vendor.js 开头追加: ${requireLines.join(', ')}`); } catch (err) { console.error('发生错误:', err); process.exitCode = 1; @@ -141,33 +57,27 @@ async function commonPatch(mode = 'production') { } async function main() { - // 解析命令行参数 const argv = process.argv.slice(2); const options = { noZip: argv.includes('--no-zip'), - mode: 'production' // 默认值 + mode: 'production' }; - // 解析 --mode 参数 const modeIndex = argv.indexOf('--mode'); if (modeIndex !== -1 && modeIndex + 1 < argv.length) { options.mode = argv[modeIndex + 1]; } - // 1) 打补丁 - await commonPatch(options.mode); - // await commonPatch('development'); + // 1) 拷贝文件 + await copyAssets(options.mode); - // 2) 创建 ZIP 文件(如果未指定 --no-zip) - if (!options.noZip) { + // 2) 创建 ZIP(仅 production 模式,且未指定 --no-zip) + if (!options.noZip && options.mode === 'production') { const cwd = path.join(__dirname, '..'); - const buildDir = options.mode === 'production' ? 'build' : 'dev'; - const sourceDir = path.join(cwd, 'unpackage', 'dist', buildDir, 'mp-weixin'); - const destDir = path.join(cwd, 'unpackage', 'dist', buildDir); + const sourceDir = path.join(cwd, 'unpackage', 'dist', 'build', 'mp-weixin'); + const destDir = path.join(cwd, 'unpackage', 'dist', 'build'); const zipFilePath = await createZipWithSystemCommand(sourceDir, destDir); console.log(`ZIP 文件路径: ${zipFilePath}`); - - // 3) 自动打开zip所在的目录 await openFileDirectory(zipFilePath); } else { console.log('跳过创建 ZIP 文件和打开目录'); @@ -187,7 +97,6 @@ async function ensureDir(dirPath) { try { await fsp.mkdir(dirPath, { recursive: true }); } catch (e) { - // ignore if exists if (e.code !== 'EEXIST') throw e; } } diff --git a/vue.config.js b/vue.config.js index 2a3d19e..4b7a3ed 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,6 +1,9 @@ const path = require('path'); +const { execSync } = require('child_process'); const { zionUniMpLoadPackagePlugin } = require('zion-uniapp-mp-load-package/webpack'); +console.log('[vue.config] 已加载'); + // 打印出process.env // for (let key in process.env) { // console.log(key, process.env[key]); @@ -29,6 +32,107 @@ try { console.log('NODE_ENV 环境变量未设置,默认使用开发模式'); } +/** + * 自定义 webpack 插件:在通用产物(vendor.js)中内联注入版本数据 + * 利用 emit 钩子在资源写入磁盘前处理,支持 HMR(每次重编译都会自动注入) + * 适用于所有平台(mp-weixin / h5 等) + */ +class VersionInjectPlugin { + constructor() { + this._cachedCommitId = null; + } + apply(compiler) { + compiler.hooks.emit.tapAsync('VersionInjectPlugin', (compilation, callback) => { + const mode = process.env.NODE_ENV === 'production' ? 'production' : 'development'; + const platform = process.env.UNI_PLATFORM || ''; + + // 获取 Git 提交 ID(缓存,避免每次 HMR 都执行) + if (!this._cachedCommitId) { + try { + this._cachedCommitId = execSync('git rev-parse --short HEAD', { cwd: __dirname }).toString().trim(); + } catch (e) { + this._cachedCommitId = 'unknown'; + } + } + + const versionData = { commitId: this._cachedCommitId, buildTime: new Date().toISOString() }; + const inlineVersion = JSON.stringify(versionData); + + // 尝试注入到 vendor.js(mp-weixin / mp-* 等平台) + const vendorKey = 'common/vendor.js'; + const vendorAsset = compilation.assets[vendorKey]; + if (vendorAsset) { + let content = typeof vendorAsset.source === 'function' ? vendorAsset.source() : vendorAsset._value; + if (typeof content !== 'string') content = content.toString(); + + // 清理旧注入 + content = content.replace(/^\s*const\s+site\s*=\s*require\s*\(['"]\.\.\/site(\.js)?['"]\);?\s*\r?\n/gm, ''); + content = content.replace(/^\s*const\s+__app_version\s*=\s*(require\s*\(['"]\.\.\/version(\.json|\.js)?['"]\)|.+);?\s*\r?\n/gm, ''); + + // 只注入版本信息(通用),site.js require 仅在 mp-weixin 生产构建时注入 + const lines = [`const __app_version = ${inlineVersion};`]; + if (platform === 'mp-weixin' && mode === 'production') { + lines.unshift('const site = require("../site.js");'); + } + + const eol = content.includes('\r\n') ? '\r\n' : '\n'; + let prefix = ''; + if (content.charCodeAt(0) === 0xfeff) { + prefix = '\uFEFF'; + content = content.slice(1); + } + + content = prefix + lines.join(eol) + eol + content; + + compilation.assets[vendorKey] = { + source: () => content, + size: () => content.length + }; + + console.log(`[VersionInject] ✅ vendor.js 已注入 (platform=${platform}, mode=${mode}, commit=${this._cachedCommitId})`); + } else { + // H5 等平台可能没有 common/vendor.js,改为尝试注入到 index.html + // #ifdef H5 + const htmlKey = 'index.html'; + const htmlAsset = compilation.assets[htmlKey]; + if (htmlAsset) { + let html = typeof htmlAsset.source === 'function' ? htmlAsset.source() : htmlAsset._value; + if (typeof html !== 'string') html = html.toString(); + // 在 前注入 script 标签 + const scriptTag = ``; + if (!html.includes('__app_version')) { + html = html.replace('', `${scriptTag}\n`); + compilation.assets[htmlKey] = { + source: () => html, + size: () => html.length + }; + console.log(`[VersionInject] ✅ index.html 已注入 (platform=${platform}, commit=${this._cachedCommitId})`); + } + } + // #endif + } + + callback(); + }); + + // 生产模式下(仅 mp-weixin),额外执行外部脚本完成 site.js 拷贝 + ZIP 打包 + if (process.env.NODE_ENV === 'production') { + compiler.hooks.afterEmit.tapAsync('MpWeixinZipPack', (compilation, callback) => { + const platform = process.env.UNI_PLATFORM || ''; + if (platform !== 'mp-weixin') return callback(); + + console.log('\n🚀 mp-weixin 生产构建完成,运行补丁脚本(site.js 拷贝 + ZIP 打包)...'); + try { + execSync(`"${process.execPath}" scripts/mp-weixin.patch.js --mode production`, { cwd: __dirname, stdio: 'inherit' }); + } catch (e) { + console.error('补丁脚本执行失败:', e.message); + } + callback(); + }); + } + } +} + // 导出配置 module.exports = { productionSourceMap: false, @@ -118,5 +222,8 @@ module.exports = { } } } + + // 所有模式下添加版本注入插件(适用于所有平台) + config.plugins.push(new VersionInjectPlugin()); } }; \ No newline at end of file