chore(mp-harmony): 修正子包 HAR name 字段 + 纳入元数据到 git

背景:
  mp-harmony 项目的 5 个 ascf shared HAR 子包 (components_diy / pages_goods /
  pages_order / pages_promotion / pages_tool) 在 ascf_build 目录下, 关键
  元数据 (oh-package.json5 / module.json5 / build-profile.json5 /
  Index.ets / hvigorfile.ts / obfuscation-rules.txt) 之前被 .gitignore
  整体忽略, 从未被 git 跟踪, 导致 "module.name 被清空" 等回归无法被
  git diff / blame 追踪。

改动:
  1. .gitignore 改造
     - 不再整体 ignore ascf_build
     - 精确 ignore 已知产物路径 (rawfile/**/*.pack.js / rawfile/**/*.html
       / rawfile/**/*.json / build/ / oh_modules/ / .preview/ / .cxx/
       / .test/ / node_modules/)
     - ! 取反保留 HAR 必需文件 (placeholder/index.*, rawfile/index.js,
       base/element/*.json)
     - 补充 entry / hvigor / 鸿蒙签名材料 / IDE 临时文件 ignore 规则
  2. 首次将 5 个 HAR 包的元数据纳入 git (40 个文件)
  3. 新增 scripts/fix-subpackage-module-names.js: 任何入口 require
     vue.config.js 时自动修复 oh-package.json5.name + module.json5.module.name
     双重覆盖, 防止 DevEco ohpm 报 "00604007 Field IS Empty Error" 或
     hvigor 报 "Schema validate failed"
  4. vue.config.js 顶层 IIFE 触发修复 (任何 require 立即生效, 不依赖
     webpack 钩子)
  5. entry/scripts/check-har-deps.js 扩展: 校验 ascf_build 子包
     module.json5.module.name 字段 (兜底校验)
  6. entry/har-deps-required.json5 扩展: 新增 subpackageModuleJson5
     路径映射 + ohModulesRoots 校验资源齐备性
  7. entry/README-HAR-DEPS.md 更新: 故障速查表新增 module.name 相关
     报错条目

预期效果:
  - HBuilderX 触发 vue-cli-service build → vue.config.js 自动修复子包
    name → DevEco ohpm install / hvigor schema 校验通过
  - check-har-deps.js 兜底, 任何回归立即被检测并报错
  - 团队成员 git pull 后能立即看到 ascf_build 元数据, 可用 git diff
    跟踪 module.name 等关键字段变更
This commit is contained in:
2026-07-30 14:26:55 +08:00
parent 3dd059a6f6
commit 8ebd7918fb
48 changed files with 2870 additions and 4 deletions

View File

@@ -70,4 +70,76 @@ node scripts/check-har-deps.js --rawfile --strict
| 首页只显示 TabBar,无 DIY 内容 | components_diy 缺失 | 加 file: 依赖 + Sync + Build |
| 12s splash 后页面空白 | 任意一个 HAR 子包缺失 | 跑校验脚本看哪个缺失 |
| 商品分类页空白 | pages_goods 缺失 | 同上 |
| "应用未关联服务空间" 报错 | uniCloud 服务未关联(与本依赖无关) | uniCloud 目录右键关联服务空间 |
| "Schema validate failed: must match pattern '^[a-zA-Z][0-9a-zA-Z_.]*$'... module.name" | vue.config.js 重新生成时把 pages_tool 的 module.json5.module.name 清空了 | vue.config.js 已自动修复(`_copyMpHarmonyBuild` 末尾调用 `fixSubpackageModuleNames`)。如需手动跑:`node -e "require('./vue.config.js').fixSubpackageModuleNames()"` |
| "00604007 Field IS Empty Error: The name of package .../pages_tool cannot be empty" (DevEco 打开项目时 ohpm install 报) | `pages_tool/oh-package.json5` 的 top-level `name` 是空字符串 | `node scripts/fix-subpackage-module-names.js`,会同时修 oh-package.json5 和 module.json5 |
| "应用未关联服务空间" 报错 | uniCloud 服务未关联(与本依赖无关) | uniCloud 目录右键关联服务空间 |
## 子包 module.name 容易丢失的原因
`vue.config.js` 重新生成鸿蒙元服务产物时,会重新输出 `ascf_build/<pkg>/src/main/module.json5`。
其中 `module.name` 字段如果模板里没正确读取 `pkgName`(或没设置),会被写成空串。
**已自动化修复**:
`vue.config.js` 暴露了 `fixSubpackageModuleNames()` 函数,会在以下场景自动触发:
1. **顶层副作用**:vue.config.js 被任何入口 require 时(**包括 HBuilderX 触发 vue-cli-service build**),
立即遍历 5 个子包,强制把 `module.name` 修正为包目录名。
2. **构建流程**:mp-harmony 生产构建的 `_copyMpHarmonyBuild()` 末尾也会再调一次。
**也就是说:只要 HBuilderX / 命令行 触发了 vue.config.js(构建必然触发),module.name 就被保证正确,无需任何手动操作。**
手动调用方式:
```bash
# 直接跑独立脚本 (推荐)
node scripts/fix-subpackage-module-names.js
```
或者 require 模块(vue.config.js 内部用的就是这个):
```bash
node -e "require('./scripts/fix-subpackage-module-names').fixSubpackageModuleNames()"
```
> ⚠️ **重要**:vue.config.js 不再 export `fixSubpackageModuleNames`。历史教训:之前把 `fixSubpackageModuleNames` 放在 `module.exports` 上,vue-cli-service 校验 vue.config.js 导出的 keys 时会报:
>
> `Invalid options in vue.config.js: "fixSubpackageModuleNames" is not allowed`
>
> 现在函数在独立模块里,vue.config.js 通过顶层 IIFE 调用它,导出干净。
输出示例:
```
🔧 [vue.config] 修正 ascf_build 子包 module.json5.module.name...
✅ components_diy: module.name "(空)" → "components_diy"
✅ pages_goods: module.name "(空)" → "pages_goods"
✅ pages_order: module.name "(空)" → "pages_order"
✅ pages_promotion: module.name "(空)" → "pages_promotion"
✅ pages_tool: module.name "(空)" → "pages_tool"
📊 修正完成: 5 个子包被更新
```
校验脚本 `check-har-deps.js` 仍作为兜底防线,确保 module.name 不会再次被覆盖为空。
**完整工作流(HBuilderX "发行" → "鸿蒙元服务")**:
1. HBuilderX 调 uniapp 编译器生成 `unpackage/dist/build/.mp-harmony/`
2. HBuilderX 调 vue-cli-service build → `require('./vue.config.js')`
3. **顶层 IIFE 触发 → 自动修复 5 个子包 module.json5.module.name**
4. webpack 编译 → `VersionInjectPlugin._copyMpHarmonyBuild()` 拷产物到 ascf_src
5. **再次触发 `fixSubpackageModuleNames()`(防御性)**
6. DevEco Studio 用 ascf_src 构建鸿蒙 HAP(此时 module.name 已正确)
**手动修复**(如需保留原 module.json5 内容但 name 字段错了):
```json5
{
"module": {
"name": "<包目录名, 比如 pages_tool>",
...
}
}
```
`name` 必须匹配 `[a-zA-Z][0-9a-zA-Z_.]*`(鸿蒙 schema 要求)。

View File

@@ -60,4 +60,16 @@
pages_promotion:{ pkg: "pages_promotion",root: "pages_promotion" },
pages_tool: { pkg: "pages_tool", root: "pages_tool" },
},
// 每个子包在 ascf_build 中的 src/main/module.json5 路径 (相对 mp-harmony 目录)
// 用于校验 module.name 字段是否被 vue.config.js 重新生成时清空
// 现象: pages_tool 的 module.json5 的 module.name 被覆盖成 "",
// 导致 hvigor schema 校验失败, build 阶段直接退出。
subpackageModuleJson5: {
components_diy: "./ascf/ascf_build/components_diy/src/main/module.json5",
pages_goods: "./ascf/ascf_build/pages_goods/src/main/module.json5",
pages_order: "./ascf/ascf_build/pages_order/src/main/module.json5",
pages_promotion: "./ascf/ascf_build/pages_promotion/src/main/module.json5",
pages_tool: "./ascf/ascf_build/pages_tool/src/main/module.json5",
},
}

View File

@@ -173,6 +173,38 @@ function main() {
}
}
// ---- 4. 校验 ascf_build 子包 module.json5 的 module.name 字段 ----
// 防止 vue.config.js 重新生成时把 module.name 清空, 导致 hvigor schema 校验失败
console.log();
console.log(color('--- ascf_build 子包 module.json5 检查 ---', 'cyan'));
const mpHarmonyDir = path.resolve(ENTRY_DIR, '..');
const subpackageModuleJson5 = config.subpackageModuleJson5 || {};
for (const har of requiredHarDeps) {
const rel = subpackageModuleJson5[har];
if (!rel) continue;
const moduleJson5Path = path.resolve(mpHarmonyDir, rel);
if (!exists(moduleJson5Path)) {
warnings.push(`ascf_build/${har}/src/main/module.json5 缺失 (${moduleJson5Path})`);
console.log(color(` ⚠ ${moduleJson5Path} 不存在`, 'yellow'));
continue;
}
let mj;
try {
mj = loadJson5(moduleJson5Path);
} catch (e) {
errors.push(`${har} 的 module.json5 解析失败: ${e.message}`);
console.log(color(` ✘ ${har} module.json5 解析失败`, 'red'));
continue;
}
const moduleName = mj && mj.module && mj.module.name;
if (!moduleName || moduleName !== har) {
errors.push(`${har} 的 module.json5.module.name 异常: "${moduleName}" (应为 "${har}", 常见原因: vue.config.js 重新生成时未写入 packageName)`);
console.log(color(` ✘ ${har} module.name = "${moduleName}" (应为 "${har}")`, 'red'));
} else {
console.log(color(` ✔ ${har} module.name = "${moduleName}"`, 'green'));
}
}
// ---- 总结 ----
console.log();
if (warnings.length) {