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
202 lines
7.3 KiB
JavaScript
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);
|
|
} |