@fulgurjs/federation 6.12.12 → 6.13.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 +10 -0
- package/dist/bridge-app-react.js +4 -4
- package/dist/bridge-app-vue.js +5 -5
- package/dist/bridge-core.js +4 -4
- package/dist/bridge-errors.js +2 -2
- package/dist/bridge-host-react.js +5 -5
- package/dist/bridge-host-vue.js +5 -5
- package/dist/bridge-session-auto.js +2 -2
- package/dist/{chunk-MUATDGMR.js → chunk-2OHKAD6I.js} +23 -1
- package/dist/{chunk-PPHNZBZX.js → chunk-MBH3TVAS.js} +1 -1
- package/dist/{chunk-YXGV4ZK6.js → chunk-NVJN2ARX.js} +2 -2
- package/dist/{chunk-UTL2F4KF.js → chunk-OQ4CGWNL.js} +1 -1
- package/dist/{chunk-5ODWDP5I.js → chunk-TSPZ3EQ4.js} +1 -1
- package/dist/{chunk-4YTQSOGQ.js → chunk-YHXQHZ3E.js} +3 -1
- package/dist/cli.js +1 -1
- package/dist/context.js +2 -2
- package/dist/index.cjs +2 -2
- package/dist/index.js +2 -2
- package/dist/react-adapter.cjs +72 -37
- package/dist/react-adapter.js +22 -3
- package/dist/react.d.ts +5 -0
- package/dist/runtime-entry.d.ts +5 -0
- package/dist/runtime.js +17 -17
- package/dist/vue-adapter.cjs +87 -12
- package/dist/vue-adapter.d.cts +11 -1
- package/dist/vue-adapter.d.ts +11 -1
- package/dist/vue-adapter.js +71 -14
- package/dist/vue.d.ts +16 -1
- package/docs/en/reference/errors.md +1 -0
- package/docs/zh/reference/errors.md +1 -0
- package/package.json +1 -1
package/dist/vue-adapter.js
CHANGED
|
@@ -2,18 +2,21 @@ import {
|
|
|
2
2
|
cleanCompName,
|
|
3
3
|
createHostPagesCore,
|
|
4
4
|
isComponentLoader,
|
|
5
|
+
moduleNameOf,
|
|
5
6
|
noRenderableExportError,
|
|
6
7
|
readSessionKey,
|
|
8
|
+
remoteNameOf,
|
|
9
|
+
reportRemoteObservation,
|
|
7
10
|
resolvePageProviderEntries,
|
|
8
11
|
shouldResetSessionCache
|
|
9
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-2OHKAD6I.js";
|
|
10
13
|
import "./chunk-TSXZ7TWA.js";
|
|
11
14
|
import {
|
|
12
15
|
ErrorCodes
|
|
13
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-YHXQHZ3E.js";
|
|
14
17
|
|
|
15
18
|
// src/vue-adapter.ts
|
|
16
|
-
import { defineAsyncComponent, defineComponent, getCurrentInstance, h, ref, shallowRef, onActivated, onUnmounted, version as vueRuntimeVersion } from "vue";
|
|
19
|
+
import { defineAsyncComponent, defineComponent, getCurrentInstance, h, onErrorCaptured, ref, shallowRef, onActivated, onUnmounted, version as vueRuntimeVersion } from "vue";
|
|
17
20
|
function isVueRenderableComponent(inner) {
|
|
18
21
|
if (!inner) return false;
|
|
19
22
|
if (typeof inner === "function") return true;
|
|
@@ -102,7 +105,7 @@ var RemoteErrorPlaceholder = /* @__PURE__ */ defineComponent({
|
|
|
102
105
|
h("p", { style: "margin:0 0 4px;font-weight:600" }, `\u8FDC\u7A0B\u7EC4\u4EF6\u52A0\u8F7D\u5931\u8D25\uFF08\u9519\u8BEF\u7801 ${code}\uFF09`),
|
|
103
106
|
h("p", { style: "margin:0 0 8px;word-break:break-all" }, message),
|
|
104
107
|
h("p", { style: "margin:0 0 8px" }, "\u4FEE\u6CD5\uFF1A\u2460 \u6838\u5BF9 spec \u7684\u300C\u8FDC\u7A0B\u540D/expose \u540D\u300D\u4E0E\u8FDC\u7A0B\u5E94\u7528 exposes \u662F\u5426\u4E00\u81F4\uFF08MFU-006/008/018\uFF09\uFF1B\u2461 \u6838\u5BF9 remotes \u5730\u5740\u7AEF\u53E3\u4E0E\u8FDC\u7A0B\u670D\u52A1\u53EF\u8FBE\u6027\u3001remoteEntry \u662F\u5426\u53EF\u8BBF\u95EE\uFF08MFU-001\uFF09\uFF1B\u2462 \u67E5\u770B window \u7684 fulgurjs:error \u4E8B\u4EF6\u4E0E console \u540C\u6E90\u9519\u8BEF\u5B9A\u4F4D\u6839\u56E0\u3002"),
|
|
105
|
-
h("p", { style: "margin:0 0 8px" }, "\
|
|
108
|
+
h("p", { style: "margin:0 0 8px" }, "\u4E0B\u4E00\u6B65\u53D6\u8BC1\uFF08\u6309\u4E8B\u5B9E\u533A\u5206\uFF0C\u4E0D\u9884\u5224\u7ED3\u8BBA\uFF09\uFF1A\u2460 \u672C\u9519\u8BEF\u4E0A\u65B9\u300C\u539F\u56E0\u300D\u4E0E fulgurjs:error \u4E8B\u4EF6\u7684 details.stage \u6807\u660E\u5931\u8D25\u9636\u6BB5\u2014\u2014container=\u5165\u53E3/\u7F51\u7EDC\uFF0Cexpose=\u6A21\u5757\u6C42\u503C/\u5BFC\u51FA\uFF0Csetup=\u8FDC\u7A0B\u521D\u59CB\u5316\uFF0Crender=\u8FDC\u7A0B\u7EC4\u4EF6\u5185\u90E8\u6E32\u67D3\uFF1B\u524D\u7F6E\u6821\u9A8C\u6216\u914D\u7F6E\u7C7B\u62D2\u7EDD\u4E0D\u53D1\u8D77\u7F51\u7EDC\u8BF7\u6C42\uFF0CNetwork \u9762\u677F\u96F6\u65B0\u8BF7\u6C42\u4E5F\u53EF\u80FD\u5B8C\u5168\u6B63\u5E38\u3002\u2461 Network \u9762\u677F\u786E\u6709\u7EA2\u8272\u8BF7\u6C42\u65F6\uFF0C\u8BFB\u8BE5\u8BF7\u6C42\u5B9E\u9645 status \u4E0E\u54CD\u5E94\u5185\u5BB9\uFF08404/502=\u8D44\u6E90\u7F3A\u5931\u6216\u4EE3\u7406\u9519\u8BEF\uFF1B200 \u4F46\u8FD4\u56DE HTML=\u5165\u53E3\u88AB SPA fallback \u8BEF\u56DE\u9000\uFF09\u3002\u2462 Network \u9762\u677F\u96F6\u65B0\u8BF7\u6C42\u4E14\u6D88\u606F\u542B import/Failed to fetch\uFF1A\u53EF\u80FD\u662F\u6D4F\u89C8\u5668\u7F13\u5B58\u4E86\u4E0A\u6B21\u540C URL \u7684 import \u5931\u8D25\uFF08module map \u5BF9\u5931\u8D25 URL \u4E0D\u518D\u53D1\u8BF7\u6C42\uFF09\uFF0C\u4E5F\u53EF\u80FD\u662F\u52A0\u8F7D\u524D\u7684\u672C\u5730\u6821\u9A8C\u62D2\u7EDD\u2014\u2014\u5148\u7528\u300C\u5237\u65B0\u9875\u9762\u91CD\u8BD5\u300D\u6574\u9875\u91CD\u8BD5\u518D\u5224\u65AD\u3002\u2463 \u5916\u58F3\u6B63\u5E38\u800C\u5185\u90E8\u7A7A\u767D\uFF1A\u53EF\u80FD\u539F\u56E0\u5305\u62EC\u8FDC\u7A0B\u7EC4\u4EF6\u6E32\u67D3\u9519\u8BEF\u88AB\u4E1A\u52A1 handler \u63A5\u7BA1\u3001\u5408\u6CD5\u7A7A\u6570\u636E\u6216\u4F9D\u8D56\u7F3A\u5931\uFF0C\u4E0D\u7B49\u4E8E\u5DF2\u786E\u8BA4 shared.vue \u5B9E\u4F8B\u5206\u88C2\uFF1B\u6838\u5BF9 window \u7684 fulgurjs:error\uFF08\u542B MFU-020/019\uFF09\u4E0E __FULGURJS_SCOPE__ \u540E\u518D\u5B9A\u4F4D\u3002"),
|
|
106
109
|
h("p", { style: "margin:0 0 10px" }, "\u300C\u91CD\u8BD5\u52A0\u8F7D\u300D\u5728\u5F53\u524D\u9875\u9762\u91CD\u5EFA\u52A0\u8F7D\uFF1B\u82E5\u6D4F\u89C8\u5668\u5DF2\u7F13\u5B58\u5931\u8D25\u7684\u6A21\u5757\uFF08\u5982\u8FDC\u7A0B\u9759\u6001\u5B50\u4F9D\u8D56\u66FE\u52A0\u8F7D\u5931\u8D25\uFF09\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"),
|
|
107
110
|
h("div", { style: "margin:0" }, buttons)
|
|
108
111
|
]);
|
|
@@ -128,6 +131,7 @@ function createRecoverableErrorPlaceholder(loader, spec, userErrorComponent) {
|
|
|
128
131
|
if (!isVueRenderableComponent(inner)) throw noRenderableExportError(spec, inner);
|
|
129
132
|
recovered.value = inner;
|
|
130
133
|
} catch (e) {
|
|
134
|
+
reportRemoteObservation({ remote: remoteNameOf(spec), error: e });
|
|
131
135
|
retryError.value = e;
|
|
132
136
|
} finally {
|
|
133
137
|
retrying.value = false;
|
|
@@ -145,6 +149,35 @@ function createRecoverableErrorPlaceholder(loader, spec, userErrorComponent) {
|
|
|
145
149
|
}
|
|
146
150
|
});
|
|
147
151
|
}
|
|
152
|
+
function remoteRenderBoundary(spec, renderErrorComponent) {
|
|
153
|
+
const error = shallowRef(void 0);
|
|
154
|
+
const epoch = ref(0);
|
|
155
|
+
const retry = () => {
|
|
156
|
+
error.value = void 0;
|
|
157
|
+
epoch.value += 1;
|
|
158
|
+
};
|
|
159
|
+
const onErrorCaptured2 = (err, _instance, info) => {
|
|
160
|
+
const reported = Object.assign(
|
|
161
|
+
new Error(
|
|
162
|
+
`\u73B0\u8C61\uFF1A\u8FDC\u7A0B\u7EC4\u4EF6 "${spec}" \u7684\u5B50\u6811\u5185\u90E8\u629B\u51FA\u9519\u8BEF\uFF08\u6E32\u67D3\u9636\u6BB5\uFF1A${info || "\u672A\u77E5"}\uFF09\u3002
|
|
163
|
+
\u6839\u56E0\uFF08\u5DF2\u8BC1\u5B9E\uFF09\uFF1A\u9519\u8BEF\u629B\u81EA\u8FDC\u7A0B\u7EC4\u4EF6\u81EA\u8EAB\u7684 setup/render/\u5D4C\u5957\u5F02\u6B65\u7EC4\u4EF6\uFF0C\u4E0E\u8054\u90A6\u7684\u6A21\u5757\u52A0\u8F7D\u65E0\u5173\uFF1B\u539F\u59CB\u5F02\u5E38\u4FDD\u7559\u5728\u672C\u9519\u8BEF\u7684 cause \u4E0E\u4E8B\u4EF6 detail \u4E2D\u3002
|
|
164
|
+
\u4FEE\u6CD5\uFF1A\u67E5\u770B cause \u7684\u539F\u59CB\u8C03\u7528\u6808\u5B9A\u4F4D\u8FDC\u7A0B\u7EC4\u4EF6\u5185\u90E8\u4EE3\u7801\u3002\u9700\u8981\u5728\u672C\u7EC4\u4EF6\u4F4D\u7F6E\u76F4\u63A5\u5C55\u793A\u9519\u8BEF\u5E76\u63D0\u4F9B\u6062\u590D\u65F6\uFF0C\u4E3A remoteComponent/createHostPages \u4F20\u5165 renderErrorComponent\uFF08\u672C\u8FB9\u754C\u5C06\u63A5\u7BA1\u5C55\u793A\uFF0C\u9519\u8BEF\u4E0D\u518D\u5411\u5168\u5C40\u4F20\u64AD\uFF09\u3002`
|
|
165
|
+
),
|
|
166
|
+
{
|
|
167
|
+
code: ErrorCodes.REMOTE_RENDER_ERROR,
|
|
168
|
+
details: { remote: remoteNameOf(spec), module: moduleNameOf(spec), phase: "render", renderInfo: info || void 0 },
|
|
169
|
+
cause: err
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
reportRemoteObservation({ remote: remoteNameOf(spec), error: reported });
|
|
173
|
+
if (renderErrorComponent) {
|
|
174
|
+
error.value = err;
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
return void 0;
|
|
178
|
+
};
|
|
179
|
+
return { onErrorCaptured: onErrorCaptured2, error, epoch, retry, view: renderErrorComponent };
|
|
180
|
+
}
|
|
148
181
|
function consumerRegistry(app, captured) {
|
|
149
182
|
return app ? {
|
|
150
183
|
component(name, comp) {
|
|
@@ -177,7 +210,7 @@ async function applyPageProviders(comp, captured) {
|
|
|
177
210
|
const providers = await resolvePageProviders(captured.providers);
|
|
178
211
|
return providers && providers.length > 0 ? withPageProviders(comp, providers) : comp;
|
|
179
212
|
}
|
|
180
|
-
function sessionComponent(inner, name, initialApp, initialSession, load, spec, loadingComponent, errorComponent) {
|
|
213
|
+
function sessionComponent(inner, name, initialApp, initialSession, load, spec, loadingComponent, errorComponent, renderErrorComponent) {
|
|
181
214
|
return defineComponent({
|
|
182
215
|
name,
|
|
183
216
|
inheritAttrs: false,
|
|
@@ -185,6 +218,8 @@ function sessionComponent(inner, name, initialApp, initialSession, load, spec, l
|
|
|
185
218
|
const app = getCurrentInstance()?.appContext.app;
|
|
186
219
|
const current = shallowRef();
|
|
187
220
|
const failure = shallowRef();
|
|
221
|
+
const boundary = remoteRenderBoundary(spec, renderErrorComponent);
|
|
222
|
+
onErrorCaptured(boundary.onErrorCaptured);
|
|
188
223
|
let session = initialSession;
|
|
189
224
|
let generation = 0;
|
|
190
225
|
let disposed = false;
|
|
@@ -196,6 +231,7 @@ function sessionComponent(inner, name, initialApp, initialSession, load, spec, l
|
|
|
196
231
|
const request = ++generation;
|
|
197
232
|
current.value = void 0;
|
|
198
233
|
failure.value = void 0;
|
|
234
|
+
boundary.error.value = void 0;
|
|
199
235
|
try {
|
|
200
236
|
const result = await load(app);
|
|
201
237
|
if (disposed || request !== generation) return;
|
|
@@ -208,7 +244,10 @@ function sessionComponent(inner, name, initialApp, initialSession, load, spec, l
|
|
|
208
244
|
session = requestedSession;
|
|
209
245
|
current.value = result;
|
|
210
246
|
} catch (error) {
|
|
211
|
-
if (!disposed && request === generation)
|
|
247
|
+
if (!disposed && request === generation) {
|
|
248
|
+
reportRemoteObservation({ remote: remoteNameOf(spec), error });
|
|
249
|
+
failure.value = error;
|
|
250
|
+
}
|
|
212
251
|
} finally {
|
|
213
252
|
pending = false;
|
|
214
253
|
}
|
|
@@ -226,7 +265,13 @@ function sessionComponent(inner, name, initialApp, initialSession, load, spec, l
|
|
|
226
265
|
generation++;
|
|
227
266
|
});
|
|
228
267
|
const ErrorView = createRecoverableErrorPlaceholder(() => load(app), spec, errorComponent);
|
|
229
|
-
return () =>
|
|
268
|
+
return () => {
|
|
269
|
+
if (boundary.view && boundary.error.value !== void 0) {
|
|
270
|
+
return h(boundary.view, { error: boundary.error.value, retry: boundary.retry });
|
|
271
|
+
}
|
|
272
|
+
const c = current.value;
|
|
273
|
+
return c ? h(c, { ...attrs, key: `${generation}-${boundary.epoch.value}` }, slots) : failure.value ? h(ErrorView, { ...attrs, error: failure.value }, slots) : loadingComponent ? h(loadingComponent) : null;
|
|
274
|
+
};
|
|
230
275
|
}
|
|
231
276
|
});
|
|
232
277
|
}
|
|
@@ -239,9 +284,16 @@ function createRemoteComponent(loadRemote) {
|
|
|
239
284
|
consumerApp: consumerRegistry(app, captured)
|
|
240
285
|
}).then(async (m) => {
|
|
241
286
|
const inner = m?.default ?? m;
|
|
242
|
-
if (!isVueRenderableComponent(inner))
|
|
287
|
+
if (!isVueRenderableComponent(inner)) {
|
|
288
|
+
const err = noRenderableExportError(spec, inner);
|
|
289
|
+
reportRemoteObservation({ remote: remoteNameOf(spec), error: err });
|
|
290
|
+
throw err;
|
|
291
|
+
}
|
|
243
292
|
const identity = vueRuntimeIdentityError(spec);
|
|
244
|
-
if (identity)
|
|
293
|
+
if (identity) {
|
|
294
|
+
reportRemoteObservation({ remote: remoteNameOf(spec), error: identity });
|
|
295
|
+
throw identity;
|
|
296
|
+
}
|
|
245
297
|
return applyPageProviders(inner, captured);
|
|
246
298
|
});
|
|
247
299
|
};
|
|
@@ -251,7 +303,7 @@ function createRemoteComponent(loadRemote) {
|
|
|
251
303
|
initialApp = app;
|
|
252
304
|
const session = readSessionKey();
|
|
253
305
|
const inner = await load(app);
|
|
254
|
-
return sessionComponent(inner, inner?.name, app, session, load, spec, opts.loadingComponent, opts.errorComponent);
|
|
306
|
+
return sessionComponent(inner, inner?.name, app, session, load, spec, opts.loadingComponent, opts.errorComponent, opts.renderErrorComponent);
|
|
255
307
|
};
|
|
256
308
|
return defineAsyncComponent({
|
|
257
309
|
loader,
|
|
@@ -263,7 +315,7 @@ function createRemoteComponent(loadRemote) {
|
|
|
263
315
|
};
|
|
264
316
|
}
|
|
265
317
|
function createHostPages(options, load) {
|
|
266
|
-
const { beforeLoad, loadingComponent, errorComponent, delay } = options;
|
|
318
|
+
const { beforeLoad, loadingComponent, errorComponent, renderErrorComponent, delay } = options;
|
|
267
319
|
const core = createHostPagesCore(options);
|
|
268
320
|
let cacheSession;
|
|
269
321
|
const compCache = /* @__PURE__ */ new Map();
|
|
@@ -283,10 +335,15 @@ function createHostPages(options, load) {
|
|
|
283
335
|
const mod = await load(spec, { consumerApp: consumerRegistry(app, captured) });
|
|
284
336
|
let inner = mod?.default ?? mod;
|
|
285
337
|
if (!isVueRenderableComponent(inner)) {
|
|
286
|
-
|
|
338
|
+
const err = noRenderableExportError(spec, inner);
|
|
339
|
+
reportRemoteObservation({ remote: remoteNameOf(spec), error: err });
|
|
340
|
+
throw err;
|
|
287
341
|
}
|
|
288
342
|
const identity = vueRuntimeIdentityError(spec);
|
|
289
|
-
if (identity)
|
|
343
|
+
if (identity) {
|
|
344
|
+
reportRemoteObservation({ remote: remoteNameOf(spec), error: identity });
|
|
345
|
+
throw identity;
|
|
346
|
+
}
|
|
290
347
|
if (keepAlivePage && inner && typeof inner === "object") {
|
|
291
348
|
inner = Object.defineProperties({ ...inner }, { name: { value: name, configurable: true } });
|
|
292
349
|
}
|
|
@@ -298,7 +355,7 @@ function createHostPages(options, load) {
|
|
|
298
355
|
initialApp = app;
|
|
299
356
|
const session = readSessionKey();
|
|
300
357
|
const inner = await loadPage(app);
|
|
301
|
-
return sessionComponent(inner, keepAlivePage ? name : inner.name, app, session, loadPage, spec, loadingComponent, errorComponent);
|
|
358
|
+
return sessionComponent(inner, keepAlivePage ? name : inner.name, app, session, loadPage, spec, loadingComponent, errorComponent, renderErrorComponent);
|
|
302
359
|
};
|
|
303
360
|
const asyncComp = defineAsyncComponent({
|
|
304
361
|
loader: pageLoader,
|
package/dist/vue.d.ts
CHANGED
|
@@ -519,6 +519,11 @@ declare function createRuntime(): {
|
|
|
519
519
|
module: string;
|
|
520
520
|
};
|
|
521
521
|
clearSessionState: () => void;
|
|
522
|
+
/** 适配器边界的观测上报入口(P03):与运行时内部 emitError 同一通路、hook 与全页去重 */
|
|
523
|
+
reportRemoteError: (info: {
|
|
524
|
+
remote: string;
|
|
525
|
+
error: unknown;
|
|
526
|
+
}) => void;
|
|
522
527
|
};
|
|
523
528
|
type FgRuntime = ReturnType<typeof createRuntime>;
|
|
524
529
|
/** 插件版本(与 package.json 同步维护于 src/version.ts,测试拦截漂移;用于跨源副本一致性诊断) */
|
|
@@ -563,6 +568,14 @@ declare function unwrapDefault(ns: any): any;
|
|
|
563
568
|
interface RemoteComponentOptions {
|
|
564
569
|
loadingComponent?: Component;
|
|
565
570
|
errorComponent?: Component;
|
|
571
|
+
/**
|
|
572
|
+
* 远程组件子树渲染错误占位(P01 可选接线):提供后,本组件边界接管远程组件内部
|
|
573
|
+
* setup/render/嵌套异步组件的渲染错误——停止该错误向全局继续传播(本边界已消费),
|
|
574
|
+
* 渲染此组件(props:error 原始异常 + retry 重新挂载远程组件)。
|
|
575
|
+
* 未提供时仅观测上报(fulgurjs:error,错误码 MFU-020,原始异常保留在 cause),
|
|
576
|
+
* 不改变错误传播语义——业务 errorHandler / onErrorCaptured 行为与接入前完全一致。
|
|
577
|
+
*/
|
|
578
|
+
renderErrorComponent?: Component;
|
|
566
579
|
retries?: number;
|
|
567
580
|
delay?: number;
|
|
568
581
|
timeout?: number;
|
|
@@ -579,8 +592,10 @@ interface HostPagesOptions extends HostPagesCoreOptions {
|
|
|
579
592
|
beforeLoad?: () => void | Promise<void>;
|
|
580
593
|
/** 加载期占位组件(骨架屏) */
|
|
581
594
|
loadingComponent?: Component;
|
|
582
|
-
/**
|
|
595
|
+
/** 错误占位(缺省 = 内置错误占位:错误码+根因+修法+重试加载/刷新页面重试;自定义时完全接管) */
|
|
583
596
|
errorComponent?: Component;
|
|
597
|
+
/** 远程页面子树渲染错误占位(可选接管:提供后本边界消费渲染错误并展示 error/retry;缺省仅观测上报) */
|
|
598
|
+
renderErrorComponent?: Component;
|
|
584
599
|
/** 骨架屏延迟 ms(默认 200,防闪) */
|
|
585
600
|
delay?: number;
|
|
586
601
|
}
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
| `MFU-014` | Runtime reports a recursive loadRemote of the same remote inside setup/onSession's synchronous segment | Loading a module of the same remote inside the initialization's synchronous segment — the call waits on itself, deadlocking | Do not load same-remote modules inside initialization; put cross-remote loads in the async segment |
|
|
74
74
|
| `MFU-018` | remoteComponent / host-pages component consumption reports "the export is not a renderable component" (with the actual export shape) | The exposes target exports a plain module/constant/non-renderable object — a successful module load does not mean a usable component | Point exposes at an `export default` component (Vue: defineComponent / `<script setup>` / functional; React: function component or memo/forwardRef); to consume a plain module use `loadRemote` instead |
|
|
75
75
|
| `MFU-019` | Vue component direct rendering reports "the renderer and the Vue instance converged in the share scope are not the same instance" (with renderer/shared instance versions) | Proven instance split: at least one side declared shared.vue, but the consumer's vue import did not converge onto the same instance (shared.vue not declared, dev prebundling bypassing the facade, or mismatched shareScope). With split instances inject/Pinia/getCurrentInstance break across instances — typically "shell renders, inner blank, no pageerror" | Both sides declare vue in `shared` (singleton recommended) with the same shareScope; in dev verify vue was not prebundled into a second copy; full sub apps that need an independent Vue runtime must use app bridging instead of remoteComponent direct rendering. Verify via `window.__FULGURJS_SCOPE__.default.vue` |
|
|
76
|
+
| `MFU-020` | The remote component subtree threw internally (its own setup/render/nested async components, including cases the region goes blank after a business errorHandler takes over) | The error originates from the remote component's own code, unrelated to federation module loading. Reported observably via `fulgurjs:error`/`onRemoteError`: the original exception is preserved in `cause`, `details.phase='render'` plus Vue's render-stage info (e.g. setup function / render function / async component loader) | Inspect the original stack on `cause` to locate the failing remote component code. To display and recover in place, pass `renderErrorComponent` to `remoteComponent`/`createHostPages` (it receives `error`/`retry` props, owns the display so the error stops propagating globally, and retry remounts the remote component); by default only observation reporting happens and business errorHandler behavior is unchanged |
|
|
76
77
|
| `MFU-015` | Runtime reports an illegal bridge contract (the `./bridge` default export lacks mount/unmount or they are not functions) | The module exposed as `./bridge` was not built with `defineBridgeApp` | Build the child app entry's default export with `defineBridgeApp(...)` (see [sub app bridge](../guide/app-bridge.md)) |
|
|
77
78
|
| `MFU-016` | Runtime reports bridge preparation or lifecycle failure (`details.phase` distinguishes getContext/mount/unmount; the root cause carries the child app's original error) | getContext returned a Promise/non-object, mount threw before the first commit, or unmount cleanup threw | Troubleshoot the child app code by phase: getContext must return a synchronous snapshot object; on mount failure clean up the app/root before throwing; fix unmount's cleanup logic — a container whose unmount threw is persistently locked out; recover with a full page refresh |
|
|
78
79
|
| `MFU-017` | Runtime reports bridge session parameters inconsistent with AppContext | The controlled `sessionKey` contradicts the global session (a getContext snapshot mismatch), an illegal value (empty string/number), or a page-level single-session conflict (generations mismatch across instances) | Unify the session across the page's controlled bridge instances; sessionKey takes only non-empty string/null/omitted; on generation switch follow "first null to unmount, clearAppContext, then write the new generation" |
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
| `MFU-014` | 运行时报 setup/onSession 同步段内递归 loadRemote 同一远程 | 初始化同步段内加载同远程模块——该调用会等待自身形成死锁 | 初始化内不要加载同远程模块;跨远程加载放异步段 |
|
|
73
73
|
| `MFU-018` | remoteComponent/宿主页面组件消费时报「导出的不是可渲染组件」(附实际导出形态) | 该 exposes 指向的文件导出了普通模块/常量/不可渲染对象——模块加载成功不等于组件可用 | exposes 指向 `export default` 组件(Vue:defineComponent/`<script setup>`/函数式;React:函数组件或 memo/forwardRef);消费普通模块改用 `loadRemote` |
|
|
74
74
|
| `MFU-019` | Vue 组件直渲染时报「渲染器与共享作用域收敛的 Vue 实例不一致」(附渲染链/共享实例双版本) | 已证实的实例分裂:至少一方声明 shared.vue,但消费方 vue 导入未收敛到同一实例(未声明 shared.vue、dev 预构建绕过门面、shareScope 不一致)。实例分裂时 inject/Pinia/getCurrentInstance 跨实例断链,常见「外壳在、内部空白且无 pageerror」 | 两侧 `shared` 均声明 vue(建议 singleton)且 shareScope 一致;dev 核对未把 vue 预构建成第二份;需独立 Vue 运行时的完整子应用改用应用桥接,不要 remoteComponent 直渲染。核实:`window.__FULGURJS_SCOPE__.default.vue` |
|
|
75
|
+
| `MFU-020` | 远程组件子树内部抛错(其 setup/render/嵌套异步组件;含错误被业务 errorHandler 接管后区域空白的场景) | 错误抛自远程组件代码本身,与联邦模块加载无关。经 `fulgurjs:error`/`onRemoteError` 观测上报:原始异常保留在 `cause`,`details.phase='render'` 并附 Vue 渲染阶段串(如 setup function / render function / async component loader) | 查看 `cause` 的原始调用栈定位远程组件内部代码。需要在该组件位置直接展示并提供恢复时,为 `remoteComponent`/`createHostPages` 传 `renderErrorComponent`(收到 `error`/`retry` props,接管展示后错误不再向全局传播,retry 重新挂载远程组件);默认仅观测上报,不改变业务 errorHandler 行为 |
|
|
75
76
|
| `MFU-015` | 运行时报桥接契约非法(`./bridge` 默认导出缺 mount/unmount 或非函数) | expose `./bridge` 的模块没有用 `defineBridgeApp` 构造契约对象 | 子应用入口改用 `defineBridgeApp(...)` 默认导出(见[子应用桥接](../guide/app-bridge.md)) |
|
|
76
77
|
| `MFU-016` | 运行时报桥接准备或生命周期失败(`details.phase` 区分 getContext/mount/unmount;根因含子应用原始错误) | getContext 返回 Promise/非对象、mount 首次提交前抛错、或 unmount 清理抛错 | 按 phase 排查子应用代码:getContext 返回同步快照对象;mount 失败先清理 app/root 再抛;unmount 修复清理逻辑——unmount 抛错的容器被持久封锁,整页刷新恢复 |
|
|
77
78
|
| `MFU-017` | 运行时报桥接会话参数与 AppContext 不一致 | 受控 `sessionKey` 与全局会话矛盾(getContext 快照不一致)、非法值(空串/数字)、或页面级单会话冲突(多实例代次不一致) | 同页受控桥接实例统一会话;sessionKey 只用 非空字符串/null/省略 三态;换代按「先 null 卸载、clearAppContext、再写新代次」顺序 |
|