195 lines
6.8 KiB
JavaScript
195 lines
6.8 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* fix-wechat-miniapp.js
|
||
*
|
||
* 该脚本用于修复微信小程序的一些问题:
|
||
* 1. 将项目根目录下的 site.js 文件拷贝到 unpackage/dist/build/mp-weixin 目录下,如果文件存在则覆盖
|
||
* 2. 将 project.config.json 及 project.private.config.json 拷贝到目标目录
|
||
* 3. 生成 version.json(包含 Git 提交 ID 和构建时间)到目标目录
|
||
* 4. 将 `const site = require("../site");` 和 `const __app_version = require("../version.json");`
|
||
* 追加到 unpackage/dist/build/mp-weixin/common/vendor.js 文件内容开头部分,
|
||
* 如果文件开头已有则跳过
|
||
*
|
||
* 使用:
|
||
* 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 在当前工作目录下)。
|
||
*/
|
||
|
||
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') {
|
||
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 下面
|
||
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) {
|
||
await fsp.copyFile(srcPath, destPath);
|
||
console.log(`已拷贝: ${srcPath} -> ${destPath}`);
|
||
} else {
|
||
console.warn(`源文件不存在,跳过复制: ${srcPath}`);
|
||
}
|
||
}
|
||
|
||
// 复制 site.js 到目标目录(覆盖)
|
||
await fsp.copyFile(srcSitePath, destSitePath);
|
||
console.log(`已拷贝: ${srcSitePath} -> ${destSitePath}`);
|
||
|
||
// 3) 生成 version.json(包含 Git 提交 ID 和构建时间)
|
||
let commitId = 'unknown';
|
||
try {
|
||
commitId = execSync('git rev-parse --short HEAD', { cwd }).toString().trim();
|
||
} catch (e) {
|
||
console.warn('无法获取 Git 提交 ID,使用 unknown 代替');
|
||
}
|
||
const versionJson = {
|
||
commitId,
|
||
buildTime: new Date().toISOString()
|
||
};
|
||
const versionPath = path.join(destDir, 'version.json');
|
||
await fsp.writeFile(versionPath, JSON.stringify(versionJson, null, 2));
|
||
console.log(`已生成: ${versionPath} (commitId: ${commitId})`);
|
||
|
||
// 4) 处理 vendor.js:在开头追加 require 语句(如果还没有的话)
|
||
const vendorExists = await exists(vendorPath);
|
||
if (!vendorExists) {
|
||
console.warn(`目标 vendor.js 不存在,跳过追加 require。路径: ${vendorPath}`);
|
||
return;
|
||
}
|
||
|
||
let vendorContent = await fsp.readFile(vendorPath, 'utf8');
|
||
|
||
const requireLine = 'const site = require("../site");';
|
||
const versionLine = 'const __app_version = require("../version.json");';
|
||
// 检查文件开头(例如前 1000 字符)是否已经包含这些 require 语句
|
||
const inspectPrefix = vendorContent.slice(0, 1000);
|
||
const hasSiteRequire = new RegExp(
|
||
'^\\s*const\\s+site\\s*=\\s*require\\s*\\([\'"]\\.\\./site[\'"]\\);?',
|
||
'm'
|
||
).test(inspectPrefix);
|
||
const hasVersionRequire = new RegExp(
|
||
'^\\s*const\\s+__app_version\\s*=\\s*require\\s*\\([\'"]\\.\\./version\\.json[\'"]\\);?',
|
||
'm'
|
||
).test(inspectPrefix);
|
||
|
||
if (hasSiteRequire && hasVersionRequire) {
|
||
console.log('vendor.js 开头已包含 require 语句,跳过追加。');
|
||
return;
|
||
}
|
||
|
||
// 把 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 linesToInject = [requireLine];
|
||
if (!hasVersionRequire) {
|
||
linesToInject.push(versionLine);
|
||
}
|
||
const newContent = prefix + linesToInject.join(eol) + eol + vendorContent;
|
||
await fsp.writeFile(vendorPath, newContent, 'utf8');
|
||
console.log(`已在 vendor.js 开头追加: ${linesToInject.join(', ')}`);
|
||
} catch (err) {
|
||
console.error('发生错误:', err);
|
||
process.exitCode = 1;
|
||
}
|
||
}
|
||
|
||
async function main() {
|
||
// 解析命令行参数
|
||
const argv = process.argv.slice(2);
|
||
const options = {
|
||
noZip: argv.includes('--no-zip'),
|
||
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');
|
||
|
||
// 2) 创建 ZIP 文件(如果未指定 --no-zip)
|
||
if (!options.noZip) {
|
||
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 zipFilePath = await createZipWithSystemCommand(sourceDir, destDir);
|
||
console.log(`ZIP 文件路径: ${zipFilePath}`);
|
||
|
||
// 3) 自动打开zip所在的目录
|
||
await openFileDirectory(zipFilePath);
|
||
} else {
|
||
console.log('跳过创建 ZIP 文件和打开目录');
|
||
}
|
||
}
|
||
|
||
async function exists(p) {
|
||
try {
|
||
await fsp.access(p, fs.constants.F_OK);
|
||
return true;
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
async function ensureDir(dirPath) {
|
||
try {
|
||
await fsp.mkdir(dirPath, { recursive: true });
|
||
} catch (e) {
|
||
// ignore if exists
|
||
if (e.code !== 'EEXIST') throw e;
|
||
}
|
||
}
|
||
|
||
main();
|
||
|
||
|