@fulgurjs/federation 6.8.6 → 6.9.0

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.
Files changed (139) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.en.md +3 -0
  3. package/README.md +3 -0
  4. package/dist/application-core-BuhXQmLF.d.cts +16 -0
  5. package/dist/application-core-DWI3eKme.d.ts +16 -0
  6. package/dist/bridge-app-react.cjs +177 -9
  7. package/dist/bridge-app-react.d.cts +15 -3
  8. package/dist/bridge-app-react.d.ts +15 -3
  9. package/dist/bridge-app-react.js +101 -9
  10. package/dist/bridge-app-vue.cjs +138 -12
  11. package/dist/bridge-app-vue.d.cts +20 -5
  12. package/dist/bridge-app-vue.d.ts +20 -5
  13. package/dist/bridge-app-vue.js +62 -12
  14. package/dist/bridge-host-react.d.cts +1 -1
  15. package/dist/bridge-host-react.d.ts +1 -1
  16. package/dist/bridge-host-vue.d.cts +1 -1
  17. package/dist/bridge-host-vue.d.ts +1 -1
  18. package/dist/chunk-6OB47FSR.js +81 -0
  19. package/dist/cli.js +350 -24
  20. package/dist/index.cjs +7 -6
  21. package/dist/index.js +7 -6
  22. package/dist/react-adapter.d.cts +1 -1
  23. package/dist/react-adapter.d.ts +1 -1
  24. package/dist/react.d.ts +29 -4
  25. package/dist/react.js +1 -0
  26. package/dist/{remote-types-xf1B6_pK.d.ts → remote-types-COmBhjRc.d.ts} +1 -1
  27. package/dist/{remote-types-58hdbx6x.d.cts → remote-types-CStGOJwu.d.cts} +1 -1
  28. package/dist/runtime.js +1 -1
  29. package/dist/vue-adapter.d.cts +1 -1
  30. package/dist/vue-adapter.d.ts +1 -1
  31. package/dist/vue-store.cjs +40 -0
  32. package/dist/vue-store.d.cts +4 -0
  33. package/dist/vue-store.d.ts +4 -0
  34. package/dist/vue-store.js +15 -0
  35. package/dist/vue.d.ts +37 -6
  36. package/dist/vue.js +2 -0
  37. package/docs/en/reference/api.md +38 -2
  38. package/docs/en/reference/types.md +27 -0
  39. package/docs/zh/reference/api.md +46 -2
  40. package/docs/zh/reference/types.md +27 -0
  41. package/examples/templates/README.md +3 -0
  42. package/examples/templates/react-host-vue-remote/README.md +24 -0
  43. package/examples/templates/react-host-vue-remote/package.json +2 -1
  44. package/examples/templates/react-host-vue-remote/pnpm-lock.yaml +7 -7
  45. package/examples/templates/react-host-vue-remote/pnpm-workspace.yaml +1 -1
  46. package/examples/templates/react-host-vue-remote/react-host/package.json +1 -1
  47. package/examples/templates/react-host-vue-remote/react-host/src/application.tsx +62 -0
  48. package/examples/templates/react-host-vue-remote/react-host/src/main.tsx +2 -62
  49. package/examples/templates/react-host-vue-remote/scripts/prod.mjs +101 -0
  50. package/examples/templates/react-host-vue-remote/vue-remote/README.md +17 -16
  51. package/examples/templates/react-host-vue-remote/vue-remote/fulgurjs.config.ts +2 -2
  52. package/examples/templates/react-host-vue-remote/vue-remote/package.json +1 -1
  53. package/examples/templates/react-host-vue-remote/vue-remote/src/AboutPage.vue +1 -0
  54. package/examples/templates/react-host-vue-remote/vue-remote/src/App.vue +15 -5
  55. package/examples/templates/react-host-vue-remote/vue-remote/src/HomePage.vue +1 -0
  56. package/examples/templates/react-host-vue-remote/vue-remote/src/application.ts +19 -0
  57. package/examples/templates/react-host-vue-remote/vue-remote/src/main.ts +2 -15
  58. package/examples/templates/react-react/README.md +25 -1
  59. package/examples/templates/react-react/host/package.json +1 -1
  60. package/examples/templates/react-react/host/src/application.tsx +33 -0
  61. package/examples/templates/react-react/host/src/main.tsx +3 -32
  62. package/examples/templates/react-react/package.json +2 -1
  63. package/examples/templates/react-react/pnpm-lock.yaml +7 -7
  64. package/examples/templates/react-react/pnpm-workspace.yaml +1 -1
  65. package/examples/templates/react-react/remote/package.json +1 -1
  66. package/examples/templates/react-react/remote/src/application.tsx +11 -0
  67. package/examples/templates/react-react/remote/src/main.tsx +3 -10
  68. package/examples/templates/react-react/scripts/prod.mjs +101 -0
  69. package/examples/templates/showcase/README.md +35 -7
  70. package/examples/templates/showcase/package.json +2 -1
  71. package/examples/templates/showcase/pnpm-lock.yaml +11 -11
  72. package/examples/templates/showcase/pnpm-workspace.yaml +1 -1
  73. package/examples/templates/showcase/react-host/package.json +1 -1
  74. package/examples/templates/showcase/react-host/src/application.tsx +28 -0
  75. package/examples/templates/showcase/react-host/src/demo-log.ts +5 -8
  76. package/examples/templates/showcase/react-host/src/main.tsx +2 -33
  77. package/examples/templates/showcase/react-host/src/routing.ts +2 -2
  78. package/examples/templates/showcase/react-remote/fulgurjs.config.ts +1 -1
  79. package/examples/templates/showcase/react-remote/package.json +1 -1
  80. package/examples/templates/showcase/react-remote/src/ChildLayout.tsx +3 -2
  81. package/examples/templates/showcase/react-remote/src/{bridge.tsx → application.tsx} +21 -21
  82. package/examples/templates/showcase/react-remote/src/child-bus.ts +23 -23
  83. package/examples/templates/showcase/react-remote/src/main.tsx +2 -18
  84. package/examples/templates/showcase/react-remote/src/pages/Locked.tsx +2 -1
  85. package/examples/templates/showcase/react-remote/src/pages/OrderDetail.tsx +2 -1
  86. package/examples/templates/showcase/react-remote/src/pages/OrderList.tsx +2 -1
  87. package/examples/templates/showcase/scripts/prod.mjs +101 -0
  88. package/examples/templates/showcase/vue-host/package.json +1 -1
  89. package/examples/templates/showcase/vue-host/src/application.ts +28 -0
  90. package/examples/templates/showcase/vue-host/src/demo-log.ts +4 -7
  91. package/examples/templates/showcase/vue-host/src/main.ts +2 -30
  92. package/examples/templates/showcase/vue-host/src/routing.ts +2 -2
  93. package/examples/templates/showcase/vue-remote/fulgurjs.config.ts +1 -1
  94. package/examples/templates/showcase/vue-remote/package.json +1 -1
  95. package/examples/templates/showcase/vue-remote/src/ChildLayout.vue +3 -2
  96. package/examples/templates/showcase/vue-remote/src/{bridge.ts → application.ts} +10 -13
  97. package/examples/templates/showcase/vue-remote/src/child-bus.ts +23 -23
  98. package/examples/templates/showcase/vue-remote/src/main.ts +2 -16
  99. package/examples/templates/showcase/vue-remote/src/pages/Locked.vue +2 -1
  100. package/examples/templates/showcase/vue-remote/src/pages/OrderDetail.vue +2 -1
  101. package/examples/templates/showcase/vue-remote/src/pages/OrderList.vue +2 -1
  102. package/examples/templates/vue-host-react-remote/README.md +24 -0
  103. package/examples/templates/vue-host-react-remote/package.json +2 -1
  104. package/examples/templates/vue-host-react-remote/pnpm-lock.yaml +7 -7
  105. package/examples/templates/vue-host-react-remote/pnpm-workspace.yaml +1 -1
  106. package/examples/templates/vue-host-react-remote/react-remote/README.md +17 -17
  107. package/examples/templates/vue-host-react-remote/react-remote/fulgurjs.config.ts +2 -2
  108. package/examples/templates/vue-host-react-remote/react-remote/package.json +1 -1
  109. package/examples/templates/vue-host-react-remote/react-remote/src/{bridge.tsx → application.tsx} +13 -24
  110. package/examples/templates/vue-host-react-remote/react-remote/src/main.tsx +2 -7
  111. package/examples/templates/vue-host-react-remote/scripts/prod.mjs +101 -0
  112. package/examples/templates/vue-host-react-remote/vue-host/package.json +1 -1
  113. package/examples/templates/vue-host-react-remote/vue-host/src/application.ts +5 -0
  114. package/examples/templates/vue-host-react-remote/vue-host/src/main.ts +2 -4
  115. package/examples/templates/vue-vue/README.md +25 -1
  116. package/examples/templates/vue-vue/host/package.json +1 -1
  117. package/examples/templates/vue-vue/host/src/application.ts +54 -0
  118. package/examples/templates/vue-vue/host/src/main.ts +3 -50
  119. package/examples/templates/vue-vue/package.json +2 -1
  120. package/examples/templates/vue-vue/pnpm-lock.yaml +7 -7
  121. package/examples/templates/vue-vue/pnpm-workspace.yaml +1 -1
  122. package/examples/templates/vue-vue/remote/package.json +1 -1
  123. package/examples/templates/vue-vue/remote/src/application.ts +6 -0
  124. package/examples/templates/vue-vue/remote/src/main.ts +3 -5
  125. package/examples/templates/vue-vue/scripts/prod.mjs +101 -0
  126. package/package.json +14 -9
  127. package/examples/templates/react-host-vue-remote/react-host/src/fulgurjs/types/bridge-vue-remote/metadata.json +0 -15
  128. package/examples/templates/react-host-vue-remote/react-host/src/fulgurjs/types/bridge-vue-remote/modules.d.ts +0 -14
  129. package/examples/templates/react-host-vue-remote/react-host/src/fulgurjs/types/bridge-vue-remote/registry.d.ts +0 -10
  130. package/examples/templates/react-host-vue-remote/vue-remote/src/bridge.ts +0 -57
  131. package/examples/templates/showcase/react-host/src/fulgurjs/types/vue-remote/metadata.json +0 -16
  132. package/examples/templates/showcase/react-host/src/fulgurjs/types/vue-remote/modules.d.ts +0 -71
  133. package/examples/templates/showcase/react-host/src/fulgurjs/types/vue-remote/registry.d.ts +0 -10
  134. package/examples/templates/showcase/vue-host/src/fulgurjs/types/react-remote/metadata.json +0 -16
  135. package/examples/templates/showcase/vue-host/src/fulgurjs/types/react-remote/modules.d.ts +0 -79
  136. package/examples/templates/showcase/vue-host/src/fulgurjs/types/react-remote/registry.d.ts +0 -10
  137. package/examples/templates/vue-host-react-remote/vue-host/src/fulgurjs/types/bridge-react-remote/metadata.json +0 -16
  138. package/examples/templates/vue-host-react-remote/vue-host/src/fulgurjs/types/bridge-react-remote/modules.d.ts +0 -10
  139. package/examples/templates/vue-host-react-remote/vue-host/src/fulgurjs/types/bridge-react-remote/registry.d.ts +0 -10
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/bridge-app-vue.ts
21
21
  var bridge_app_vue_exports = {};
22
22
  __export(bridge_app_vue_exports, {
23
+ defineApplication: () => defineApplication,
23
24
  defineBridgeApp: () => defineBridgeApp
24
25
  });
25
26
  module.exports = __toCommonJS(bridge_app_vue_exports);
@@ -262,12 +263,102 @@ async function installVueBridgeRouter(app, router, ctx) {
262
263
  return connection;
263
264
  }
264
265
 
266
+ // src/application-core.ts
267
+ function waitForStart(result, signal) {
268
+ return new Promise((resolve, reject) => {
269
+ let settled = false;
270
+ const finish = (failed, error) => {
271
+ if (settled) return;
272
+ settled = true;
273
+ signal.removeEventListener("abort", abort);
274
+ if (failed) reject(error);
275
+ else resolve();
276
+ };
277
+ const abort = () => {
278
+ const error = new Error("\u5E94\u7528\u542F\u52A8\u5DF2\u53D6\u6D88\u3002");
279
+ error.name = "AbortError";
280
+ finish(true, error);
281
+ };
282
+ Promise.resolve(result).then(() => finish(false), (error) => finish(true, error));
283
+ signal.addEventListener("abort", abort, { once: true });
284
+ if (signal.aborted) abort();
285
+ });
286
+ }
287
+ function createApplication(bridge, standalone) {
288
+ const entries = /* @__PURE__ */ new WeakMap();
289
+ const blocked = /* @__PURE__ */ new WeakSet();
290
+ const stop = (el) => {
291
+ const entry = entries.get(el);
292
+ if (!entry) {
293
+ try {
294
+ bridge.unmount(el);
295
+ } catch (error) {
296
+ blocked.add(el);
297
+ throw error;
298
+ }
299
+ return;
300
+ }
301
+ entry.controller.abort();
302
+ try {
303
+ standalone.unmount(el);
304
+ entries.delete(el);
305
+ } catch (error) {
306
+ entry.blocked = true;
307
+ blocked.add(el);
308
+ throw error;
309
+ }
310
+ };
311
+ return {
312
+ ...bridge.routing ? { routing: bridge.routing } : {},
313
+ mount(el, props, options) {
314
+ if (entries.has(el) || blocked.has(el)) throw new Error("\u8BE5\u5BB9\u5668\u5DF2\u6709\u72EC\u7ACB\u5E94\u7528\u6216\u5378\u8F7D\u5931\u8D25\u7684\u5B9E\u4F8B\uFF1B\u5148\u6B63\u5E38\u5378\u8F7D\uFF0C\u5378\u8F7D\u5931\u8D25\u65F6\u6574\u9875\u5237\u65B0\u3002");
315
+ return bridge.mount(el, props, options);
316
+ },
317
+ unmount: stop,
318
+ async start(target, ...args) {
319
+ const el = typeof target === "string" ? document.querySelector(target) : target;
320
+ const ElementClass = el?.ownerDocument.defaultView?.HTMLElement;
321
+ if (!ElementClass || !(el instanceof ElementClass)) throw new Error(`\u5E94\u7528\u6302\u8F7D\u5BB9\u5668\u4E0D\u5B58\u5728\u6216\u4E0D\u662F HTMLElement\uFF1A${typeof target === "string" ? target : "target"}`);
322
+ if (entries.has(el) || blocked.has(el)) throw new Error("\u8BE5\u5BB9\u5668\u5DF2\u6709\u72EC\u7ACB\u5E94\u7528\u6216\u5378\u8F7D\u5931\u8D25\u7684\u5B9E\u4F8B\uFF1B\u4E0D\u80FD\u91CD\u590D start\u3002");
323
+ const entry = { controller: new AbortController(), blocked: false };
324
+ entries.set(el, entry);
325
+ try {
326
+ await waitForStart(standalone.mount(el, { ...args[0] ?? {} }, { signal: entry.controller.signal }), entry.controller.signal);
327
+ if (entry.controller.signal.aborted || entries.get(el) !== entry) {
328
+ const error = new Error("\u5E94\u7528\u542F\u52A8\u5DF2\u53D6\u6D88\uFF0C\u8FDF\u5230\u7684\u521D\u59CB\u5316\u7ED3\u679C\u4E0D\u4F1A\u91CD\u65B0\u6302\u8F7D\u3002");
329
+ error.name = "AbortError";
330
+ throw error;
331
+ }
332
+ } catch (error) {
333
+ if (entries.get(el) === entry && !entry.blocked) entries.delete(el);
334
+ entry.controller.abort();
335
+ throw error;
336
+ }
337
+ return { element: el, unmount() {
338
+ if (entries.get(el) === entry) stop(el);
339
+ } };
340
+ }
341
+ };
342
+ }
343
+
265
344
  // src/bridge-app-vue.ts
266
345
  var appsByEl = /* @__PURE__ */ new WeakMap();
267
346
  function isAppSetup(result) {
268
347
  return !!result && typeof result === "object" && "app" in result && "router" in result;
269
348
  }
270
349
  function defineBridgeApp(factory, options = {}) {
350
+ return createVueAppContract(factory, options, "bridge");
351
+ }
352
+ function defineApplication(factory, options = {}) {
353
+ const contract = (mode) => createVueAppContract((props, ctx) => {
354
+ const context = { ...ctx, mode, signal: ctx.signal };
355
+ if (mode === "bridge") markBridgeMount(context);
356
+ return factory(props, context);
357
+ }, options, mode, true);
358
+ return createApplication(contract("bridge"), contract("standalone"));
359
+ }
360
+ function createVueAppContract(factory, options, mode, localRouter = false) {
361
+ const owner = /* @__PURE__ */ Symbol("vue-application");
271
362
  const attach = (el, app, instance) => {
272
363
  if (!app || typeof app.mount !== "function" || typeof app.unmount !== "function") {
273
364
  throw new Error(
@@ -275,7 +366,7 @@ function defineBridgeApp(factory, options = {}) {
275
366
  );
276
367
  }
277
368
  instance.app = app;
278
- markBridgeMount(app);
369
+ if (mode === "bridge") markBridgeMount(app);
279
370
  try {
280
371
  app.mount(el);
281
372
  } catch (e) {
@@ -288,7 +379,7 @@ function defineBridgeApp(factory, options = {}) {
288
379
  instance.mounted = true;
289
380
  };
290
381
  return {
291
- ...options.routing ? { routing: { protocol: 1 } } : {},
382
+ ...mode === "bridge" && options.routing ? { routing: { protocol: 1 } } : {},
292
383
  // 同步工厂保持同步语义(容器占用/工厂抛错同步抛,BN03/BN02 口径不变);
293
384
  // Promise 工厂(URL 同步初始路由准备)走异步续体:挂起期间作废(signal aborted)
294
385
  // 则结果丢弃不落挂(迟到初始化不得复活,BN06 同源语义)。
@@ -297,21 +388,27 @@ function defineBridgeApp(factory, options = {}) {
297
388
  throw new Error("\u540C\u4E00\u5BB9\u5668 el \u5DF2\u6302\u8F7D\u672C\u6865\u63A5\u5E94\u7528\uFF08\u5BB9\u5668\u5DF2\u88AB\u5360\u7528\uFF09\u3002\u540C\u4E00\u5BB9\u5668\u672A\u5378\u8F7D\u524D\u91CD\u590D mount \u662F\u5951\u7EA6\u8FDD\u4F8B\u2014\u2014\u5148 unmount \u518D mount\u3002");
298
389
  }
299
390
  const snapshot = { ...props ?? {} };
300
- const ctx = { signal: mountOptions?.signal, routing: mountOptions?.routing };
301
- markBridgeMount(ctx);
302
391
  const controller = new AbortController();
392
+ const ctx = { signal: controller.signal, routing: mountOptions?.routing };
393
+ if (mode === "bridge") markBridgeMount(ctx);
303
394
  const abort = () => controller.abort();
304
395
  mountOptions?.signal?.addEventListener("abort", abort, { once: true });
305
396
  if (mountOptions?.signal?.aborted) controller.abort();
306
397
  const instance = {
398
+ owner,
307
399
  mounted: false,
308
400
  controller,
309
401
  removeAbortListener: () => mountOptions?.signal?.removeEventListener("abort", abort)
310
402
  };
403
+ controller.signal.addEventListener("abort", () => {
404
+ if (!instance.mounted) instance.cleanupPending?.();
405
+ }, { once: true });
311
406
  appsByEl.set(el, instance);
312
407
  const active = () => appsByEl.get(el) === instance && !controller.signal.aborted;
313
408
  const fail = (error) => {
314
409
  instance.connection?.dispose();
410
+ instance.cleanupPending?.();
411
+ instance.cleanupPending = void 0;
315
412
  instance.removeAbortListener();
316
413
  controller.abort();
317
414
  if (appsByEl.get(el) === instance) appsByEl.delete(el);
@@ -321,19 +418,41 @@ function defineBridgeApp(factory, options = {}) {
321
418
  if (!active()) return;
322
419
  try {
323
420
  if (isAppSetup(result)) {
324
- if (!options.routing) {
421
+ if (mode === "bridge" && !options.routing && !localRouter) {
325
422
  throw new Error("defineBridgeApp \u8FD4\u56DE { app, router } \u65F6\u5FC5\u987B\u58F0\u660E { routing: true }\uFF1Brouter \u5E94\u4F7F\u7528 createMemoryHistory()\uFF0C\u4E0D\u8981\u63D0\u524D app.use(router)\u3002");
326
423
  }
327
- markBridgeMount(result.app);
328
- instance.connection = await installVueBridgeRouter(result.app, result.router, {
329
- routing: ctx.routing,
330
- signal: controller.signal
331
- });
424
+ if (mode === "bridge" && options.routing) {
425
+ markBridgeMount(result.app);
426
+ instance.connection = await installVueBridgeRouter(result.app, result.router, {
427
+ routing: ctx.routing,
428
+ signal: controller.signal
429
+ });
430
+ } else {
431
+ const router = result.router;
432
+ if (typeof router.install !== "function" || typeof router.isReady !== "function") {
433
+ throw new Error("\u672C\u5730\u8DEF\u7531\u88C5\u914D\u5FC5\u987B\u8FD4\u56DE\u5B9E\u9645 vue-router \u5B9E\u4F8B\uFF1B\u4E0D\u8981\u8FD4\u56DE\u5BFC\u822A\u7AEF\u53E3\u6216\u5DF2\u5B89\u88C5\u5230\u5176\u4ED6 app \u7684 router\u3002");
434
+ }
435
+ result.app.use(router);
436
+ const history = router.options?.history;
437
+ let cleaned = false;
438
+ instance.cleanupPending = () => {
439
+ if (cleaned) return;
440
+ cleaned = true;
441
+ try {
442
+ history?.destroy?.();
443
+ } catch (error) {
444
+ instance.cleanupFailure = { error };
445
+ }
446
+ };
447
+ await router.isReady();
448
+ }
332
449
  if (!active()) {
333
- instance.connection.dispose();
450
+ instance.connection?.dispose();
451
+ instance.cleanupPending?.();
334
452
  return;
335
453
  }
336
454
  attach(el, result.app, instance);
455
+ instance.cleanupPending = void 0;
337
456
  } else {
338
457
  attach(el, result, instance);
339
458
  }
@@ -343,6 +462,11 @@ function defineBridgeApp(factory, options = {}) {
343
462
  }
344
463
  };
345
464
  try {
465
+ if (controller.signal.aborted) {
466
+ instance.removeAbortListener();
467
+ if (appsByEl.get(el) === instance) appsByEl.delete(el);
468
+ return;
469
+ }
346
470
  const produced = factory(snapshot, ctx);
347
471
  const thenable = produced?.then;
348
472
  if (typeof thenable === "function") {
@@ -362,11 +486,12 @@ function defineBridgeApp(factory, options = {}) {
362
486
  },
363
487
  unmount(el) {
364
488
  const instance = appsByEl.get(el);
365
- if (!instance) return;
489
+ if (!instance || instance.owner !== owner) return;
366
490
  appsByEl.delete(el);
367
491
  instance.controller.abort();
368
492
  instance.removeAbortListener();
369
493
  instance.connection?.dispose();
494
+ if (instance.cleanupFailure) throw instance.cleanupFailure.error;
370
495
  if (!instance.mounted) return;
371
496
  try {
372
497
  instance.app.unmount();
@@ -378,5 +503,6 @@ function defineBridgeApp(factory, options = {}) {
378
503
  }
379
504
  // Annotate the CommonJS export names for ESM import in node:
380
505
  0 && (module.exports = {
506
+ defineApplication,
381
507
  defineBridgeApp
382
508
  });
@@ -1,9 +1,10 @@
1
1
  import { App } from 'vue';
2
2
  import { B as BridgeChildRoute, V as VueRouterLike, a as BridgeApp } from './bridge-core-77BT1__I.cjs';
3
+ import { A as Application } from './application-core-BuhXQmLF.cjs';
3
4
  import './context.cjs';
4
5
 
5
6
  /**
6
- * Vue 子应用桥接适配(/runtime 导出 defineBridgeApp;任务书 §3.3 D1/D2)。
7
+ * Vue 子应用桥接适配(/vue 导出 defineBridgeApp 与 defineApplication)。
7
8
  *
8
9
  * 工厂返回 VueApp,或已装配业务插件与守卫的 { app, router };后者自动接线 memory
9
10
  * router、等待初始导航再安装。helper 管理挂载/卸载及每容器每代次的路由释放。
@@ -16,7 +17,7 @@ import './context.cjs';
16
17
  * - unmount 未知容器为 no-op;mount/unmount 的原始错误**原样抛出**——MFU-016 包装
17
18
  * (真实 spec + phase + cause)由宿主适配器在生命周期边界统一完成(见 bridgeHostError)。
18
19
  *
19
- * 本文件零 React:/runtime 导入图隔离由 tests/runtime-entry-graph.test.ts 守护。
20
+ * 本文件零 React:/vue 导入图隔离由 tests/runtime-entry-graph.test.ts 守护。
20
21
  */
21
22
 
22
23
  /** 工厂第二参数:挂载生命周期与路由通道(URL 同步;不混入业务 props) */
@@ -43,7 +44,7 @@ type VueBridgeAppFactory<P = Record<string, unknown>> = (props: P, ctx?: VueBrid
43
44
  * 经注册表提取为包装组件的 appProps 类型;未声明具体 P 的远程保持
44
45
  * Record<string, unknown>(诚实通用面,绝不凭空推导业务字段)。
45
46
  */
46
- type FgBridgePropsMarker<P extends Record<string, unknown>> = {
47
+ type FgBridgePropsMarker<P extends object> = {
47
48
  __fgBridgeProps?: P;
48
49
  };
49
50
  interface DefineVueBridgeAppOptions {
@@ -62,6 +63,20 @@ interface DefineVueBridgeAppOptions {
62
63
  * export default defineBridgeApp((props) => { const app = createApp(App, props); app.use(router); return app })
63
64
  * ```
64
65
  */
65
- declare function defineBridgeApp<P extends Record<string, unknown> = Record<string, unknown>>(factory: VueBridgeAppFactory<P>, options?: DefineVueBridgeAppOptions): BridgeApp & FgBridgePropsMarker<P>;
66
+ declare function defineBridgeApp<P extends object = Record<string, unknown>>(factory: VueBridgeAppFactory<P>, options?: DefineVueBridgeAppOptions): BridgeApp & FgBridgePropsMarker<P>;
67
+ interface VueApplicationContext extends VueBridgeAppContext {
68
+ mode: 'standalone' | 'bridge';
69
+ /** Always present; aborts when this application instance is stopped. */
70
+ signal: AbortSignal;
71
+ }
72
+ interface VueApplicationSetup extends VueBridgeAppSetup {
73
+ router: VueRouterLike & {
74
+ install(app: App): void;
75
+ isReady(): Promise<void>;
76
+ };
77
+ }
78
+ type VueApplicationFactory<P = Record<string, unknown>> = (props: P, context: VueApplicationContext) => App | VueApplicationSetup | Promise<App | VueApplicationSetup>;
79
+ /** One assembly function for the standalone entry and the exposed application. */
80
+ declare function defineApplication<P extends object = Record<string, unknown>>(factory: VueApplicationFactory<P>, options?: DefineVueBridgeAppOptions): Application<P>;
66
81
 
67
- export { BridgeApp, type DefineVueBridgeAppOptions, type FgBridgePropsMarker, type VueBridgeAppContext, type VueBridgeAppFactory, type VueBridgeAppSetup, defineBridgeApp };
82
+ export { BridgeApp, type DefineVueBridgeAppOptions, type FgBridgePropsMarker, type VueApplicationContext, type VueApplicationFactory, type VueApplicationSetup, type VueBridgeAppContext, type VueBridgeAppFactory, type VueBridgeAppSetup, defineApplication, defineBridgeApp };
@@ -1,9 +1,10 @@
1
1
  import { App } from 'vue';
2
2
  import { B as BridgeChildRoute, V as VueRouterLike, a as BridgeApp } from './bridge-core-CoQRVgnZ.js';
3
+ import { A as Application } from './application-core-DWI3eKme.js';
3
4
  import './context.js';
4
5
 
5
6
  /**
6
- * Vue 子应用桥接适配(/runtime 导出 defineBridgeApp;任务书 §3.3 D1/D2)。
7
+ * Vue 子应用桥接适配(/vue 导出 defineBridgeApp 与 defineApplication)。
7
8
  *
8
9
  * 工厂返回 VueApp,或已装配业务插件与守卫的 { app, router };后者自动接线 memory
9
10
  * router、等待初始导航再安装。helper 管理挂载/卸载及每容器每代次的路由释放。
@@ -16,7 +17,7 @@ import './context.js';
16
17
  * - unmount 未知容器为 no-op;mount/unmount 的原始错误**原样抛出**——MFU-016 包装
17
18
  * (真实 spec + phase + cause)由宿主适配器在生命周期边界统一完成(见 bridgeHostError)。
18
19
  *
19
- * 本文件零 React:/runtime 导入图隔离由 tests/runtime-entry-graph.test.ts 守护。
20
+ * 本文件零 React:/vue 导入图隔离由 tests/runtime-entry-graph.test.ts 守护。
20
21
  */
21
22
 
22
23
  /** 工厂第二参数:挂载生命周期与路由通道(URL 同步;不混入业务 props) */
@@ -43,7 +44,7 @@ type VueBridgeAppFactory<P = Record<string, unknown>> = (props: P, ctx?: VueBrid
43
44
  * 经注册表提取为包装组件的 appProps 类型;未声明具体 P 的远程保持
44
45
  * Record<string, unknown>(诚实通用面,绝不凭空推导业务字段)。
45
46
  */
46
- type FgBridgePropsMarker<P extends Record<string, unknown>> = {
47
+ type FgBridgePropsMarker<P extends object> = {
47
48
  __fgBridgeProps?: P;
48
49
  };
49
50
  interface DefineVueBridgeAppOptions {
@@ -62,6 +63,20 @@ interface DefineVueBridgeAppOptions {
62
63
  * export default defineBridgeApp((props) => { const app = createApp(App, props); app.use(router); return app })
63
64
  * ```
64
65
  */
65
- declare function defineBridgeApp<P extends Record<string, unknown> = Record<string, unknown>>(factory: VueBridgeAppFactory<P>, options?: DefineVueBridgeAppOptions): BridgeApp & FgBridgePropsMarker<P>;
66
+ declare function defineBridgeApp<P extends object = Record<string, unknown>>(factory: VueBridgeAppFactory<P>, options?: DefineVueBridgeAppOptions): BridgeApp & FgBridgePropsMarker<P>;
67
+ interface VueApplicationContext extends VueBridgeAppContext {
68
+ mode: 'standalone' | 'bridge';
69
+ /** Always present; aborts when this application instance is stopped. */
70
+ signal: AbortSignal;
71
+ }
72
+ interface VueApplicationSetup extends VueBridgeAppSetup {
73
+ router: VueRouterLike & {
74
+ install(app: App): void;
75
+ isReady(): Promise<void>;
76
+ };
77
+ }
78
+ type VueApplicationFactory<P = Record<string, unknown>> = (props: P, context: VueApplicationContext) => App | VueApplicationSetup | Promise<App | VueApplicationSetup>;
79
+ /** One assembly function for the standalone entry and the exposed application. */
80
+ declare function defineApplication<P extends object = Record<string, unknown>>(factory: VueApplicationFactory<P>, options?: DefineVueBridgeAppOptions): Application<P>;
66
81
 
67
- export { BridgeApp, type DefineVueBridgeAppOptions, type FgBridgePropsMarker, type VueBridgeAppContext, type VueBridgeAppFactory, type VueBridgeAppSetup, defineBridgeApp };
82
+ export { BridgeApp, type DefineVueBridgeAppOptions, type FgBridgePropsMarker, type VueApplicationContext, type VueApplicationFactory, type VueApplicationSetup, type VueBridgeAppContext, type VueBridgeAppFactory, type VueBridgeAppSetup, defineApplication, defineBridgeApp };
@@ -1,3 +1,6 @@
1
+ import {
2
+ createApplication
3
+ } from "./chunk-6OB47FSR.js";
1
4
  import {
2
5
  sameLocation
3
6
  } from "./chunk-6FMTBDIM.js";
@@ -193,6 +196,18 @@ function isAppSetup(result) {
193
196
  return !!result && typeof result === "object" && "app" in result && "router" in result;
194
197
  }
195
198
  function defineBridgeApp(factory, options = {}) {
199
+ return createVueAppContract(factory, options, "bridge");
200
+ }
201
+ function defineApplication(factory, options = {}) {
202
+ const contract = (mode) => createVueAppContract((props, ctx) => {
203
+ const context = { ...ctx, mode, signal: ctx.signal };
204
+ if (mode === "bridge") markBridgeMount(context);
205
+ return factory(props, context);
206
+ }, options, mode, true);
207
+ return createApplication(contract("bridge"), contract("standalone"));
208
+ }
209
+ function createVueAppContract(factory, options, mode, localRouter = false) {
210
+ const owner = /* @__PURE__ */ Symbol("vue-application");
196
211
  const attach = (el, app, instance) => {
197
212
  if (!app || typeof app.mount !== "function" || typeof app.unmount !== "function") {
198
213
  throw new Error(
@@ -200,7 +215,7 @@ function defineBridgeApp(factory, options = {}) {
200
215
  );
201
216
  }
202
217
  instance.app = app;
203
- markBridgeMount(app);
218
+ if (mode === "bridge") markBridgeMount(app);
204
219
  try {
205
220
  app.mount(el);
206
221
  } catch (e) {
@@ -213,7 +228,7 @@ function defineBridgeApp(factory, options = {}) {
213
228
  instance.mounted = true;
214
229
  };
215
230
  return {
216
- ...options.routing ? { routing: { protocol: 1 } } : {},
231
+ ...mode === "bridge" && options.routing ? { routing: { protocol: 1 } } : {},
217
232
  // 同步工厂保持同步语义(容器占用/工厂抛错同步抛,BN03/BN02 口径不变);
218
233
  // Promise 工厂(URL 同步初始路由准备)走异步续体:挂起期间作废(signal aborted)
219
234
  // 则结果丢弃不落挂(迟到初始化不得复活,BN06 同源语义)。
@@ -222,21 +237,27 @@ function defineBridgeApp(factory, options = {}) {
222
237
  throw new Error("\u540C\u4E00\u5BB9\u5668 el \u5DF2\u6302\u8F7D\u672C\u6865\u63A5\u5E94\u7528\uFF08\u5BB9\u5668\u5DF2\u88AB\u5360\u7528\uFF09\u3002\u540C\u4E00\u5BB9\u5668\u672A\u5378\u8F7D\u524D\u91CD\u590D mount \u662F\u5951\u7EA6\u8FDD\u4F8B\u2014\u2014\u5148 unmount \u518D mount\u3002");
223
238
  }
224
239
  const snapshot = { ...props ?? {} };
225
- const ctx = { signal: mountOptions?.signal, routing: mountOptions?.routing };
226
- markBridgeMount(ctx);
227
240
  const controller = new AbortController();
241
+ const ctx = { signal: controller.signal, routing: mountOptions?.routing };
242
+ if (mode === "bridge") markBridgeMount(ctx);
228
243
  const abort = () => controller.abort();
229
244
  mountOptions?.signal?.addEventListener("abort", abort, { once: true });
230
245
  if (mountOptions?.signal?.aborted) controller.abort();
231
246
  const instance = {
247
+ owner,
232
248
  mounted: false,
233
249
  controller,
234
250
  removeAbortListener: () => mountOptions?.signal?.removeEventListener("abort", abort)
235
251
  };
252
+ controller.signal.addEventListener("abort", () => {
253
+ if (!instance.mounted) instance.cleanupPending?.();
254
+ }, { once: true });
236
255
  appsByEl.set(el, instance);
237
256
  const active = () => appsByEl.get(el) === instance && !controller.signal.aborted;
238
257
  const fail = (error) => {
239
258
  instance.connection?.dispose();
259
+ instance.cleanupPending?.();
260
+ instance.cleanupPending = void 0;
240
261
  instance.removeAbortListener();
241
262
  controller.abort();
242
263
  if (appsByEl.get(el) === instance) appsByEl.delete(el);
@@ -246,19 +267,41 @@ function defineBridgeApp(factory, options = {}) {
246
267
  if (!active()) return;
247
268
  try {
248
269
  if (isAppSetup(result)) {
249
- if (!options.routing) {
270
+ if (mode === "bridge" && !options.routing && !localRouter) {
250
271
  throw new Error("defineBridgeApp \u8FD4\u56DE { app, router } \u65F6\u5FC5\u987B\u58F0\u660E { routing: true }\uFF1Brouter \u5E94\u4F7F\u7528 createMemoryHistory()\uFF0C\u4E0D\u8981\u63D0\u524D app.use(router)\u3002");
251
272
  }
252
- markBridgeMount(result.app);
253
- instance.connection = await installVueBridgeRouter(result.app, result.router, {
254
- routing: ctx.routing,
255
- signal: controller.signal
256
- });
273
+ if (mode === "bridge" && options.routing) {
274
+ markBridgeMount(result.app);
275
+ instance.connection = await installVueBridgeRouter(result.app, result.router, {
276
+ routing: ctx.routing,
277
+ signal: controller.signal
278
+ });
279
+ } else {
280
+ const router = result.router;
281
+ if (typeof router.install !== "function" || typeof router.isReady !== "function") {
282
+ throw new Error("\u672C\u5730\u8DEF\u7531\u88C5\u914D\u5FC5\u987B\u8FD4\u56DE\u5B9E\u9645 vue-router \u5B9E\u4F8B\uFF1B\u4E0D\u8981\u8FD4\u56DE\u5BFC\u822A\u7AEF\u53E3\u6216\u5DF2\u5B89\u88C5\u5230\u5176\u4ED6 app \u7684 router\u3002");
283
+ }
284
+ result.app.use(router);
285
+ const history = router.options?.history;
286
+ let cleaned = false;
287
+ instance.cleanupPending = () => {
288
+ if (cleaned) return;
289
+ cleaned = true;
290
+ try {
291
+ history?.destroy?.();
292
+ } catch (error) {
293
+ instance.cleanupFailure = { error };
294
+ }
295
+ };
296
+ await router.isReady();
297
+ }
257
298
  if (!active()) {
258
- instance.connection.dispose();
299
+ instance.connection?.dispose();
300
+ instance.cleanupPending?.();
259
301
  return;
260
302
  }
261
303
  attach(el, result.app, instance);
304
+ instance.cleanupPending = void 0;
262
305
  } else {
263
306
  attach(el, result, instance);
264
307
  }
@@ -268,6 +311,11 @@ function defineBridgeApp(factory, options = {}) {
268
311
  }
269
312
  };
270
313
  try {
314
+ if (controller.signal.aborted) {
315
+ instance.removeAbortListener();
316
+ if (appsByEl.get(el) === instance) appsByEl.delete(el);
317
+ return;
318
+ }
271
319
  const produced = factory(snapshot, ctx);
272
320
  const thenable = produced?.then;
273
321
  if (typeof thenable === "function") {
@@ -287,11 +335,12 @@ function defineBridgeApp(factory, options = {}) {
287
335
  },
288
336
  unmount(el) {
289
337
  const instance = appsByEl.get(el);
290
- if (!instance) return;
338
+ if (!instance || instance.owner !== owner) return;
291
339
  appsByEl.delete(el);
292
340
  instance.controller.abort();
293
341
  instance.removeAbortListener();
294
342
  instance.connection?.dispose();
343
+ if (instance.cleanupFailure) throw instance.cleanupFailure.error;
295
344
  if (!instance.mounted) return;
296
345
  try {
297
346
  instance.app.unmount();
@@ -302,5 +351,6 @@ function defineBridgeApp(factory, options = {}) {
302
351
  };
303
352
  }
304
353
  export {
354
+ defineApplication,
305
355
  defineBridgeApp
306
356
  };
@@ -1,7 +1,7 @@
1
1
  import { ReactNode, ComponentType } from 'react';
2
2
  import { AppContext } from './context.cjs';
3
3
  import { b as BridgeHostRouting } from './bridge-core-77BT1__I.cjs';
4
- import { F as FgBridgeEntry, a as FgBridgeAppProps } from './remote-types-58hdbx6x.cjs';
4
+ import { F as FgBridgeEntry, a as FgBridgeAppProps } from './remote-types-CStGOJwu.cjs';
5
5
  import { FgTypeAuto } from '@fulgurjs/federation/internal/registry.js';
6
6
 
7
7
  /**
@@ -1,7 +1,7 @@
1
1
  import { ReactNode, ComponentType } from 'react';
2
2
  import { AppContext } from './context.js';
3
3
  import { b as BridgeHostRouting } from './bridge-core-CoQRVgnZ.js';
4
- import { F as FgBridgeEntry, a as FgBridgeAppProps } from './remote-types-xf1B6_pK.js';
4
+ import { F as FgBridgeEntry, a as FgBridgeAppProps } from './remote-types-COmBhjRc.js';
5
5
  import { FgTypeAuto } from '@fulgurjs/federation/internal/registry.js';
6
6
 
7
7
  /**
@@ -1,7 +1,7 @@
1
1
  import { DefineComponent, Component } from 'vue';
2
2
  import { AppContext } from './context.cjs';
3
3
  import { b as BridgeHostRouting } from './bridge-core-77BT1__I.cjs';
4
- import { a as FgBridgeAppProps, F as FgBridgeEntry } from './remote-types-58hdbx6x.cjs';
4
+ import { a as FgBridgeAppProps, F as FgBridgeEntry } from './remote-types-CStGOJwu.cjs';
5
5
  import { FgTypeAuto } from '@fulgurjs/federation/internal/registry.js';
6
6
 
7
7
  /**
@@ -1,7 +1,7 @@
1
1
  import { DefineComponent, Component } from 'vue';
2
2
  import { AppContext } from './context.js';
3
3
  import { b as BridgeHostRouting } from './bridge-core-CoQRVgnZ.js';
4
- import { a as FgBridgeAppProps, F as FgBridgeEntry } from './remote-types-xf1B6_pK.js';
4
+ import { a as FgBridgeAppProps, F as FgBridgeEntry } from './remote-types-COmBhjRc.js';
5
5
  import { FgTypeAuto } from '@fulgurjs/federation/internal/registry.js';
6
6
 
7
7
  /**
@@ -0,0 +1,81 @@
1
+ // src/application-core.ts
2
+ function waitForStart(result, signal) {
3
+ return new Promise((resolve, reject) => {
4
+ let settled = false;
5
+ const finish = (failed, error) => {
6
+ if (settled) return;
7
+ settled = true;
8
+ signal.removeEventListener("abort", abort);
9
+ if (failed) reject(error);
10
+ else resolve();
11
+ };
12
+ const abort = () => {
13
+ const error = new Error("\u5E94\u7528\u542F\u52A8\u5DF2\u53D6\u6D88\u3002");
14
+ error.name = "AbortError";
15
+ finish(true, error);
16
+ };
17
+ Promise.resolve(result).then(() => finish(false), (error) => finish(true, error));
18
+ signal.addEventListener("abort", abort, { once: true });
19
+ if (signal.aborted) abort();
20
+ });
21
+ }
22
+ function createApplication(bridge, standalone) {
23
+ const entries = /* @__PURE__ */ new WeakMap();
24
+ const blocked = /* @__PURE__ */ new WeakSet();
25
+ const stop = (el) => {
26
+ const entry = entries.get(el);
27
+ if (!entry) {
28
+ try {
29
+ bridge.unmount(el);
30
+ } catch (error) {
31
+ blocked.add(el);
32
+ throw error;
33
+ }
34
+ return;
35
+ }
36
+ entry.controller.abort();
37
+ try {
38
+ standalone.unmount(el);
39
+ entries.delete(el);
40
+ } catch (error) {
41
+ entry.blocked = true;
42
+ blocked.add(el);
43
+ throw error;
44
+ }
45
+ };
46
+ return {
47
+ ...bridge.routing ? { routing: bridge.routing } : {},
48
+ mount(el, props, options) {
49
+ if (entries.has(el) || blocked.has(el)) throw new Error("\u8BE5\u5BB9\u5668\u5DF2\u6709\u72EC\u7ACB\u5E94\u7528\u6216\u5378\u8F7D\u5931\u8D25\u7684\u5B9E\u4F8B\uFF1B\u5148\u6B63\u5E38\u5378\u8F7D\uFF0C\u5378\u8F7D\u5931\u8D25\u65F6\u6574\u9875\u5237\u65B0\u3002");
50
+ return bridge.mount(el, props, options);
51
+ },
52
+ unmount: stop,
53
+ async start(target, ...args) {
54
+ const el = typeof target === "string" ? document.querySelector(target) : target;
55
+ const ElementClass = el?.ownerDocument.defaultView?.HTMLElement;
56
+ if (!ElementClass || !(el instanceof ElementClass)) throw new Error(`\u5E94\u7528\u6302\u8F7D\u5BB9\u5668\u4E0D\u5B58\u5728\u6216\u4E0D\u662F HTMLElement\uFF1A${typeof target === "string" ? target : "target"}`);
57
+ if (entries.has(el) || blocked.has(el)) throw new Error("\u8BE5\u5BB9\u5668\u5DF2\u6709\u72EC\u7ACB\u5E94\u7528\u6216\u5378\u8F7D\u5931\u8D25\u7684\u5B9E\u4F8B\uFF1B\u4E0D\u80FD\u91CD\u590D start\u3002");
58
+ const entry = { controller: new AbortController(), blocked: false };
59
+ entries.set(el, entry);
60
+ try {
61
+ await waitForStart(standalone.mount(el, { ...args[0] ?? {} }, { signal: entry.controller.signal }), entry.controller.signal);
62
+ if (entry.controller.signal.aborted || entries.get(el) !== entry) {
63
+ const error = new Error("\u5E94\u7528\u542F\u52A8\u5DF2\u53D6\u6D88\uFF0C\u8FDF\u5230\u7684\u521D\u59CB\u5316\u7ED3\u679C\u4E0D\u4F1A\u91CD\u65B0\u6302\u8F7D\u3002");
64
+ error.name = "AbortError";
65
+ throw error;
66
+ }
67
+ } catch (error) {
68
+ if (entries.get(el) === entry && !entry.blocked) entries.delete(el);
69
+ entry.controller.abort();
70
+ throw error;
71
+ }
72
+ return { element: el, unmount() {
73
+ if (entries.get(el) === entry) stop(el);
74
+ } };
75
+ }
76
+ };
77
+ }
78
+
79
+ export {
80
+ createApplication
81
+ };