Files
lucky_shop/stub-app-projects/mp-harmony/entry/scripts/check-har-deps.js
ZF sun df9d45fc1d refactor(mp-harmony): add HAR dependency checks and debug logs
1. add debug logs for diy component lifecycle and data flow
2. add required HAR dependency declarations for mp-harmony entry module
3. add har-deps config, validation script and documentation
2026-07-30 11:43:25 +08:00

202 lines
7.3 KiB
JavaScript

#!/usr/bin/env node
/* eslint-disable no-console */
/**
* 鸿蒙元服务 entry 模块依赖校验脚本
*
* 目的:
* 防止 entry 的 HAP 打包时丢失 5 个 ascf shared HAR 子包依赖,
* 否则运行时会找不到 components-diy/diy-group.pack.js 等子包 chunk,
* DIY 首页 + 商品分类 + 订单 + 营销页全部失效 (componentPlaceholder fallback 成 view)。
*
* 使用:
* node scripts/check-har-deps.js # 仅校验 entry/build/.../module.json
* node scripts/check-har-deps.js --rawfile # 同时校验 rawfile 资源是否就位
* node scripts/check-har-deps.js --strict # 任一缺失即 exit 1
*
* 默认情况:
* 缺失时仅打印警告 (CI 友好, 不阻塞开发), 加 --strict 才严格失败。
*
* 依赖:
* ./har-deps-required.json5 (本脚本的单一事实来源)
*/
'use strict';
const fs = require('fs');
const path = require('path');
const parseJson5 = require('./load-json5');
const ENTRY_DIR = path.resolve(__dirname, '..');
const CONFIG_PATH = path.join(ENTRY_DIR, 'har-deps-required.json5');
function loadJson5(filePath) {
const raw = fs.readFileSync(filePath, 'utf8');
return parseJson5(raw);
}
function exists(p) {
try {
fs.accessSync(p, fs.constants.F_OK);
return true;
} catch {
return false;
}
}
function listDir(p) {
try {
return fs.readdirSync(p);
} catch {
return [];
}
}
function color(s, c) {
const codes = {
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
cyan: '\x1b[36m',
gray: '\x1b[90m',
reset: '\x1b[0m',
};
return process.stdout.isTTY ? codes[c] + s + codes.reset : s;
}
function main() {
const args = process.argv.slice(2);
const checkRawfile = args.includes('--rawfile');
const strict = args.includes('--strict');
if (!exists(CONFIG_PATH)) {
console.error(color(`✘ 缺少白名单配置: ${CONFIG_PATH}`, 'red'));
process.exit(strict ? 1 : 0);
}
const config = loadJson5(CONFIG_PATH);
const requiredHarDeps = config.requiredHarDeps || [];
const expectedSources = config.expectedDependencySources || {};
const moduleJsonRel = (config.buildArtifacts && config.buildArtifacts.moduleJson)
|| 'build/default/intermediates/package/default/module.json';
const moduleJsonPath = path.join(ENTRY_DIR, moduleJsonRel);
console.log(color('=== HAR 子包依赖校验 ===', 'cyan'));
console.log(`配置白名单: ${requiredHarDeps.join(', ')}`);
console.log(`module.json: ${moduleJsonPath}`);
console.log();
const errors = [];
const warnings = [];
// ---- 1. 校验 module.json dependencies ----
if (!exists(moduleJsonPath)) {
warnings.push(`module.json 不存在 (${moduleJsonPath}), 跳过依赖检查。可能尚未 Build。`);
} else {
let mj;
try {
mj = JSON.parse(fs.readFileSync(moduleJsonPath, 'utf8'));
} catch (e) {
errors.push(`module.json 解析失败: ${e.message}`);
}
if (mj) {
const deps = (mj.module && mj.module.dependencies) || mj.dependencies || [];
const depNames = new Set(deps.map(d => d.moduleName));
for (const har of requiredHarDeps) {
if (depNames.has(har)) {
console.log(color(` ✔ module.json.dependencies 包含 ${har}`, 'green'));
} else {
errors.push(`module.json.dependencies 缺失 ${har} (实际: ${[...depNames].join(', ') || '空'})`);
console.log(color(` ✘ module.json.dependencies 缺失 ${har}`, 'red'));
}
}
}
}
// ---- 2. 校验 oh_modules 子包资源是否就位 (可选) ----
if (checkRawfile) {
console.log();
console.log(color('--- oh_modules 子包资源检查 ---', 'cyan'));
const ohModulesRoots = (config.ohModulesRoots) || {};
const ohModulesDir = path.join(ENTRY_DIR, 'oh_modules');
if (!exists(ohModulesDir)) {
warnings.push(`oh_modules 目录不存在 (${ohModulesDir}), 请先在 DevEco 中 Sync 项目`);
}
for (const har of requiredHarDeps) {
const cfg = ohModulesRoots[har];
if (!cfg) continue;
const subDir = path.join(ohModulesDir, cfg.pkg, 'src', 'main', 'resources', 'rawfile', cfg.root);
if (!exists(subDir)) {
errors.push(`oh_modules/${cfg.pkg}/.../rawfile/${cfg.root} 缺失 (鸿蒙运行时会找不到组件)`);
console.log(color(` ✘ oh_modules/${cfg.pkg}/.../rawfile/${cfg.root} 缺失`, 'red'));
} else {
const files = listDir(subDir);
const packFiles = files.filter(f => f.endsWith('.pack.js'));
const inner = listDir(subDir).filter(f => {
try { return fs.statSync(path.join(subDir, f)).isDirectory(); } catch { return false; }
});
const totalPack = packFiles.length + inner.reduce((acc, d) => {
try { return acc + fs.readdirSync(path.join(subDir, d)).filter(f => f.endsWith('.pack.js')).length; }
catch { return acc; }
}, 0);
if (totalPack === 0) {
warnings.push(`oh_modules/${cfg.pkg}/.../rawfile/${cfg.root} 存在但无 .pack.js`);
console.log(color(` ⚠ oh_modules/${cfg.pkg}/.../rawfile/${cfg.root} 无 .pack.js`, 'yellow'));
} else {
console.log(color(` ✔ oh_modules/${cfg.pkg}/.../rawfile/${cfg.root} 存在, ${totalPack} 个 .pack.js`, 'green'));
}
}
}
}
// ---- 3. 校验 oh-package.json5 的 dependencies 与白名单一致 ----
const ohPkgPath = path.join(ENTRY_DIR, 'oh-package.json5');
if (exists(ohPkgPath)) {
console.log();
console.log(color('--- oh-package.json5 检查 ---', 'cyan'));
const ohPkg = loadJson5(ohPkgPath);
const ohDeps = ohPkg.dependencies || {};
for (const har of requiredHarDeps) {
if (!(har in ohDeps)) {
errors.push(`oh-package.json5.dependencies 缺失 ${har}`);
console.log(color(` ✘ oh-package.json5 缺失 ${har}`, 'red'));
} else {
const expected = expectedSources[har];
const actual = ohDeps[har];
if (expected && actual !== expected) {
warnings.push(`oh-package.json5 中 ${har} 的 source 不是预期: ${actual} (预期 ${expected})`);
console.log(color(` ⚠ ${har} source 异常: ${actual}`, 'yellow'));
} else {
console.log(color(` ✔ oh-package.json5 包含 ${har} (${actual})`, 'green'));
}
}
}
}
// ---- 总结 ----
console.log();
if (warnings.length) {
console.log(color(`警告 (${warnings.length}):`, 'yellow'));
for (const w of warnings) console.log(' - ' + w);
}
if (errors.length) {
console.log();
console.log(color(`错误 (${errors.length}):`, 'red'));
for (const e of errors) console.log(' - ' + e);
console.log();
console.log(color('✘ 校验失败: entry 模块缺少必要的 HAR 子包依赖。', 'red'));
console.log(color(' 原因: 这会导致运行时找不到 components-diy/diy-group.pack.js 等子包 chunk,', 'gray'));
console.log(color(' DIY 首页 + 商品分类 + 订单 + 营销页全部失效, 12s splash 兜底超时。', 'gray'));
console.log(color(' 修复: 在 entry/oh-package.json5 的 dependencies 里补齐 5 个 file: 依赖,', 'gray'));
console.log(color(' 同步 ./har-deps-required.json5, 然后重新 Build。', 'gray'));
process.exit(strict ? 1 : 0);
}
console.log(color('✔ 校验通过', 'green'));
}
try {
main();
} catch (e) {
console.error(color(`脚本异常: ${e.stack || e.message}`, 'red'));
process.exit(1);
}