@softarc/native-federation-runtime 3.5.0 → 4.0.0-RC1
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/README.md +6 -2
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +320 -0
- package/dist/lib/get-shared.d.ts +20 -0
- package/dist/lib/get-shared.d.ts.map +1 -0
- package/dist/lib/init-federation.d.ts +105 -0
- package/dist/lib/init-federation.d.ts.map +1 -0
- package/dist/lib/load-remote-module.d.ts +83 -0
- package/dist/lib/load-remote-module.d.ts.map +1 -0
- package/dist/lib/model/build-notifications-options.d.ts +2 -0
- package/dist/lib/model/build-notifications-options.d.ts.map +1 -0
- package/dist/lib/model/externals.d.ts +4 -0
- package/dist/lib/model/externals.d.ts.map +1 -0
- package/dist/lib/model/federation-info.d.ts +7 -0
- package/dist/lib/model/federation-info.d.ts.map +1 -0
- package/dist/lib/model/global-cache.d.ts +12 -0
- package/dist/lib/model/global-cache.d.ts.map +1 -0
- package/dist/lib/model/import-map.d.ts +8 -0
- package/dist/lib/model/import-map.d.ts.map +1 -0
- package/dist/lib/model/remotes.d.ts +10 -0
- package/dist/lib/model/remotes.d.ts.map +1 -0
- package/dist/lib/utils/add-import-map.d.ts +3 -0
- package/dist/lib/utils/add-import-map.d.ts.map +1 -0
- package/dist/lib/utils/path-utils.d.ts +14 -0
- package/dist/lib/utils/path-utils.d.ts.map +1 -0
- package/dist/lib/utils/trusted-types.d.ts +2 -0
- package/dist/lib/utils/trusted-types.d.ts.map +1 -0
- package/dist/lib/watch-federation-build.d.ts +10 -0
- package/dist/lib/watch-federation-build.d.ts.map +1 -0
- package/package.json +35 -16
- package/LICENSE +0 -8
- package/fesm2022/softarc-native-federation-runtime.mjs +0 -568
- package/fesm2022/softarc-native-federation-runtime.mjs.map +0 -1
- package/index.d.ts +0 -230
package/README.md
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
#
|
|
1
|
+
# runtime
|
|
2
2
|
|
|
3
3
|
This library was generated with [Nx](https://nx.dev).
|
|
4
4
|
|
|
5
|
+
## Building
|
|
6
|
+
|
|
7
|
+
Run `nx build runtime` to build the library.
|
|
8
|
+
|
|
5
9
|
## Running unit tests
|
|
6
10
|
|
|
7
|
-
Run `nx test
|
|
11
|
+
Run `nx test runtime` to execute the unit tests via [Vitest](https://vitest.dev/).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export * from './lib/init-federation.js';
|
|
2
|
+
export * from './lib/load-remote-module.js';
|
|
3
|
+
export * from './lib/model/build-notifications-options.js';
|
|
4
|
+
export * from './lib/model/federation-info.js';
|
|
5
|
+
export * from './lib/model/import-map.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2BAA2B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
// packages/runtime/src/lib/model/global-cache.ts
|
|
2
|
+
var nfNamespace = "__NATIVE_FEDERATION__";
|
|
3
|
+
var global = globalThis;
|
|
4
|
+
global[nfNamespace] ??= {
|
|
5
|
+
externals: /* @__PURE__ */ new Map(),
|
|
6
|
+
remoteNamesToRemote: /* @__PURE__ */ new Map(),
|
|
7
|
+
baseUrlToRemoteNames: /* @__PURE__ */ new Map()
|
|
8
|
+
};
|
|
9
|
+
var globalCache = global[nfNamespace];
|
|
10
|
+
|
|
11
|
+
// packages/runtime/src/lib/model/externals.ts
|
|
12
|
+
var externals = globalCache.externals;
|
|
13
|
+
function getExternalKey(shared) {
|
|
14
|
+
return `${shared.packageName}@${shared.version}`;
|
|
15
|
+
}
|
|
16
|
+
function getExternalUrl(shared) {
|
|
17
|
+
const packageKey = getExternalKey(shared);
|
|
18
|
+
return externals.get(packageKey);
|
|
19
|
+
}
|
|
20
|
+
function setExternalUrl(shared, url) {
|
|
21
|
+
const packageKey = getExternalKey(shared);
|
|
22
|
+
externals.set(packageKey, url);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// packages/runtime/src/lib/model/import-map.ts
|
|
26
|
+
function mergeImportMaps(map1, map2) {
|
|
27
|
+
return {
|
|
28
|
+
imports: { ...map1.imports, ...map2.imports },
|
|
29
|
+
scopes: { ...map1.scopes, ...map2.scopes }
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// packages/runtime/src/lib/model/remotes.ts
|
|
34
|
+
var remoteNamesToRemote = globalCache.remoteNamesToRemote;
|
|
35
|
+
var baseUrlToRemoteNames = globalCache.baseUrlToRemoteNames;
|
|
36
|
+
function addRemote(remoteName, remote) {
|
|
37
|
+
remoteNamesToRemote.set(remoteName, remote);
|
|
38
|
+
baseUrlToRemoteNames.set(remote.baseUrl, remoteName);
|
|
39
|
+
}
|
|
40
|
+
function getRemoteNameByBaseUrl(baseUrl) {
|
|
41
|
+
return baseUrlToRemoteNames.get(baseUrl);
|
|
42
|
+
}
|
|
43
|
+
function isRemoteInitialized(baseUrl) {
|
|
44
|
+
return baseUrlToRemoteNames.has(baseUrl);
|
|
45
|
+
}
|
|
46
|
+
function getRemote(remoteName) {
|
|
47
|
+
return remoteNamesToRemote.get(remoteName);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// packages/runtime/src/lib/utils/trusted-types.ts
|
|
51
|
+
var global2 = globalThis;
|
|
52
|
+
var policy;
|
|
53
|
+
function createPolicy() {
|
|
54
|
+
if (policy === void 0) {
|
|
55
|
+
policy = null;
|
|
56
|
+
if (global2.trustedTypes) {
|
|
57
|
+
try {
|
|
58
|
+
policy = global2.trustedTypes.createPolicy(
|
|
59
|
+
"native-federation",
|
|
60
|
+
{
|
|
61
|
+
createHTML: (html) => html,
|
|
62
|
+
createScript: (script) => script,
|
|
63
|
+
createScriptURL: (url) => url
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
} catch {
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return policy;
|
|
71
|
+
}
|
|
72
|
+
function tryCreateTrustedScript(script) {
|
|
73
|
+
return createPolicy()?.createScript(script) ?? script;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// packages/runtime/src/lib/utils/add-import-map.ts
|
|
77
|
+
function appendImportMap(importMap) {
|
|
78
|
+
document.head.appendChild(
|
|
79
|
+
Object.assign(document.createElement("script"), {
|
|
80
|
+
type: tryCreateTrustedScript("importmap-shim"),
|
|
81
|
+
textContent: tryCreateTrustedScript(JSON.stringify(importMap))
|
|
82
|
+
})
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// packages/runtime/src/lib/utils/path-utils.ts
|
|
87
|
+
function getDirectory(url) {
|
|
88
|
+
const parts = url.split("/");
|
|
89
|
+
parts.pop();
|
|
90
|
+
return parts.join("/");
|
|
91
|
+
}
|
|
92
|
+
function joinPaths(path1, path2) {
|
|
93
|
+
while (path1.endsWith("/")) {
|
|
94
|
+
path1 = path1.substring(0, path1.length - 1);
|
|
95
|
+
}
|
|
96
|
+
if (path2.startsWith("./")) {
|
|
97
|
+
path2 = path2.substring(2, path2.length);
|
|
98
|
+
}
|
|
99
|
+
return `${path1}/${path2}`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// packages/runtime/src/lib/watch-federation-build.ts
|
|
103
|
+
import { BuildNotificationType } from "@softarc/native-federation/domain";
|
|
104
|
+
function watchFederationBuildCompletion(endpoint) {
|
|
105
|
+
const eventSource = new EventSource(endpoint);
|
|
106
|
+
eventSource.onmessage = function(event) {
|
|
107
|
+
const data = JSON.parse(event.data);
|
|
108
|
+
if (data.type === BuildNotificationType.COMPLETED) {
|
|
109
|
+
console.log("[Federation] Rebuild completed, reloading...");
|
|
110
|
+
window.location.reload();
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
eventSource.onerror = function(event) {
|
|
114
|
+
console.warn("[Federation] SSE connection error:", event);
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// packages/runtime/src/lib/init-federation.ts
|
|
119
|
+
async function initFederation(remotesOrManifestUrl = {}, options) {
|
|
120
|
+
const cacheTag = options?.cacheTag ? `?t=${options.cacheTag}` : "";
|
|
121
|
+
const normalizedRemotes = typeof remotesOrManifestUrl === "string" ? await loadManifest(remotesOrManifestUrl + cacheTag) : remotesOrManifestUrl;
|
|
122
|
+
const hostInfo = await loadFederationInfo(`./remoteEntry.json${cacheTag}`);
|
|
123
|
+
const hostImportMap = await processHostInfo(hostInfo);
|
|
124
|
+
const remotesImportMap = await fetchAndRegisterRemotes(normalizedRemotes, {
|
|
125
|
+
throwIfRemoteNotFound: false,
|
|
126
|
+
...options
|
|
127
|
+
});
|
|
128
|
+
const mergedImportMap = mergeImportMaps(hostImportMap, remotesImportMap);
|
|
129
|
+
appendImportMap(mergedImportMap);
|
|
130
|
+
return mergedImportMap;
|
|
131
|
+
}
|
|
132
|
+
async function loadManifest(manifestUrl) {
|
|
133
|
+
const manifest = await fetch(manifestUrl).then((r) => r.json());
|
|
134
|
+
return manifest;
|
|
135
|
+
}
|
|
136
|
+
function applyCacheTag(url, cacheTag) {
|
|
137
|
+
if (!cacheTag)
|
|
138
|
+
return url;
|
|
139
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
140
|
+
return `${url}${separator}t=${cacheTag}`;
|
|
141
|
+
}
|
|
142
|
+
function handleRemoteLoadError(remoteName, remoteUrl, options, originalError) {
|
|
143
|
+
const errorMessage = `Error loading remote entry for ${remoteName} from file ${remoteUrl}`;
|
|
144
|
+
if (options.throwIfRemoteNotFound) {
|
|
145
|
+
throw new Error(errorMessage);
|
|
146
|
+
}
|
|
147
|
+
console.error(errorMessage);
|
|
148
|
+
console.error(originalError);
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
async function fetchAndRegisterRemotes(remotes, options = { throwIfRemoteNotFound: false }) {
|
|
152
|
+
const fetchAndRegisterRemotePromises = Object.entries(remotes).map(
|
|
153
|
+
async ([remoteName, remoteUrl]) => {
|
|
154
|
+
try {
|
|
155
|
+
const urlWithCache = applyCacheTag(remoteUrl, options.cacheTag);
|
|
156
|
+
return await fetchAndRegisterRemote(urlWithCache, remoteName);
|
|
157
|
+
} catch (e) {
|
|
158
|
+
return handleRemoteLoadError(remoteName, remoteUrl, options, e);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
const remoteImportMaps = await Promise.all(fetchAndRegisterRemotePromises);
|
|
163
|
+
const importMap = remoteImportMaps.reduce(
|
|
164
|
+
(acc, remoteImportMap) => remoteImportMap ? mergeImportMaps(acc, remoteImportMap) : acc,
|
|
165
|
+
{ imports: {}, scopes: {} }
|
|
166
|
+
);
|
|
167
|
+
return importMap;
|
|
168
|
+
}
|
|
169
|
+
async function processRemoteInfos(remotes, options = { throwIfRemoteNotFound: false }) {
|
|
170
|
+
return fetchAndRegisterRemotes(remotes, options);
|
|
171
|
+
}
|
|
172
|
+
async function fetchAndRegisterRemote(federationInfoUrl, remoteName) {
|
|
173
|
+
const baseUrl = getDirectory(federationInfoUrl);
|
|
174
|
+
const remoteInfo = await loadFederationInfo(federationInfoUrl);
|
|
175
|
+
if (!remoteName) {
|
|
176
|
+
remoteName = remoteInfo.name;
|
|
177
|
+
}
|
|
178
|
+
if (remoteInfo.buildNotificationsEndpoint) {
|
|
179
|
+
watchFederationBuildCompletion(baseUrl + remoteInfo.buildNotificationsEndpoint);
|
|
180
|
+
}
|
|
181
|
+
const importMap = createRemoteImportMap(remoteInfo, remoteName, baseUrl);
|
|
182
|
+
addRemote(remoteName, { ...remoteInfo, baseUrl });
|
|
183
|
+
return importMap;
|
|
184
|
+
}
|
|
185
|
+
function createRemoteImportMap(remoteInfo, remoteName, baseUrl) {
|
|
186
|
+
const imports = processExposed(remoteInfo, remoteName, baseUrl);
|
|
187
|
+
const scopes = processRemoteImports(remoteInfo, baseUrl);
|
|
188
|
+
return { imports, scopes };
|
|
189
|
+
}
|
|
190
|
+
async function loadFederationInfo(remoteEntryUrl) {
|
|
191
|
+
const info = await fetch(remoteEntryUrl).then((r) => r.json());
|
|
192
|
+
return info;
|
|
193
|
+
}
|
|
194
|
+
function processRemoteImports(remoteInfo, baseUrl) {
|
|
195
|
+
const scopes = {};
|
|
196
|
+
const scopedImports = {};
|
|
197
|
+
for (const shared of remoteInfo.shared) {
|
|
198
|
+
const outFileName = getExternalUrl(shared) ?? joinPaths(baseUrl, shared.outFileName);
|
|
199
|
+
setExternalUrl(shared, outFileName);
|
|
200
|
+
scopedImports[shared.packageName] = outFileName;
|
|
201
|
+
}
|
|
202
|
+
scopes[baseUrl + "/"] = scopedImports;
|
|
203
|
+
return scopes;
|
|
204
|
+
}
|
|
205
|
+
function processExposed(remoteInfo, remoteName, baseUrl) {
|
|
206
|
+
const imports = {};
|
|
207
|
+
for (const exposed of remoteInfo.exposes) {
|
|
208
|
+
const key = joinPaths(remoteName, exposed.key);
|
|
209
|
+
const value = joinPaths(baseUrl, exposed.outFileName);
|
|
210
|
+
imports[key] = value;
|
|
211
|
+
}
|
|
212
|
+
return imports;
|
|
213
|
+
}
|
|
214
|
+
async function processHostInfo(hostInfo, relBundlesPath = "./") {
|
|
215
|
+
const imports = hostInfo.shared.reduce(
|
|
216
|
+
(acc, cur) => ({
|
|
217
|
+
...acc,
|
|
218
|
+
[cur.packageName]: relBundlesPath + cur.outFileName
|
|
219
|
+
}),
|
|
220
|
+
{}
|
|
221
|
+
);
|
|
222
|
+
for (const shared of hostInfo.shared) {
|
|
223
|
+
setExternalUrl(shared, relBundlesPath + shared.outFileName);
|
|
224
|
+
}
|
|
225
|
+
return { imports, scopes: {} };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// packages/runtime/src/lib/load-remote-module.ts
|
|
229
|
+
async function loadRemoteModule(optionsOrRemoteName, exposedModule) {
|
|
230
|
+
const options = normalizeOptions(optionsOrRemoteName, exposedModule);
|
|
231
|
+
await ensureRemoteInitialized(options);
|
|
232
|
+
const remoteName = getRemoteNameByOptions(options);
|
|
233
|
+
const remote = getRemote(remoteName);
|
|
234
|
+
const fallback = options.fallback;
|
|
235
|
+
const remoteError = !remote ? "unknown remote " + remoteName : "";
|
|
236
|
+
if (!remote && !fallback)
|
|
237
|
+
throw new Error(remoteError);
|
|
238
|
+
if (!remote) {
|
|
239
|
+
logClientError(remoteError);
|
|
240
|
+
return Promise.resolve(fallback);
|
|
241
|
+
}
|
|
242
|
+
const exposedModuleInfo = remote.exposes.find((e) => e.key === options.exposedModule);
|
|
243
|
+
const exposedError = !exposedModuleInfo ? `Unknown exposed module ${options.exposedModule} in remote ${remoteName}` : "";
|
|
244
|
+
if (!exposedModuleInfo && !fallback)
|
|
245
|
+
throw new Error(exposedError);
|
|
246
|
+
if (!exposedModuleInfo) {
|
|
247
|
+
logClientError(exposedError);
|
|
248
|
+
return Promise.resolve(fallback);
|
|
249
|
+
}
|
|
250
|
+
const moduleUrl = joinPaths(remote.baseUrl, exposedModuleInfo.outFileName);
|
|
251
|
+
try {
|
|
252
|
+
const module = _import(moduleUrl);
|
|
253
|
+
return module;
|
|
254
|
+
} catch (e) {
|
|
255
|
+
if (fallback) {
|
|
256
|
+
console.error("error loading remote module", e);
|
|
257
|
+
return fallback;
|
|
258
|
+
}
|
|
259
|
+
throw e;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function _import(moduleUrl) {
|
|
263
|
+
return typeof importShim !== "undefined" ? importShim(moduleUrl) : import(
|
|
264
|
+
/* @vite-ignore */
|
|
265
|
+
moduleUrl
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
function getRemoteNameByOptions(options) {
|
|
269
|
+
let remoteName;
|
|
270
|
+
if (options.remoteName) {
|
|
271
|
+
remoteName = options.remoteName;
|
|
272
|
+
} else if (options.remoteEntry) {
|
|
273
|
+
const baseUrl = getDirectory(options.remoteEntry);
|
|
274
|
+
remoteName = getRemoteNameByBaseUrl(baseUrl);
|
|
275
|
+
} else {
|
|
276
|
+
throw new Error("unexpected arguments: Please pass remoteName or remoteEntry");
|
|
277
|
+
}
|
|
278
|
+
if (!remoteName) {
|
|
279
|
+
throw new Error("unknown remoteName " + remoteName);
|
|
280
|
+
}
|
|
281
|
+
return remoteName;
|
|
282
|
+
}
|
|
283
|
+
async function ensureRemoteInitialized(options) {
|
|
284
|
+
if (options.remoteEntry && !isRemoteInitialized(getDirectory(options.remoteEntry))) {
|
|
285
|
+
const importMap = await fetchAndRegisterRemote(options.remoteEntry);
|
|
286
|
+
appendImportMap(importMap);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function normalizeOptions(optionsOrRemoteName, exposedModule) {
|
|
290
|
+
let options;
|
|
291
|
+
if (typeof optionsOrRemoteName === "string" && exposedModule) {
|
|
292
|
+
options = {
|
|
293
|
+
remoteName: optionsOrRemoteName,
|
|
294
|
+
exposedModule
|
|
295
|
+
};
|
|
296
|
+
} else if (typeof optionsOrRemoteName === "object" && !exposedModule) {
|
|
297
|
+
options = optionsOrRemoteName;
|
|
298
|
+
} else {
|
|
299
|
+
throw new Error("unexpected arguments: please pass options or a remoteName/exposedModule-pair");
|
|
300
|
+
}
|
|
301
|
+
return options;
|
|
302
|
+
}
|
|
303
|
+
function logClientError(error) {
|
|
304
|
+
if (typeof window !== "undefined") {
|
|
305
|
+
console.error(error);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// packages/runtime/src/lib/model/build-notifications-options.ts
|
|
310
|
+
var BUILD_NOTIFICATIONS_ENDPOINT = "/@angular-architects/native-federation:build-notifications";
|
|
311
|
+
export {
|
|
312
|
+
BUILD_NOTIFICATIONS_ENDPOINT,
|
|
313
|
+
fetchAndRegisterRemote,
|
|
314
|
+
fetchAndRegisterRemotes,
|
|
315
|
+
initFederation,
|
|
316
|
+
loadRemoteModule,
|
|
317
|
+
mergeImportMaps,
|
|
318
|
+
processHostInfo,
|
|
319
|
+
processRemoteInfos
|
|
320
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type Type<T> = new () => T;
|
|
2
|
+
export type ShareObject = {
|
|
3
|
+
version: string;
|
|
4
|
+
scope?: string;
|
|
5
|
+
get: () => Promise<() => Type<unknown>>;
|
|
6
|
+
shareConfig?: {
|
|
7
|
+
singleton?: boolean;
|
|
8
|
+
requiredVersion: string;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
export type ShareConfig = {
|
|
12
|
+
[pkgName: string]: Array<ShareObject>;
|
|
13
|
+
};
|
|
14
|
+
export type ShareOptions = {
|
|
15
|
+
singleton: boolean;
|
|
16
|
+
requiredVersionPrefix: '^' | '~' | '>' | '>=' | '';
|
|
17
|
+
};
|
|
18
|
+
export declare function getShared(options?: ShareOptions): ShareConfig;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=get-shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-shared.d.ts","sourceRoot":"","sources":["../../src/lib/get-shared.ts"],"names":[],"mappings":"AAAA,KAAK,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC;AAS3B,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACxC,WAAW,CAAC,EAAE;QACZ,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,qBAAqB,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;CACpD,CAAC;AAOF,wBAAgB,SAAS,CAAC,OAAO,eAAsB,eAyCtD"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { FederationInfo } from '@softarc/native-federation/domain';
|
|
2
|
+
import { type InitFederationOptions, type ProcessRemoteInfoOptions } from './model/federation-info.js';
|
|
3
|
+
import { type ImportMap } from './model/import-map.js';
|
|
4
|
+
/**
|
|
5
|
+
* Initializes the Native Federation runtime for the host application.
|
|
6
|
+
*
|
|
7
|
+
* This is the main entry point for setting up federation. It performs the following:
|
|
8
|
+
* 1. Loads the host's remoteEntry.json to discover shared dependencies
|
|
9
|
+
* 2. Loads each remote's remoteEntry.json to discover exposed modules
|
|
10
|
+
* 3. Creates an ES Module import map with proper scoping
|
|
11
|
+
* 4. Injects the import map into the DOM as a <script type="importmap-shim">
|
|
12
|
+
*
|
|
13
|
+
* The import map allows dynamic imports to resolve correctly:
|
|
14
|
+
* - Host shared deps go in root imports (e.g., "angular": "./angular.js")
|
|
15
|
+
* - Remote exposed modules go in root imports (e.g., "mfe1/Component": "http://...")
|
|
16
|
+
* - Remote shared deps go in scoped imports for proper resolution
|
|
17
|
+
*
|
|
18
|
+
* @param remotesOrManifestUrl - Either:
|
|
19
|
+
* - A record of remote names to their remoteEntry.json URLs
|
|
20
|
+
* Example: { mfe1: 'http://localhost:3000/remoteEntry.json' }
|
|
21
|
+
* - A URL to a manifest.json that contains the remotes record
|
|
22
|
+
* Example: 'http://localhost:3000/federation-manifest.json'
|
|
23
|
+
*
|
|
24
|
+
* @param options - Configuration options:
|
|
25
|
+
* - cacheTag: A version string to append as query param for cache busting
|
|
26
|
+
* Example: { cacheTag: 'v1.0.0' } results in '?t=v1.0.0' on all requests
|
|
27
|
+
*
|
|
28
|
+
* @returns The final merged ImportMap that was injected into the DOM
|
|
29
|
+
*
|
|
30
|
+
*/
|
|
31
|
+
export declare function initFederation(remotesOrManifestUrl?: Record<string, string> | string, options?: InitFederationOptions): Promise<ImportMap>;
|
|
32
|
+
/**
|
|
33
|
+
* Fetches and registers multiple remote applications in parallel and merges their import maps.
|
|
34
|
+
*
|
|
35
|
+
* This function is the orchestrator for loading all remotes. It:
|
|
36
|
+
* 1. Creates a promise for each remote to load its remoteEntry.json
|
|
37
|
+
* 2. Applies cache busting to each remote URL
|
|
38
|
+
* 3. Handles errors gracefully (logs or throws based on options)
|
|
39
|
+
* 4. Merges all successful remote import maps into one
|
|
40
|
+
*
|
|
41
|
+
* Each remote contributes:
|
|
42
|
+
* - Its exposed modules to the root imports
|
|
43
|
+
* - Its shared dependencies to scoped imports
|
|
44
|
+
*
|
|
45
|
+
* @param remotes - Record of remote names to their remoteEntry.json URLs
|
|
46
|
+
* @param options - Processing options including:
|
|
47
|
+
* - throwIfRemoteNotFound: Whether to throw or log on remote load failure
|
|
48
|
+
* - cacheTag: Cache busting tag to append to URLs
|
|
49
|
+
*
|
|
50
|
+
* @returns Merged import map containing all remotes' contributions
|
|
51
|
+
*
|
|
52
|
+
*/
|
|
53
|
+
export declare function fetchAndRegisterRemotes(remotes: Record<string, string>, options?: ProcessRemoteInfoOptions): Promise<ImportMap>;
|
|
54
|
+
/**
|
|
55
|
+
* @deprecated Use `fetchAndRegisterRemotes` instead.
|
|
56
|
+
* @param remotes
|
|
57
|
+
* @param options
|
|
58
|
+
* @returns
|
|
59
|
+
*/
|
|
60
|
+
export declare function processRemoteInfos(remotes: Record<string, string>, options?: ProcessRemoteInfoOptions): Promise<ImportMap>;
|
|
61
|
+
/**
|
|
62
|
+
* Fetches a single remote application's remoteEntry.json file and registers it in the system (global registry).
|
|
63
|
+
*
|
|
64
|
+
* This function handles everything needed to integrate one remote:
|
|
65
|
+
* 1. Fetches the remote's remoteEntry.json file
|
|
66
|
+
* 2. Extracts the base URL from the remoteEntry path
|
|
67
|
+
* 3. Creates import map entries for exposed modules and shared deps
|
|
68
|
+
* 4. Registers the remote in the global remotes registry
|
|
69
|
+
* 5. Sets up hot reload watching if configured (development mode)
|
|
70
|
+
*
|
|
71
|
+
* @param federationInfoUrl - Full URL to the remote's remoteEntry.json
|
|
72
|
+
* @param remoteName - Name to use for this remote (optional, uses info.name if not provided)
|
|
73
|
+
*
|
|
74
|
+
* @returns Import map containing this remote's exposed modules and shared dependencies
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const importMap = await fetchAndRegisterRemote(
|
|
79
|
+
* 'http://localhost:3000/mfe1/remoteEntry.json',
|
|
80
|
+
* 'mfe1'
|
|
81
|
+
* );
|
|
82
|
+
* // Result: {
|
|
83
|
+
* // imports: { 'mfe1/Component': 'http://localhost:3000/mfe1/Component.js' },
|
|
84
|
+
* // scopes: { 'http://localhost:3000/mfe1/': { 'lodash': '...' } }
|
|
85
|
+
* // }
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export declare function fetchAndRegisterRemote(federationInfoUrl: string, remoteName?: string): Promise<ImportMap>;
|
|
89
|
+
/**
|
|
90
|
+
* Processes the host application's federation info into an import map.
|
|
91
|
+
*
|
|
92
|
+
* The host app typically doesn't expose modules (it's the consumer),
|
|
93
|
+
* but it does share dependencies that should be available to remotes.
|
|
94
|
+
*
|
|
95
|
+
* Host shared dependencies go in root-level imports (not scoped) because:
|
|
96
|
+
* 1. The host loads first and establishes the base environment
|
|
97
|
+
* 2. Remotes should prefer host versions to avoid duplication
|
|
98
|
+
*
|
|
99
|
+
* @param hostInfo - Federation info from the host's remoteEntry.json
|
|
100
|
+
* @param relBundlesPath - Relative path to the host's bundle directory (default: './')
|
|
101
|
+
*
|
|
102
|
+
* @returns Import map with host's shared dependencies in root imports
|
|
103
|
+
*/
|
|
104
|
+
export declare function processHostInfo(hostInfo: FederationInfo, relBundlesPath?: string): Promise<ImportMap>;
|
|
105
|
+
//# sourceMappingURL=init-federation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-federation.d.ts","sourceRoot":"","sources":["../../src/lib/init-federation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAExE,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC9B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,KAAK,SAAS,EAA8C,MAAM,uBAAuB,CAAC;AAMnG;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,cAAc,CAClC,oBAAoB,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAW,EAC1D,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,SAAS,CAAC,CA4BpB;AA8CD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,OAAO,GAAE,wBAA2D,GACnE,OAAO,CAAC,SAAS,CAAC,CAuBpB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,OAAO,GAAE,wBAA2D,GACnE,OAAO,CAAC,SAAS,CAAC,CAEpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,sBAAsB,CAC1C,iBAAiB,EAAE,MAAM,EACzB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,SAAS,CAAC,CAqBpB;AAqID;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,cAAc,EACxB,cAAc,SAAO,GACpB,OAAO,CAAC,SAAS,CAAC,CAkBpB"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for loading a remote module.
|
|
3
|
+
*
|
|
4
|
+
* @template T - The expected type of the module's exports
|
|
5
|
+
*
|
|
6
|
+
* @property remoteEntry - Optional URL to the remote's remoteEntry.json file.
|
|
7
|
+
* Used for lazy-loading remotes that weren't registered during initFederation
|
|
8
|
+
* Example: 'http://localhost:3000/remoteEntry.json'
|
|
9
|
+
*
|
|
10
|
+
* @property remoteName - Optional name of the remote application.
|
|
11
|
+
* Should match the name used during initFederation or the name in remoteEntry.json.
|
|
12
|
+
* Example: 'mfe1'
|
|
13
|
+
*
|
|
14
|
+
* @property exposedModule - The key of the exposed module to load (required).
|
|
15
|
+
* Must match the key defined in the remote's federation config.
|
|
16
|
+
* Example: './Component' or './Dashboard'
|
|
17
|
+
*
|
|
18
|
+
* @property fallback - Optional fallback value to return if the remote or module cannot be loaded.
|
|
19
|
+
* Prevents throwing errors and provides graceful degradation.
|
|
20
|
+
* Example: A default component or null
|
|
21
|
+
*/
|
|
22
|
+
export type LoadRemoteModuleOptions<T = any> = {
|
|
23
|
+
remoteEntry?: string;
|
|
24
|
+
remoteName?: string;
|
|
25
|
+
exposedModule: string;
|
|
26
|
+
fallback?: T;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Dynamically loads a remote module at runtime from a federated application.
|
|
30
|
+
*
|
|
31
|
+
* This is the primary API for consuming remote modules after federation has been initialized.
|
|
32
|
+
* It supports two calling patterns:
|
|
33
|
+
*
|
|
34
|
+
* **Pattern 1: Using options object**
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const module = await loadRemoteModule({
|
|
37
|
+
* remoteName: 'mfe1',
|
|
38
|
+
* exposedModule: './Component',
|
|
39
|
+
* fallback: DefaultComponent
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* **Pattern 2: Using positional arguments**
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const module = await loadRemoteModule('mfe1', './Component');
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* ## Loading Process
|
|
49
|
+
*
|
|
50
|
+
* 1. **Normalize Options**: Converts arguments into a standard options object
|
|
51
|
+
* 2. **Ensure Remote Initialized**: If remoteEntry is provided and remote isn't loaded,
|
|
52
|
+
* fetches and registers it dynamically
|
|
53
|
+
* 3. **Resolve Remote Name**: Determines remote name from options or remoteEntry URL
|
|
54
|
+
* 4. **Validate Remote**: Checks if remote exists in the registry
|
|
55
|
+
* 5. **Validate Exposed Module**: Verifies the requested module is exposed by the remote
|
|
56
|
+
* 6. **Import Module**: Uses dynamic import or import-shim to load the module
|
|
57
|
+
* 7. **Handle Errors**: Returns fallback if provided, otherwise throws
|
|
58
|
+
*
|
|
59
|
+
* ## Lazy Loading Support
|
|
60
|
+
*
|
|
61
|
+
* If you provide a `remoteEntry` URL for a remote that wasn't initialized during
|
|
62
|
+
* `initFederation()`, this function will automatically:
|
|
63
|
+
* - Fetch the remote's remoteEntry.json
|
|
64
|
+
* - Register it in the global registry
|
|
65
|
+
* - Update the import map
|
|
66
|
+
* - Then load the requested module
|
|
67
|
+
*
|
|
68
|
+
* This enables on-demand loading of remotes based on user interactions.
|
|
69
|
+
*
|
|
70
|
+
*
|
|
71
|
+
* @template T - The expected type of the module's exports
|
|
72
|
+
*
|
|
73
|
+
* @param options - Configuration object for loading the remote module
|
|
74
|
+
* @returns Promise resolving to the loaded module or fallback value
|
|
75
|
+
*
|
|
76
|
+
* @throws Error if remote is not found and no fallback is provided
|
|
77
|
+
* @throws Error if exposed module doesn't exist and no fallback is provided
|
|
78
|
+
* @throws Error if module import fails and no fallback is provided
|
|
79
|
+
*
|
|
80
|
+
*/
|
|
81
|
+
export declare function loadRemoteModule<T = any>(options: LoadRemoteModuleOptions): Promise<T>;
|
|
82
|
+
export declare function loadRemoteModule<T = any>(remoteName: string, exposedModule: string): Promise<T>;
|
|
83
|
+
//# sourceMappingURL=load-remote-module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-remote-module.d.ts","sourceRoot":"","sources":["../../src/lib/load-remote-module.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,uBAAuB,CAAC,CAAC,GAAG,GAAG,IAAI;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,CAAC;CACd,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,GAAG,GAAG,EAAE,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAC9F,wBAAsB,gBAAgB,CAAC,CAAC,GAAG,GAAG,EAC5C,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-notifications-options.d.ts","sourceRoot":"","sources":["../../../src/lib/model/build-notifications-options.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,4BAA4B,+DACqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"externals.d.ts","sourceRoot":"","sources":["../../../src/lib/model/externals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AASpE,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAGrE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAGpE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"federation-info.d.ts","sourceRoot":"","sources":["../../../src/lib/model/federation-info.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,wBAAyB,SAAQ,qBAAqB;IACrE,qBAAqB,EAAE,OAAO,CAAC;CAChC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Remote } from './remotes.js';
|
|
2
|
+
export declare const nfNamespace = "__NATIVE_FEDERATION__";
|
|
3
|
+
export type NfCache = {
|
|
4
|
+
externals: Map<string, string>;
|
|
5
|
+
remoteNamesToRemote: Map<string, Remote>;
|
|
6
|
+
baseUrlToRemoteNames: Map<string, string>;
|
|
7
|
+
};
|
|
8
|
+
export type Global = {
|
|
9
|
+
[nfNamespace]: NfCache;
|
|
10
|
+
};
|
|
11
|
+
export declare const globalCache: NfCache;
|
|
12
|
+
//# sourceMappingURL=global-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-cache.d.ts","sourceRoot":"","sources":["../../../src/lib/model/global-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,eAAO,MAAM,WAAW,0BAA0B,CAAC;AAEnD,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,mBAAmB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,oBAAoB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAUF,eAAO,MAAM,WAAW,SAAsB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type Imports = Record<string, string>;
|
|
2
|
+
export type Scopes = Record<string, Imports>;
|
|
3
|
+
export type ImportMap = {
|
|
4
|
+
imports: Imports;
|
|
5
|
+
scopes: Scopes;
|
|
6
|
+
};
|
|
7
|
+
export declare function mergeImportMaps(map1: ImportMap, map2: ImportMap): ImportMap;
|
|
8
|
+
//# sourceMappingURL=import-map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-map.d.ts","sourceRoot":"","sources":["../../../src/lib/model/import-map.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE7C,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE7C,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,SAAS,CAK3E"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FederationInfo } from '@softarc/native-federation/domain';
|
|
2
|
+
export type Remote = FederationInfo & {
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
};
|
|
5
|
+
export declare function addRemote(remoteName: string, remote: Remote): void;
|
|
6
|
+
export declare function getRemoteNameByBaseUrl(baseUrl: string): string | undefined;
|
|
7
|
+
export declare function isRemoteInitialized(baseUrl: string): boolean;
|
|
8
|
+
export declare function getRemote(remoteName: string): Remote | undefined;
|
|
9
|
+
export declare function hasRemote(remoteName: string): boolean;
|
|
10
|
+
//# sourceMappingURL=remotes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remotes.d.ts","sourceRoot":"","sources":["../../../src/lib/model/remotes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAGxE,MAAM,MAAM,MAAM,GAAG,cAAc,GAAG;IACpC,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAKF,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAGlE;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE1E;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEhE;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAErD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-import-map.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/add-import-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGxD,wBAAgB,eAAe,CAAC,SAAS,EAAE,SAAS,QAOnD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the full directory of a given path.
|
|
3
|
+
* @param url - The path to get the directory of.
|
|
4
|
+
* @returns The full directory of the path.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getDirectory(url: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Joins two paths together taking into account trailing slashes and "./" prefixes.
|
|
9
|
+
* @param path1 - The first path to join.
|
|
10
|
+
* @param path2 - The second path to join.
|
|
11
|
+
* @returns The joined path.
|
|
12
|
+
*/
|
|
13
|
+
export declare function joinPaths(path1: string, path2: string): string;
|
|
14
|
+
//# sourceMappingURL=path-utils.d.ts.map
|