@dd-code/uni-tools 1.0.14 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -629,6 +629,11 @@ var downloadProjectFiles = function (manifestList) { return __awaiter(void 0, vo
629
629
  });
630
630
  }); };
631
631
 
632
+ /**
633
+ * 计算需要下载/更新的 Manifest 列表
634
+ * - 比较 node_modules 缓存中的 manifest 哈希与远端 manifest 哈希
635
+ * - 返回需要更新的清单(用于后续下载项目文件到本地缓存)
636
+ */
632
637
  var checkDownloadFilesIsExpired = function (manifestList) {
633
638
  var filterList = manifestList.filter(function (conf) {
634
639
  var targetPath = getNodeModulesEnvAppCodeFilePath(conf, MANIFEST_NAME);
@@ -638,6 +643,14 @@ var checkDownloadFilesIsExpired = function (manifestList) {
638
643
  });
639
644
  return filterList;
640
645
  };
646
+ /**
647
+ * Manifest 管理器(构建态/运行态共享状态)
648
+ * - value:当前应用 Manifest(会随构建过程逐步填充)
649
+ * - setEnv:读取 cli/vite 环境,设置 isRoot/isServe/code/appCode/publicPath 等
650
+ * - setPagesJson/setFiles/setExposes:在插件流程中填充 pages 与产物清单与运行时暴露
651
+ * - saveFile:落盘 Manifest(计算 hash,剔除临时字段 isServe)
652
+ * - dependencies:记录其他应用的 Manifest(用于主应用合并)
653
+ */
641
654
  var createManifestManager = function () {
642
655
  var envObj = process.env;
643
656
  var row = {
@@ -690,25 +703,16 @@ var createManifestManager = function () {
690
703
  },
691
704
  };
692
705
  };
693
- var getRootMainManifestJson = function (code, mode) { return __awaiter(void 0, void 0, void 0, function () {
694
- var pageManifest, nodeModulesManifest, cdnUrl, manifestJson;
706
+ /**
707
+ * CDN 获取主应用 Manifest(ROOT_APP_CODE)
708
+ * - 仅用于校验/兜底:优先使用本地 dist 或缓存 node_modules 的 Manifest
709
+ */
710
+ var downloadMainAppManifestJson = function (currentManifest) { return __awaiter(void 0, void 0, void 0, function () {
711
+ var mode, code, cdnUrl, manifestJson;
695
712
  return __generator(this, function (_b) {
696
713
  switch (_b.label) {
697
714
  case 0:
698
- try {
699
- pageManifest = uniReadFile(path.join(process.env.UNI_OUTPUT_DIR, MANIFEST_NAME));
700
- if (Object.keys(pageManifest).length !== 0) {
701
- return [2 /*return*/, pageManifest];
702
- }
703
- }
704
- catch (_c) { }
705
- try {
706
- nodeModulesManifest = uniReadFile(path.join(SAVE_CDN_FILE_PATH, mode, ROOT_APP_CODE, MANIFEST_NAME));
707
- if (Object.keys(nodeModulesManifest).length !== 0) {
708
- return [2 /*return*/, nodeModulesManifest];
709
- }
710
- }
711
- catch (_d) { }
715
+ mode = currentManifest.mode, code = currentManifest.code;
712
716
  _b.label = 1;
713
717
  case 1:
714
718
  _b.trys.push([1, 3, , 4]);
@@ -720,19 +724,72 @@ var getRootMainManifestJson = function (code, mode) { return __awaiter(void 0, v
720
724
  return [4 /*yield*/, fetchFileByPath(cdnUrl)];
721
725
  case 2:
722
726
  manifestJson = _b.sent();
723
- if (Object.keys(manifestJson).length !== 0) {
724
- return [2 /*return*/, manifestJson];
725
- }
726
- return [3 /*break*/, 4];
727
+ return [2 /*return*/, manifestJson];
727
728
  case 3:
728
729
  _b.sent();
729
730
  return [3 /*break*/, 4];
730
- case 4: return [2 /*return*/, { exposes: {} }];
731
+ case 4: return [2 /*return*/, {}];
732
+ }
733
+ });
734
+ }); };
735
+ /**
736
+ * 读取根主应用 Manifest(优先级:dist > node_modules 缓存 > CDN)
737
+ * - 兼容不同构建场景:
738
+ * - isServe(WS 联调)或内部构建(inner build)下无需校验哈希
739
+ * - 其他场景严格校验本地与远端 Manifest 的 hash 一致性
740
+ * - 选择顺序:
741
+ * 1) 当前构建输出目录的 app.json(dist)
742
+ * 2) node_modules 缓存目录中的 app.json(save cdn file path)
743
+ * 3) 远端 CDN 拉取的 Manifest(兜底)
744
+ */
745
+ var getRootMainManifestJson = function (currentManifest) { return __awaiter(void 0, void 0, void 0, function () {
746
+ var mode, isInnerBuild, isWsBuild, needCheckHash, originHostManifestJson, checkHash, distPagePath, pageManifest, nodeModulePath, nodeModulesManifest;
747
+ return __generator(this, function (_a) {
748
+ switch (_a.label) {
749
+ case 0:
750
+ mode = currentManifest.mode;
751
+ isInnerBuild = checkIsInnerBuild();
752
+ isWsBuild = currentManifest.isServe;
753
+ needCheckHash = !(isWsBuild || isInnerBuild);
754
+ return [4 /*yield*/, downloadMainAppManifestJson(currentManifest)];
755
+ case 1:
756
+ originHostManifestJson = _a.sent();
757
+ checkHash = function (target) {
758
+ if ((originHostManifestJson === null || originHostManifestJson === void 0 ? void 0 : originHostManifestJson.hash) && needCheckHash && (originHostManifestJson === null || originHostManifestJson === void 0 ? void 0 : originHostManifestJson.hash) !== target.hash) {
759
+ throw new Error("originHostManifestJson hash not equal");
760
+ }
761
+ };
762
+ try {
763
+ distPagePath = path.join(process.env.UNI_OUTPUT_DIR, MANIFEST_NAME);
764
+ pageManifest = uniReadFile(distPagePath);
765
+ checkHash(pageManifest);
766
+ console.log("distPagePath done");
767
+ if (Object.keys(pageManifest).length !== 0) {
768
+ return [2 /*return*/, pageManifest];
769
+ }
770
+ }
771
+ catch (_b) { }
772
+ try {
773
+ nodeModulePath = path.join(SAVE_CDN_FILE_PATH, mode, ROOT_APP_CODE, MANIFEST_NAME);
774
+ nodeModulesManifest = uniReadFile(nodeModulePath);
775
+ checkHash(nodeModulesManifest);
776
+ console.log("nodeModulePath done");
777
+ if (Object.keys(nodeModulesManifest).length !== 0) {
778
+ return [2 /*return*/, nodeModulesManifest];
779
+ }
780
+ }
781
+ catch (_c) { }
782
+ console.log('origin done');
783
+ return [2 /*return*/, originHostManifestJson];
731
784
  }
732
785
  });
733
786
  }); };
734
787
 
735
788
  var num = 5;
789
+ /**
790
+ * 从主应用 HTTP 服务拉取当前进程环境(含 UNI_OUTPUT_DIR)
791
+ * - serve 非联调模式下,子应用通过此接口获知主应用输出根目录
792
+ */
736
793
  var getMainProcess = function () { return __awaiter(void 0, void 0, void 0, function () {
737
794
  var URL, mainProcess, result;
738
795
  return __generator(this, function (_a) {
@@ -750,6 +807,10 @@ var getMainProcess = function () { return __awaiter(void 0, void 0, void 0, func
750
807
  }
751
808
  });
752
809
  }); };
810
+ /**
811
+ * 简易重试(最多 5 次,每次 100ms)
812
+ * - 主应用 HTTP 服务启动可能有延迟,子应用循环尝试获取
813
+ */
753
814
  var getMainProcessLoop = function () { return __awaiter(void 0, void 0, void 0, function () {
754
815
  var mainProcess;
755
816
  return __generator(this, function (_a) {
@@ -805,6 +866,10 @@ var resetOutDir = function (currentManifestJson, config) { return __awaiter(void
805
866
  process.env.MFE_ROOT_OUTPUT_DIR = (_a = process.env.MFE_SOURCE_OUTPUT_DIR) === null || _a === void 0 ? void 0 : _a.replace(exp, "/").replace(/\/$/, "");
806
867
  // if (!currentManifestJson.value.isRoot)
807
868
  // console.log(config);
869
+ /**
870
+ * 非内部构建下,将 UNI_OUTPUT_DIR 统一指向主应用根输出目录
871
+ * - 便于后续写入 app.json 与拷贝产物
872
+ */
808
873
  if (!checkIsInnerBuild()) {
809
874
  // setTimeout(() => {
810
875
  process.env.UNI_OUTPUT_DIR = process.env.MFE_ROOT_OUTPUT_DIR;
@@ -815,6 +880,11 @@ var resetOutDir = function (currentManifestJson, config) { return __awaiter(void
815
880
  });
816
881
  }); };
817
882
 
883
+ /**
884
+ * 接管 uni 内置复制钩子
885
+ * - 通过 before/after 钩子记录从源到目标的拷贝行为
886
+ * - 便于在 Manifest 插件中收集运行期拷贝产生的文件清单
887
+ */
818
888
  var addUniCopyPluginHook = function (_a) {
819
889
  var before = _a.before, after = _a.after;
820
890
  var FileWatcher = require("@dcloudio/uni-cli-shared/dist/watcher").FileWatcher;
@@ -836,6 +906,11 @@ var copyFilesByTargetPath = function (sourcePath, targetPath) {
836
906
  fsExtra.ensureDirSync(targetDir);
837
907
  }
838
908
  catch (err) { }
909
+ /**
910
+ * 内容比较:
911
+ * - 仅当源/目标均为文件且内容完全一致时跳过,避免无效写入
912
+ * - 目录或不存在的目标不跳过
913
+ */
839
914
  var shouldSkip = function () {
840
915
  try {
841
916
  var s = fs.statSync(sourcePath);
@@ -844,6 +919,11 @@ var copyFilesByTargetPath = function (sourcePath, targetPath) {
844
919
  return false;
845
920
  var sb = fs.readFileSync(sourcePath);
846
921
  var tb = fs.readFileSync(targetPath);
922
+ /**
923
+ * Buffer 比较:
924
+ * - 长度与内容完全一致时跳过
925
+ * - 保留二进制级别比较,适配图片/字体等非文本文件
926
+ */
847
927
  return sb.length === tb.length && sb.equals(tb);
848
928
  }
849
929
  catch (_a) {
@@ -932,6 +1012,13 @@ var initPrePagesJson = function () {
932
1012
  var pagesPath = path.resolve(process.cwd(), "src/pages.json");
933
1013
  return fs.readFileSync(pagesPath, "utf-8");
934
1014
  };
1015
+ /**
1016
+ * 解析并预处理 pages.json
1017
+ * - 读取全局 preprocess 上下文(根据平台注入不同变量)
1018
+ * - 使用 @dcloudio 的 preprocess 对 pages.json 做条件编译(如 #ifdef/#endif)
1019
+ * - 返回 JS 对象形式的 pages 配置
1020
+ * - isFormat=true 且平台为 mp-weixin 时,转换为微信特定格式(去除 globalStyle 并映射到 window/subPackages)
1021
+ */
935
1022
  var getPagesJson = function (jsonFile, isFormat) {
936
1023
  if (isFormat === void 0) { isFormat = false; }
937
1024
  var platform = process.env.UNI_PLATFORM;
@@ -944,6 +1031,12 @@ var getPagesJson = function (jsonFile, isFormat) {
944
1031
  }
945
1032
  return pagesConfig;
946
1033
  };
1034
+ /**
1035
+ * 将 Uni 的 pages.json 转换为微信小程序格式
1036
+ * - window:映射 globalStyle,并兼容 mp-weixin 特定字段
1037
+ * - subPackages:后续会在 app-json.ts 中由各子应用补充到主应用
1038
+ * - usingComponents:保留全局组件声明
1039
+ */
947
1040
  var transformToWeixinFormat = function (uniPagesConfig) {
948
1041
  var _a;
949
1042
  var weixinConfig = __assign({ pages: [], window: {}, tabBar: null, subPackages: [], usingComponents: {} }, uniPagesConfig);
@@ -1009,6 +1102,19 @@ var transformToWeixinFormat = function (uniPagesConfig) {
1009
1102
  };
1010
1103
 
1011
1104
  // import { addRunningAppToSave } from "../running-core";
1105
+ /**
1106
+ * Manifest 采集与产物清单插件
1107
+ * - 目标:收集构建阶段产物与运行期拷贝的文件列表,生成可供主应用消费的文件清单
1108
+ * - CollectFiles:
1109
+ * - emitted:bundle 产物与拷贝文件的统一索引(fileName -> fileUrl)
1110
+ * - callbackFiles:拦截 uni 的复制钩子,收集被拷贝的源与目标相对路径
1111
+ * - copyFilesToPublishDir:将 outDir 下的产物拷贝到 publish 目录,便于后续上载/分发
1112
+ * - 插件钩子:
1113
+ * - config:记录 outDir,拦截 uni 拷贝行为
1114
+ * - renderStart:解析 pages.json,写入到 Manifest 状态
1115
+ * - writeBundle:收集本次打包输出的 chunk 信息
1116
+ * - closeBundle:汇总拷贝与产物,写入 Manifest 文件并拷贝到发布目录
1117
+ */
1012
1118
  var CollectFiles = /** @class */ (function () {
1013
1119
  function CollectFiles() {
1014
1120
  this.callbackFiles = [];
@@ -1028,6 +1134,11 @@ var CollectFiles = /** @class */ (function () {
1028
1134
  Object.keys(bundles).forEach(function (key) {
1029
1135
  var boundle = bundles[key];
1030
1136
  var fileName = boundle.fileName, source = boundle.source, code = boundle.code;
1137
+ /**
1138
+ * code/source:
1139
+ * - chunk 使用 code 字段,asset 使用 source 字段
1140
+ * - 统一抽象为 fileInfo 行(包含 fileUrl 与大小哈希)
1141
+ */
1031
1142
  var fileInfo = genreFileInfoRow({ fileName: fileName, source: code || source });
1032
1143
  _this.emitted.set(fileName, fileInfo);
1033
1144
  });
@@ -1122,6 +1233,12 @@ var createManifestPlugin = function (manifestJson) {
1122
1233
  };
1123
1234
  };
1124
1235
 
1236
+ /**
1237
+ * 主应用 app.json 渲染与写入
1238
+ * - renderPagesJsonByArray:将多个子应用的 pages.json 以分包形式合入主应用
1239
+ * - genreFullMainAppJsonByManifestList:按 Manifest 列表生成完整的主应用 app.json
1240
+ * - genreNewAppJson:内容比较后写入 app.json,避免无效写入导致的频繁重启
1241
+ */
1125
1242
  var renderPagesJsonByArray = function (appPages, pageJson) {
1126
1243
  var _loop_1 = function (app) {
1127
1244
  var _a = getPagesJson(JSON.stringify((app === null || app === void 0 ? void 0 : app.pagesJson) || {}), true).pages, pages = _a === void 0 ? [] : _a;
@@ -1155,6 +1272,14 @@ var genreNewAppJson = function (outputPageJsonPath, appJson, manifestList) {
1155
1272
  }
1156
1273
  };
1157
1274
 
1275
+ /**
1276
+ * 运行期联调核心
1277
+ * - getAppsManifestList:在主应用非联调构建模式下,返回所有子应用的 Manifest 路径列表
1278
+ * - startDistWatcher:监听子应用输出目录的父级变更,增量拷贝到主应用分包路径,并上报变更
1279
+ * - 设计要点:
1280
+ * - 监听父级目录以覆盖新增/删除场景;通过 `isTargetFile` 过滤目标变化
1281
+ * - 拷贝时进行内容比较,避免触发无效写入
1282
+ */
1158
1283
  var getAppsManifestList = function (mode) {
1159
1284
  var _a;
1160
1285
  var manifest = formatCliCommandConfig(mode);
@@ -1184,6 +1309,11 @@ var startDistWatcher = function (mainPwd, onReady, onChange) {
1184
1309
  var filePath = path.resolve(root);
1185
1310
  checkAndgenreDir(filePath);
1186
1311
  var parentDir = path.dirname(filePath);
1312
+ /**
1313
+ * 监听父级目录:
1314
+ * - uni 输出目录在构建时可能新增/删除文件或目录,监听父级可捕捉到此类变化
1315
+ * - 通过 isTargetFile 精确过滤与目标目录相关的事件
1316
+ */
1187
1317
  var watcher = createFileWatcher(parentDir);
1188
1318
  var isTargetFile = function (p) {
1189
1319
  return p.startsWith(filePath + path.sep) || p === filePath;
@@ -1198,6 +1328,11 @@ var startDistWatcher = function (mainPwd, onReady, onChange) {
1198
1328
  var sourcePath = p;
1199
1329
  var targetPath = path.join(mainPwd, rel);
1200
1330
  if (["add", "change"].includes(evt)) {
1331
+ /**
1332
+ * 增量拷贝:
1333
+ * - 目录结构保持一致,从子应用输出拷贝到主应用分包路径
1334
+ * - 通过 copyFilesByTargetPath 的内容比较避免重复写入
1335
+ */
1201
1336
  copyFilesByTargetPath(sourcePath, targetPath);
1202
1337
  }
1203
1338
  onChange === null || onChange === void 0 ? void 0 : onChange({ type: evt, p: p, sourcePath: sourcePath, targetPath: targetPath });
@@ -1206,6 +1341,13 @@ var startDistWatcher = function (mainPwd, onReady, onChange) {
1206
1341
  };
1207
1342
 
1208
1343
  var app = null;
1344
+ /**
1345
+ * 创建开发态 HTTP 服务
1346
+ * - 单例复用:避免重复创建与重复监听
1347
+ * - 路由:
1348
+ * - GET `${HTTP_PATH}/root-path`:返回当前进程的环境变量(主应用输出位置等)
1349
+ * - 与 WS 服务配合:WSServer 绑定同一个 HTTP server 进行升级
1350
+ */
1209
1351
  var createHttpServer = function () {
1210
1352
  if (app)
1211
1353
  return { server: app, start: function () { } };
@@ -1215,6 +1357,11 @@ var createHttpServer = function () {
1215
1357
  res.send(process.env);
1216
1358
  });
1217
1359
  app.use(cors({ origin: "*" }));
1360
+ /**
1361
+ * 返回:
1362
+ * - server:HTTP Server 实例(供 WS 复用)
1363
+ * - start(type):启动监听并输出日志,type 用于日志区分('http' | 'ws')
1364
+ */
1218
1365
  return {
1219
1366
  server: server,
1220
1367
  start: function (type) {
@@ -1232,6 +1379,10 @@ var WsServer = /** @class */ (function () {
1232
1379
  this.httpServer = createHttpServer();
1233
1380
  this.clientMap = new Map();
1234
1381
  }
1382
+ /**
1383
+ * 单例获取 WS 服务实例
1384
+ * - 若已创建则复用并更新消息回调
1385
+ */
1235
1386
  WsServer.getInstance = function (handleMessage) {
1236
1387
  if (!WsServer.instance) {
1237
1388
  WsServer.instance = new WsServer(handleMessage);
@@ -1259,12 +1410,18 @@ var WsServer = /** @class */ (function () {
1259
1410
  this.handleMessage = callback;
1260
1411
  }
1261
1412
  };
1413
+ /**
1414
+ * 向指定 appCode 的客户端发送消息
1415
+ */
1262
1416
  WsServer.prototype.sendMessageToApp = function (appCode, message) {
1263
1417
  var ws = this.clientMap.get(appCode);
1264
1418
  if (ws) {
1265
1419
  ws.send(typeof message === "string" ? message : JSON.stringify(message));
1266
1420
  }
1267
1421
  };
1422
+ /**
1423
+ * 连接事件:建立客户端映射并下发初始化信息(主应用输出目录)
1424
+ */
1268
1425
  WsServer.prototype.onConnection = function () {
1269
1426
  var _this = this;
1270
1427
  this.wss.on("connection", function (ws, request) {
@@ -1303,6 +1460,9 @@ var WsClientServer = /** @class */ (function () {
1303
1460
  this.ws = null;
1304
1461
  this.isConnected = false;
1305
1462
  }
1463
+ /**
1464
+ * 获取客户端单例
1465
+ */
1306
1466
  WsClientServer.getInstance = function (handleMessage) {
1307
1467
  if (!WsClientServer.instance) {
1308
1468
  WsClientServer.instance = new WsClientServer(handleMessage);
@@ -1356,6 +1516,9 @@ var WsClientServer = /** @class */ (function () {
1356
1516
  this.handleMessage = callback;
1357
1517
  }
1358
1518
  };
1519
+ /**
1520
+ * 简单重试策略:一定时间后重新连接
1521
+ */
1359
1522
  WsClientServer.prototype.retryConnect = function (appCode) {
1360
1523
  var _this = this;
1361
1524
  if (this.isConnected)
@@ -1380,6 +1543,20 @@ var WsClientServer = /** @class */ (function () {
1380
1543
  // export const mfeServer = new WsServer();
1381
1544
  // export const mfeClientServer = new WsClientServer();
1382
1545
 
1546
+ /**
1547
+ * 主应用插件(Main App)
1548
+ * - 服务端(根应用):
1549
+ * - 启动 WS + HTTP 服务,向子应用广播初始化信息(主应用输出目录)
1550
+ * - 接收子应用文件变更事件,拉取对应子应用 Manifest 并增量更新主应用 app.json
1551
+ * - 客户端(子应用):
1552
+ * - 连接主应用 WS,接收初始化 pwd 后将自身构建产物增量拷贝到主应用分包路径
1553
+ * - 在构建完成后启动本地 DistWatcher,监控自身输出变更并通过 WS 通知主应用
1554
+ * - 构建阶段:
1555
+ * - 合并所有依赖子应用的 pages.json,生成最终主应用 app.json,内容比较避免无效写入
1556
+ * - 关键点:
1557
+ * - `isBuild`/`isServe`/`isRoot` 三态控制插件行为,避免生产与联调逻辑相互影响
1558
+ * - `copyFilesByTargetPath` 与 `genreNewAppJson` 均内置内容比较,防止频繁重启
1559
+ */
1383
1560
  var filterManifestJsonListAndMainPageJson = function (manifestJsonList) {
1384
1561
  var outputPageJsonPath = getMainAppJsonPath();
1385
1562
  return {
@@ -1431,6 +1608,11 @@ var createMainAppPlugin = function (manifestJson) {
1431
1608
  startDistWatcher(state.mainPwd, function () {
1432
1609
  state.isWatcherReady = true;
1433
1610
  }, function (change) {
1611
+ /**
1612
+ * 通过 WS 将子应用的输出变更上报主应用
1613
+ * - 包含事件类型、源/目标路径、相对路径等
1614
+ * - 主应用端在收到 CHANGE 后增量更新 app.json
1615
+ */
1434
1616
  state.fn = function () {
1435
1617
  return state.mfeClientServer.sendMessage(E_WS_TYPE.CHANGE, __assign(__assign({}, change), { appCode: manifestJson.value.appCode }));
1436
1618
  };
@@ -1448,6 +1630,10 @@ var createMainAppPlugin = function (manifestJson) {
1448
1630
  copyFilesByTargetPath(sourcePath, targetPath);
1449
1631
  };
1450
1632
  var watchFile = function () {
1633
+ /**
1634
+ * 在非 serve + 主应用构建时,监听所有子应用 Manifest 文件变化
1635
+ * - 变化时重算并写入 app.json,保持主应用 pages 配置最新
1636
+ */
1451
1637
  var allManifest = getAppsManifestList(manifestJson.value.mode);
1452
1638
  var watchFileList = allManifest.map(function (item) { return item.filePath; });
1453
1639
  var watcher = createFileWatcher(watchFileList);
@@ -1473,13 +1659,16 @@ var createMainAppPlugin = function (manifestJson) {
1473
1659
  start();
1474
1660
  return [2 /*return*/];
1475
1661
  }
1662
+ /**
1663
+ * 联调开发:启动根应用 WS 服务,负责给子应用下发初始化信息并接收变更事件
1664
+ */
1476
1665
  createMainAppServer();
1477
- // const subs = findLocalSubApps();
1478
- // if (subs.length) {
1479
- // startLocalSubApps(subs, "mp-weixin", manifestJson.value.mode);
1480
- // }
1481
1666
  }
1482
1667
  else {
1668
+ /**
1669
+ * 子应用:作为 WS 客户端连接主应用
1670
+ * - 收到 INIT 后,将自身产物拷贝到主应用分包路径
1671
+ */
1483
1672
  state.mfeClientServer = createMainAppClient(manifestJson, function (data) {
1484
1673
  copyAppDistModule(data);
1485
1674
  });
@@ -1549,10 +1738,35 @@ var createMainAppPlugin = function (manifestJson) {
1549
1738
  ];
1550
1739
  };
1551
1740
 
1741
+ /**
1742
+ * 运行时暴露插件(Exposes)
1743
+ * - 目标:在页面/模块中以 `@dd-code/runtime` 或 `@dd-code/runtime/<name>` 引用主应用的公共导出
1744
+ * - 流程:
1745
+ * 1) configResolved:从主应用 Manifest 读取 exposes 映射('.'、'./axios' 等)
1746
+ * 2) resolveId:拦截并识别 runtime 请求
1747
+ * 3) load:按请求的子路径拼装 require 代码,指向主应用模块(使用相对路径计算)
1748
+ * 4) buildStart:为每个 exposes 键发射独立的入口 chunk,确保输出到根目录
1749
+ * 5) generateBundle:收集产物映射(fileName + exports),保存到当前 Manifest
1750
+ * - 注意:
1751
+ * - `RUNTIME_NAME_REGEXP` 用于识别所有 runtime 形式,键以 '.' 开头并支持层级 './xxx'
1752
+ * - require 的相对路径通过 `renderRuntimeCode` 按当前 appCode + 构建位置计算,保持稳定
1753
+ */
1552
1754
  var buildName = "mfe_runtime/__mfe_{template}_runtime__.js";
1553
1755
  var RUNTIME_NAME = "@dd-code/runtime";
1554
1756
  // const runtimeDir = 'mfe_runtime'
1555
1757
  var RUNTIME_NAME_REGEXP = new RegExp(RUNTIME_NAME + "(/.*)?");
1758
+ /**
1759
+ * 生成 runtime 入口代码
1760
+ * - 参数:
1761
+ * - moduleExpose:主应用 exposes 配置中指定的模块信息({ path, exports })
1762
+ * - appCode:当前应用代码,用于计算运行时代码与目标模块的相对路径
1763
+ * - 相对路径计算:
1764
+ * - runtime 文件输出位置:mfe_runtime/__mfe_{template}_runtime__.js
1765
+ * - 运行时代码中 require 的相对路径需指向主应用根下的模块文件(如 store/index.js)
1766
+ * - deepPath = 相对路径(从 runtime 所在目录到项目根 "."),用于拼接 require('deepPath/<filePath>')
1767
+ * - 导出约定:
1768
+ * - 仅支持命名导出列表(exports: string[]),以 `export const {name} = require(...)` 形式暴露
1769
+ */
1556
1770
  var renderRuntimeCode = function (moduleExpose, appCode) {
1557
1771
  var deepPath = path.relative(path.join(appCode, path.dirname(buildName)), ".");
1558
1772
  var resultCode = "";
@@ -1570,12 +1784,19 @@ var createExposesPlugin = function (options, currentManifestJson) {
1570
1784
  {
1571
1785
  name: "@chagee:uni-exposes",
1572
1786
  enforce: "post",
1787
+ /**
1788
+ * 读取主应用的 exposes 配置
1789
+ * - 来源:根应用构建时生成的 Manifest(含 exposes 映射)
1790
+ * - 示例:
1791
+ * { '.': { path: 'store/index.js', exports: ['userStore'] },
1792
+ * './axios': { path: 'axios/index.js', exports: ['axios'] } }
1793
+ */
1573
1794
  configResolved: function (config) {
1574
1795
  return __awaiter(this, void 0, void 0, function () {
1575
1796
  var manifestJson;
1576
1797
  return __generator(this, function (_a) {
1577
1798
  switch (_a.label) {
1578
- case 0: return [4 /*yield*/, getRootMainManifestJson(currentManifestJson.value.code, currentManifestJson.value.mode)];
1799
+ case 0: return [4 /*yield*/, getRootMainManifestJson(currentManifestJson.value)];
1579
1800
  case 1:
1580
1801
  manifestJson = _a.sent();
1581
1802
  mainAppExposeCode = manifestJson.exposes || {};
@@ -1584,6 +1805,11 @@ var createExposesPlugin = function (options, currentManifestJson) {
1584
1805
  });
1585
1806
  });
1586
1807
  },
1808
+ /**
1809
+ * 统一拦截 runtime 引用
1810
+ * - 支持 @dd-code/runtime 与 @dd-code/runtime/<name>
1811
+ * - 返回原始 id,交由 load 钩子生成具体代码
1812
+ */
1587
1813
  resolveId: function (id, importer) {
1588
1814
  return __awaiter(this, void 0, void 0, function () {
1589
1815
  return __generator(this, function (_a) {
@@ -1594,6 +1820,11 @@ var createExposesPlugin = function (options, currentManifestJson) {
1594
1820
  });
1595
1821
  });
1596
1822
  },
1823
+ /**
1824
+ * 生成运行时代码
1825
+ * - 通过解析 id 获取子路径('.' 或 './name')
1826
+ * - 按 exposes 映射找到对应模块与导出列表,拼装 require 代码
1827
+ */
1597
1828
  load: function (id) {
1598
1829
  return __awaiter(this, void 0, void 0, function () {
1599
1830
  var matched, deepPath, moduleExpose;
@@ -1608,6 +1839,11 @@ var createExposesPlugin = function (options, currentManifestJson) {
1608
1839
  });
1609
1840
  });
1610
1841
  },
1842
+ /**
1843
+ * 为每个 exposes 键发射一个 runtime chunk
1844
+ * - fileName 模板中 {template} 取键名,将非路径字符替换为可用形式(如 './axios' -> '_axios')
1845
+ * - 保证各入口在输出根目录下具有稳定文件名
1846
+ */
1611
1847
  buildStart: function () {
1612
1848
  return __awaiter(this, void 0, void 0, function () {
1613
1849
  var _i, _a, _b, spec, r, id, fileName, fileNameWithoutExt;
@@ -1616,14 +1852,16 @@ var createExposesPlugin = function (options, currentManifestJson) {
1616
1852
  switch (_c.label) {
1617
1853
  case 0:
1618
1854
  // 显式发射 runtime chunk,确保它被打包到根目录
1619
- Object.keys(mainAppExposeCode).forEach(function (key) {
1620
- var keyDir = key.replace(/\./g, "").replace(/\//g, "_");
1621
- _this.emitFile({
1622
- type: "chunk",
1623
- id: path.join(RUNTIME_NAME, key),
1624
- fileName: buildName.replace("{template}", keyDir),
1855
+ if (!currentManifestJson.value.isRoot) {
1856
+ Object.keys(mainAppExposeCode).forEach(function (key) {
1857
+ var keyDir = key.replace(/\./g, "").replace(/\//g, "_");
1858
+ _this.emitFile({
1859
+ type: "chunk",
1860
+ id: path.join(RUNTIME_NAME, key),
1861
+ fileName: buildName.replace("{template}", keyDir),
1862
+ });
1625
1863
  });
1626
- });
1864
+ }
1627
1865
  _i = 0, _a = Object.entries(options.exposes || {});
1628
1866
  _c.label = 1;
1629
1867
  case 1:
@@ -1651,6 +1889,11 @@ var createExposesPlugin = function (options, currentManifestJson) {
1651
1889
  });
1652
1890
  });
1653
1891
  },
1892
+ /**
1893
+ * 产物阶段:收集 exposes 的打包路径与导出列表
1894
+ * - 通过 chunk.modules[moduleId.id] 反查模块所属 chunk
1895
+ * - 保存到当前 Manifest,以便下游消费
1896
+ */
1654
1897
  generateBundle: function (_, bundles) {
1655
1898
  return __awaiter(this, void 0, void 0, function () {
1656
1899
  var chunks, resolveIdsMap, _loop_1, this_1, _a, _b, _c, _i, i;
@@ -1709,6 +1952,19 @@ var createExposesPlugin = function (options, currentManifestJson) {
1709
1952
  ];
1710
1953
  };
1711
1954
 
1955
+ /**
1956
+ * mp-weixin 平台插件聚合器
1957
+ * - 初始化并维护当前构建的 Manifest 管理器(state + IO)
1958
+ * - 根据模式预清理发布目录并重置 outDir(避免脏数据影响产物)
1959
+ * - 组合注册各业务插件:运行时暴露、资源搬运、Manifest 采集与主应用逻辑
1960
+ * - 插件间通过 `currentManifestJson` 共享上下文(环境、文件列表、依赖、exposes 映射)
1961
+ * - 插件注册顺序:
1962
+ * 1) pre: @dd-code:genre-params(设置环境、重置 outDir)
1963
+ * 2) post: exposes(生成 runtime 入口与 exposes 产物映射)
1964
+ * 3) pre: apps-assets(下载/搬运其它应用资源到主输出目录)
1965
+ * 4) default: manifest-plugin(采集 pages.json 与产物清单)
1966
+ * 5) post: main-app(serve/watch/merge 核心逻辑)
1967
+ */
1712
1968
  var createMpWeixinUniPlugin = function (options) {
1713
1969
  if (options === void 0) { options = {}; }
1714
1970
  var currentManifestJson = createManifestManager();