@fulgurjs/federation 4.0.0 → 4.2.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 +49 -0
- package/README.md +369 -138
- package/dist/chunk-NUZKZUTD.js +144 -0
- package/dist/chunk-TSXZ7TWA.js +144 -0
- package/dist/{chunk-3VBYOVH4.js → chunk-WBCXLR2N.js} +9 -1
- package/dist/{chunk-X4LZDAZQ.js → chunk-XIO5Y2IM.js} +1 -1
- package/dist/cli.js +1149 -208
- package/dist/config.cjs +66 -6
- package/dist/config.d.cts +31 -4
- package/dist/config.d.ts +31 -4
- package/dist/config.js +65 -6
- package/dist/context.cjs +12 -2
- package/dist/context.d.cts +21 -5
- package/dist/context.d.ts +21 -5
- package/dist/context.js +12 -3
- package/dist/index.cjs +72 -21
- package/dist/index.d.cts +2 -92
- package/dist/index.d.ts +2 -92
- package/dist/index.js +72 -21
- package/dist/options-CRGpSmVj.d.cts +100 -0
- package/dist/options-CRGpSmVj.d.ts +100 -0
- package/dist/pages.js +4 -139
- package/dist/runtime-entry.d.ts +86 -5
- package/dist/runtime-entry.js +3 -3
- package/dist/runtime.js +10 -3
- package/dist/vue-adapter.cjs +241 -0
- package/dist/vue-adapter.d.cts +47 -1
- package/dist/vue-adapter.d.ts +47 -1
- package/dist/vue-adapter.js +4 -1
- package/dist/vue.cjs +402 -3
- package/dist/vue.d.cts +6 -2
- package/dist/vue.d.ts +6 -2
- package/dist/vue.js +2 -1
- package/docs//350/277/201/347/247/273/346/214/207/345/215/227.md +20 -17
- package/examples/fulgurjs.config.example.ts +29 -37
- package/package.json +1 -1
- package/dist/chunk-AYS56IRF.js +0 -42
package/dist/config.cjs
CHANGED
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var config_exports = {};
|
|
32
32
|
__export(config_exports, {
|
|
33
33
|
defineRepoConfig: () => defineRepoConfig,
|
|
34
|
+
federationOptionsForApp: () => federationOptionsForApp,
|
|
34
35
|
loadRepoConfig: () => loadRepoConfig
|
|
35
36
|
});
|
|
36
37
|
module.exports = __toCommonJS(config_exports);
|
|
@@ -44,19 +45,30 @@ async function loadRepoConfig(configPath) {
|
|
|
44
45
|
const fs = await import("fs");
|
|
45
46
|
const os = await import("os");
|
|
46
47
|
const path = await import("path");
|
|
47
|
-
const selfDir =
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
const selfDir = await (async () => {
|
|
49
|
+
try {
|
|
50
|
+
return path.dirname(fileURLToPath(import_meta.url));
|
|
51
|
+
} catch {
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
return __dirname;
|
|
55
|
+
} catch {
|
|
56
|
+
}
|
|
57
|
+
return "";
|
|
58
|
+
})();
|
|
59
|
+
const selfConfigJs = selfDir ? path.join(selfDir, "config.js") : "";
|
|
60
|
+
const SELF_SPEC = selfConfigJs && fs.existsSync(selfConfigJs) ? pathToFileURL(selfConfigJs).href : "@fulgurjs-federation-config-unavailable";
|
|
50
61
|
const rewriteSelfImports = (source) => source.replace(/(['"])@fulgurjs\/federation\/config\1/g, (_m, q) => `${q}${SELF_SPEC}${q}`);
|
|
62
|
+
let cacheBust = 0;
|
|
51
63
|
const importConfigs = async (cacheKey) => {
|
|
52
|
-
return await import(`${cacheKey}?t=${Date.now()}`);
|
|
64
|
+
return await import(`${cacheKey}?t=${Date.now()}-${++cacheBust}`);
|
|
53
65
|
};
|
|
54
66
|
let mod;
|
|
55
67
|
if (configPath.endsWith(".json")) {
|
|
56
68
|
mod = { default: JSON.parse(fs.readFileSync(configPath, "utf8")) };
|
|
57
69
|
} else {
|
|
58
70
|
const source = rewriteSelfImports(fs.readFileSync(configPath, "utf8"));
|
|
59
|
-
const tmpBase = path.join(os.tmpdir(), `fulgurjs-config-${Date.now()}`);
|
|
71
|
+
const tmpBase = path.join(os.tmpdir(), `fulgurjs-config-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
|
|
60
72
|
if (/\.(ts|mts|cts)$/.test(configPath)) {
|
|
61
73
|
try {
|
|
62
74
|
const tmpTs = `${tmpBase}.ts`;
|
|
@@ -101,14 +113,62 @@ async function loadRepoConfig(configPath) {
|
|
|
101
113
|
throw new Error(
|
|
102
114
|
`[fulgurjs:init] \u5E94\u7528 "${app.path}" \u65E2\u65E0 host \u4E5F\u65E0 remote \u89D2\u8272
|
|
103
115
|
\u6839\u56E0\uFF1A\u5E94\u7528\u5FC5\u987B\u81F3\u5C11\u58F0\u660E\u4E00\u4E2A\u89D2\u8272
|
|
104
|
-
\u4FEE\u6CD5\uFF1A\u5BBF\u4E3B\u8865 host: {
|
|
116
|
+
\u4FEE\u6CD5\uFF1A\u5BBF\u4E3B\u8865 host: { remotePrefixes, remotes }\uFF08pages \u53EF\u9009\uFF09\uFF0C\u8FDC\u7A0B\u8865 remote: { exposes }`
|
|
105
117
|
);
|
|
106
118
|
}
|
|
107
119
|
}
|
|
108
120
|
return cfg;
|
|
109
121
|
}
|
|
122
|
+
function federationOptionsForApp(config, appPathOrName) {
|
|
123
|
+
const app = config.apps.find(
|
|
124
|
+
(a) => a.path === appPathOrName || a.name === appPathOrName
|
|
125
|
+
);
|
|
126
|
+
if (!app) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`[fulgurjs] \u5E94\u7528 "${appPathOrName}" \u4E0D\u5728\u4ED3\u5E93\u914D\u7F6E\u4E2D
|
|
129
|
+
\u53EF\u7528\u5E94\u7528: ${config.apps.map((a) => `${a.path}(${a.name})`).join("\u3001")}
|
|
130
|
+
\u4FEE\u6CD5: \u4FEE\u6B63\u5E94\u7528\u76EE\u5F55\u540D\u6216\u5BB9\u5668\u540D\uFF08fulgurjs.config.ts apps \u6570\u7EC4\u5185\u4E8C\u9009\u4E00\u5339\u914D\uFF09`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
if (!app.host && !app.remote) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`[fulgurjs] \u5E94\u7528 "${app.path}" \u65E2\u65E0 host \u4E5F\u65E0 remote \u89D2\u8272
|
|
136
|
+
\u4FEE\u6CD5: \u5BBF\u4E3B\u8865 host: { remotePrefixes, remotes }\uFF0C\u8FDC\u7A0B\u8865 remote: { exposes }`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
const remotes = {};
|
|
140
|
+
const remoteSource = /* @__PURE__ */ new Map();
|
|
141
|
+
const mergeRemotes = (from, role) => {
|
|
142
|
+
for (const [key, addr] of Object.entries(from ?? {})) {
|
|
143
|
+
const prev = remotes[key];
|
|
144
|
+
if (prev && (prev.dev !== addr.dev || prev.prod !== addr.prod)) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`[fulgurjs] \u5E94\u7528 "${app.path}" \u7684\u8FDC\u7A0B "${key}" \u5728 ${role} \u4E0E ${remoteSource.get(key)} \u4E24\u5904\u5730\u5740\u4E0D\u4E00\u81F4
|
|
147
|
+
${remoteSource.get(key)}: dev=${prev.dev} prod=${prev.prod}
|
|
148
|
+
${role}: dev=${addr.dev} prod=${addr.prod}
|
|
149
|
+
\u4FEE\u6CD5: \u4FEE\u6B63 fulgurjs.config.ts \u4F7F\u4E24\u5904\u4E00\u81F4\uFF08\u540C\u4E00\u8FDC\u7A0B\u5728\u4E00\u4E2A\u5E94\u7528\u5185\u53EA\u80FD\u6709\u4E00\u4E2A\u5730\u5740\uFF09`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
remotes[key] = addr;
|
|
153
|
+
remoteSource.set(key, role);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
mergeRemotes(app.host?.remotes, "host.remotes");
|
|
157
|
+
mergeRemotes(app.remote?.remotes, "remote.remotes");
|
|
158
|
+
const hasExposes = !!app.remote && Object.keys(app.remote.exposes).length > 0;
|
|
159
|
+
const hasRemotes = Object.keys(remotes).length > 0;
|
|
160
|
+
return {
|
|
161
|
+
name: app.name,
|
|
162
|
+
...hasRemotes ? { remotes } : {},
|
|
163
|
+
...hasExposes ? { exposes: app.remote.exposes } : {},
|
|
164
|
+
...app.remote?.setup ? { setup: app.remote.setup } : {},
|
|
165
|
+
...app.shared ? { shared: app.shared } : {},
|
|
166
|
+
devSharedSelf: app.devSharedSelf ?? (hasExposes || !!app.remote?.setup)
|
|
167
|
+
};
|
|
168
|
+
}
|
|
110
169
|
// Annotate the CommonJS export names for ESM import in node:
|
|
111
170
|
0 && (module.exports = {
|
|
112
171
|
defineRepoConfig,
|
|
172
|
+
federationOptionsForApp,
|
|
113
173
|
loadRepoConfig
|
|
114
174
|
});
|
package/dist/config.d.cts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { F as FederationOptions } from './options-CRGpSmVj.cjs';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* W1 fulgurjs.config.ts:单配置文件驱动的 schema + 加载器(项目无关,决策见排期文档 §4:
|
|
3
5
|
* 主包内置 bin + 单配置文件驱动,可入库可复跑)。
|
|
@@ -12,14 +14,22 @@ interface PageEntry {
|
|
|
12
14
|
spec?: string;
|
|
13
15
|
/** 页签标题 */
|
|
14
16
|
title?: string;
|
|
17
|
+
/** 页面保活开关(按页显式开启;默认关闭) */
|
|
18
|
+
keepAlive?: boolean;
|
|
15
19
|
}
|
|
16
20
|
interface RemoteAddress {
|
|
17
21
|
dev: string;
|
|
18
22
|
prod: string;
|
|
19
23
|
}
|
|
20
24
|
interface HostConfig {
|
|
21
|
-
/**
|
|
22
|
-
|
|
25
|
+
/**
|
|
26
|
+
* 页面路由表(可选):应用代码的页面表是运行时页面真源(供宿主路由与
|
|
27
|
+
* createHostPages 共用),仓库配置中的副本仅供 init/explain 摘要与核对。
|
|
28
|
+
* 不再强制——缺省时 CLI 摘要按实际提供数量报告。
|
|
29
|
+
*/
|
|
30
|
+
pages?: PageEntry[];
|
|
31
|
+
/** 页面 spec 推导规则(与宿主 createHostPages 的 deriveSpec 保持一致;缺省 = 去首段 + 剥 :参 段) */
|
|
32
|
+
deriveSpec?: (route: string) => string;
|
|
23
33
|
/** 路由前缀 → 远程名 */
|
|
24
34
|
remotePrefixes: Record<string, string>;
|
|
25
35
|
/** 消费的远程地址(键 = import 前缀;裸 URL,对象形式不支持 name@ 前缀) */
|
|
@@ -28,7 +38,9 @@ interface HostConfig {
|
|
|
28
38
|
interface RemoteConfig {
|
|
29
39
|
/** exposes:./键 → 源文件(独立页) */
|
|
30
40
|
exposes: Record<string, string>;
|
|
31
|
-
/**
|
|
41
|
+
/** 远程初始化入口(默认导出 setup(context),可选具名导出 onSession(context)) */
|
|
42
|
+
setup?: string;
|
|
43
|
+
/** 反向消费的远程(双向联邦时) */
|
|
32
44
|
remotes?: Record<string, RemoteAddress>;
|
|
33
45
|
}
|
|
34
46
|
interface AppConfig {
|
|
@@ -51,6 +63,8 @@ interface AppConfig {
|
|
|
51
63
|
singleton?: boolean;
|
|
52
64
|
requiredVersion?: string;
|
|
53
65
|
}>;
|
|
66
|
+
/** 显式覆盖 dev 下自身源码参与 shared 协商改写;缺省按角色推断(见 federationOptionsForApp) */
|
|
67
|
+
devSharedSelf?: boolean;
|
|
54
68
|
}
|
|
55
69
|
interface DeployConfig {
|
|
56
70
|
/** NGINX 站点根(样板输出用,可选) */
|
|
@@ -75,5 +89,18 @@ declare function defineRepoConfig(config: UserConfig): UserConfig;
|
|
|
75
89
|
* 老版本 Node 回退 esbuild 转译(先试配置工程,再试 CLI 自带依赖树)。
|
|
76
90
|
*/
|
|
77
91
|
declare function loadRepoConfig(configPath: string): Promise<RepoConfig>;
|
|
92
|
+
/**
|
|
93
|
+
* 仓库配置 → 某应用的 federation() Vite 插件选项(§3.4 单配置驱动)。
|
|
94
|
+
*
|
|
95
|
+
* 转换范围:name、宿主/反向 remotes(两处同键冲突即报错,带两边值)、exposes、
|
|
96
|
+
* 可选 setup、shared、devSharedSelf。build.target/base/端口/代理/插件顺序等仍归各应用
|
|
97
|
+
* vite.config.ts 管理——本函数只生成 federation({...}) 的入参。
|
|
98
|
+
*
|
|
99
|
+
* devSharedSelf 来源(优先级):app.devSharedSelf 显式值 > 角色推断。
|
|
100
|
+
* 推断规则:提供 exposes(含仅 setup)的应用为 true(其源码被宿主消费,需协商到宿主
|
|
101
|
+
* 实例);纯宿主(只消费)为 false。双向联邦漏配该项曾是已知错误配置(§12.4),
|
|
102
|
+
* 推断后不再依赖背诵。
|
|
103
|
+
*/
|
|
104
|
+
declare function federationOptionsForApp(config: RepoConfig, appPathOrName: string): FederationOptions;
|
|
78
105
|
|
|
79
|
-
export { type AppConfig, type DeployConfig, type HostConfig, type PageEntry, type RemoteAddress, type RemoteConfig, type RepoConfig, type UserConfig, defineRepoConfig, loadRepoConfig };
|
|
106
|
+
export { type AppConfig, type DeployConfig, type HostConfig, type PageEntry, type RemoteAddress, type RemoteConfig, type RepoConfig, type UserConfig, defineRepoConfig, federationOptionsForApp, loadRepoConfig };
|
package/dist/config.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { F as FederationOptions } from './options-CRGpSmVj.js';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* W1 fulgurjs.config.ts:单配置文件驱动的 schema + 加载器(项目无关,决策见排期文档 §4:
|
|
3
5
|
* 主包内置 bin + 单配置文件驱动,可入库可复跑)。
|
|
@@ -12,14 +14,22 @@ interface PageEntry {
|
|
|
12
14
|
spec?: string;
|
|
13
15
|
/** 页签标题 */
|
|
14
16
|
title?: string;
|
|
17
|
+
/** 页面保活开关(按页显式开启;默认关闭) */
|
|
18
|
+
keepAlive?: boolean;
|
|
15
19
|
}
|
|
16
20
|
interface RemoteAddress {
|
|
17
21
|
dev: string;
|
|
18
22
|
prod: string;
|
|
19
23
|
}
|
|
20
24
|
interface HostConfig {
|
|
21
|
-
/**
|
|
22
|
-
|
|
25
|
+
/**
|
|
26
|
+
* 页面路由表(可选):应用代码的页面表是运行时页面真源(供宿主路由与
|
|
27
|
+
* createHostPages 共用),仓库配置中的副本仅供 init/explain 摘要与核对。
|
|
28
|
+
* 不再强制——缺省时 CLI 摘要按实际提供数量报告。
|
|
29
|
+
*/
|
|
30
|
+
pages?: PageEntry[];
|
|
31
|
+
/** 页面 spec 推导规则(与宿主 createHostPages 的 deriveSpec 保持一致;缺省 = 去首段 + 剥 :参 段) */
|
|
32
|
+
deriveSpec?: (route: string) => string;
|
|
23
33
|
/** 路由前缀 → 远程名 */
|
|
24
34
|
remotePrefixes: Record<string, string>;
|
|
25
35
|
/** 消费的远程地址(键 = import 前缀;裸 URL,对象形式不支持 name@ 前缀) */
|
|
@@ -28,7 +38,9 @@ interface HostConfig {
|
|
|
28
38
|
interface RemoteConfig {
|
|
29
39
|
/** exposes:./键 → 源文件(独立页) */
|
|
30
40
|
exposes: Record<string, string>;
|
|
31
|
-
/**
|
|
41
|
+
/** 远程初始化入口(默认导出 setup(context),可选具名导出 onSession(context)) */
|
|
42
|
+
setup?: string;
|
|
43
|
+
/** 反向消费的远程(双向联邦时) */
|
|
32
44
|
remotes?: Record<string, RemoteAddress>;
|
|
33
45
|
}
|
|
34
46
|
interface AppConfig {
|
|
@@ -51,6 +63,8 @@ interface AppConfig {
|
|
|
51
63
|
singleton?: boolean;
|
|
52
64
|
requiredVersion?: string;
|
|
53
65
|
}>;
|
|
66
|
+
/** 显式覆盖 dev 下自身源码参与 shared 协商改写;缺省按角色推断(见 federationOptionsForApp) */
|
|
67
|
+
devSharedSelf?: boolean;
|
|
54
68
|
}
|
|
55
69
|
interface DeployConfig {
|
|
56
70
|
/** NGINX 站点根(样板输出用,可选) */
|
|
@@ -75,5 +89,18 @@ declare function defineRepoConfig(config: UserConfig): UserConfig;
|
|
|
75
89
|
* 老版本 Node 回退 esbuild 转译(先试配置工程,再试 CLI 自带依赖树)。
|
|
76
90
|
*/
|
|
77
91
|
declare function loadRepoConfig(configPath: string): Promise<RepoConfig>;
|
|
92
|
+
/**
|
|
93
|
+
* 仓库配置 → 某应用的 federation() Vite 插件选项(§3.4 单配置驱动)。
|
|
94
|
+
*
|
|
95
|
+
* 转换范围:name、宿主/反向 remotes(两处同键冲突即报错,带两边值)、exposes、
|
|
96
|
+
* 可选 setup、shared、devSharedSelf。build.target/base/端口/代理/插件顺序等仍归各应用
|
|
97
|
+
* vite.config.ts 管理——本函数只生成 federation({...}) 的入参。
|
|
98
|
+
*
|
|
99
|
+
* devSharedSelf 来源(优先级):app.devSharedSelf 显式值 > 角色推断。
|
|
100
|
+
* 推断规则:提供 exposes(含仅 setup)的应用为 true(其源码被宿主消费,需协商到宿主
|
|
101
|
+
* 实例);纯宿主(只消费)为 false。双向联邦漏配该项曾是已知错误配置(§12.4),
|
|
102
|
+
* 推断后不再依赖背诵。
|
|
103
|
+
*/
|
|
104
|
+
declare function federationOptionsForApp(config: RepoConfig, appPathOrName: string): FederationOptions;
|
|
78
105
|
|
|
79
|
-
export { type AppConfig, type DeployConfig, type HostConfig, type PageEntry, type RemoteAddress, type RemoteConfig, type RepoConfig, type UserConfig, defineRepoConfig, loadRepoConfig };
|
|
106
|
+
export { type AppConfig, type DeployConfig, type HostConfig, type PageEntry, type RemoteAddress, type RemoteConfig, type RepoConfig, type UserConfig, defineRepoConfig, federationOptionsForApp, loadRepoConfig };
|
package/dist/config.js
CHANGED
|
@@ -8,19 +8,30 @@ async function loadRepoConfig(configPath) {
|
|
|
8
8
|
const fs = await import("fs");
|
|
9
9
|
const os = await import("os");
|
|
10
10
|
const path = await import("path");
|
|
11
|
-
const selfDir =
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
const selfDir = await (async () => {
|
|
12
|
+
try {
|
|
13
|
+
return path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
} catch {
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
return __dirname;
|
|
18
|
+
} catch {
|
|
19
|
+
}
|
|
20
|
+
return "";
|
|
21
|
+
})();
|
|
22
|
+
const selfConfigJs = selfDir ? path.join(selfDir, "config.js") : "";
|
|
23
|
+
const SELF_SPEC = selfConfigJs && fs.existsSync(selfConfigJs) ? pathToFileURL(selfConfigJs).href : "@fulgurjs-federation-config-unavailable";
|
|
14
24
|
const rewriteSelfImports = (source) => source.replace(/(['"])@fulgurjs\/federation\/config\1/g, (_m, q) => `${q}${SELF_SPEC}${q}`);
|
|
25
|
+
let cacheBust = 0;
|
|
15
26
|
const importConfigs = async (cacheKey) => {
|
|
16
|
-
return await import(`${cacheKey}?t=${Date.now()}`);
|
|
27
|
+
return await import(`${cacheKey}?t=${Date.now()}-${++cacheBust}`);
|
|
17
28
|
};
|
|
18
29
|
let mod;
|
|
19
30
|
if (configPath.endsWith(".json")) {
|
|
20
31
|
mod = { default: JSON.parse(fs.readFileSync(configPath, "utf8")) };
|
|
21
32
|
} else {
|
|
22
33
|
const source = rewriteSelfImports(fs.readFileSync(configPath, "utf8"));
|
|
23
|
-
const tmpBase = path.join(os.tmpdir(), `fulgurjs-config-${Date.now()}`);
|
|
34
|
+
const tmpBase = path.join(os.tmpdir(), `fulgurjs-config-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
|
|
24
35
|
if (/\.(ts|mts|cts)$/.test(configPath)) {
|
|
25
36
|
try {
|
|
26
37
|
const tmpTs = `${tmpBase}.ts`;
|
|
@@ -65,13 +76,61 @@ async function loadRepoConfig(configPath) {
|
|
|
65
76
|
throw new Error(
|
|
66
77
|
`[fulgurjs:init] \u5E94\u7528 "${app.path}" \u65E2\u65E0 host \u4E5F\u65E0 remote \u89D2\u8272
|
|
67
78
|
\u6839\u56E0\uFF1A\u5E94\u7528\u5FC5\u987B\u81F3\u5C11\u58F0\u660E\u4E00\u4E2A\u89D2\u8272
|
|
68
|
-
\u4FEE\u6CD5\uFF1A\u5BBF\u4E3B\u8865 host: {
|
|
79
|
+
\u4FEE\u6CD5\uFF1A\u5BBF\u4E3B\u8865 host: { remotePrefixes, remotes }\uFF08pages \u53EF\u9009\uFF09\uFF0C\u8FDC\u7A0B\u8865 remote: { exposes }`
|
|
69
80
|
);
|
|
70
81
|
}
|
|
71
82
|
}
|
|
72
83
|
return cfg;
|
|
73
84
|
}
|
|
85
|
+
function federationOptionsForApp(config, appPathOrName) {
|
|
86
|
+
const app = config.apps.find(
|
|
87
|
+
(a) => a.path === appPathOrName || a.name === appPathOrName
|
|
88
|
+
);
|
|
89
|
+
if (!app) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`[fulgurjs] \u5E94\u7528 "${appPathOrName}" \u4E0D\u5728\u4ED3\u5E93\u914D\u7F6E\u4E2D
|
|
92
|
+
\u53EF\u7528\u5E94\u7528: ${config.apps.map((a) => `${a.path}(${a.name})`).join("\u3001")}
|
|
93
|
+
\u4FEE\u6CD5: \u4FEE\u6B63\u5E94\u7528\u76EE\u5F55\u540D\u6216\u5BB9\u5668\u540D\uFF08fulgurjs.config.ts apps \u6570\u7EC4\u5185\u4E8C\u9009\u4E00\u5339\u914D\uFF09`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (!app.host && !app.remote) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`[fulgurjs] \u5E94\u7528 "${app.path}" \u65E2\u65E0 host \u4E5F\u65E0 remote \u89D2\u8272
|
|
99
|
+
\u4FEE\u6CD5: \u5BBF\u4E3B\u8865 host: { remotePrefixes, remotes }\uFF0C\u8FDC\u7A0B\u8865 remote: { exposes }`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
const remotes = {};
|
|
103
|
+
const remoteSource = /* @__PURE__ */ new Map();
|
|
104
|
+
const mergeRemotes = (from, role) => {
|
|
105
|
+
for (const [key, addr] of Object.entries(from ?? {})) {
|
|
106
|
+
const prev = remotes[key];
|
|
107
|
+
if (prev && (prev.dev !== addr.dev || prev.prod !== addr.prod)) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`[fulgurjs] \u5E94\u7528 "${app.path}" \u7684\u8FDC\u7A0B "${key}" \u5728 ${role} \u4E0E ${remoteSource.get(key)} \u4E24\u5904\u5730\u5740\u4E0D\u4E00\u81F4
|
|
110
|
+
${remoteSource.get(key)}: dev=${prev.dev} prod=${prev.prod}
|
|
111
|
+
${role}: dev=${addr.dev} prod=${addr.prod}
|
|
112
|
+
\u4FEE\u6CD5: \u4FEE\u6B63 fulgurjs.config.ts \u4F7F\u4E24\u5904\u4E00\u81F4\uFF08\u540C\u4E00\u8FDC\u7A0B\u5728\u4E00\u4E2A\u5E94\u7528\u5185\u53EA\u80FD\u6709\u4E00\u4E2A\u5730\u5740\uFF09`
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
remotes[key] = addr;
|
|
116
|
+
remoteSource.set(key, role);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
mergeRemotes(app.host?.remotes, "host.remotes");
|
|
120
|
+
mergeRemotes(app.remote?.remotes, "remote.remotes");
|
|
121
|
+
const hasExposes = !!app.remote && Object.keys(app.remote.exposes).length > 0;
|
|
122
|
+
const hasRemotes = Object.keys(remotes).length > 0;
|
|
123
|
+
return {
|
|
124
|
+
name: app.name,
|
|
125
|
+
...hasRemotes ? { remotes } : {},
|
|
126
|
+
...hasExposes ? { exposes: app.remote.exposes } : {},
|
|
127
|
+
...app.remote?.setup ? { setup: app.remote.setup } : {},
|
|
128
|
+
...app.shared ? { shared: app.shared } : {},
|
|
129
|
+
devSharedSelf: app.devSharedSelf ?? (hasExposes || !!app.remote?.setup)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
74
132
|
export {
|
|
75
133
|
defineRepoConfig,
|
|
134
|
+
federationOptionsForApp,
|
|
76
135
|
loadRepoConfig
|
|
77
136
|
};
|
package/dist/context.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var context_exports = {};
|
|
22
22
|
__export(context_exports, {
|
|
23
23
|
ContextErrorCodes: () => ContextErrorCodes,
|
|
24
|
+
clearAppContext: () => clearAppContext,
|
|
24
25
|
getAppContext: () => getAppContext,
|
|
25
26
|
provideAppContext: () => provideAppContext,
|
|
26
27
|
requireAppContext: () => requireAppContext
|
|
@@ -52,7 +53,7 @@ function requireRuntime() {
|
|
|
52
53
|
if (!rt || typeof rt.loadRemote !== "function") {
|
|
53
54
|
throw new FgError(
|
|
54
55
|
ContextErrorCodes.CONTEXT_NO_RUNTIME,
|
|
55
|
-
"fulgurjs runtime singleton not found on this page (globalThis.__FULGURJS_RUNTIME__ is undefined).\n \u6839\u56E0: \u5F53\u524D\u9875\u9762\u6CA1\u6709\u7ECF\u5BBF\u4E3B\u7684\u8054\u90A6\u8FD0\u884C\u65F6\u52A0\u8F7D\uFF08\u72EC\u7ACB\u76F4\u5F00\u8FDC\u7A0B\u9875\uFF0C\u6216\u5BBF\u4E3B\u6865\u665A\u4E8E\u672C\u8C03\u7528\u6267\u884C\uFF09\u3002\n \u4FEE\u6CD5: \u2460 \u4ECE\u5BBF\u4E3B\u5E94\u7528\u7684\u8054\u90A6\u8DEF\u7531\u6253\u5F00\u672C\u9875\u9762\uFF08\u5BBF\u4E3B
|
|
56
|
+
"fulgurjs runtime singleton not found on this page (globalThis.__FULGURJS_RUNTIME__ is undefined).\n \u6839\u56E0: \u5F53\u524D\u9875\u9762\u6CA1\u6709\u7ECF\u5BBF\u4E3B\u7684\u8054\u90A6\u8FD0\u884C\u65F6\u52A0\u8F7D\uFF08\u72EC\u7ACB\u76F4\u5F00\u8FDC\u7A0B\u9875\uFF0C\u6216\u5BBF\u4E3B\u6865\u665A\u4E8E\u672C\u8C03\u7528\u6267\u884C\uFF09\u3002\n \u4FEE\u6CD5: \u2460 \u4ECE\u5BBF\u4E3B\u5E94\u7528\u7684\u8054\u90A6\u8DEF\u7531\u6253\u5F00\u672C\u9875\u9762\uFF08\u5BBF\u4E3B\u6865\u4F1A\u5148\u52A0\u8F7D\u8FD0\u884C\u65F6\u5E76\u63D0\u4F9B context\uFF09\uFF1B\n \u2461 \u82E5\u4F60\u662F\u5BBF\u4E3B\u6865\u4F5C\u8005\uFF1A\u628A provideAppContext \u653E\u5728\u6865\u521D\u59CB\u5316\u5C3E\u90E8\uFF08\u65F6\u5E8F\u5951\u7EA6 bridge \u2192 \u8FDC\u7A0B setup \u2192 \u9875\u9762\u6A21\u5757\uFF09\u3002",
|
|
56
57
|
{ runtime: false }
|
|
57
58
|
);
|
|
58
59
|
}
|
|
@@ -63,6 +64,14 @@ function provideAppContext(config) {
|
|
|
63
64
|
const g = globalThis;
|
|
64
65
|
g[APP_CONTEXT_STORAGE_KEY] = { ...g[APP_CONTEXT_STORAGE_KEY] ?? {}, ...config };
|
|
65
66
|
}
|
|
67
|
+
function clearAppContext() {
|
|
68
|
+
const g = globalThis;
|
|
69
|
+
delete g[APP_CONTEXT_STORAGE_KEY];
|
|
70
|
+
try {
|
|
71
|
+
g.__FULGURJS_RUNTIME__?.clearSessionState?.();
|
|
72
|
+
} catch {
|
|
73
|
+
}
|
|
74
|
+
}
|
|
66
75
|
function getAppContext() {
|
|
67
76
|
requireRuntime();
|
|
68
77
|
return globalThis[APP_CONTEXT_STORAGE_KEY] ?? {};
|
|
@@ -78,7 +87,7 @@ function requireAppContext(...keys) {
|
|
|
78
87
|
got: ${got.length ? got.map((k) => `"${k}"`).join(", ") : "(empty \u2014 \u5BBF\u4E3B\u6865\u4ECE\u672A\u8C03\u7528 provideAppContext?)"}
|
|
79
88
|
expected: \u5BBF\u4E3B\u6865\u5FC5\u987B\u5728\u4EFB\u4F55\u8FDC\u7A0B\u9875\u9762\u52A0\u8F7D\u524D\u63D0\u4F9B ${missing.map((k) => `"${k}"`).join(" / ")}
|
|
80
89
|
example: host/src/fulgurjs/host/bridge.ts \u2192 provideAppContext({ ${keys.join(", ")}, ... })
|
|
81
|
-
\u4FEE\u6CD5: \u68C0\u67E5\u5BBF\u4E3B\u5E94\u7528 fulgurjs
|
|
90
|
+
\u4FEE\u6CD5: \u68C0\u67E5\u5BBF\u4E3B\u5E94\u7528\u7684 fulgurjs \u6865\u662F\u5426\u5728 loadRemote \u9875\u9762\u524D\u5B8C\u6210 context provide\uFF08\u65F6\u5E8F\u5951\u7EA6 bridge \u2192 \u8FDC\u7A0B setup \u2192 \u9875\u9762\u6A21\u5757\uFF09`,
|
|
82
91
|
{ missing, got }
|
|
83
92
|
);
|
|
84
93
|
throw err;
|
|
@@ -86,6 +95,7 @@ function requireAppContext(...keys) {
|
|
|
86
95
|
// Annotate the CommonJS export names for ESM import in node:
|
|
87
96
|
0 && (module.exports = {
|
|
88
97
|
ContextErrorCodes,
|
|
98
|
+
clearAppContext,
|
|
89
99
|
getAppContext,
|
|
90
100
|
provideAppContext,
|
|
91
101
|
requireAppContext
|
package/dist/context.d.cts
CHANGED
|
@@ -30,27 +30,43 @@ interface AppContext {
|
|
|
30
30
|
locale?: unknown;
|
|
31
31
|
/** 事件/方法池:events.main.* 宿主提供、events.bpm.* / events.lowcode.* 子应用反向注册 */
|
|
32
32
|
events?: Record<string, any>;
|
|
33
|
+
/**
|
|
34
|
+
* 非敏感登录代次 ID:宿主每次成功登录/重新登录生成新值,token 刷新但会话未变时沿用。
|
|
35
|
+
* 远程 onSession 按它去重(同一代次只执行一次)。不是用户 ID、不是 token、不作为授权凭证。
|
|
36
|
+
* 远程声明了 onSession 时必填(缺省即 MFU-013)。
|
|
37
|
+
*/
|
|
38
|
+
sessionKey?: string;
|
|
33
39
|
/** 项目扩展位(formUrl/baseUrl 等自定义键,按需自行提供) */
|
|
34
40
|
[key: string]: unknown;
|
|
35
41
|
}
|
|
36
42
|
/**
|
|
37
43
|
* 宿主写入跨应用上下文(merge 语义,幂等可多次调用,后写覆盖同键)。
|
|
38
44
|
*
|
|
39
|
-
* 宿主桥(host/src/fulgurjs/host/bridge.ts
|
|
40
|
-
* provideAppContext({ user,
|
|
45
|
+
* 宿主桥(host/src/fulgurjs/host/bridge.ts)在登录完成后调用:
|
|
46
|
+
* provideAppContext({ user, getToken, store, hostApp, locale, sessionKey, events: { main: mainEvents }, ... })
|
|
47
|
+
* 登录态变化(换账号/token 刷新)时再次调用即以最新值覆盖同键——不要用布尔闩锁把桥封成只跑一次。
|
|
41
48
|
*/
|
|
42
49
|
declare function provideAppContext(config: Partial<AppContext> & Record<string, unknown>): void;
|
|
50
|
+
/**
|
|
51
|
+
* 宿主退出登录时清理:删除整个 context 对象(旧 user/getToken 引用一并失效),并通知
|
|
52
|
+
* 运行时单例作废全部远程的会话信号与 onSession 去重状态(下次登录必须重新执行 onSession)。
|
|
53
|
+
*
|
|
54
|
+
* 边界(契约):只清 AppContext 与会话初始化状态;不重置远程模块缓存、共享模块图与
|
|
55
|
+
* 应用级 setup 注册(同一页面内组件与共享实例继续复用)。页面无运行时单例时静默幂等
|
|
56
|
+
* (退出动作不依赖联邦形态,不得因缺运行时而打断登出流程)。
|
|
57
|
+
*/
|
|
58
|
+
declare function clearAppContext(): void;
|
|
43
59
|
/**
|
|
44
60
|
* 读上下文快照(传输层快照:顶层 merge 结果 + 嵌套对象引用共享)。
|
|
45
61
|
* 页面无运行时单例(独立直开远程页)→ CC-002 显式抛错,不静默回空。
|
|
46
62
|
*/
|
|
47
63
|
declare function getAppContext(): AppContext;
|
|
48
64
|
/**
|
|
49
|
-
* 显式校验读取(远程 boot 消费入口):任一键缺失 → CC-001 三段式。
|
|
65
|
+
* 显式校验读取(远程 setup/boot 消费入口):任一键缺失 → CC-001 三段式。
|
|
50
66
|
*
|
|
51
67
|
* 用法:const { store, user, hostApp } = requireAppContext('store', 'user', 'hostApp')
|
|
52
|
-
*
|
|
68
|
+
* 时序契约:宿主桥先 provide,远程 setup/onSession 后 require——违反即在初始化处显式失败。
|
|
53
69
|
*/
|
|
54
70
|
declare function requireAppContext(...keys: string[]): AppContext;
|
|
55
71
|
|
|
56
|
-
export { type AppContext, ContextErrorCodes, getAppContext, provideAppContext, requireAppContext };
|
|
72
|
+
export { type AppContext, ContextErrorCodes, clearAppContext, getAppContext, provideAppContext, requireAppContext };
|
package/dist/context.d.ts
CHANGED
|
@@ -30,27 +30,43 @@ interface AppContext {
|
|
|
30
30
|
locale?: unknown;
|
|
31
31
|
/** 事件/方法池:events.main.* 宿主提供、events.bpm.* / events.lowcode.* 子应用反向注册 */
|
|
32
32
|
events?: Record<string, any>;
|
|
33
|
+
/**
|
|
34
|
+
* 非敏感登录代次 ID:宿主每次成功登录/重新登录生成新值,token 刷新但会话未变时沿用。
|
|
35
|
+
* 远程 onSession 按它去重(同一代次只执行一次)。不是用户 ID、不是 token、不作为授权凭证。
|
|
36
|
+
* 远程声明了 onSession 时必填(缺省即 MFU-013)。
|
|
37
|
+
*/
|
|
38
|
+
sessionKey?: string;
|
|
33
39
|
/** 项目扩展位(formUrl/baseUrl 等自定义键,按需自行提供) */
|
|
34
40
|
[key: string]: unknown;
|
|
35
41
|
}
|
|
36
42
|
/**
|
|
37
43
|
* 宿主写入跨应用上下文(merge 语义,幂等可多次调用,后写覆盖同键)。
|
|
38
44
|
*
|
|
39
|
-
* 宿主桥(host/src/fulgurjs/host/bridge.ts
|
|
40
|
-
* provideAppContext({ user,
|
|
45
|
+
* 宿主桥(host/src/fulgurjs/host/bridge.ts)在登录完成后调用:
|
|
46
|
+
* provideAppContext({ user, getToken, store, hostApp, locale, sessionKey, events: { main: mainEvents }, ... })
|
|
47
|
+
* 登录态变化(换账号/token 刷新)时再次调用即以最新值覆盖同键——不要用布尔闩锁把桥封成只跑一次。
|
|
41
48
|
*/
|
|
42
49
|
declare function provideAppContext(config: Partial<AppContext> & Record<string, unknown>): void;
|
|
50
|
+
/**
|
|
51
|
+
* 宿主退出登录时清理:删除整个 context 对象(旧 user/getToken 引用一并失效),并通知
|
|
52
|
+
* 运行时单例作废全部远程的会话信号与 onSession 去重状态(下次登录必须重新执行 onSession)。
|
|
53
|
+
*
|
|
54
|
+
* 边界(契约):只清 AppContext 与会话初始化状态;不重置远程模块缓存、共享模块图与
|
|
55
|
+
* 应用级 setup 注册(同一页面内组件与共享实例继续复用)。页面无运行时单例时静默幂等
|
|
56
|
+
* (退出动作不依赖联邦形态,不得因缺运行时而打断登出流程)。
|
|
57
|
+
*/
|
|
58
|
+
declare function clearAppContext(): void;
|
|
43
59
|
/**
|
|
44
60
|
* 读上下文快照(传输层快照:顶层 merge 结果 + 嵌套对象引用共享)。
|
|
45
61
|
* 页面无运行时单例(独立直开远程页)→ CC-002 显式抛错,不静默回空。
|
|
46
62
|
*/
|
|
47
63
|
declare function getAppContext(): AppContext;
|
|
48
64
|
/**
|
|
49
|
-
* 显式校验读取(远程 boot 消费入口):任一键缺失 → CC-001 三段式。
|
|
65
|
+
* 显式校验读取(远程 setup/boot 消费入口):任一键缺失 → CC-001 三段式。
|
|
50
66
|
*
|
|
51
67
|
* 用法:const { store, user, hostApp } = requireAppContext('store', 'user', 'hostApp')
|
|
52
|
-
*
|
|
68
|
+
* 时序契约:宿主桥先 provide,远程 setup/onSession 后 require——违反即在初始化处显式失败。
|
|
53
69
|
*/
|
|
54
70
|
declare function requireAppContext(...keys: string[]): AppContext;
|
|
55
71
|
|
|
56
|
-
export { type AppContext, ContextErrorCodes, getAppContext, provideAppContext, requireAppContext };
|
|
72
|
+
export { type AppContext, ContextErrorCodes, clearAppContext, getAppContext, provideAppContext, requireAppContext };
|
package/dist/context.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FgError
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-WBCXLR2N.js";
|
|
4
4
|
|
|
5
5
|
// src/context.ts
|
|
6
6
|
var ContextErrorCodes = {
|
|
@@ -15,7 +15,7 @@ function requireRuntime() {
|
|
|
15
15
|
if (!rt || typeof rt.loadRemote !== "function") {
|
|
16
16
|
throw new FgError(
|
|
17
17
|
ContextErrorCodes.CONTEXT_NO_RUNTIME,
|
|
18
|
-
"fulgurjs runtime singleton not found on this page (globalThis.__FULGURJS_RUNTIME__ is undefined).\n \u6839\u56E0: \u5F53\u524D\u9875\u9762\u6CA1\u6709\u7ECF\u5BBF\u4E3B\u7684\u8054\u90A6\u8FD0\u884C\u65F6\u52A0\u8F7D\uFF08\u72EC\u7ACB\u76F4\u5F00\u8FDC\u7A0B\u9875\uFF0C\u6216\u5BBF\u4E3B\u6865\u665A\u4E8E\u672C\u8C03\u7528\u6267\u884C\uFF09\u3002\n \u4FEE\u6CD5: \u2460 \u4ECE\u5BBF\u4E3B\u5E94\u7528\u7684\u8054\u90A6\u8DEF\u7531\u6253\u5F00\u672C\u9875\u9762\uFF08\u5BBF\u4E3B
|
|
18
|
+
"fulgurjs runtime singleton not found on this page (globalThis.__FULGURJS_RUNTIME__ is undefined).\n \u6839\u56E0: \u5F53\u524D\u9875\u9762\u6CA1\u6709\u7ECF\u5BBF\u4E3B\u7684\u8054\u90A6\u8FD0\u884C\u65F6\u52A0\u8F7D\uFF08\u72EC\u7ACB\u76F4\u5F00\u8FDC\u7A0B\u9875\uFF0C\u6216\u5BBF\u4E3B\u6865\u665A\u4E8E\u672C\u8C03\u7528\u6267\u884C\uFF09\u3002\n \u4FEE\u6CD5: \u2460 \u4ECE\u5BBF\u4E3B\u5E94\u7528\u7684\u8054\u90A6\u8DEF\u7531\u6253\u5F00\u672C\u9875\u9762\uFF08\u5BBF\u4E3B\u6865\u4F1A\u5148\u52A0\u8F7D\u8FD0\u884C\u65F6\u5E76\u63D0\u4F9B context\uFF09\uFF1B\n \u2461 \u82E5\u4F60\u662F\u5BBF\u4E3B\u6865\u4F5C\u8005\uFF1A\u628A provideAppContext \u653E\u5728\u6865\u521D\u59CB\u5316\u5C3E\u90E8\uFF08\u65F6\u5E8F\u5951\u7EA6 bridge \u2192 \u8FDC\u7A0B setup \u2192 \u9875\u9762\u6A21\u5757\uFF09\u3002",
|
|
19
19
|
{ runtime: false }
|
|
20
20
|
);
|
|
21
21
|
}
|
|
@@ -26,6 +26,14 @@ function provideAppContext(config) {
|
|
|
26
26
|
const g = globalThis;
|
|
27
27
|
g[APP_CONTEXT_STORAGE_KEY] = { ...g[APP_CONTEXT_STORAGE_KEY] ?? {}, ...config };
|
|
28
28
|
}
|
|
29
|
+
function clearAppContext() {
|
|
30
|
+
const g = globalThis;
|
|
31
|
+
delete g[APP_CONTEXT_STORAGE_KEY];
|
|
32
|
+
try {
|
|
33
|
+
g.__FULGURJS_RUNTIME__?.clearSessionState?.();
|
|
34
|
+
} catch {
|
|
35
|
+
}
|
|
36
|
+
}
|
|
29
37
|
function getAppContext() {
|
|
30
38
|
requireRuntime();
|
|
31
39
|
return globalThis[APP_CONTEXT_STORAGE_KEY] ?? {};
|
|
@@ -41,13 +49,14 @@ function requireAppContext(...keys) {
|
|
|
41
49
|
got: ${got.length ? got.map((k) => `"${k}"`).join(", ") : "(empty \u2014 \u5BBF\u4E3B\u6865\u4ECE\u672A\u8C03\u7528 provideAppContext?)"}
|
|
42
50
|
expected: \u5BBF\u4E3B\u6865\u5FC5\u987B\u5728\u4EFB\u4F55\u8FDC\u7A0B\u9875\u9762\u52A0\u8F7D\u524D\u63D0\u4F9B ${missing.map((k) => `"${k}"`).join(" / ")}
|
|
43
51
|
example: host/src/fulgurjs/host/bridge.ts \u2192 provideAppContext({ ${keys.join(", ")}, ... })
|
|
44
|
-
\u4FEE\u6CD5: \u68C0\u67E5\u5BBF\u4E3B\u5E94\u7528 fulgurjs
|
|
52
|
+
\u4FEE\u6CD5: \u68C0\u67E5\u5BBF\u4E3B\u5E94\u7528\u7684 fulgurjs \u6865\u662F\u5426\u5728 loadRemote \u9875\u9762\u524D\u5B8C\u6210 context provide\uFF08\u65F6\u5E8F\u5951\u7EA6 bridge \u2192 \u8FDC\u7A0B setup \u2192 \u9875\u9762\u6A21\u5757\uFF09`,
|
|
45
53
|
{ missing, got }
|
|
46
54
|
);
|
|
47
55
|
throw err;
|
|
48
56
|
}
|
|
49
57
|
export {
|
|
50
58
|
ContextErrorCodes,
|
|
59
|
+
clearAppContext,
|
|
51
60
|
getAppContext,
|
|
52
61
|
provideAppContext,
|
|
53
62
|
requireAppContext
|