@fulgurjs/federation 5.3.2 → 5.4.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.
- package/CHANGELOG.md +15 -0
- package/DESIGN.md +4 -0
- package/README.en.md +26 -4
- package/README.md +85 -1
- package/dist/bridge-app-react.cjs +14 -4
- package/dist/bridge-app-react.d.cts +16 -4
- package/dist/bridge-app-react.d.ts +16 -4
- package/dist/bridge-app-react.js +6 -4
- package/dist/bridge-app-vue.cjs +55 -9
- package/dist/bridge-app-vue.d.cts +25 -4
- package/dist/bridge-app-vue.d.ts +25 -4
- package/dist/bridge-app-vue.js +47 -9
- package/dist/bridge-core-BOWvVUxO.d.ts +91 -0
- package/dist/bridge-core.cjs +9 -1
- package/dist/bridge-core.d.cts +8 -1
- package/dist/bridge-core.d.ts +8 -1
- package/dist/bridge-core.js +2 -2
- package/dist/bridge-errors.cjs +55 -3
- package/dist/bridge-errors.d.cts +18 -2
- package/dist/bridge-errors.d.ts +18 -2
- package/dist/bridge-errors.js +11 -3
- package/dist/{bridge-host-react-C55RmGll.d.ts → bridge-host-react-CMVd-ym0.d.ts} +1 -1
- package/dist/bridge-host-react.cjs +324 -3
- package/dist/bridge-host-react.d.cts +2 -0
- package/dist/bridge-host-react.d.ts +2 -0
- package/dist/bridge-host-react.js +30 -4
- package/dist/{bridge-host-vue-BAxDKqGH.d.ts → bridge-host-vue-BuCGlLdS.d.ts} +1 -1
- package/dist/bridge-host-vue.cjs +335 -3
- package/dist/bridge-host-vue.js +42 -5
- package/dist/bridge-react.d.ts +5 -3
- package/dist/bridge-router-core-BxBx-reP.d.cts +44 -0
- package/dist/bridge-router-core-BxBx-reP.d.ts +44 -0
- package/dist/bridge-router-react.d.ts +96 -0
- package/dist/bridge-router-react.js +70 -0
- package/dist/bridge-router-vue.d.ts +75 -0
- package/dist/bridge-router-vue.js +73 -0
- package/dist/bridge-vue.d.ts +2 -2
- package/dist/bridge.d.ts +6 -4
- package/dist/{chunk-TOT3P7AK.js → chunk-BTJGYDHT.js} +412 -27
- package/dist/{chunk-MMXKQN2H.js → chunk-GF6KOH67.js} +39 -4
- package/dist/{chunk-DH2QMM4Y.js → chunk-JQF7KYZF.js} +50 -2
- package/dist/{chunk-X4F2BHNM.js → chunk-OXEAGRPY.js} +27 -3
- package/dist/{chunk-LE2G23E7.js → chunk-PRUYHYX2.js} +1 -1
- package/dist/chunk-WOTR2FUQ.js +266 -0
- package/dist/index.cjs +136 -15
- package/dist/index.js +136 -15
- package/dist/react.d.ts +56 -4
- package/dist/runtime-entry.d.ts +65 -4
- package/dist/runtime.js +18 -18
- package/examples/bridge/react-host/package-lock.json +107 -106
- package/examples/bridge/react-host/package.json +1 -1
- package/examples/bridge/react-remote/package-lock.json +107 -106
- package/examples/bridge/react-remote/package.json +1 -1
- package/examples/bridge/vue-host/package-lock.json +107 -106
- package/examples/bridge/vue-host/package.json +1 -1
- package/examples/bridge/vue-remote/package-lock.json +107 -106
- package/examples/bridge/vue-remote/package.json +1 -1
- package/examples/react/host/package-lock.json +3 -3
- package/examples/react/host/package.json +1 -1
- package/examples/react/remote/package-lock.json +3 -3
- package/examples/react/remote/package.json +1 -1
- package/examples/vue/host/package-lock.json +3 -3
- package/examples/vue/host/package.json +1 -1
- package/examples/vue/remote/package-lock.json +3 -3
- package/examples/vue/remote/package.json +1 -1
- package/package.json +28 -4
- package/dist/bridge-core-6uLJiMVa.d.ts +0 -42
|
@@ -252,6 +252,14 @@ function createRuntime() {
|
|
|
252
252
|
const remotes = /* @__PURE__ */ new Map();
|
|
253
253
|
const plugins = [];
|
|
254
254
|
const reportedSingletonSkews = /* @__PURE__ */ new Set();
|
|
255
|
+
const resolvedShareSnapshots = /* @__PURE__ */ new Map();
|
|
256
|
+
const shareRequestKey = (name, opts) => JSON.stringify([
|
|
257
|
+
opts.shareScope || "default",
|
|
258
|
+
opts.shareKey || name,
|
|
259
|
+
opts.requiredVersion ?? null,
|
|
260
|
+
!!opts.singleton,
|
|
261
|
+
!!opts.strictVersion
|
|
262
|
+
]);
|
|
255
263
|
const loadedModules = /* @__PURE__ */ new Map();
|
|
256
264
|
const remoteManifests = /* @__PURE__ */ new Map();
|
|
257
265
|
const stylesheetLoads = /* @__PURE__ */ new WeakMap();
|
|
@@ -472,14 +480,16 @@ function createRuntime() {
|
|
|
472
480
|
}
|
|
473
481
|
function registerPlugins2(list) {
|
|
474
482
|
plugins.push(...list);
|
|
483
|
+
resolvedShareSnapshots.clear();
|
|
475
484
|
applyPlugins();
|
|
476
485
|
}
|
|
477
|
-
|
|
486
|
+
function selectShareEntry(name, opts, readyOnly = false) {
|
|
478
487
|
const scopeName = opts.shareScope || "default";
|
|
479
488
|
const shareKey = opts.shareKey || name;
|
|
480
489
|
const scope = getScope(scopeName);
|
|
481
490
|
const byName = scope[shareKey] || {};
|
|
482
|
-
const versions = Object.keys(byName);
|
|
491
|
+
const versions = Object.keys(byName).filter((v) => !readyOnly || opts.singleton || byName[v].value !== void 0);
|
|
492
|
+
if (readyOnly && versions.length === 0) return void 0;
|
|
483
493
|
const req = opts.requiredVersion;
|
|
484
494
|
const satisfying = versions.filter(
|
|
485
495
|
(v) => req === void 0 || req === false || satisfies(v, req)
|
|
@@ -512,49 +522,121 @@ function createRuntime() {
|
|
|
512
522
|
pick = [...satisfying].sort(compareVersions).pop();
|
|
513
523
|
if (!pick) {
|
|
514
524
|
if (opts.strictVersion) {
|
|
515
|
-
const
|
|
525
|
+
const err = new FgError(
|
|
516
526
|
ErrorCodes.SHARE_STRICT_VERSION,
|
|
517
527
|
`\u73B0\u8C61\uFF1A\u5171\u4EAB\u4F5C\u7528\u57DF "${scopeName}" \u4E2D\u627E\u4E0D\u5230\u7B26\u5408\u8981\u6C42\u7684 "${shareKey}"\u3002
|
|
518
528
|
\u539F\u56E0\uFF1A\u8981\u6C42\u7248\u672C ${req}\uFF0C\u5F53\u524D\u53EF\u7528\u7248\u672C\u4E3A ${versions.join("\u3001") || "\u65E0"}\u3002
|
|
519
529
|
\u4FEE\u6CD5\uFF1A\u7EDF\u4E00\u5BBF\u4E3B\u4E0E\u8FDC\u7A0B\u7684\u4F9D\u8D56\u7248\u672C\uFF0C\u6216\u4FEE\u6B63 shared.requiredVersion\u3002`
|
|
520
530
|
);
|
|
521
|
-
emitError({ remote: shareKey, error:
|
|
522
|
-
throw
|
|
531
|
+
emitError({ remote: shareKey, error: err });
|
|
532
|
+
throw err;
|
|
523
533
|
}
|
|
524
|
-
|
|
525
|
-
const err = new FgError(
|
|
526
|
-
ErrorCodes.SHARE_NOT_AVAILABLE,
|
|
527
|
-
`\u73B0\u8C61\uFF1A\u65E0\u6CD5\u52A0\u8F7D\u5171\u4EAB\u4F9D\u8D56 "${shareKey}"\u3002
|
|
528
|
-
\u539F\u56E0\uFF1A\u4F5C\u7528\u57DF "${scopeName}" \u4E2D\u6CA1\u6709\u7B26\u5408 ${req ?? "\u4EFB\u610F\u7248\u672C"} \u8981\u6C42\u7684\u7248\u672C\uFF0C\u4E14\u672A\u914D\u7F6E\u672C\u5730\u526F\u672C\u3002
|
|
529
|
-
\u4FEE\u6CD5\uFF1A\u5728\u5BBF\u4E3B\u6216\u8FDC\u7A0B\u6CE8\u518C\u8BE5\u4F9D\u8D56\uFF0C\u6216\u4E3A shared \u914D\u7F6E\u53EF\u7528\u7684\u672C\u5730\u526F\u672C\u3002`,
|
|
530
|
-
{ shareKey, requiredVersion: req }
|
|
531
|
-
);
|
|
532
|
-
emitError({ remote: shareKey, error: err });
|
|
533
|
-
throw err;
|
|
534
|
+
return void 0;
|
|
534
535
|
}
|
|
535
536
|
}
|
|
536
|
-
|
|
537
|
+
return byName[pick];
|
|
538
|
+
}
|
|
539
|
+
function registerFallbackInstance(name, opts, instance) {
|
|
540
|
+
const localVersion = opts.localVersion;
|
|
541
|
+
if (!localVersion || instance === void 0) return;
|
|
542
|
+
const scopeName = opts.shareScope || "default";
|
|
543
|
+
const key = opts.shareKey || name;
|
|
544
|
+
const scope = getScope(scopeName);
|
|
545
|
+
const byName = Object.hasOwn(scope, key) ? scope[key] : void 0;
|
|
546
|
+
if (byName && Object.keys(byName).length > 0) {
|
|
547
|
+
try {
|
|
548
|
+
const pick = selectShareEntry(name, opts);
|
|
549
|
+
if (pick && pick.value === void 0 && pick.version === localVersion) {
|
|
550
|
+
pick.value = instance;
|
|
551
|
+
pick.loaded = true;
|
|
552
|
+
}
|
|
553
|
+
} catch {
|
|
554
|
+
}
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
registerShare2(scopeName, key, localVersion, () => Promise.resolve(instance), {
|
|
558
|
+
from: "fulgurjs:local-fallback",
|
|
559
|
+
loaded: true
|
|
560
|
+
});
|
|
561
|
+
const fresh = scope[key]?.[localVersion];
|
|
562
|
+
if (fresh) fresh.value = instance;
|
|
563
|
+
}
|
|
564
|
+
async function loadShare2(name, opts = {}) {
|
|
565
|
+
const scopeName = opts.shareScope || "default";
|
|
566
|
+
const shareKey = opts.shareKey || name;
|
|
567
|
+
const byName = getScope(scopeName)[shareKey] || {};
|
|
568
|
+
let entry = selectShareEntry(name, opts);
|
|
569
|
+
if (!entry) {
|
|
570
|
+
if (opts.fallback) {
|
|
571
|
+
const instance2 = await opts.fallback();
|
|
572
|
+
registerFallbackInstance(name, opts, instance2);
|
|
573
|
+
return instance2;
|
|
574
|
+
}
|
|
575
|
+
const err = new FgError(
|
|
576
|
+
ErrorCodes.SHARE_NOT_AVAILABLE,
|
|
577
|
+
`\u73B0\u8C61\uFF1A\u65E0\u6CD5\u52A0\u8F7D\u5171\u4EAB\u4F9D\u8D56 "${shareKey}"\u3002
|
|
578
|
+
\u539F\u56E0\uFF1A\u4F5C\u7528\u57DF "${scopeName}" \u4E2D\u6CA1\u6709\u7B26\u5408 ${opts.requiredVersion ?? "\u4EFB\u610F\u7248\u672C"} \u8981\u6C42\u7684\u7248\u672C\uFF0C\u4E14\u672A\u914D\u7F6E\u672C\u5730\u526F\u672C\u3002
|
|
579
|
+
\u4FEE\u6CD5\uFF1A\u5728\u5BBF\u4E3B\u6216\u8FDC\u7A0B\u6CE8\u518C\u8BE5\u4F9D\u8D56\uFF0C\u6216\u4E3A shared \u914D\u7F6E\u53EF\u7528\u7684\u672C\u5730\u526F\u672C\u3002`,
|
|
580
|
+
{ shareKey, requiredVersion: opts.requiredVersion }
|
|
581
|
+
);
|
|
582
|
+
emitError({ remote: shareKey, error: err });
|
|
583
|
+
throw err;
|
|
584
|
+
}
|
|
537
585
|
if (hooks.resolveShare) {
|
|
538
586
|
const picked = await hooks.resolveShare({
|
|
539
587
|
shareKey,
|
|
540
588
|
shareScope: scopeName,
|
|
541
|
-
requiredVersion:
|
|
589
|
+
requiredVersion: opts.requiredVersion,
|
|
542
590
|
picked: entry,
|
|
543
591
|
available: Object.values(byName)
|
|
544
592
|
});
|
|
545
593
|
if (picked) entry = picked;
|
|
546
594
|
}
|
|
595
|
+
if (entry.value !== void 0) {
|
|
596
|
+
resolvedShareSnapshots.set(shareRequestKey(name, opts), entry);
|
|
597
|
+
return entry.value;
|
|
598
|
+
}
|
|
547
599
|
entry.loaded = true;
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
600
|
+
if (!entry.pendingGet) {
|
|
601
|
+
try {
|
|
602
|
+
entry.pendingGet = entry.get();
|
|
603
|
+
} catch (e) {
|
|
604
|
+
entry.pendingGet = Promise.reject(e);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
const pending = entry.pendingGet;
|
|
608
|
+
let instance;
|
|
609
|
+
try {
|
|
610
|
+
instance = await pending;
|
|
611
|
+
} catch (e) {
|
|
612
|
+
if (entry.value !== void 0) {
|
|
613
|
+
resolvedShareSnapshots.set(shareRequestKey(name, opts), entry);
|
|
614
|
+
return entry.value;
|
|
615
|
+
}
|
|
616
|
+
entry.loaded = false;
|
|
617
|
+
throw e;
|
|
618
|
+
} finally {
|
|
619
|
+
if (entry.pendingGet === pending) entry.pendingGet = void 0;
|
|
620
|
+
}
|
|
621
|
+
if (entry.value === void 0) entry.value = instance;
|
|
622
|
+
resolvedShareSnapshots.set(shareRequestKey(name, opts), entry);
|
|
623
|
+
return entry.value;
|
|
551
624
|
}
|
|
552
625
|
function getLoadedShare2(name, opts = {}) {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
626
|
+
if (hooks.resolveShare) return resolvedShareSnapshots.get(shareRequestKey(name, opts))?.value;
|
|
627
|
+
return selectShareEntry(name, opts, true)?.value;
|
|
628
|
+
}
|
|
629
|
+
function pinLoadedShare2(name, opts, localVersion, instance) {
|
|
630
|
+
if (instance === void 0) return;
|
|
631
|
+
let entry;
|
|
632
|
+
try {
|
|
633
|
+
entry = selectShareEntry(name, opts);
|
|
634
|
+
} catch {
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
if (!entry || entry.value !== void 0 || entry.version !== localVersion) return;
|
|
638
|
+
entry.value = instance;
|
|
639
|
+
entry.loaded = true;
|
|
558
640
|
}
|
|
559
641
|
function sanitizeUrl(u) {
|
|
560
642
|
try {
|
|
@@ -986,6 +1068,7 @@ ${hints.join("\n")}`,
|
|
|
986
1068
|
registerPlugins: registerPlugins2,
|
|
987
1069
|
loadShare: loadShare2,
|
|
988
1070
|
getLoadedShare: getLoadedShare2,
|
|
1071
|
+
pinLoadedShare: pinLoadedShare2,
|
|
989
1072
|
loadRemote: loadRemote2,
|
|
990
1073
|
getContainer: getContainer2,
|
|
991
1074
|
preloadRemote: preloadRemote2,
|
|
@@ -1007,6 +1090,7 @@ var registerRemote = runtime.registerRemote;
|
|
|
1007
1090
|
var registerPlugins = runtime.registerPlugins;
|
|
1008
1091
|
var loadShare = runtime.loadShare;
|
|
1009
1092
|
var getLoadedShare = runtime.getLoadedShare;
|
|
1093
|
+
var pinLoadedShare = runtime.pinLoadedShare;
|
|
1010
1094
|
var loadRemote = runtime.loadRemote;
|
|
1011
1095
|
var getContainer = runtime.getContainer;
|
|
1012
1096
|
var preloadRemote = runtime.preloadRemote;
|
|
@@ -1054,7 +1138,15 @@ var BridgeErrorCodes = {
|
|
|
1054
1138
|
/** 桥接准备或生命周期失败(details.phase = getContext | mount | unmount) */
|
|
1055
1139
|
BRIDGE_LIFECYCLE_FAILED: "MFU-016",
|
|
1056
1140
|
/** 桥接会话参数与 AppContext 不一致(受控 sessionKey 与全局会话矛盾) */
|
|
1057
|
-
BRIDGE_SESSION_MISMATCH: "MFU-017"
|
|
1141
|
+
BRIDGE_SESSION_MISMATCH: "MFU-017",
|
|
1142
|
+
/** 路由同步配置/前缀冲突(basePath 非法、同页前缀冲突或重叠) */
|
|
1143
|
+
ROUTING_CONFIG_INVALID: "MFU-030",
|
|
1144
|
+
/** 路由协议缺失/通道失效(子应用未声明 routing 协议,或已销毁通道被再次使用) */
|
|
1145
|
+
ROUTING_PROTOCOL_MISSING: "MFU-031",
|
|
1146
|
+
/** 非法导航(目标越界前缀、非法 go 参数、失效实例的请求) */
|
|
1147
|
+
ROUTING_NAVIGATION_INVALID: "MFU-032",
|
|
1148
|
+
/** 路由准备/同步失败(重定向循环、子应用路由准备失败且已阻止错误页面显示) */
|
|
1149
|
+
ROUTING_SYNC_FAILED: "MFU-033"
|
|
1058
1150
|
};
|
|
1059
1151
|
function invalidBridgeContractError(spec, mod) {
|
|
1060
1152
|
const actual = mod === null ? "null" : typeof mod;
|
|
@@ -1111,6 +1203,42 @@ function invalidSessionKeyError(spec, value) {
|
|
|
1111
1203
|
{ spec, value: String(value) }
|
|
1112
1204
|
);
|
|
1113
1205
|
}
|
|
1206
|
+
function routingConfigError(spec, reason) {
|
|
1207
|
+
return new FgError(
|
|
1208
|
+
BridgeErrorCodes.ROUTING_CONFIG_INVALID,
|
|
1209
|
+
`\u73B0\u8C61\uFF1A\u6865\u63A5\u5E94\u7528 "${spec}" \u7684 URL \u540C\u6B65\u914D\u7F6E\u65E0\u6CD5\u542F\u7528\u3002
|
|
1210
|
+
\u539F\u56E0\uFF1A${reason}
|
|
1211
|
+
\u4FEE\u6CD5\uFF1A\u4FEE\u6B63 routing.basePath \u4E3A\u5BBF\u4E3B\u8DEF\u7531\u89C6\u89D2\u7684\u9759\u6001\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u5982 "/approval"\uFF09\uFF0C\u5E76\u4FDD\u8BC1\u540C\u9875\u5404\u540C\u6B65\u5B9E\u4F8B\u524D\u7F00\u4E92\u4E0D\u91CD\u53E0\uFF1B\u5BBF\u4E3B\u8DEF\u7531\u9700\u58F0\u660E\u5BF9\u5E94\u7684\u540E\u7F00\u5339\u914D\uFF08Vue "/approval/:pathMatch(.*)*"\u3001React "/approval/*"\uFF09\u3002`,
|
|
1212
|
+
{ spec }
|
|
1213
|
+
);
|
|
1214
|
+
}
|
|
1215
|
+
function routingProtocolError(spec, reason) {
|
|
1216
|
+
return new FgError(
|
|
1217
|
+
BridgeErrorCodes.ROUTING_PROTOCOL_MISSING,
|
|
1218
|
+
`\u73B0\u8C61\uFF1A\u6865\u63A5\u5E94\u7528 "${spec}" \u7684 URL \u540C\u6B65\u901A\u9053\u4E0D\u53EF\u7528\u3002
|
|
1219
|
+
\u539F\u56E0\uFF1A${reason}
|
|
1220
|
+
\u4FEE\u6CD5\uFF1A\u5B50\u5E94\u7528\u4EE5 defineBridgeApp(\u5DE5\u5382, { routing: true }) \u58F0\u660E\u8DEF\u7531\u534F\u8BAE\u5E76\u5728\u5DE5\u5382\u7B2C\u4E8C\u53C2\u6570\u63A5\u6536 { signal, routing } \u63A5\u7EBF\u53D7\u63A7\u8DEF\u7531\uFF1B\u901A\u9053\u968F\u6302\u8F7D\u751F\u547D\u5468\u671F\u521B\u5EFA\uFF0C\u9500\u6BC1\u540E\u4E0D\u5F97\u590D\u7528\uFF08\u91CD\u6302\u4F1A\u5F97\u5230\u65B0\u901A\u9053\uFF09\u3002`,
|
|
1221
|
+
{ spec }
|
|
1222
|
+
);
|
|
1223
|
+
}
|
|
1224
|
+
function routingNavigationError(spec, reason) {
|
|
1225
|
+
return new FgError(
|
|
1226
|
+
BridgeErrorCodes.ROUTING_NAVIGATION_INVALID,
|
|
1227
|
+
`\u73B0\u8C61\uFF1A\u6865\u63A5\u5E94\u7528 "${spec}" \u7684\u4E00\u6B21\u5BFC\u822A\u8BF7\u6C42\u88AB\u62D2\u7EDD\u3002
|
|
1228
|
+
\u539F\u56E0\uFF1A${reason}
|
|
1229
|
+
\u4FEE\u6CD5\uFF1A\u5B50\u5E94\u7528\u5BFC\u822A\u76EE\u6807\u5FC5\u987B\u4F4D\u4E8E\u81EA\u8EAB basePath \u524D\u7F00\u5185\uFF08\u8DE8\u524D\u7F00\u8BF7\u7528\u5BBF\u4E3B\u83DC\u5355/\u5BBF\u4E3B\u80FD\u529B\uFF09\uFF1Bgo \u53C2\u6570\u4E3A\u6709\u9650\u6574\u6570\u4E14 |delta| \u2264 50\u3002`,
|
|
1230
|
+
{ spec }
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
function routingSyncError(spec, reason, chain) {
|
|
1234
|
+
return new FgError(
|
|
1235
|
+
BridgeErrorCodes.ROUTING_SYNC_FAILED,
|
|
1236
|
+
`\u73B0\u8C61\uFF1A\u6865\u63A5\u5E94\u7528 "${spec}" \u7684 URL \u540C\u6B65\u5728\u91CD\u5B9A\u5411\u94FE\u4E0A\u8D85\u51FA\u4E0A\u9650\uFF08${chain.length} \u6B21\uFF09\u3002
|
|
1237
|
+
\u539F\u56E0\uFF1A${reason}
|
|
1238
|
+
\u4FEE\u6CD5\uFF1A\u68C0\u67E5\u5B50\u5E94\u7528\u8DEF\u7531\u7684\u91CD\u5B9A\u5411\u89C4\u5219\u662F\u5426\u4E92\u76F8\u6210\u73AF\uFF1B\u540C\u6B65\u91CD\u5B9A\u5411\u4F7F\u7528 replace \u4E14\u4E0D\u5F97\u5BF9\u540C\u4E00\u4F4D\u7F6E\u91CD\u590D\u53D1\u8D77\u3002\u76EE\u6807\u94FE\uFF1A${chain.join(" \u2192 ")}\u3002`,
|
|
1239
|
+
{ spec, chain: [...chain] }
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1114
1242
|
|
|
1115
1243
|
// src/bridge-core.ts
|
|
1116
1244
|
function assertBridgeContract(spec, mod) {
|
|
@@ -1215,6 +1343,261 @@ function withBridgeTimeout(p, ms, spec) {
|
|
|
1215
1343
|
});
|
|
1216
1344
|
}
|
|
1217
1345
|
|
|
1346
|
+
// src/bridge-router-core.ts
|
|
1347
|
+
var MAX_REDIRECT_PER_REQUEST = 5;
|
|
1348
|
+
var MAX_GO_DELTA = 50;
|
|
1349
|
+
function normalizeBasePath(basePath, spec) {
|
|
1350
|
+
const bad = (reason) => routingConfigError(spec, reason);
|
|
1351
|
+
if (typeof basePath !== "string" || basePath === "") throw bad("basePath \u4E0D\u80FD\u4E3A\u7A7A\u3002");
|
|
1352
|
+
if (basePath === "/") throw bad('basePath \u4E0D\u80FD\u662F\u6839 "/"\u2014\u2014\u6839\u8DEF\u5F84\u5C5E\u4E8E\u5BBF\u4E3B\u81EA\u8EAB\u9875\u9762\uFF0C\u8BF7\u4E3A\u540C\u6B65\u5B9E\u4F8B\u5206\u914D\u72EC\u7ACB\u524D\u7F00\u3002');
|
|
1353
|
+
if (!basePath.startsWith("/")) throw bad(`basePath \u5FC5\u987B\u4EE5 "/" \u5F00\u5934\uFF1A\u5F53\u524D\u4E3A "${basePath}"\u3002`);
|
|
1354
|
+
if (/[?#]/.test(basePath) || basePath.includes("://")) throw bad(`basePath \u4E0D\u80FD\u5305\u542B query/hash/\u534F\u8BAE\uFF1A\u5F53\u524D\u4E3A "${basePath}"\u3002`);
|
|
1355
|
+
if (basePath.includes("*") || basePath.includes(":")) throw bad(`basePath \u4E0D\u63A5\u53D7\u901A\u914D\u7B26\u6216\u53C2\u6570\u6A21\u677F\uFF1A\u5F53\u524D\u4E3A "${basePath}"\u3002\u8BF7\u4F7F\u7528\u9759\u6001\u7EDD\u5BF9\u8DEF\u5F84\u3002`);
|
|
1356
|
+
return basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
|
|
1357
|
+
}
|
|
1358
|
+
function matchesBasePath(hostPathname, basePath) {
|
|
1359
|
+
return hostPathname === basePath || hostPathname.startsWith(basePath + "/");
|
|
1360
|
+
}
|
|
1361
|
+
function overlapsBasePath(a, b) {
|
|
1362
|
+
return a === b || a.startsWith(b + "/") || b.startsWith(a + "/");
|
|
1363
|
+
}
|
|
1364
|
+
function toChildLocation(host, basePath) {
|
|
1365
|
+
const rest = host.pathname === basePath ? "/" : host.pathname.slice(basePath.length);
|
|
1366
|
+
return { pathname: rest || "/", search: host.search, hash: host.hash };
|
|
1367
|
+
}
|
|
1368
|
+
function toHostLocation(child, basePath, spec) {
|
|
1369
|
+
const childPath = child.pathname === "/" ? "" : child.pathname;
|
|
1370
|
+
if (childPath !== "" && !childPath.startsWith("/")) {
|
|
1371
|
+
throw routingNavigationError(spec, `\u5BFC\u822A\u76EE\u6807 pathname \u5FC5\u987B\u4EE5 "/" \u5F00\u5934\uFF1A\u5F53\u524D\u4E3A "${child.pathname}"\u3002`);
|
|
1372
|
+
}
|
|
1373
|
+
return { pathname: basePath + childPath, search: child.search, hash: child.hash };
|
|
1374
|
+
}
|
|
1375
|
+
function sameLocation(a, b) {
|
|
1376
|
+
return a.pathname === b.pathname && a.search === b.search && a.hash === b.hash;
|
|
1377
|
+
}
|
|
1378
|
+
function assertChildTargetInScope(target, basePath, spec) {
|
|
1379
|
+
if (target.pathname.includes("\0") || target.pathname.split("/").includes("..")) {
|
|
1380
|
+
throw routingNavigationError(spec, `\u5BFC\u822A\u76EE\u6807\u8BD5\u56FE\u9003\u9038\u81EA\u8EAB\u524D\u7F00\uFF1Apathname "${target.pathname}"\u3002\u8DE8\u524D\u7F00\u5BFC\u822A\u8BF7\u901A\u8FC7\u5BBF\u4E3B\u83DC\u5355\u7B49\u5BBF\u4E3B\u80FD\u529B\u5B8C\u6210\u3002`);
|
|
1381
|
+
}
|
|
1382
|
+
const host = toHostLocation(target, basePath, spec);
|
|
1383
|
+
if (!matchesBasePath(host.pathname, basePath)) {
|
|
1384
|
+
throw routingNavigationError(spec, `\u5BFC\u822A\u76EE\u6807 ${host.pathname} \u4E0D\u5728\u524D\u7F00 ${basePath} \u4E0B\u3002`);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
var activeRoutingPrefixes = /* @__PURE__ */ new Map();
|
|
1388
|
+
function acquireRoutingPrefix(basePath, spec) {
|
|
1389
|
+
for (const [active] of activeRoutingPrefixes) {
|
|
1390
|
+
if ((activeRoutingPrefixes.get(active) ?? 0) > 0 && overlapsBasePath(active, basePath)) {
|
|
1391
|
+
throw routingConfigError(spec, `\u540C\u9875\u5DF2\u6709\u5360\u7528\u524D\u7F00 "${active}" \u7684\u540C\u6B65\u5B9E\u4F8B\uFF0C\u65B0\u5B9E\u4F8B "${spec}" \u7684 basePath "${basePath}" \u4E0E\u5176\u91CD\u53E0\u3002`);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
activeRoutingPrefixes.set(basePath, (activeRoutingPrefixes.get(basePath) ?? 0) + 1);
|
|
1395
|
+
let released = false;
|
|
1396
|
+
return () => {
|
|
1397
|
+
if (released) return;
|
|
1398
|
+
released = true;
|
|
1399
|
+
activeRoutingPrefixes.set(basePath, Math.max(0, (activeRoutingPrefixes.get(basePath) ?? 1) - 1));
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
function assertBridgeRoutingProtocol(spec, contract) {
|
|
1403
|
+
const r = contract?.routing;
|
|
1404
|
+
if (!r || r.protocol !== 1) {
|
|
1405
|
+
throw routingProtocolError(
|
|
1406
|
+
spec,
|
|
1407
|
+
`\u8FDC\u7A0B\u5951\u7EA6\u672A\u58F0\u660E\u8DEF\u7531\u534F\u8BAE\uFF08\u671F\u671B routing: { protocol: 1 }\uFF0C\u5B9E\u9645 ${r === void 0 ? "\u7F3A\u5931" : `protocol=${String(r?.protocol)}`}\uFF09\u3002\u5F00\u542F URL \u540C\u6B65\u4E0D\u80FD\u9759\u9ED8\u9000\u56DE memory \u6A21\u5F0F\u3002`
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
var RoutingChannel = class {
|
|
1412
|
+
id;
|
|
1413
|
+
basePath;
|
|
1414
|
+
spec;
|
|
1415
|
+
host;
|
|
1416
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1417
|
+
current;
|
|
1418
|
+
lastConfirmed;
|
|
1419
|
+
seq = 0;
|
|
1420
|
+
inflight = null;
|
|
1421
|
+
disposed = false;
|
|
1422
|
+
active = true;
|
|
1423
|
+
releasePrefix;
|
|
1424
|
+
unsubHost;
|
|
1425
|
+
/** 连续内部 replace 计数(有界重定向检测) */
|
|
1426
|
+
redirectChain = [];
|
|
1427
|
+
redirectTimer;
|
|
1428
|
+
/** 诊断观测钩子(测试断言/诊断用) */
|
|
1429
|
+
onEvent;
|
|
1430
|
+
constructor(id, basePath, host, spec) {
|
|
1431
|
+
this.id = id;
|
|
1432
|
+
this.spec = spec;
|
|
1433
|
+
this.basePath = normalizeBasePath(basePath, spec);
|
|
1434
|
+
this.host = host;
|
|
1435
|
+
this.current = toChildLocation(host.getLocation(), this.basePath);
|
|
1436
|
+
this.lastConfirmed = { ...this.current };
|
|
1437
|
+
this.releasePrefix = acquireRoutingPrefix(this.basePath, spec);
|
|
1438
|
+
this.unsubHost = host.subscribe((loc) => this.handleHostLocation(loc));
|
|
1439
|
+
}
|
|
1440
|
+
emit(loc) {
|
|
1441
|
+
this.current = { ...loc };
|
|
1442
|
+
for (const l of [...this.listeners]) {
|
|
1443
|
+
try {
|
|
1444
|
+
l(this.current);
|
|
1445
|
+
} catch (e) {
|
|
1446
|
+
console.error("[fulgurjs] \u5B50\u5E94\u7528\u8DEF\u7531\u8BA2\u9605\u8005\u5F02\u5E38\uFF08\u5DF2\u9694\u79BB\uFF0C\u4E0D\u5F71\u54CD\u5BBF\u4E3B\uFF09\uFF1A", e);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
handleHostLocation(hostLoc) {
|
|
1451
|
+
if (this.disposed) return;
|
|
1452
|
+
if (!matchesBasePath(hostLoc.pathname, this.basePath)) {
|
|
1453
|
+
this.onEvent?.({ type: "prefix-miss", pathname: hostLoc.pathname });
|
|
1454
|
+
return;
|
|
1455
|
+
}
|
|
1456
|
+
if (!this.active) {
|
|
1457
|
+
this.onEvent?.({ type: "paused-host-loc" });
|
|
1458
|
+
return;
|
|
1459
|
+
}
|
|
1460
|
+
const child = toChildLocation(hostLoc, this.basePath);
|
|
1461
|
+
if (this.inflight && sameLocation(child, this.inflight.target)) {
|
|
1462
|
+
const { seq, resolve } = this.inflight;
|
|
1463
|
+
this.inflight = null;
|
|
1464
|
+
this.lastConfirmed = child;
|
|
1465
|
+
this.emit(child);
|
|
1466
|
+
this.onEvent?.({ type: "request-confirmed", seq });
|
|
1467
|
+
resolve({ status: "committed", location: { ...child } });
|
|
1468
|
+
return;
|
|
1469
|
+
}
|
|
1470
|
+
if (this.inflight) {
|
|
1471
|
+
const { seq, resolve } = this.inflight;
|
|
1472
|
+
this.inflight = null;
|
|
1473
|
+
this.lastConfirmed = child;
|
|
1474
|
+
this.emit(child);
|
|
1475
|
+
this.onEvent?.({ type: "request-superseded", seq });
|
|
1476
|
+
resolve({ status: "cancelled", location: { ...child } });
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
this.lastConfirmed = child;
|
|
1480
|
+
this.emit(child);
|
|
1481
|
+
this.onEvent?.({ type: "host-broadcast" });
|
|
1482
|
+
}
|
|
1483
|
+
getLocation() {
|
|
1484
|
+
return { ...this.current };
|
|
1485
|
+
}
|
|
1486
|
+
subscribe(listener) {
|
|
1487
|
+
if (this.disposed) {
|
|
1488
|
+
throw routingProtocolError(this.spec, `\u901A\u9053 ${this.id} \u5DF2\u9500\u6BC1\uFF0C\u4E0D\u80FD\u518D\u8BA2\u9605\uFF08\u65E7\u5B9E\u4F8B\u7684\u8FDF\u5230\u8BA2\u9605\u5FC5\u987B\u5931\u6548\uFF1B\u91CD\u6302\u4F1A\u5F97\u5230\u65B0\u901A\u9053\uFF09\u3002`);
|
|
1489
|
+
}
|
|
1490
|
+
this.listeners.add(listener);
|
|
1491
|
+
return () => {
|
|
1492
|
+
this.listeners.delete(listener);
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
async navigate(target, action) {
|
|
1496
|
+
if (this.disposed || !this.active) {
|
|
1497
|
+
this.onEvent?.({ type: this.disposed ? "rejected-disposed" : "rejected-inactive" });
|
|
1498
|
+
return { status: "cancelled", location: { ...this.lastConfirmed } };
|
|
1499
|
+
}
|
|
1500
|
+
assertChildTargetInScope(target, this.basePath, this.spec);
|
|
1501
|
+
if (sameLocation(target, this.lastConfirmed)) {
|
|
1502
|
+
this.onEvent?.({ type: "noop" });
|
|
1503
|
+
return { status: "committed", location: { ...this.lastConfirmed } };
|
|
1504
|
+
}
|
|
1505
|
+
if (action === "replace") {
|
|
1506
|
+
this.redirectChain.push(target.pathname + target.search + target.hash);
|
|
1507
|
+
} else {
|
|
1508
|
+
this.redirectChain = [];
|
|
1509
|
+
}
|
|
1510
|
+
if (this.redirectTimer) clearTimeout(this.redirectTimer);
|
|
1511
|
+
this.redirectTimer = setTimeout(() => {
|
|
1512
|
+
this.redirectChain = [];
|
|
1513
|
+
}, 1e3);
|
|
1514
|
+
if (this.redirectChain.length > MAX_REDIRECT_PER_REQUEST) {
|
|
1515
|
+
const chain = [...this.redirectChain];
|
|
1516
|
+
this.redirectChain = [];
|
|
1517
|
+
throw routingSyncError(this.spec, "\u540C\u4E00\u901A\u9053\u7684\u8FDE\u7EED replace \u91CD\u5B9A\u5411\u8D85\u8FC7\u4E0A\u9650\uFF08\u7591\u4F3C\u5B50\u5E94\u7528\u8DEF\u7531\u4E92\u76F8\u6210\u73AF\uFF09\u3002", chain);
|
|
1518
|
+
}
|
|
1519
|
+
if (this.inflight) {
|
|
1520
|
+
const prev = this.inflight;
|
|
1521
|
+
await new Promise((resolve) => {
|
|
1522
|
+
const timer = setInterval(() => {
|
|
1523
|
+
if (this.inflight !== prev) {
|
|
1524
|
+
clearInterval(timer);
|
|
1525
|
+
resolve();
|
|
1526
|
+
}
|
|
1527
|
+
}, 0);
|
|
1528
|
+
});
|
|
1529
|
+
if (this.disposed || !this.active) {
|
|
1530
|
+
return { status: "cancelled", location: { ...this.lastConfirmed } };
|
|
1531
|
+
}
|
|
1532
|
+
if (sameLocation(target, this.lastConfirmed)) {
|
|
1533
|
+
return { status: "committed", location: { ...this.lastConfirmed } };
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
const seq = ++this.seq;
|
|
1537
|
+
this.onEvent?.({ type: "request-start", seq, target: { ...target }, action });
|
|
1538
|
+
return new Promise((resolve) => {
|
|
1539
|
+
this.inflight = { seq, target: { ...target }, resolve };
|
|
1540
|
+
this.host.navigate(toHostLocation(target, this.basePath, this.spec), action).then((result) => {
|
|
1541
|
+
if (!this.inflight || this.inflight.seq !== seq) return;
|
|
1542
|
+
if (this.disposed || !this.active) {
|
|
1543
|
+
this.inflight = null;
|
|
1544
|
+
resolve({ status: "cancelled", location: { ...this.lastConfirmed } });
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
this.inflight = null;
|
|
1548
|
+
if (result.status === "committed") {
|
|
1549
|
+
const child = toChildLocation(result.location, this.basePath);
|
|
1550
|
+
this.lastConfirmed = child;
|
|
1551
|
+
this.emit(child);
|
|
1552
|
+
} else {
|
|
1553
|
+
this.emit({ ...this.lastConfirmed });
|
|
1554
|
+
}
|
|
1555
|
+
this.onEvent?.({ type: "host-verdict", seq, status: result.status });
|
|
1556
|
+
resolve(
|
|
1557
|
+
result.status === "committed" ? { status: "committed", location: { ...this.lastConfirmed } } : { status: "cancelled", location: { ...this.lastConfirmed } }
|
|
1558
|
+
);
|
|
1559
|
+
}).catch(() => {
|
|
1560
|
+
if (this.inflight?.seq === seq) {
|
|
1561
|
+
this.inflight = null;
|
|
1562
|
+
this.onEvent?.({ type: "host-error", seq });
|
|
1563
|
+
this.emit({ ...this.lastConfirmed });
|
|
1564
|
+
resolve({ status: "cancelled", location: { ...this.lastConfirmed } });
|
|
1565
|
+
}
|
|
1566
|
+
});
|
|
1567
|
+
});
|
|
1568
|
+
}
|
|
1569
|
+
/** 委托宿主历史(有限整数);不创建第二条独立历史 */
|
|
1570
|
+
go(delta) {
|
|
1571
|
+
if (this.disposed || !this.active) return;
|
|
1572
|
+
if (typeof delta !== "number" || !Number.isInteger(delta) || Math.abs(delta) > MAX_GO_DELTA) {
|
|
1573
|
+
throw routingNavigationError(this.spec, `go \u53C2\u6570\u5FC5\u987B\u662F\u6709\u9650\u6574\u6570\uFF08|delta| \u2264 ${MAX_GO_DELTA}\uFF09\uFF1A\u5F53\u524D\u4E3A ${String(delta)}\u3002`);
|
|
1574
|
+
}
|
|
1575
|
+
this.host.go(delta);
|
|
1576
|
+
}
|
|
1577
|
+
/** KeepAlive deactivate:暂停广播与写入;通道与订阅保留(activate 后 resync) */
|
|
1578
|
+
setActive(active) {
|
|
1579
|
+
if (this.disposed) return;
|
|
1580
|
+
this.active = active;
|
|
1581
|
+
this.onEvent?.({ type: active ? "resumed" : "paused" });
|
|
1582
|
+
if (active) this.handleHostLocation(this.host.getLocation());
|
|
1583
|
+
}
|
|
1584
|
+
/** 挂载生命周期结束:清理订阅/登记/在飞请求;此后一切写入失效 */
|
|
1585
|
+
dispose() {
|
|
1586
|
+
if (this.disposed) return;
|
|
1587
|
+
this.disposed = true;
|
|
1588
|
+
if (this.redirectTimer) clearTimeout(this.redirectTimer);
|
|
1589
|
+
this.unsubHost();
|
|
1590
|
+
this.releasePrefix();
|
|
1591
|
+
if (this.inflight) {
|
|
1592
|
+
const { resolve } = this.inflight;
|
|
1593
|
+
this.inflight = null;
|
|
1594
|
+
resolve({ status: "cancelled", location: { ...this.lastConfirmed } });
|
|
1595
|
+
}
|
|
1596
|
+
this.listeners.clear();
|
|
1597
|
+
this.onEvent?.({ type: "disposed" });
|
|
1598
|
+
}
|
|
1599
|
+
};
|
|
1600
|
+
|
|
1218
1601
|
export {
|
|
1219
1602
|
loadRemote,
|
|
1220
1603
|
provideAppContext,
|
|
@@ -1225,5 +1608,7 @@ export {
|
|
|
1225
1608
|
resolveBridgeContext,
|
|
1226
1609
|
assertControlledSessionKey,
|
|
1227
1610
|
assertBridgeOptions,
|
|
1228
|
-
withBridgeTimeout
|
|
1611
|
+
withBridgeTimeout,
|
|
1612
|
+
assertBridgeRoutingProtocol,
|
|
1613
|
+
RoutingChannel
|
|
1229
1614
|
};
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
|
+
RoutingChannel,
|
|
2
3
|
acquireBridgeSession,
|
|
3
4
|
assertBridgeContract,
|
|
4
5
|
assertBridgeOptions,
|
|
6
|
+
assertBridgeRoutingProtocol,
|
|
5
7
|
assertControlledSessionKey,
|
|
6
8
|
bridgeLifecycleError,
|
|
7
9
|
provideAppContext,
|
|
8
10
|
releaseBridgeSession,
|
|
9
11
|
resolveBridgeContext,
|
|
10
12
|
withBridgeTimeout
|
|
11
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-BTJGYDHT.js";
|
|
12
14
|
|
|
13
15
|
// src/bridge-host-vue.ts
|
|
14
|
-
import { defineComponent, h, onBeforeUnmount, onMounted, ref, shallowRef, toRaw, watch } from "vue";
|
|
16
|
+
import { defineComponent, h, onActivated, onBeforeUnmount, onDeactivated, onMounted, ref, shallowRef, toRaw, watch } from "vue";
|
|
17
|
+
var assertBridgeRoutingProtocolSpec = (spec, contract) => assertBridgeRoutingProtocol(spec, contract);
|
|
18
|
+
function routingKey(routing) {
|
|
19
|
+
if (!routing) return void 0;
|
|
20
|
+
return routing.basePath + "|" + String(routing.navigation && typeof routing.navigation.navigate === "function");
|
|
21
|
+
}
|
|
15
22
|
var ERROR_STYLE = {
|
|
16
23
|
padding: "16px",
|
|
17
24
|
border: "1px solid #fde2e2",
|
|
@@ -89,7 +96,9 @@ function createVueBridgeAppWithLoader(loadRemote) {
|
|
|
89
96
|
props: {
|
|
90
97
|
appProps: { type: Object, required: false, default: void 0 },
|
|
91
98
|
// 桥接控制参数:undefined(不启用受控会话)/ null(登出态)/ 非空字符串(登录代次)
|
|
92
|
-
sessionKey: { type: null, required: false, default: void 0 }
|
|
99
|
+
sessionKey: { type: null, required: false, default: void 0 },
|
|
100
|
+
// URL 同步控制通道(独立于 appProps/Context;省略 = 原 memory 模式)
|
|
101
|
+
routing: { type: Object, required: false, default: void 0 }
|
|
93
102
|
},
|
|
94
103
|
setup(props) {
|
|
95
104
|
const status = ref("idle");
|
|
@@ -99,6 +108,8 @@ function createVueBridgeAppWithLoader(loadRemote) {
|
|
|
99
108
|
let contract;
|
|
100
109
|
let containerBlocked = false;
|
|
101
110
|
let acquiredSession;
|
|
111
|
+
let channel;
|
|
112
|
+
let genAbort;
|
|
102
113
|
const releaseAcquired = () => {
|
|
103
114
|
if (acquiredSession !== void 0) {
|
|
104
115
|
releaseBridgeSession(acquiredSession);
|
|
@@ -110,6 +121,10 @@ function createVueBridgeAppWithLoader(loadRemote) {
|
|
|
110
121
|
generation++;
|
|
111
122
|
const el = container.value;
|
|
112
123
|
releaseAcquired();
|
|
124
|
+
genAbort?.abort();
|
|
125
|
+
genAbort = void 0;
|
|
126
|
+
channel?.dispose();
|
|
127
|
+
channel = void 0;
|
|
113
128
|
if (contract && el) {
|
|
114
129
|
const c = contract;
|
|
115
130
|
contract = void 0;
|
|
@@ -151,7 +166,18 @@ function createVueBridgeAppWithLoader(loadRemote) {
|
|
|
151
166
|
if (myGeneration !== generation) return;
|
|
152
167
|
contract = assertBridgeContract(spec, mod);
|
|
153
168
|
const appPropsSource = props.appProps ? toRaw(props.appProps) : void 0;
|
|
154
|
-
|
|
169
|
+
genAbort = new AbortController();
|
|
170
|
+
let mountOptions = { signal: genAbort.signal };
|
|
171
|
+
if (props.routing) {
|
|
172
|
+
assertBridgeRoutingProtocolSpec(spec, contract);
|
|
173
|
+
const navigation = props.routing.navigation;
|
|
174
|
+
const latestLoc = navigation.getLocation();
|
|
175
|
+
if (myGeneration !== generation) return;
|
|
176
|
+
channel = new RoutingChannel(`bridge-vue:${spec}:${myGeneration}`, props.routing.basePath, navigation, spec);
|
|
177
|
+
mountOptions = { signal: genAbort.signal, routing: channel };
|
|
178
|
+
void latestLoc;
|
|
179
|
+
}
|
|
180
|
+
await contract.mount(el, { ...appPropsSource ?? {} }, mountOptions);
|
|
155
181
|
if (myGeneration !== generation) return;
|
|
156
182
|
status.value = "ready";
|
|
157
183
|
} catch (e) {
|
|
@@ -176,6 +202,15 @@ function createVueBridgeAppWithLoader(loadRemote) {
|
|
|
176
202
|
watch(() => props.sessionKey, () => {
|
|
177
203
|
start();
|
|
178
204
|
});
|
|
205
|
+
watch(() => routingKey(props.routing), (after, before) => {
|
|
206
|
+
if (after !== before) start();
|
|
207
|
+
});
|
|
208
|
+
onDeactivated(() => {
|
|
209
|
+
channel?.setActive(false);
|
|
210
|
+
});
|
|
211
|
+
onActivated(() => {
|
|
212
|
+
channel?.setActive(true);
|
|
213
|
+
});
|
|
179
214
|
onBeforeUnmount(() => {
|
|
180
215
|
invalidate();
|
|
181
216
|
});
|