@fulgurjs/federation 5.2.5 → 5.3.1
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 +23 -0
- package/DESIGN.md +7 -0
- package/README.en.md +86 -4
- package/README.md +125 -3
- package/dist/bridge-app-react.cjs +185 -0
- package/dist/bridge-app-react.d.cts +37 -0
- package/dist/bridge-app-react.d.ts +37 -0
- package/dist/bridge-app-react.js +115 -0
- package/dist/bridge-app-vue.cjs +111 -0
- package/dist/bridge-app-vue.d.cts +34 -0
- package/dist/bridge-app-vue.d.ts +34 -0
- package/dist/bridge-app-vue.js +51 -0
- package/dist/bridge-core-6uLJiMVa.d.ts +42 -0
- package/dist/bridge-core.cjs +232 -0
- package/dist/bridge-core.d.cts +51 -0
- package/dist/bridge-core.d.ts +51 -0
- package/dist/bridge-core.js +21 -0
- package/dist/bridge-errors.cjs +114 -0
- package/dist/bridge-errors.d.cts +36 -0
- package/dist/bridge-errors.d.ts +36 -0
- package/dist/bridge-errors.js +15 -0
- package/dist/bridge-host-react-C55RmGll.d.ts +35 -0
- package/dist/bridge-host-react.cjs +400 -0
- package/dist/bridge-host-react.d.cts +45 -0
- package/dist/bridge-host-react.d.ts +45 -0
- package/dist/bridge-host-react.js +183 -0
- package/dist/bridge-host-vue-BAxDKqGH.d.ts +32 -0
- package/dist/bridge-host-vue.cjs +437 -0
- package/dist/bridge-host-vue.d.cts +39 -0
- package/dist/bridge-host-vue.d.ts +39 -0
- package/dist/bridge-host-vue.js +214 -0
- package/dist/bridge-react.d.ts +12 -0
- package/dist/bridge-react.js +3 -0
- package/dist/bridge-vue.d.ts +8 -0
- package/dist/bridge-vue.js +3 -0
- package/dist/bridge.d.ts +16 -0
- package/dist/bridge.js +5 -0
- package/dist/chunk-DH2QMM4Y.js +76 -0
- package/dist/chunk-LE2G23E7.js +122 -0
- package/dist/chunk-MMXKQN2H.js +210 -0
- package/dist/chunk-OF2JCXTZ.js +15 -0
- package/dist/chunk-TOT3P7AK.js +1229 -0
- package/dist/chunk-TSYLDY6H.js +64 -0
- package/dist/chunk-X4F2BHNM.js +179 -0
- package/dist/context.js +8 -64
- package/dist/index.cjs +139 -13
- package/dist/index.js +139 -13
- package/dist/react.d.ts +47 -2
- package/dist/react.js +2 -0
- package/dist/runtime-entry.d.ts +44 -2
- package/dist/runtime-entry.js +1 -1
- package/dist/runtime.js +19 -19
- package/dist/vue.js +2 -0
- package/docs/webpack-mf-/345/257/271/347/205/247/344/270/216/347/274/272/345/217/243.md +1 -1
- package/docs//350/277/201/347/247/273/346/214/207/345/215/227.md +1 -1
- package/examples/README.en.md +20 -0
- package/examples/README.md +20 -0
- package/examples/bridge/README.md +36 -0
- package/examples/bridge/react-host/README.md +23 -0
- package/examples/bridge/react-host/fulgurjs.config.ts +20 -0
- package/examples/bridge/react-host/index.html +11 -0
- package/examples/bridge/react-host/package-lock.json +2457 -0
- package/examples/bridge/react-host/package.json +24 -0
- package/examples/bridge/react-host/src/env.d.ts +7 -0
- package/examples/bridge/react-host/src/host-session.ts +26 -0
- package/examples/bridge/react-host/src/main.tsx +62 -0
- package/examples/bridge/react-host/tsconfig.json +13 -0
- package/examples/bridge/react-host/vite.config.ts +9 -0
- package/examples/bridge/react-remote/README.md +20 -0
- package/examples/bridge/react-remote/fulgurjs.config.ts +17 -0
- package/examples/bridge/react-remote/index.html +11 -0
- package/examples/bridge/react-remote/package-lock.json +2382 -0
- package/examples/bridge/react-remote/package.json +24 -0
- package/examples/bridge/react-remote/src/bridge.tsx +66 -0
- package/examples/bridge/react-remote/src/env.d.ts +7 -0
- package/examples/bridge/react-remote/src/main.tsx +7 -0
- package/examples/bridge/react-remote/tsconfig.json +13 -0
- package/examples/bridge/react-remote/vite.config.ts +9 -0
- package/examples/bridge/vue-host/README.md +24 -0
- package/examples/bridge/vue-host/fulgurjs.config.ts +22 -0
- package/examples/bridge/vue-host/index.html +11 -0
- package/examples/bridge/vue-host/package-lock.json +1885 -0
- package/examples/bridge/vue-host/package.json +24 -0
- package/examples/bridge/vue-host/src/App.vue +70 -0
- package/examples/bridge/vue-host/src/env.d.ts +7 -0
- package/examples/bridge/vue-host/src/host-session.ts +29 -0
- package/examples/bridge/vue-host/src/main.ts +4 -0
- package/examples/bridge/vue-host/tsconfig.json +13 -0
- package/examples/bridge/vue-host/vite.config.ts +9 -0
- package/examples/bridge/vue-remote/README.md +19 -0
- package/examples/bridge/vue-remote/fulgurjs.config.ts +16 -0
- package/examples/bridge/vue-remote/index.html +11 -0
- package/examples/bridge/vue-remote/package-lock.json +1856 -0
- package/examples/bridge/vue-remote/package.json +21 -0
- package/examples/bridge/vue-remote/src/App.vue +12 -0
- package/examples/bridge/vue-remote/src/bridge.ts +57 -0
- package/examples/bridge/vue-remote/src/env.d.ts +7 -0
- package/examples/bridge/vue-remote/src/main.ts +15 -0
- package/examples/bridge/vue-remote/tsconfig.json +13 -0
- package/examples/bridge/vue-remote/vite.config.ts +9 -0
- package/package.json +43 -2
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import {
|
|
2
|
+
acquireBridgeSession,
|
|
3
|
+
assertBridgeContract,
|
|
4
|
+
assertBridgeOptions,
|
|
5
|
+
assertControlledSessionKey,
|
|
6
|
+
releaseBridgeSession,
|
|
7
|
+
resolveBridgeContext,
|
|
8
|
+
withBridgeTimeout
|
|
9
|
+
} from "./chunk-LE2G23E7.js";
|
|
10
|
+
import {
|
|
11
|
+
bridgeLifecycleError
|
|
12
|
+
} from "./chunk-DH2QMM4Y.js";
|
|
13
|
+
import {
|
|
14
|
+
provideAppContext
|
|
15
|
+
} from "./chunk-TSYLDY6H.js";
|
|
16
|
+
import "./chunk-OF2JCXTZ.js";
|
|
17
|
+
|
|
18
|
+
// src/bridge-host-vue.ts
|
|
19
|
+
import { defineComponent, h, onBeforeUnmount, onMounted, ref, shallowRef, toRaw, watch } from "vue";
|
|
20
|
+
var ERROR_STYLE = {
|
|
21
|
+
padding: "16px",
|
|
22
|
+
border: "1px solid #fde2e2",
|
|
23
|
+
borderRadius: "4px",
|
|
24
|
+
background: "#fef0f0",
|
|
25
|
+
color: "#c45656",
|
|
26
|
+
fontSize: "13px",
|
|
27
|
+
lineHeight: "1.6"
|
|
28
|
+
};
|
|
29
|
+
var BUTTON_STYLE = {
|
|
30
|
+
padding: "4px 14px",
|
|
31
|
+
marginRight: "8px",
|
|
32
|
+
border: "1px solid #c45656",
|
|
33
|
+
borderRadius: "4px",
|
|
34
|
+
background: "#c45656",
|
|
35
|
+
color: "#fff",
|
|
36
|
+
fontSize: "13px",
|
|
37
|
+
cursor: "pointer"
|
|
38
|
+
};
|
|
39
|
+
var SECONDARY_BUTTON_STYLE = {
|
|
40
|
+
padding: "4px 14px",
|
|
41
|
+
border: "1px solid #c45656",
|
|
42
|
+
borderRadius: "4px",
|
|
43
|
+
background: "#fff",
|
|
44
|
+
color: "#c45656",
|
|
45
|
+
fontSize: "13px",
|
|
46
|
+
cursor: "pointer"
|
|
47
|
+
};
|
|
48
|
+
var BridgeErrorPlaceholder = defineComponent({
|
|
49
|
+
name: "FulgurjsBridgeError",
|
|
50
|
+
props: {
|
|
51
|
+
error: { type: Object, default: void 0 },
|
|
52
|
+
retry: { type: Function, required: false, default: void 0 }
|
|
53
|
+
},
|
|
54
|
+
setup(props) {
|
|
55
|
+
const reloadPage = () => {
|
|
56
|
+
window.location.reload();
|
|
57
|
+
};
|
|
58
|
+
return () => {
|
|
59
|
+
const err = props.error;
|
|
60
|
+
const code = err?.code ?? "UNKNOWN";
|
|
61
|
+
const message = err?.message ?? String(props.error ?? "unknown error");
|
|
62
|
+
return h("div", { style: ERROR_STYLE, "data-fulgurjs-error": code }, [
|
|
63
|
+
h("p", { style: "margin:0 0 4px;font-weight:600" }, `\u6865\u63A5\u5E94\u7528\u52A0\u8F7D\u5931\u8D25\uFF08\u9519\u8BEF\u7801 ${code}\uFF09`),
|
|
64
|
+
h("p", { style: "margin:0 0 8px;word-break:break-all" }, message),
|
|
65
|
+
h("p", { style: "margin:0 0 10px" }, "\u300C\u91CD\u8BD5\u52A0\u8F7D\u300D\u5728\u5F53\u524D\u9875\u9762\u91CD\u5EFA\u6302\u8F7D\uFF1B\u82E5\u6D4F\u89C8\u5668\u5DF2\u7F13\u5B58\u5931\u8D25\u7684\u6A21\u5757\uFF0C\u8BF7\u7528\u300C\u5237\u65B0\u9875\u9762\u91CD\u8BD5\u300D\u2014\u2014\u5B83\u4F1A\u6574\u9875\u5237\u65B0\uFF08\u4FDD\u7559\u5F53\u524D\u5730\u5740\uFF09\uFF0C\u672A\u4FDD\u5B58\u7684\u9875\u9762\u72B6\u6001\u4F1A\u4E22\u5931\u3002"),
|
|
66
|
+
h("div", { style: "margin:0" }, [
|
|
67
|
+
props.retry ? h("button", {
|
|
68
|
+
key: "retry",
|
|
69
|
+
style: BUTTON_STYLE,
|
|
70
|
+
type: "button",
|
|
71
|
+
"data-fulgurjs-retry": "",
|
|
72
|
+
onClick: () => props.retry?.()
|
|
73
|
+
}, "\u91CD\u8BD5\u52A0\u8F7D") : null,
|
|
74
|
+
h("button", {
|
|
75
|
+
key: "reload",
|
|
76
|
+
style: SECONDARY_BUTTON_STYLE,
|
|
77
|
+
type: "button",
|
|
78
|
+
"data-fulgurjs-reload": "",
|
|
79
|
+
onClick: reloadPage
|
|
80
|
+
}, "\u5237\u65B0\u9875\u9762\u91CD\u8BD5")
|
|
81
|
+
])
|
|
82
|
+
]);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
function createVueBridgeAppWithLoader(loadRemote) {
|
|
87
|
+
return function createVueBridgeApp(spec, options = {}) {
|
|
88
|
+
assertBridgeOptions(`createVueBridgeApp("${spec}")`, options);
|
|
89
|
+
const componentName = "FulgurjsBridge_" + spec.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
90
|
+
return defineComponent({
|
|
91
|
+
name: componentName,
|
|
92
|
+
// 多根组件:宿主传入的 class/style 等不自动继承(v1 不提供样式透传,外观由宿主外层元素控制)
|
|
93
|
+
inheritAttrs: false,
|
|
94
|
+
props: {
|
|
95
|
+
appProps: { type: Object, required: false, default: void 0 },
|
|
96
|
+
// 桥接控制参数:undefined(不启用受控会话)/ null(登出态)/ 非空字符串(登录代次)
|
|
97
|
+
sessionKey: { type: null, required: false, default: void 0 }
|
|
98
|
+
},
|
|
99
|
+
setup(props) {
|
|
100
|
+
const status = ref("idle");
|
|
101
|
+
const error = shallowRef(void 0);
|
|
102
|
+
const container = ref(null);
|
|
103
|
+
let generation = 0;
|
|
104
|
+
let contract;
|
|
105
|
+
let containerBlocked = false;
|
|
106
|
+
let acquiredSession;
|
|
107
|
+
const releaseAcquired = () => {
|
|
108
|
+
if (acquiredSession !== void 0) {
|
|
109
|
+
releaseBridgeSession(acquiredSession);
|
|
110
|
+
acquiredSession = void 0;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const invalidate = () => {
|
|
114
|
+
if (containerBlocked) return false;
|
|
115
|
+
generation++;
|
|
116
|
+
const el = container.value;
|
|
117
|
+
releaseAcquired();
|
|
118
|
+
if (contract && el) {
|
|
119
|
+
const c = contract;
|
|
120
|
+
contract = void 0;
|
|
121
|
+
try {
|
|
122
|
+
c.unmount(el);
|
|
123
|
+
} catch (e) {
|
|
124
|
+
const err = bridgeLifecycleError("unmount", spec, e instanceof Error ? e : String(e));
|
|
125
|
+
containerBlocked = true;
|
|
126
|
+
console.error("[fulgurjs] \u6865\u63A5\u5E94\u7528\u5378\u8F7D\u5931\u8D25\uFF0C\u8BE5\u5BB9\u5668\u5DF2\u5C01\u9501\uFF08\u540C\u9875\u53EA\u80FD\u5237\u65B0\u6062\u590D\uFF09\uFF1A", err);
|
|
127
|
+
error.value = err;
|
|
128
|
+
status.value = "error";
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return true;
|
|
133
|
+
};
|
|
134
|
+
const run = async (myGeneration) => {
|
|
135
|
+
const el = container.value;
|
|
136
|
+
if (!el) return;
|
|
137
|
+
const sk = props.sessionKey;
|
|
138
|
+
status.value = "pending";
|
|
139
|
+
error.value = void 0;
|
|
140
|
+
if (sk === null) {
|
|
141
|
+
status.value = "idle";
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
assertControlledSessionKey(spec, sk);
|
|
146
|
+
const controlled = typeof sk === "string" ? sk : void 0;
|
|
147
|
+
if (controlled !== void 0 && controlled !== acquiredSession) {
|
|
148
|
+
releaseAcquired();
|
|
149
|
+
acquireBridgeSession(spec, controlled);
|
|
150
|
+
acquiredSession = controlled;
|
|
151
|
+
}
|
|
152
|
+
const resolution = resolveBridgeContext(spec, controlled, options.getContext);
|
|
153
|
+
if (resolution.provide) provideAppContext(resolution.provide);
|
|
154
|
+
const load = loadRemote(spec, { retries: options.retries });
|
|
155
|
+
const mod = options.timeout !== void 0 ? await withBridgeTimeout(load, options.timeout, spec) : await load;
|
|
156
|
+
if (myGeneration !== generation) return;
|
|
157
|
+
contract = assertBridgeContract(spec, mod);
|
|
158
|
+
const appPropsSource = props.appProps ? toRaw(props.appProps) : void 0;
|
|
159
|
+
await contract.mount(el, { ...appPropsSource ?? {} });
|
|
160
|
+
if (myGeneration !== generation) return;
|
|
161
|
+
status.value = "ready";
|
|
162
|
+
} catch (e) {
|
|
163
|
+
if (myGeneration !== generation) return;
|
|
164
|
+
error.value = e;
|
|
165
|
+
status.value = "error";
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
const start = () => {
|
|
169
|
+
const ok = invalidate();
|
|
170
|
+
if (!ok) return;
|
|
171
|
+
const myGeneration = generation;
|
|
172
|
+
void run(myGeneration);
|
|
173
|
+
};
|
|
174
|
+
const retry = () => {
|
|
175
|
+
start();
|
|
176
|
+
};
|
|
177
|
+
onMounted(() => {
|
|
178
|
+
const myGeneration = generation;
|
|
179
|
+
void run(myGeneration);
|
|
180
|
+
});
|
|
181
|
+
watch(() => props.sessionKey, () => {
|
|
182
|
+
start();
|
|
183
|
+
});
|
|
184
|
+
onBeforeUnmount(() => {
|
|
185
|
+
invalidate();
|
|
186
|
+
});
|
|
187
|
+
return () => {
|
|
188
|
+
const children = [];
|
|
189
|
+
if (status.value === "pending" && options.loadingComponent) {
|
|
190
|
+
children.push(h(options.loadingComponent, { key: "loading" }));
|
|
191
|
+
}
|
|
192
|
+
if (status.value === "error") {
|
|
193
|
+
const err = error.value;
|
|
194
|
+
if (options.errorComponent) {
|
|
195
|
+
children.push(h(options.errorComponent, { key: "error", error: err }));
|
|
196
|
+
} else {
|
|
197
|
+
children.push(h(BridgeErrorPlaceholder, { key: "error", error: err, retry: containerBlocked ? void 0 : retry }));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
children.push(h("div", {
|
|
201
|
+
key: "bridge-root",
|
|
202
|
+
ref: container,
|
|
203
|
+
"data-fulgurjs-bridge-root": spec,
|
|
204
|
+
"data-fulgurjs-bridge-status": status.value
|
|
205
|
+
}));
|
|
206
|
+
return children;
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
export {
|
|
213
|
+
createVueBridgeAppWithLoader
|
|
214
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { R as ReactBridgeAppOptions } from './bridge-host-react-C55RmGll.js';
|
|
3
|
+
export { B as BridgeErrorFallback } from './bridge-host-react-C55RmGll.js';
|
|
4
|
+
export { A as AppContext, B as BridgeApp } from './bridge-core-6uLJiMVa.js';
|
|
5
|
+
|
|
6
|
+
/** React 宿主桥接工厂:返回 `ComponentType<{ appProps: P; sessionKey?: string | null }>` */
|
|
7
|
+
declare const createReactBridgeApp: <P = Record<string, unknown>>(spec: string, options?: ReactBridgeAppOptions) => react.ComponentType<{
|
|
8
|
+
appProps?: P;
|
|
9
|
+
sessionKey?: string | null;
|
|
10
|
+
}>;
|
|
11
|
+
|
|
12
|
+
export { ReactBridgeAppOptions, createReactBridgeApp };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as vue from 'vue';
|
|
2
|
+
import { V as VueBridgeAppOptions } from './bridge-host-vue-BAxDKqGH.js';
|
|
3
|
+
export { A as AppContext, B as BridgeApp } from './bridge-core-6uLJiMVa.js';
|
|
4
|
+
|
|
5
|
+
/** Vue 宿主桥接工厂:返回 `{ appProps: P; sessionKey?: string | null }` 形态的包装组件 */
|
|
6
|
+
declare const createVueBridgeApp: <P = Record<string, unknown>>(spec: string, options?: VueBridgeAppOptions) => vue.Component;
|
|
7
|
+
|
|
8
|
+
export { VueBridgeAppOptions, createVueBridgeApp };
|
package/dist/bridge.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { R as ReactBridgeAppOptions } from './bridge-host-react-C55RmGll.js';
|
|
3
|
+
export { B as BridgeErrorFallback } from './bridge-host-react-C55RmGll.js';
|
|
4
|
+
import * as vue from 'vue';
|
|
5
|
+
import { V as VueBridgeAppOptions } from './bridge-host-vue-BAxDKqGH.js';
|
|
6
|
+
export { A as AppContext, B as BridgeApp } from './bridge-core-6uLJiMVa.js';
|
|
7
|
+
|
|
8
|
+
/** Vue 宿主桥接工厂:返回 `{ appProps: P; sessionKey?: string | null }` 形态的包装组件 */
|
|
9
|
+
declare const createVueBridgeApp: <P = Record<string, unknown>>(spec: string, options?: VueBridgeAppOptions) => vue.Component;
|
|
10
|
+
/** React 宿主桥接工厂:返回 `ComponentType<{ appProps: P; sessionKey?: string | null }>` */
|
|
11
|
+
declare const createReactBridgeApp: <P = Record<string, unknown>>(spec: string, options?: ReactBridgeAppOptions) => react.ComponentType<{
|
|
12
|
+
appProps?: P;
|
|
13
|
+
sessionKey?: string | null;
|
|
14
|
+
}>;
|
|
15
|
+
|
|
16
|
+
export { ReactBridgeAppOptions, VueBridgeAppOptions, createReactBridgeApp, createVueBridgeApp };
|
package/dist/bridge.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { loadRemote } from "./runtime.js";
|
|
2
|
+
import { createVueBridgeAppWithLoader } from "./bridge-host-vue.js";
|
|
3
|
+
import { createReactBridgeAppWithLoader } from "./bridge-host-react.js";
|
|
4
|
+
export const createVueBridgeApp = createVueBridgeAppWithLoader(loadRemote);
|
|
5
|
+
export const createReactBridgeApp = createReactBridgeAppWithLoader(loadRemote);
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FgError
|
|
3
|
+
} from "./chunk-OF2JCXTZ.js";
|
|
4
|
+
|
|
5
|
+
// src/bridge-errors.ts
|
|
6
|
+
var BridgeErrorCodes = {
|
|
7
|
+
/** 桥接契约非法(./bridge 默认导出缺 mount/unmount 或不是函数) */
|
|
8
|
+
BRIDGE_INVALID_CONTRACT: "MFU-015",
|
|
9
|
+
/** 桥接准备或生命周期失败(details.phase = getContext | mount | unmount) */
|
|
10
|
+
BRIDGE_LIFECYCLE_FAILED: "MFU-016",
|
|
11
|
+
/** 桥接会话参数与 AppContext 不一致(受控 sessionKey 与全局会话矛盾) */
|
|
12
|
+
BRIDGE_SESSION_MISMATCH: "MFU-017"
|
|
13
|
+
};
|
|
14
|
+
function invalidBridgeContractError(spec, mod) {
|
|
15
|
+
const actual = mod === null ? "null" : typeof mod;
|
|
16
|
+
const missing = [];
|
|
17
|
+
if (typeof mod?.mount !== "function") missing.push("mount");
|
|
18
|
+
if (typeof mod?.unmount !== "function") missing.push("unmount");
|
|
19
|
+
return new FgError(
|
|
20
|
+
BridgeErrorCodes.BRIDGE_INVALID_CONTRACT,
|
|
21
|
+
`\u73B0\u8C61\uFF1A\u8FDC\u7A0B\u6A21\u5757 "${spec}" \u7684\u9ED8\u8BA4\u5BFC\u51FA\u4E0D\u662F\u5408\u6CD5\u7684\u6865\u63A5\u5951\u7EA6\uFF08BridgeApp\uFF09\u3002
|
|
22
|
+
\u6839\u56E0: \u5BFC\u51FA\u503C\u4E3A ${actual}` + (missing.length ? `\uFF0C\u7F3A\u5C11\u51FD\u6570\u7C7B\u578B\u7684 ${missing.map((m) => `"${m}"`).join(" / ")} \u5BFC\u51FA\u3002` : "\u3002") + `
|
|
23
|
+
\u4FEE\u6CD5: \u8FDC\u7A0B\u4FA7\u7528 defineBridgeApp(...) \u521B\u5EFA\u5951\u7EA6\u5E76\u4F5C\u4E3A\u6A21\u5757\u9ED8\u8BA4\u5BFC\u51FA\u2014\u2014
|
|
24
|
+
Vue \u5B50\u5E94\u7528: import { defineBridgeApp } from '@fulgurjs/federation/runtime'\uFF1B
|
|
25
|
+
React \u5B50\u5E94\u7528: import { defineBridgeApp } from '@fulgurjs/federation/react'\u3002
|
|
26
|
+
\u5951\u7EA6\u5FC5\u987B\u5305\u542B mount(el, props?) \u4E0E unmount(el) \u4E24\u4E2A\u51FD\u6570\u3002`,
|
|
27
|
+
{ spec, missing, actual }
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
function bridgeLifecycleError(phase, spec, cause, extra) {
|
|
31
|
+
const raw = cause instanceof Error ? cause.message : String(cause ?? "unknown");
|
|
32
|
+
const fixes = {
|
|
33
|
+
getContext: "\u4FEE\u6CD5: \u2460 getContext \u5FC5\u987B\u662F\u540C\u6B65\u3001\u65E0\u526F\u4F5C\u7528\u7684 getter\uFF08\u4E0D\u5F97\u8FD4\u56DE Promise/thenable\uFF09\uFF1B\n \u2461 \u8FD4\u56DE\u503C\u987B\u662F\u5305\u542B\u672C\u6B21\u4F1A\u8BDD\u5FEB\u7167\u7684\u5BF9\u8C61\uFF08\u53D7\u63A7 sessionKey \u65F6\u987B\u542B\u76F8\u540C sessionKey\uFF09\uFF1B\n \u2462 \u5F02\u6B65\u83B7\u53D6\u7528\u6237\u8D44\u6599\u8BF7\u5728\u5BBF\u4E3B\u5B8C\u6210\u540E\u518D\u8BA9\u6865\u63A5\u7EC4\u4EF6\u8FDB\u5165\u53EF\u6302\u8F7D\u72B6\u6001\u3002",
|
|
34
|
+
mount: "\u4FEE\u6CD5: \u2460 \u67E5\u770B\u6839\u56E0\u4E2D\u5B50\u5E94\u7528 mount \u7684\u539F\u59CB\u9519\u8BEF\uFF08\u5DE5\u5382\u629B\u9519\u6216\u9996\u6B21\u6E32\u67D3\u5931\u8D25\uFF09\uFF1B\n \u2461 \u540C\u4E00\u5BB9\u5668\u672A\u5378\u8F7D\u524D\u91CD\u590D mount \u662F\u5951\u7EA6\u8FDD\u4F8B\u2014\u2014\u5148 unmount \u518D mount\uFF1B\n \u2462 \u4FEE\u590D\u540E\u70B9\u51FB\u300C\u91CD\u8BD5\u52A0\u8F7D\u300D\u5728\u540C\u9875\u91CD\u5EFA\u6302\u8F7D\u3002",
|
|
35
|
+
unmount: "\u4FEE\u6CD5: \u2460 \u6839\u56E0\u6765\u81EA\u5B50\u5E94\u7528 unmount \u5B9E\u73B0\uFF08app.unmount/root.unmount \u629B\u9519\uFF09\uFF1B\n \u2461 \u8BE5\u5BB9\u5668\u6E05\u7406\u72B6\u6001\u4E0D\u786E\u5B9A\uFF0C\u63D2\u4EF6\u5DF2\u6301\u4E45\u5C01\u9501\u8BE5\u5BB9\u5668\u2014\u2014\u540C\u9875\u300C\u91CD\u8BD5\u52A0\u8F7D\u300D\u4E0E\n \u6362\u4F1A\u8BDD\u90FD\u4E0D\u4F1A\u5728\u6B64\u5BB9\u5668\u91CD\u65B0\u6302\u8F7D\uFF1B\n \u2462 \u53EA\u80FD\u6574\u9875\u5237\u65B0\u6062\u590D\uFF08\u300C\u5237\u65B0\u9875\u9762\u91CD\u8BD5\u300D\uFF09\uFF1B\u6B8B\u7559\u8D44\u6E90\uFF08\u4E8B\u4EF6\u8BA2\u9605/\u5B9A\u65F6\u5668/\u5168\u5C40\u526F\u4F5C\u7528\uFF09\u8BF7\u5982\u5B9E\u6392\u67E5\u3002"
|
|
36
|
+
};
|
|
37
|
+
return new FgError(
|
|
38
|
+
BridgeErrorCodes.BRIDGE_LIFECYCLE_FAILED,
|
|
39
|
+
`\u73B0\u8C61\uFF1A\u6865\u63A5\u5E94\u7528 "${spec}" \u7684 ${phase} \u9636\u6BB5\u5931\u8D25\u3002
|
|
40
|
+
\u6839\u56E0: ${raw}
|
|
41
|
+
` + fixes[phase],
|
|
42
|
+
{ phase, spec, cause: String(raw), ...extra },
|
|
43
|
+
{ cause }
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
function bridgeSessionMismatchError(spec, controlled, actual, extra) {
|
|
47
|
+
const actualText = actual === void 0 ? "undefined\uFF08\u9875\u9762\u5C1A\u65E0 AppContext\uFF09" : typeof actual === "string" ? `"${actual}"` : String(actual);
|
|
48
|
+
return new FgError(
|
|
49
|
+
BridgeErrorCodes.BRIDGE_SESSION_MISMATCH,
|
|
50
|
+
`\u73B0\u8C61\uFF1A\u6865\u63A5\u5E94\u7528 "${spec}" \u7684\u53D7\u63A7 sessionKey\uFF08"${controlled}"\uFF09\u4E0E\u5F53\u524D\u4F1A\u8BDD\u4E0D\u4E00\u81F4\uFF08\u5F53\u524D ${actualText}\uFF09\u3002
|
|
51
|
+
\u6839\u56E0: AppContext \u662F\u9875\u9762\u7EA7\u5355\u4F8B\uFF0C\u540C\u9875\u6240\u6709\u6865\u63A5\u5B9E\u4F8B\u5FC5\u987B\u4F7F\u7528\u540C\u4E00\u767B\u5F55\u4EE3\u6B21\uFF1B
|
|
52
|
+
getContext \u5FEB\u7167\u7684 sessionKey\uFF08\u6216\u73B0\u6709 AppContext \u7684 sessionKey\uFF09\u4E0E\u53D7\u63A7\u503C\u4E0D\u540C\u3002
|
|
53
|
+
\u4FEE\u6CD5: \u2460 \u6362\u8D26\u53F7\u65F6\u5148\u8BA9\u53D7\u63A7 prop \u7F6E null \u5E76\u7B49\u5F85\u5378\u8F7D\uFF0C\u518D clearAppContext() \u6E05\u65E7\u8D26\u53F7\u3001
|
|
54
|
+
\u51C6\u5907\u65B0\u8D26\u53F7\u5B8C\u6574\u5FEB\u7167\u540E\u66F4\u65B0\u53D7\u63A7 prop\uFF1B
|
|
55
|
+
\u2461 \u65E0 getContext \u65F6\uFF0C\u5148\u7531\u5BBF\u4E3B\u6865 provideAppContext({...\u65B0\u4F1A\u8BDD, sessionKey}) \u518D\u6302\u8F7D\uFF1B
|
|
56
|
+
\u2462 \u540C\u9875\u4E0D\u8981\u540C\u65F6\u6302\u8F7D\u4E0D\u540C\u8D26\u53F7\u7684\u6865\u63A5\u5B9E\u4F8B\uFF08\u9875\u9762\u7EA7\u5355\u4F1A\u8BDD\u7EA6\u675F\uFF09\u3002`,
|
|
57
|
+
{ spec, controlled, actual: String(actual), ...extra }
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
function invalidSessionKeyError(spec, value) {
|
|
61
|
+
return new FgError(
|
|
62
|
+
BridgeErrorCodes.BRIDGE_SESSION_MISMATCH,
|
|
63
|
+
`\u73B0\u8C61\uFF1A\u6865\u63A5\u5E94\u7528 "${spec}" \u6536\u5230\u975E\u6CD5\u7684\u53D7\u63A7 sessionKey\uFF1A${typeof value === "string" ? '\u7A7A\u5B57\u7B26\u4E32 ""' : `${typeof value}\uFF08${String(value)}\uFF09`}\u3002
|
|
64
|
+
\u6839\u56E0: sessionKey \u53EA\u63A5\u53D7 undefined\uFF08\u4E0D\u542F\u7528\u53D7\u63A7\u4F1A\u8BDD\uFF09\u3001null\uFF08\u767B\u51FA\u6001\uFF09\u6216\u975E\u7A7A\u5B57\u7B26\u4E32\uFF08\u767B\u5F55\u4EE3\u6B21 ID\uFF09\u3002
|
|
65
|
+
\u4FEE\u6CD5: \u767B\u51FA\u4F20 null \u800C\u4E0D\u662F\u7A7A\u5B57\u7B26\u4E32\uFF1B\u767B\u5F55\u4EE3\u6B21\u7528\u975E\u7A7A\u5B57\u7B26\u4E32\uFF1B\u4E0D\u8981\u4F20\u6570\u5B57/\u5E03\u5C14\u7B49\u5176\u4ED6\u7C7B\u578B\u3002`,
|
|
66
|
+
{ spec, value: String(value) }
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export {
|
|
71
|
+
BridgeErrorCodes,
|
|
72
|
+
invalidBridgeContractError,
|
|
73
|
+
bridgeLifecycleError,
|
|
74
|
+
bridgeSessionMismatchError,
|
|
75
|
+
invalidSessionKeyError
|
|
76
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {
|
|
2
|
+
bridgeLifecycleError,
|
|
3
|
+
bridgeSessionMismatchError,
|
|
4
|
+
invalidBridgeContractError,
|
|
5
|
+
invalidSessionKeyError
|
|
6
|
+
} from "./chunk-DH2QMM4Y.js";
|
|
7
|
+
import {
|
|
8
|
+
clearAppContext
|
|
9
|
+
} from "./chunk-TSYLDY6H.js";
|
|
10
|
+
|
|
11
|
+
// src/bridge-core.ts
|
|
12
|
+
function assertBridgeContract(spec, mod) {
|
|
13
|
+
const contract = mod?.default ?? mod;
|
|
14
|
+
if (contract === null || typeof contract !== "object" || typeof contract.mount !== "function" || typeof contract.unmount !== "function") {
|
|
15
|
+
throw invalidBridgeContractError(spec, mod);
|
|
16
|
+
}
|
|
17
|
+
return contract;
|
|
18
|
+
}
|
|
19
|
+
var activeBridgeSessions = /* @__PURE__ */ new Map();
|
|
20
|
+
function acquireBridgeSession(spec, sessionKey) {
|
|
21
|
+
for (const [active] of activeBridgeSessions) {
|
|
22
|
+
if (active !== sessionKey && (activeBridgeSessions.get(active) ?? 0) > 0) {
|
|
23
|
+
throw bridgeSessionMismatchError(spec, sessionKey, active, { reason: "active-instance" });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
activeBridgeSessions.set(sessionKey, (activeBridgeSessions.get(sessionKey) ?? 0) + 1);
|
|
27
|
+
}
|
|
28
|
+
function releaseBridgeSession(sessionKey) {
|
|
29
|
+
const n = activeBridgeSessions.get(sessionKey) ?? 0;
|
|
30
|
+
if (n <= 1) activeBridgeSessions.delete(sessionKey);
|
|
31
|
+
else activeBridgeSessions.set(sessionKey, n - 1);
|
|
32
|
+
}
|
|
33
|
+
function resolveBridgeContext(spec, controlled, getContext) {
|
|
34
|
+
if (getContext) {
|
|
35
|
+
let snapshot;
|
|
36
|
+
try {
|
|
37
|
+
snapshot = getContext();
|
|
38
|
+
} catch (e) {
|
|
39
|
+
throw bridgeLifecycleError("getContext", spec, e);
|
|
40
|
+
}
|
|
41
|
+
if (snapshot === null || typeof snapshot !== "object" || typeof snapshot.then === "function") {
|
|
42
|
+
throw bridgeLifecycleError("getContext", spec, describeContextValue(snapshot));
|
|
43
|
+
}
|
|
44
|
+
if (controlled !== void 0 && snapshot.sessionKey !== controlled) {
|
|
45
|
+
throw bridgeSessionMismatchError(spec, controlled, snapshot.sessionKey, { reason: "getter-snapshot" });
|
|
46
|
+
}
|
|
47
|
+
const current = currentSessionKey();
|
|
48
|
+
if (snapshot.sessionKey !== void 0 && snapshot.sessionKey !== current) {
|
|
49
|
+
clearAppContext();
|
|
50
|
+
}
|
|
51
|
+
return { provide: snapshot };
|
|
52
|
+
}
|
|
53
|
+
if (controlled !== void 0) {
|
|
54
|
+
const current = currentSessionKey();
|
|
55
|
+
if (current !== controlled) {
|
|
56
|
+
throw bridgeSessionMismatchError(spec, controlled, current, { reason: "app-context" });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return {};
|
|
60
|
+
}
|
|
61
|
+
function currentSessionKey() {
|
|
62
|
+
const sk = (globalThis.__FULGURJS_APP_CONFIG__ ?? {}).sessionKey;
|
|
63
|
+
return typeof sk === "string" && sk !== "" ? sk : void 0;
|
|
64
|
+
}
|
|
65
|
+
function describeContextValue(snapshot) {
|
|
66
|
+
if (snapshot === null) {
|
|
67
|
+
return "getContext \u8FD4\u56DE\u4E86 null\u3002\u5B83\u5FC5\u987B\u662F\u540C\u6B65\u8FD4\u56DE\u5FEB\u7167\u5BF9\u8C61\u7684\u7EAF getter\uFF1A\u8FD4\u56DE\u503C\u5E94\u4E3A\u5305\u542B\u672C\u6B21\u4F1A\u8BDD\u5FEB\u7167\u7684\u5BF9\u8C61\uFF08\u53D7\u63A7 sessionKey \u65F6\u987B\u542B\u76F8\u540C sessionKey\uFF09\uFF0C\u4E0D\u80FD\u8FD4\u56DE null\u3002";
|
|
68
|
+
}
|
|
69
|
+
if (snapshot === void 0) {
|
|
70
|
+
return "getContext \u8FD4\u56DE\u4E86 undefined\u3002\u5B83\u5FC5\u987B\u662F\u540C\u6B65\u8FD4\u56DE\u5FEB\u7167\u5BF9\u8C61\u7684\u7EAF getter\uFF1A\u8FD4\u56DE\u503C\u5E94\u4E3A\u5305\u542B\u672C\u6B21\u4F1A\u8BDD\u5FEB\u7167\u7684\u5BF9\u8C61\uFF0C\u8BF7\u68C0\u67E5 getter \u662F\u5426\u6F0F\u5199 return \u6216\u8FD4\u56DE\u4E86\u672A\u521D\u59CB\u5316\u7684\u53D8\u91CF\u3002";
|
|
71
|
+
}
|
|
72
|
+
if (typeof snapshot.then === "function") {
|
|
73
|
+
return "getContext \u8FD4\u56DE\u4E86 Promise/thenable\u3002\u5B83\u5FC5\u987B\u662F\u540C\u6B65 getter\uFF0C\u4E0D\u5F97\u8FD4\u56DE Promise\uFF1A\u5F02\u6B65\u83B7\u53D6\u7528\u6237\u8D44\u6599\u8BF7\u5728\u5BBF\u4E3B\u5B8C\u6210\u540E\u518D\u8BA9\u6865\u63A5\u7EC4\u4EF6\u8FDB\u5165\u53EF\u6302\u8F7D\u72B6\u6001\u3002";
|
|
74
|
+
}
|
|
75
|
+
return `getContext \u8FD4\u56DE\u4E86\u975E\u5BF9\u8C61\u503C\uFF08${typeof snapshot}\uFF1A"${String(snapshot)}"\uFF09\u3002\u5B83\u5FC5\u987B\u662F\u540C\u6B65\u8FD4\u56DE\u5FEB\u7167\u5BF9\u8C61\u7684\u7EAF getter\uFF0C\u8FD4\u56DE\u503C\u5E94\u4E3A\u5BF9\u8C61\u800C\u4E0D\u662F\u539F\u59CB\u503C\u3002`;
|
|
76
|
+
}
|
|
77
|
+
function assertControlledSessionKey(spec, value) {
|
|
78
|
+
if (value === void 0 || value === null) return;
|
|
79
|
+
if (typeof value === "string" && value !== "") return;
|
|
80
|
+
throw invalidSessionKeyError(spec, value);
|
|
81
|
+
}
|
|
82
|
+
function assertBridgeOptions(source, opts) {
|
|
83
|
+
if (opts.retries !== void 0 && (typeof opts.retries !== "number" || !Number.isInteger(opts.retries) || opts.retries < 0 || opts.retries > 10)) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`[fulgurjs] ${source} \u7684 retries \u914D\u7F6E\u65E0\u6548\uFF1A\u5F53\u524D\u4E3A ${String(opts.retries)}\uFF0C\u5E94\u4E3A 0 \u5230 10 \u7684\u6574\u6570\u3002\u8BF7\u4FEE\u6B63\u9009\u9879\u3002`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
if (opts.timeout !== void 0 && (typeof opts.timeout !== "number" || !Number.isFinite(opts.timeout) || opts.timeout <= 0)) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`[fulgurjs] ${source} \u7684 timeout \u914D\u7F6E\u65E0\u6548\uFF1A\u5F53\u524D\u4E3A ${String(opts.timeout)}\uFF0C\u5E94\u4E3A\u5927\u4E8E 0 \u7684\u6709\u9650\u6BEB\u79D2\u6570\u3002\u8BF7\u4FEE\u6B63\u9009\u9879\u3002`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function withBridgeTimeout(p, ms, spec) {
|
|
95
|
+
return new Promise((resolve, reject) => {
|
|
96
|
+
const timer = setTimeout(() => {
|
|
97
|
+
reject(new Error(
|
|
98
|
+
`[fulgurjs] \u6865\u63A5\u5E94\u7528 "${spec}" \u52A0\u8F7D\u7B49\u5F85\u8D85\u8FC7 ${ms} \u6BEB\u79D2\uFF08\u9002\u914D\u5C42 timeout\uFF09\u3002\u8BE5\u8D85\u65F6\u53EA\u7ED3\u675F\u672C\u6B21\u7B49\u5F85\uFF0C\u4E0D\u53D6\u6D88\u5DF2\u53D1\u51FA\u7684\u5171\u4EAB\u8BF7\u6C42\uFF1B\u53EF\u70B9\u51FB\u300C\u91CD\u8BD5\u52A0\u8F7D\u300D\u5EFA\u7ACB\u65B0\u7684\u5C1D\u8BD5\u3002`
|
|
99
|
+
));
|
|
100
|
+
}, ms);
|
|
101
|
+
p.then(
|
|
102
|
+
(v) => {
|
|
103
|
+
clearTimeout(timer);
|
|
104
|
+
resolve(v);
|
|
105
|
+
},
|
|
106
|
+
(e) => {
|
|
107
|
+
clearTimeout(timer);
|
|
108
|
+
reject(e);
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export {
|
|
115
|
+
assertBridgeContract,
|
|
116
|
+
acquireBridgeSession,
|
|
117
|
+
releaseBridgeSession,
|
|
118
|
+
resolveBridgeContext,
|
|
119
|
+
assertControlledSessionKey,
|
|
120
|
+
assertBridgeOptions,
|
|
121
|
+
withBridgeTimeout
|
|
122
|
+
};
|