@fulgurjs/federation 3.0.1 → 4.1.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.
@@ -0,0 +1,307 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/vue-adapter.ts
21
+ var vue_adapter_exports = {};
22
+ __export(vue_adapter_exports, {
23
+ createHostPages: () => createHostPages,
24
+ createRemoteComponent: () => createRemoteComponent
25
+ });
26
+ module.exports = __toCommonJS(vue_adapter_exports);
27
+ var import_vue = require("vue");
28
+
29
+ // src/pages.ts
30
+ var normSpec = (s) => s.replace(/^[./]+/, "").replace(/\/+$/, "");
31
+ var hasParam = (route) => /(^|\/):[\w]+/.test(route);
32
+ var segs = (route) => route.split("/").filter(Boolean);
33
+ function defaultDeriveSpec(route) {
34
+ return segs(route).slice(1).filter((seg) => !seg.startsWith(":")).join("/");
35
+ }
36
+ function shadows(earlier, later) {
37
+ const a = segs(earlier);
38
+ const b = segs(later);
39
+ if (a.length !== b.length) return null;
40
+ if (earlier === later) return "full";
41
+ let hasParam2 = false;
42
+ for (let i = 0; i < a.length; i++) {
43
+ if (a[i] === b[i]) continue;
44
+ if (a[i].startsWith(":")) {
45
+ hasParam2 = true;
46
+ continue;
47
+ }
48
+ return null;
49
+ }
50
+ return hasParam2 ? "param" : null;
51
+ }
52
+ function remoteOfRoute(route, remotes) {
53
+ if (!remotes) return null;
54
+ for (const [prefix, name] of Object.entries(remotes)) {
55
+ if (route === prefix.replace(/\/+$/, "") || route.startsWith(prefix)) return name;
56
+ }
57
+ return null;
58
+ }
59
+ function validatePages(pages, options = {}) {
60
+ const deriveSpec = options.deriveSpec ?? defaultDeriveSpec;
61
+ const violations = [];
62
+ const effective = pages.map((p) => normSpec(p.spec ?? deriveSpec(p.route)));
63
+ pages.forEach((p, i) => {
64
+ if (p.spec || !hasParam(p.route)) return;
65
+ pages.forEach((q, j) => {
66
+ if (i === j) return;
67
+ if (effective[j] !== effective[i]) return;
68
+ violations.push({
69
+ rule: "R1",
70
+ level: "error",
71
+ message: `[R1] \u8DEF\u7531 "${p.route}" \u5265\u53C2\u63A8\u5BFC spec "${effective[i]}" \u4E0E\u8DEF\u7531 "${q.route}"${q.spec ? "\uFF08\u663E\u5F0F spec\uFF09" : ""}\u6536\u655B\u76F8\u540C\u3002
72
+ \u6839\u56E0\uFF1A\u53C2\u6570\u6BB5\u5265\u79BB\u540E expose \u952E\u4E0E\u5176\u5B83\u6761\u76EE\u76F8\u540C\uFF0C\u8BE5\u8DEF\u7531\u4F1A\u9759\u9ED8\u52A0\u8F7D\u9519\u8BEF\u7EC4\u4EF6
73
+ \uFF08\u771F\u5B9E\u4E8B\u6545\uFF1A\u5E26\u53C2\u52A8\u4F5C\u9875\u8BEF\u8D70\u5217\u8868/\u66F4\u65B0\u8BED\u4E49\uFF0C\u6570\u636E\u98CE\u9669\uFF09\u3002
74
+ \u4FEE\u6CD5\uFF1A\u4E3A\u8BE5\u6761\u76EE\u663E\u5F0F\u58F0\u660E spec: '...'\uFF08\u6307\u5411\u5E26\u53C2\u9875\u9762\u81EA\u5DF1\u7684 expose\uFF09\uFF0C\u6216\u8C03\u6574\u8DEF\u7531\u62C6\u5206\u3002`
75
+ });
76
+ });
77
+ });
78
+ const seenSpec = /* @__PURE__ */ new Map();
79
+ pages.forEach((p, i) => {
80
+ const key = effective[i];
81
+ if (seenSpec.has(key)) {
82
+ const first = pages[seenSpec.get(key)];
83
+ const bothExplicit = !!p.spec && !!first.spec;
84
+ violations.push({
85
+ rule: "R2",
86
+ level: "warn",
87
+ message: `[R2] \u8DEF\u7531 "${p.route}" \u4E0E "${first.route}" \u6709\u6548 spec \u76F8\u540C\uFF08"${key}"\uFF09\u3002${bothExplicit ? "\u4E24\u6761\u5747\u4E3A\u663E\u5F0F spec" : "\u5176\u4E2D\u542B\u63A8\u5BFC spec"}\u2014\u2014\u82E5\u4E3A\u523B\u610F\u7684\u83DC\u5355\u522B\u540D\u53EF\u5FFD\u7565\u672C\u8B66\u544A\uFF0C\u5426\u5219\u8BF7\u6838\u5BF9\u3002`
88
+ });
89
+ } else {
90
+ seenSpec.set(key, i);
91
+ }
92
+ });
93
+ if (options.schema && options.remotes) {
94
+ pages.forEach((p, i) => {
95
+ const remote = remoteOfRoute(p.route, options.remotes);
96
+ if (!remote) return;
97
+ const entry = options.schema[remote];
98
+ if (!entry || entry.exists === false) return;
99
+ const exposes = new Set((entry.exposes ?? []).map(normSpec));
100
+ if (!exposes.has(effective[i])) {
101
+ violations.push({
102
+ rule: "R3",
103
+ level: "error",
104
+ message: `[R3] \u8DEF\u7531 "${p.route}" \u7684 spec "${effective[i]}" \u4E0D\u5728\u8FDC\u7A0B "${remote}" \u7684 exposes \u6E05\u5355\u4E2D\u3002
105
+ \u6839\u56E0\uFF1Aspec \u62FC\u5199\u4E0E\u8FDC\u7A0B exposes \u952E\u4E0D\u4E00\u81F4\uFF08\u8FD0\u884C\u65F6\u5C06 MFU-006 \u52A0\u8F7D\u5931\u8D25\uFF09\u3002
106
+ \u4FEE\u6CD5\uFF1A\u6838\u5BF9\u8FDC\u7A0B vite.config exposes \u952E\u540D\uFF0C\u6216\u4FEE\u6B63\u672C\u8868 spec\u3002
107
+ \u8FDC\u7A0B\u5B9E\u9645 exposes\uFF08\u524D 10\uFF09\uFF1A${[...exposes].slice(0, 10).join("\u3001") || "\uFF08\u7A7A\uFF09"}`
108
+ });
109
+ }
110
+ });
111
+ }
112
+ pages.forEach((p, i) => {
113
+ pages.forEach((q, j) => {
114
+ if (j <= i) return;
115
+ const kind = shadows(p.route, q.route);
116
+ if (!kind) return;
117
+ violations.push({
118
+ rule: "R4",
119
+ level: "error",
120
+ message: kind === "full" ? `[R4] \u8DEF\u7531\u5B8C\u5168\u91CD\u590D\uFF1A"${p.route}"\uFF08\u7B2C ${i + 1} \u6761\uFF09\u4E0E "${q.route}"\uFF08\u7B2C ${j + 1} \u6761\uFF09\u3002` : `[R4] \u8DEF\u7531 "${q.route}"\uFF08\u7B2C ${j + 1} \u6761\uFF09\u4F1A\u88AB\u66F4\u9760\u524D\u7684 "${p.route}" \u906E\u853D\uFF08\u5339\u914D\u5148\u5230\u5148\u5F97\uFF0C\u540E\u8005\u6210\u6B7B\u8DEF\u7531\uFF09\u3002
121
+ \u4FEE\u6CD5\uFF1A\u8C03\u6574\u6570\u7EC4\u987A\u5E8F\uFF08\u66F4\u5177\u4F53\u7684\u9759\u6001\u8DEF\u7531\u653E\u524D\u9762\uFF09\u6216\u5408\u5E76\u6761\u76EE\u3002`
122
+ });
123
+ });
124
+ });
125
+ const seenName = /* @__PURE__ */ new Map();
126
+ pages.forEach((p, i) => {
127
+ const name = typeof p.name === "string" ? p.name : "";
128
+ if (!name) return;
129
+ if (seenName.has(name)) {
130
+ violations.push({
131
+ rule: "R5",
132
+ level: "warn",
133
+ message: `[R5] name "${name}" \u91CD\u590D\uFF08"${pages[seenName.get(name)].route}" \u4E0E "${p.route}"\uFF09\u2014\u2014vue-router \u547D\u540D\u8DF3\u8F6C push({name}) \u5C06\u547D\u4E2D\u524D\u8005\uFF0C\u8BF7\u6838\u5BF9\u3002`
134
+ });
135
+ } else {
136
+ seenName.set(name, i);
137
+ }
138
+ });
139
+ return violations;
140
+ }
141
+ function formatViolations(violations) {
142
+ const errors = violations.filter((v) => v.level === "error");
143
+ const warns = violations.filter((v) => v.level === "warn");
144
+ let out = "";
145
+ if (errors.length) {
146
+ out += `[fulgurjs] \u8DEF\u7531\u8868\u6821\u9A8C\u5931\u8D25\uFF08${errors.length} \u9879\uFF0CERROR\uFF09\uFF1A
147
+ ` + errors.map((v) => v.message).join("\n") + "\n";
148
+ }
149
+ if (warns.length) {
150
+ out += `[fulgurjs] \u8DEF\u7531\u8868\u6821\u9A8C\u8B66\u544A\uFF08${warns.length} \u9879\uFF0CWARN\uFF09\uFF1A
151
+ ` + warns.map((v) => v.message).join("\n");
152
+ }
153
+ return out.trim();
154
+ }
155
+ function definePages(pages, options = {}) {
156
+ const violations = validatePages(pages, options);
157
+ const errors = violations.filter((v) => v.level === "error");
158
+ const warns = violations.filter((v) => v.level === "warn");
159
+ const text = formatViolations(violations);
160
+ if (text) {
161
+ if (errors.length && options.strict !== false) {
162
+ throw new Error(text);
163
+ }
164
+ console[errors.length ? "error" : "warn"](text);
165
+ }
166
+ return pages;
167
+ }
168
+
169
+ // src/vue-adapter.ts
170
+ var ERROR_STYLE = {
171
+ padding: "16px",
172
+ border: "1px solid #fde2e2",
173
+ borderRadius: "4px",
174
+ background: "#fef0f0",
175
+ color: "#c45656",
176
+ fontSize: "13px",
177
+ lineHeight: "1.6"
178
+ };
179
+ var RemoteErrorPlaceholder = (0, import_vue.defineComponent)({
180
+ name: "FulgurjsRemoteError",
181
+ props: { error: { type: Object, default: void 0 } },
182
+ setup(props) {
183
+ return () => {
184
+ const err = props.error;
185
+ const code = err?.code ?? "UNKNOWN";
186
+ const message = err?.message ?? String(props.error ?? "unknown error");
187
+ return (0, import_vue.h)("div", { style: ERROR_STYLE }, [
188
+ (0, import_vue.h)("p", { style: "margin:0 0 4px;font-weight:600" }, `\u8FDC\u7A0B\u7EC4\u4EF6\u52A0\u8F7D\u5931\u8D25\uFF08\u9519\u8BEF\u7801 ${code}\uFF09`),
189
+ (0, import_vue.h)("p", { style: "margin:0 0 8px;word-break:break-all" }, message),
190
+ (0, import_vue.h)("p", { style: "margin:0" }, "\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\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")
191
+ ]);
192
+ };
193
+ }
194
+ });
195
+ function createRemoteComponent(loadRemote) {
196
+ return function remoteComponent(spec, opts = {}) {
197
+ return (0, import_vue.defineAsyncComponent)({
198
+ loader: () => loadRemote(spec, { retries: opts.retries }).then((m) => m.default ?? m),
199
+ loadingComponent: opts.loadingComponent,
200
+ errorComponent: opts.errorComponent ?? RemoteErrorPlaceholder,
201
+ delay: opts.delay,
202
+ timeout: opts.timeout
203
+ });
204
+ };
205
+ }
206
+ var cleanCompName = (spec) => "Fulgurjs_" + spec.replace(/[^A-Za-z0-9_-]/g, "_");
207
+ function defaultDeriveSpec2(route) {
208
+ return route.split("/").filter(Boolean).slice(1).filter((seg) => !seg.startsWith(":")).join("/");
209
+ }
210
+ function createHostPages(options, load) {
211
+ const { pages, remotePrefixes, deriveSpec, schema, strict, base, beforeLoad, loadingComponent, errorComponent, delay } = options;
212
+ definePages(pages, { deriveSpec, remotes: remotePrefixes, schema, strict });
213
+ const prefixes = Object.entries(remotePrefixes).map(([p, name]) => [p.endsWith("/") ? p : `${p}/`, name]).sort((a, b) => b[0].length - a[0].length);
214
+ const remoteOf = (route) => {
215
+ for (const [prefix, name] of prefixes) {
216
+ if (route.startsWith(prefix) || `${route}/` === prefix) return name;
217
+ }
218
+ throw new Error(
219
+ `[fulgurjs] page route "${route}" matches none of remotePrefixes { ${Object.entries(remotePrefixes).map(([k, v]) => `'${k}': '${v}'`).join(", ")} }
220
+ \u6839\u56E0: \u9875\u9762\u8868\u6761\u76EE\u7684\u8DEF\u7531\u4E0D\u5728\u4EFB\u4F55\u5DF2\u58F0\u660E\u7684\u8FDC\u7A0B\u524D\u7F00\u4E0B\u3002
221
+ \u4FEE\u6CD5: \u5728 remotePrefixes \u8865\u5145\u8BE5\u8DEF\u7531\u524D\u7F00 \u2192 \u8FDC\u7A0B\u540D\u7684\u6620\u5C04\uFF0C\u6216\u4FEE\u6B63\u9875\u9762\u8868 route\u3002`
222
+ );
223
+ };
224
+ for (const page of pages) remoteOf(page.route);
225
+ const specOf = (page) => {
226
+ const s = page.spec ?? (deriveSpec ? deriveSpec(page.route) : defaultDeriveSpec2(page.route));
227
+ return `${remoteOf(page.route)}/${String(s).replace(/^[./]+/, "")}`;
228
+ };
229
+ const baseNorm = base && base !== "/" ? base.endsWith("/") ? base : `${base}/` : "";
230
+ const matchSegments = (pattern, path) => {
231
+ const patSegs = pattern.split("/").filter(Boolean);
232
+ const pathSegs = path.split("/").filter(Boolean);
233
+ if (patSegs.length !== pathSegs.length) return null;
234
+ const params = {};
235
+ for (let i = 0; i < patSegs.length; i++) {
236
+ const seg = patSegs[i];
237
+ if (seg.startsWith(":")) {
238
+ try {
239
+ params[seg.slice(1)] = decodeURIComponent(pathSegs[i]);
240
+ } catch {
241
+ return null;
242
+ }
243
+ } else if (seg !== pathSegs[i]) {
244
+ return null;
245
+ }
246
+ }
247
+ return params;
248
+ };
249
+ let cacheSession;
250
+ const compCache = /* @__PURE__ */ new Map();
251
+ const resolve = (rawPath) => {
252
+ let clean = String(rawPath ?? "");
253
+ if (baseNorm) {
254
+ if (clean === baseNorm.replace(/\/$/, "")) clean = "/";
255
+ else if (clean.startsWith(baseNorm)) clean = `/${clean.slice(baseNorm.length)}`;
256
+ }
257
+ clean = (clean.replace(/\/+$/, "") || "/").split("?")[0].split("#")[0];
258
+ for (const page of pages) {
259
+ const params = matchSegments(page.route, clean);
260
+ if (params) return { page, remote: remoteOf(page.route), spec: specOf(page), params };
261
+ }
262
+ return null;
263
+ };
264
+ const component = (spec) => {
265
+ const sk = (globalThis.__FULGURJS_APP_CONFIG__ ?? {}).sessionKey;
266
+ const sessionKey = typeof sk === "string" ? sk : void 0;
267
+ if (sessionKey !== cacheSession) {
268
+ compCache.clear();
269
+ cacheSession = sessionKey;
270
+ }
271
+ let comp = compCache.get(spec);
272
+ if (!comp) {
273
+ const name = cleanCompName(spec);
274
+ const asyncComp = (0, import_vue.defineAsyncComponent)({
275
+ loader: async () => {
276
+ await beforeLoad?.();
277
+ const mod = await load(spec);
278
+ const inner = mod?.default ?? mod;
279
+ if (!inner) {
280
+ throw new Error(
281
+ `[fulgurjs] remote module "${spec}" did not export a component (got ${inner === null ? "null" : typeof inner})\u3002
282
+ \u4FEE\u6CD5: \u6838\u5BF9\u8FDC\u7A0B exposes \u952E\u540D\u4E0E\u9875\u9762\u8868 spec \u662F\u5426\u4E00\u81F4\uFF08MFU-006 \u8BED\u4E49\uFF09`
283
+ );
284
+ }
285
+ return inner;
286
+ },
287
+ loadingComponent,
288
+ errorComponent: errorComponent ?? RemoteErrorPlaceholder,
289
+ delay
290
+ });
291
+ comp = (0, import_vue.defineComponent)({
292
+ name,
293
+ inheritAttrs: false,
294
+ setup: (_props, ctx) => () => (0, import_vue.h)(asyncComp, ctx.attrs, ctx.slots)
295
+ });
296
+ compCache.set(spec, comp);
297
+ }
298
+ return comp;
299
+ };
300
+ const keepAliveNames = pages.filter((p) => p.keepAlive).map((p) => cleanCompName(specOf(p)));
301
+ return { pages, resolve, component, keepAliveNames };
302
+ }
303
+ // Annotate the CommonJS export names for ESM import in node:
304
+ 0 && (module.exports = {
305
+ createHostPages,
306
+ createRemoteComponent
307
+ });
@@ -0,0 +1,62 @@
1
+ import { Component } from 'vue';
2
+ import { PageRouteLike, RemoteSchemaEntry } from './pages.cjs';
3
+
4
+ /** Vue 适配层只接收加载函数,不静态引用运行时内核。 */
5
+
6
+ interface RemoteComponentOptions {
7
+ loadingComponent?: Component;
8
+ errorComponent?: Component;
9
+ retries?: number;
10
+ delay?: number;
11
+ timeout?: number;
12
+ }
13
+ declare function createRemoteComponent(loadRemote: (spec: string, opts?: {
14
+ retries?: number;
15
+ }) => Promise<any>): (spec: string, opts?: RemoteComponentOptions) => Component;
16
+ interface HostPagesOptions {
17
+ /** 页面表(宿主路由与布局共用的唯一数据源;definePages R1–R5 校验照常执行) */
18
+ pages: PageRouteLike[];
19
+ /** 路由前缀 → remote 名(最长前缀匹配;页面路由无匹配前缀时创建期即报错) */
20
+ remotePrefixes: Record<string, string>;
21
+ /** 缺省 spec 推导(缺省 = 去首段前缀 + 剥 :参数 段,同 definePages 默认) */
22
+ deriveSpec?: (route: string) => string;
23
+ /** 远程 exposes 清单(dev 由 remoteSchema 提供;build 为空表时按语义诚实降级) */
24
+ schema?: Record<string, RemoteSchemaEntry>;
25
+ /** ERROR 级校验失败是否 throw(默认 true) */
26
+ strict?: boolean;
27
+ /** 站点 base 前缀(如 '/main'):resolve 时先剥离再匹配路由空间 */
28
+ base?: string;
29
+ /** 每次页面模块实际加载前执行(同步或异步);宿主在此提供最新 context */
30
+ beforeLoad?: () => void | Promise<void>;
31
+ /** 加载期占位组件(骨架屏) */
32
+ loadingComponent?: Component;
33
+ /** 错误占位组件(缺省 = 内置三段式错误占位:错误码+根因+修法) */
34
+ errorComponent?: Component;
35
+ /** 骨架屏延迟 ms(默认 200,防闪) */
36
+ delay?: number;
37
+ }
38
+ interface ResolvedHostPage {
39
+ /** 原页面记录(含宿主自由扩展字段 name/title/keepAlive/...) */
40
+ page: PageRouteLike;
41
+ /** 命中的 remote 名 */
42
+ remote: string;
43
+ /** 完整加载 spec(`<remote>/<exposes 键>`,loadRemote 直用) */
44
+ spec: string;
45
+ /** 路径参数(解码失败只让该次匹配失败,不让页面初始化崩溃) */
46
+ params: Record<string, string>;
47
+ }
48
+ interface HostPages {
49
+ /** 原页面记录 */
50
+ pages: PageRouteLike[];
51
+ /** 路径 → 页面解析(兼容 base 前缀与深链;无匹配返回 null) */
52
+ resolve(path: string): ResolvedHostPage | null;
53
+ /** 按 spec 取异步页面组件(同 spec 复用;换登录代次后重建以触发会话同步) */
54
+ component(spec: string): Component;
55
+ /** 保活白名单:keepAlive 页面的组件 name(与实际被 KeepAlive 缓存的包装组件一致) */
56
+ keepAliveNames: string[];
57
+ }
58
+ declare function createHostPages(options: HostPagesOptions, load: (spec: string, opts?: {
59
+ retries?: number;
60
+ }) => Promise<any>): HostPages;
61
+
62
+ export { type HostPages, type HostPagesOptions, type RemoteComponentOptions, type ResolvedHostPage, createHostPages, createRemoteComponent };
@@ -0,0 +1,62 @@
1
+ import { Component } from 'vue';
2
+ import { PageRouteLike, RemoteSchemaEntry } from './pages.js';
3
+
4
+ /** Vue 适配层只接收加载函数,不静态引用运行时内核。 */
5
+
6
+ interface RemoteComponentOptions {
7
+ loadingComponent?: Component;
8
+ errorComponent?: Component;
9
+ retries?: number;
10
+ delay?: number;
11
+ timeout?: number;
12
+ }
13
+ declare function createRemoteComponent(loadRemote: (spec: string, opts?: {
14
+ retries?: number;
15
+ }) => Promise<any>): (spec: string, opts?: RemoteComponentOptions) => Component;
16
+ interface HostPagesOptions {
17
+ /** 页面表(宿主路由与布局共用的唯一数据源;definePages R1–R5 校验照常执行) */
18
+ pages: PageRouteLike[];
19
+ /** 路由前缀 → remote 名(最长前缀匹配;页面路由无匹配前缀时创建期即报错) */
20
+ remotePrefixes: Record<string, string>;
21
+ /** 缺省 spec 推导(缺省 = 去首段前缀 + 剥 :参数 段,同 definePages 默认) */
22
+ deriveSpec?: (route: string) => string;
23
+ /** 远程 exposes 清单(dev 由 remoteSchema 提供;build 为空表时按语义诚实降级) */
24
+ schema?: Record<string, RemoteSchemaEntry>;
25
+ /** ERROR 级校验失败是否 throw(默认 true) */
26
+ strict?: boolean;
27
+ /** 站点 base 前缀(如 '/main'):resolve 时先剥离再匹配路由空间 */
28
+ base?: string;
29
+ /** 每次页面模块实际加载前执行(同步或异步);宿主在此提供最新 context */
30
+ beforeLoad?: () => void | Promise<void>;
31
+ /** 加载期占位组件(骨架屏) */
32
+ loadingComponent?: Component;
33
+ /** 错误占位组件(缺省 = 内置三段式错误占位:错误码+根因+修法) */
34
+ errorComponent?: Component;
35
+ /** 骨架屏延迟 ms(默认 200,防闪) */
36
+ delay?: number;
37
+ }
38
+ interface ResolvedHostPage {
39
+ /** 原页面记录(含宿主自由扩展字段 name/title/keepAlive/...) */
40
+ page: PageRouteLike;
41
+ /** 命中的 remote 名 */
42
+ remote: string;
43
+ /** 完整加载 spec(`<remote>/<exposes 键>`,loadRemote 直用) */
44
+ spec: string;
45
+ /** 路径参数(解码失败只让该次匹配失败,不让页面初始化崩溃) */
46
+ params: Record<string, string>;
47
+ }
48
+ interface HostPages {
49
+ /** 原页面记录 */
50
+ pages: PageRouteLike[];
51
+ /** 路径 → 页面解析(兼容 base 前缀与深链;无匹配返回 null) */
52
+ resolve(path: string): ResolvedHostPage | null;
53
+ /** 按 spec 取异步页面组件(同 spec 复用;换登录代次后重建以触发会话同步) */
54
+ component(spec: string): Component;
55
+ /** 保活白名单:keepAlive 页面的组件 name(与实际被 KeepAlive 缓存的包装组件一致) */
56
+ keepAliveNames: string[];
57
+ }
58
+ declare function createHostPages(options: HostPagesOptions, load: (spec: string, opts?: {
59
+ retries?: number;
60
+ }) => Promise<any>): HostPages;
61
+
62
+ export { type HostPages, type HostPagesOptions, type RemoteComponentOptions, type ResolvedHostPage, createHostPages, createRemoteComponent };
@@ -0,0 +1,9 @@
1
+ import {
2
+ createHostPages,
3
+ createRemoteComponent
4
+ } from "./chunk-NUZKZUTD.js";
5
+ import "./chunk-TSXZ7TWA.js";
6
+ export {
7
+ createHostPages,
8
+ createRemoteComponent
9
+ };