@module-federation/node 2.7.47 → 2.7.48
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/dist/src/utils/flush-chunks.d.mts +4 -2
- package/dist/src/utils/flush-chunks.d.ts +4 -2
- package/dist/src/utils/flush-chunks.js +116 -74
- package/dist/src/utils/flush-chunks.js.map +1 -1
- package/dist/src/utils/flush-chunks.mjs +116 -74
- package/dist/src/utils/flush-chunks.mjs.map +1 -1
- package/package.json +4 -4
|
@@ -1,15 +1,17 @@
|
|
|
1
|
+
import { RemoteInfo } from "@module-federation/runtime/types";
|
|
2
|
+
|
|
1
3
|
//#region src/utils/flush-chunks.d.ts
|
|
2
4
|
/**
|
|
3
5
|
* Initialize usedChunks and share it globally.
|
|
4
6
|
* @type {Set}
|
|
5
7
|
*/
|
|
6
8
|
declare const usedChunks: any;
|
|
7
|
-
declare const getAllKnownRemotes: () =>
|
|
9
|
+
declare const getAllKnownRemotes: () => Record<string, RemoteInfo>;
|
|
8
10
|
/**
|
|
9
11
|
* Flush the chunks and return a deduplicated array of chunks.
|
|
10
12
|
* @returns {Promise<Array>} A promise that resolves to an array of deduplicated chunks.
|
|
11
13
|
*/
|
|
12
|
-
declare const flushChunks: () => Promise<
|
|
14
|
+
declare const flushChunks: () => Promise<string[]>;
|
|
13
15
|
//#endregion
|
|
14
16
|
export { flushChunks, getAllKnownRemotes, usedChunks };
|
|
15
17
|
//# sourceMappingURL=flush-chunks.d.mts.map
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
+
import { RemoteInfo } from "@module-federation/runtime/types";
|
|
2
|
+
|
|
1
3
|
//#region src/utils/flush-chunks.d.ts
|
|
2
4
|
/**
|
|
3
5
|
* Initialize usedChunks and share it globally.
|
|
4
6
|
* @type {Set}
|
|
5
7
|
*/
|
|
6
8
|
declare const usedChunks: any;
|
|
7
|
-
declare const getAllKnownRemotes: () =>
|
|
9
|
+
declare const getAllKnownRemotes: () => Record<string, RemoteInfo>;
|
|
8
10
|
/**
|
|
9
11
|
* Flush the chunks and return a deduplicated array of chunks.
|
|
10
12
|
* @returns {Promise<Array>} A promise that resolves to an array of deduplicated chunks.
|
|
11
13
|
*/
|
|
12
|
-
declare const flushChunks: () => Promise<
|
|
14
|
+
declare const flushChunks: () => Promise<string[]>;
|
|
13
15
|
//#endregion
|
|
14
16
|
export { flushChunks, getAllKnownRemotes, usedChunks };
|
|
15
17
|
//# sourceMappingURL=flush-chunks.d.ts.map
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_runtime = require('../../_virtual/_rolldown/runtime.js');
|
|
3
|
+
let _module_federation_sdk = require("@module-federation/sdk");
|
|
2
4
|
|
|
3
5
|
//#region src/utils/flush-chunks.ts
|
|
4
6
|
if (!globalThis.usedChunks) globalThis.usedChunks = /* @__PURE__ */ new Set();
|
|
@@ -7,83 +9,107 @@ if (!globalThis.usedChunks) globalThis.usedChunks = /* @__PURE__ */ new Set();
|
|
|
7
9
|
* @type {Set}
|
|
8
10
|
*/
|
|
9
11
|
const { usedChunks } = globalThis;
|
|
10
|
-
|
|
11
|
-
* Load hostStats from the JSON file.
|
|
12
|
-
* @returns {object} hostStats - An object containing host stats data.
|
|
13
|
-
*/
|
|
14
|
-
const loadHostStats = () => {
|
|
15
|
-
try {
|
|
16
|
-
return __non_webpack_require__("../federated-stats.json");
|
|
17
|
-
} catch (e) {
|
|
18
|
-
return {};
|
|
19
|
-
}
|
|
20
|
-
};
|
|
12
|
+
const getFederationController = () => new Function("return globalThis")().__FEDERATION__;
|
|
21
13
|
const getAllKnownRemotes = function() {
|
|
22
|
-
const federationController =
|
|
14
|
+
const federationController = getFederationController();
|
|
23
15
|
if (!federationController || !federationController.__INSTANCES__) return {};
|
|
24
|
-
|
|
25
|
-
for (const instance of federationController.__INSTANCES__) for (const [
|
|
16
|
+
const collected = {};
|
|
17
|
+
for (const instance of federationController.__INSTANCES__) for (const [, cacheModule] of instance.moduleCache) if (cacheModule.remoteInfo) {
|
|
18
|
+
const remoteInfo = cacheModule.remoteInfo;
|
|
19
|
+
collected[remoteInfo.name] = remoteInfo;
|
|
20
|
+
if (remoteInfo.alias) collected[remoteInfo.alias] = remoteInfo;
|
|
21
|
+
}
|
|
26
22
|
return collected;
|
|
27
23
|
};
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
24
|
+
const getConfiguredManifestUrls = () => {
|
|
25
|
+
const manifestUrls = /* @__PURE__ */ new Map();
|
|
26
|
+
const federationController = getFederationController();
|
|
27
|
+
for (const instance of federationController?.__INSTANCES__ || []) for (const configuredRemote of instance.options?.remotes || []) {
|
|
28
|
+
if (!("entry" in configuredRemote)) continue;
|
|
29
|
+
try {
|
|
30
|
+
if (!new URL(configuredRemote.entry).pathname.endsWith(".json")) continue;
|
|
31
|
+
} catch {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
manifestUrls.set(configuredRemote.name, configuredRemote.entry);
|
|
35
|
+
if (configuredRemote.alias) manifestUrls.set(configuredRemote.alias, configuredRemote.entry);
|
|
36
|
+
}
|
|
37
|
+
return manifestUrls;
|
|
41
38
|
};
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
39
|
+
const parseUsedChunk = (chunk, remoteNames) => {
|
|
40
|
+
const normalizedChunk = chunk.replace("->", "/");
|
|
41
|
+
const remote = remoteNames.find((name) => normalizedChunk === name || normalizedChunk.startsWith(`${name}/`)) || normalizedChunk.split("/", 1)[0];
|
|
42
|
+
const request = normalizedChunk.slice(remote.length).replace(/^\//, "");
|
|
43
|
+
return [remote, request.startsWith("./") ? request : `./${request}`];
|
|
44
|
+
};
|
|
45
|
+
const getMetadataUrl = (entry, filename) => {
|
|
46
|
+
const url = new URL(entry);
|
|
47
|
+
url.pathname = `${url.pathname.slice(0, url.pathname.lastIndexOf("/") + 1)}${filename}`;
|
|
48
|
+
url.pathname = url.pathname.replace("/ssr/", "/chunks/");
|
|
49
|
+
return url.href;
|
|
50
|
+
};
|
|
51
|
+
const getManifestUrl = (remoteInfo, configuredManifestUrl) => {
|
|
52
|
+
if (configuredManifestUrl) return configuredManifestUrl;
|
|
53
|
+
return getMetadataUrl(remoteInfo.entry, "mf-manifest.json");
|
|
54
|
+
};
|
|
55
|
+
const getAssetBaseUrl = (metadataUrl) => {
|
|
56
|
+
const baseUrl = new URL(metadataUrl);
|
|
57
|
+
const staticPathIndex = baseUrl.pathname.indexOf("/static/");
|
|
58
|
+
baseUrl.pathname = staticPathIndex === -1 ? baseUrl.pathname.slice(0, baseUrl.pathname.lastIndexOf("/") + 1) : baseUrl.pathname.slice(0, staticPathIndex + 1);
|
|
59
|
+
baseUrl.search = "";
|
|
60
|
+
baseUrl.hash = "";
|
|
61
|
+
return baseUrl;
|
|
62
|
+
};
|
|
63
|
+
const fetchJson = async (url) => {
|
|
64
|
+
const response = await fetch(url);
|
|
65
|
+
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
|
|
66
|
+
return response.json();
|
|
67
|
+
};
|
|
68
|
+
const collectManifestAssets = (manifest, manifestUrl, requests) => {
|
|
50
69
|
const chunks = /* @__PURE__ */ new Set();
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (!knownRemotes[remote]) {
|
|
58
|
-
console.error(`flush chunks: Remote ${remote} is not defined in the global config`);
|
|
59
|
-
return;
|
|
70
|
+
const missingRequests = new Set(requests);
|
|
71
|
+
let assetBaseUrl = getAssetBaseUrl(manifestUrl);
|
|
72
|
+
const resourceBasePath = (0, _module_federation_sdk.getResourceUrl)(manifest.metaData, "");
|
|
73
|
+
if (resourceBasePath !== "auto") {
|
|
74
|
+
const normalizedBasePath = resourceBasePath && !resourceBasePath.endsWith("/") ? `${resourceBasePath}/` : resourceBasePath || "./";
|
|
75
|
+
assetBaseUrl = new URL(normalizedBasePath, manifestUrl);
|
|
60
76
|
}
|
|
77
|
+
const resolveAssetUrl = (file) => new URL(file, assetBaseUrl).href;
|
|
78
|
+
for (const expose of manifest.exposes) {
|
|
79
|
+
const request = expose.path || `./${expose.name}`;
|
|
80
|
+
if (!requests.has(request)) continue;
|
|
81
|
+
if (expose.assets.js.sync.length > 0 || expose.assets.css.sync.length > 0) missingRequests.delete(request);
|
|
82
|
+
for (const file of expose.assets.js.sync) chunks.add(resolveAssetUrl(file));
|
|
83
|
+
for (const file of expose.assets.css.sync) chunks.add(resolveAssetUrl(file));
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
chunks: Array.from(chunks),
|
|
87
|
+
missingRequests
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
const collectLegacyAssets = (stats, statsUrl, requests) => {
|
|
91
|
+
const chunks = /* @__PURE__ */ new Set();
|
|
92
|
+
const assetBaseUrl = getAssetBaseUrl(statsUrl);
|
|
93
|
+
for (const federatedModule of stats.federatedModules || []) for (const request of requests) for (const file of federatedModule.exposes?.[request] || []) chunks.add(new URL(file, assetBaseUrl).href);
|
|
94
|
+
return Array.from(chunks);
|
|
95
|
+
};
|
|
96
|
+
const processRemote = async (remoteInfo, requests, configuredManifestUrl) => {
|
|
97
|
+
const manifestUrl = getManifestUrl(remoteInfo, configuredManifestUrl);
|
|
98
|
+
let manifestChunks = [];
|
|
99
|
+
let legacyRequests = requests;
|
|
61
100
|
try {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
Object.values(chunk).forEach((chunk) => {
|
|
75
|
-
if (chunk.files) chunk.files.forEach((file) => {
|
|
76
|
-
chunks.add(prefix + file);
|
|
77
|
-
});
|
|
78
|
-
if (chunk.requiredModules) chunk.requiredModules.forEach((module) => {
|
|
79
|
-
if (shareMap[module]) {}
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
return Array.from(chunks);
|
|
85
|
-
} catch (e) {
|
|
86
|
-
console.error("flush error:", e);
|
|
101
|
+
const { chunks, missingRequests } = collectManifestAssets(await fetchJson(manifestUrl), manifestUrl, requests);
|
|
102
|
+
manifestChunks = chunks;
|
|
103
|
+
if (!missingRequests.size) return chunks;
|
|
104
|
+
legacyRequests = missingRequests;
|
|
105
|
+
} catch {}
|
|
106
|
+
const statsUrl = getMetadataUrl(remoteInfo.entry, "federated-stats.json");
|
|
107
|
+
try {
|
|
108
|
+
const stats = await fetchJson(statsUrl);
|
|
109
|
+
return Array.from(new Set([...manifestChunks, ...collectLegacyAssets(stats, statsUrl, legacyRequests)]));
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (!manifestChunks.length) console.error("flush error:", error);
|
|
112
|
+
return manifestChunks;
|
|
87
113
|
}
|
|
88
114
|
};
|
|
89
115
|
/**
|
|
@@ -91,12 +117,28 @@ const processChunk = async (chunk, shareMap, hostStats) => {
|
|
|
91
117
|
* @returns {Promise<Array>} A promise that resolves to an array of deduplicated chunks.
|
|
92
118
|
*/
|
|
93
119
|
const flushChunks = async () => {
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
const
|
|
120
|
+
const knownRemotes = getAllKnownRemotes();
|
|
121
|
+
const configuredManifestUrls = getConfiguredManifestUrls();
|
|
122
|
+
const remoteNames = Object.keys(knownRemotes).sort((left, right) => right.length - left.length);
|
|
123
|
+
const requestsByRemote = /* @__PURE__ */ new Map();
|
|
124
|
+
for (const chunk of usedChunks) {
|
|
125
|
+
const [remote, request] = parseUsedChunk(chunk, remoteNames);
|
|
126
|
+
const remoteInfo = knownRemotes[remote];
|
|
127
|
+
if (!remoteInfo) {
|
|
128
|
+
console.error(`flush chunks: Remote ${remote} is not defined in the global config`);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const remoteRequests = requestsByRemote.get(remoteInfo.name) || {
|
|
132
|
+
remoteInfo,
|
|
133
|
+
manifestUrl: configuredManifestUrls.get(remote) || configuredManifestUrls.get(remoteInfo.name),
|
|
134
|
+
requests: /* @__PURE__ */ new Set()
|
|
135
|
+
};
|
|
136
|
+
remoteRequests.requests.add(request);
|
|
137
|
+
requestsByRemote.set(remoteInfo.name, remoteRequests);
|
|
138
|
+
}
|
|
98
139
|
usedChunks.clear();
|
|
99
|
-
|
|
140
|
+
const allFlushed = await Promise.all(Array.from(requestsByRemote.values(), ({ remoteInfo, requests, manifestUrl }) => processRemote(remoteInfo, requests, manifestUrl)));
|
|
141
|
+
return Array.from(new Set(allFlushed.flat()));
|
|
100
142
|
};
|
|
101
143
|
|
|
102
144
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flush-chunks.js","names":[],"sources":["../../../src/utils/flush-chunks.ts"],"sourcesContent":["/* eslint-disable no-undef */\n\n// @ts-ignore\nif (!globalThis.usedChunks) {\n // @ts-ignore\n globalThis.usedChunks = new Set();\n}\n/**\n * Initialize usedChunks and share it globally.\n * @type {Set}\n */\n// @ts-ignore\nexport const { usedChunks } = globalThis;\n/**\n * Load hostStats from the JSON file.\n * @returns {object} hostStats - An object containing host stats data.\n */\nconst loadHostStats = () => {\n try {\n //@ts-ignore\n return __non_webpack_require__('../federated-stats.json');\n } catch (e) {\n return {};\n }\n};\n\nexport const getAllKnownRemotes = function () {\n // Attempt to access the global federation controller safely\n const federationController = new Function('return globalThis')()\n .__FEDERATION__;\n if (!federationController || !federationController.__INSTANCES__) {\n // If the federation controller or instances are not defined, return an empty object\n return {};\n }\n\n var collected = {};\n // Use a for...of loop to iterate over all federation instances\n for (const instance of federationController.__INSTANCES__) {\n // Use another for...of loop to iterate over the module cache Map entries\n for (const [key, cacheModule] of instance.moduleCache) {\n // Check if the cacheModule has remoteInfo and use it to collect remote names\n if (cacheModule.remoteInfo) {\n //@ts-ignore\n collected[cacheModule.remoteInfo.name] = cacheModule.remoteInfo;\n }\n }\n }\n return collected;\n};\n\n/**\n * Create a shareMap based on the loaded modules.\n * @returns {object} shareMap - An object containing the shareMap data.\n */\nconst createShareMap = () => {\n // Check if __webpack_share_scopes__ is defined and has a default property\n // @ts-ignore\n if (__webpack_share_scopes__?.default) {\n // Reduce the keys of the default property to create the share map\n // @ts-ignore\n return Object.keys(__webpack_share_scopes__.default).reduce((acc, key) => {\n // @ts-ignore\n const shareMap = __webpack_share_scopes__.default[key];\n // shareScope may equal undefined or null if it has unexpected value\n if (!shareMap || typeof shareMap !== 'object') {\n return acc;\n }\n // Get the loaded modules for the current key\n const loadedModules = Object.values(shareMap)\n // Filter out the modules that are not loaded\n // @ts-ignore\n .filter((sharedModule) => sharedModule.loaded)\n // Map the filtered modules to their 'from' properties\n // @ts-ignore\n .map((sharedModule) => sharedModule.from);\n\n // If there are any loaded modules, add them to the accumulator object\n if (loadedModules.length > 0) {\n // @ts-ignore\n acc[key] = loadedModules;\n }\n // Return the accumulator object for the next iteration\n return acc;\n }, {});\n }\n // If __webpack_share_scopes__ is not defined or doesn't have a default property, return an empty object\n return {};\n};\n\n/**\n * Process a single chunk and return an array of updated chunks.\n * @param {string} chunk - A chunk string containing remote and request data.\n * @param {object} shareMap - An object containing the shareMap data.\n * @param {object} hostStats - An object containing host stats data.\n * @returns {Promise<Array>} A promise that resolves to an array of updated chunks.\n */\n// @ts-ignore\nconst processChunk = async (chunk, shareMap, hostStats) => {\n const chunks = new Set();\n const normalizedChunk = chunk.includes('->')\n ? chunk.replace('->', '/')\n : chunk;\n const remoteSeparatorIndex = normalizedChunk.indexOf('/');\n const remote =\n remoteSeparatorIndex === -1\n ? normalizedChunk\n : normalizedChunk.slice(0, remoteSeparatorIndex);\n const req =\n remoteSeparatorIndex === -1\n ? ''\n : normalizedChunk.slice(remoteSeparatorIndex + 1);\n const request = req?.startsWith('./') ? req : './' + req;\n const knownRemotes = getAllKnownRemotes();\n //@ts-ignore\n if (!knownRemotes[remote]) {\n console.error(\n `flush chunks: Remote ${remote} is not defined in the global config`,\n );\n return;\n }\n\n try {\n //@ts-ignore\n const remoteName = new URL(knownRemotes[remote].entry).pathname\n .split('/')\n .pop();\n //@ts-ignore\n\n const statsFile = knownRemotes[remote].entry\n .replace(remoteName, 'federated-stats.json')\n .replace('ssr', 'chunks');\n let stats = {};\n\n try {\n stats = await fetch(statsFile).then((res) => res.json());\n } catch (e) {\n console.error('flush error', e);\n }\n //@ts-ignore\n\n const [prefix] = knownRemotes[remote].entry.split('static/');\n //@ts-ignore\n\n if (stats.federatedModules) {\n //@ts-ignore\n\n stats.federatedModules.forEach((modules) => {\n if (modules.exposes?.[request]) {\n //@ts-ignore\n\n modules.exposes[request].forEach((chunk) => {\n chunks.add([prefix, chunk].join(''));\n\n Object.values(chunk).forEach((chunk) => {\n //@ts-ignore\n\n if (chunk.files) {\n //@ts-ignore\n\n chunk.files.forEach((file) => {\n chunks.add(prefix + file);\n });\n }\n //@ts-ignore\n\n if (chunk.requiredModules) {\n //@ts-ignore\n\n chunk.requiredModules.forEach((module) => {\n if (shareMap[module]) {\n // If the module is from the host, log the host stats\n }\n });\n }\n });\n });\n }\n });\n }\n\n return Array.from(chunks);\n } catch (e) {\n console.error('flush error:', e);\n }\n};\n\n/**\n * Flush the chunks and return a deduplicated array of chunks.\n * @returns {Promise<Array>} A promise that resolves to an array of deduplicated chunks.\n */\nexport const flushChunks = async () => {\n const hostStats = loadHostStats();\n const shareMap = createShareMap();\n\n const allFlushed = await Promise.all(\n Array.from(usedChunks).map(async (chunk) =>\n processChunk(chunk, shareMap, hostStats),\n ),\n );\n\n // Deduplicate the chunks array\n const dedupe = Array.from(new Set([...allFlushed.flat()]));\n\n // Clear usedChunks\n usedChunks.clear();\n // Filter out any undefined or null values\n return dedupe.filter(Boolean);\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"flush-chunks.js","names":[],"sources":["../../../src/utils/flush-chunks.ts"],"sourcesContent":["/* eslint-disable no-undef */\n\nimport { getResourceUrl, type Manifest } from '@module-federation/sdk';\nimport type { RemoteInfo } from '@module-federation/runtime/types';\n\ntype LegacyFederatedStats = {\n federatedModules?: Array<{\n exposes?: Record<string, string[]>;\n }>;\n};\n\ntype RemoteRequests = {\n remoteInfo: RemoteInfo;\n manifestUrl?: string;\n requests: Set<string>;\n};\n\n// @ts-ignore\nif (!globalThis.usedChunks) {\n // @ts-ignore\n globalThis.usedChunks = new Set();\n}\n/**\n * Initialize usedChunks and share it globally.\n * @type {Set}\n */\n// @ts-ignore\nexport const { usedChunks } = globalThis;\nconst getFederationController = () =>\n new Function('return globalThis')().__FEDERATION__;\n\nexport const getAllKnownRemotes = function (): Record<string, RemoteInfo> {\n const federationController = getFederationController();\n if (!federationController || !federationController.__INSTANCES__) {\n return {};\n }\n\n const collected: Record<string, RemoteInfo> = {};\n for (const instance of federationController.__INSTANCES__) {\n for (const [, cacheModule] of instance.moduleCache) {\n if (cacheModule.remoteInfo) {\n const remoteInfo = cacheModule.remoteInfo as RemoteInfo;\n collected[remoteInfo.name] = remoteInfo;\n if (remoteInfo.alias) collected[remoteInfo.alias] = remoteInfo;\n }\n }\n }\n return collected;\n};\n\nconst getConfiguredManifestUrls = (): Map<string, string> => {\n const manifestUrls = new Map<string, string>();\n const federationController = getFederationController();\n\n for (const instance of federationController?.__INSTANCES__ || []) {\n for (const configuredRemote of instance.options?.remotes || []) {\n if (!('entry' in configuredRemote)) continue;\n try {\n if (!new URL(configuredRemote.entry).pathname.endsWith('.json')) {\n continue;\n }\n } catch {\n continue;\n }\n manifestUrls.set(configuredRemote.name, configuredRemote.entry);\n if (configuredRemote.alias) {\n manifestUrls.set(configuredRemote.alias, configuredRemote.entry);\n }\n }\n }\n\n return manifestUrls;\n};\n\nconst parseUsedChunk = (\n chunk: string,\n remoteNames: string[],\n): [remote: string, request: string] => {\n const normalizedChunk = chunk.replace('->', '/');\n const remote =\n remoteNames.find(\n (name) =>\n normalizedChunk === name || normalizedChunk.startsWith(`${name}/`),\n ) || normalizedChunk.split('/', 1)[0];\n const request = normalizedChunk.slice(remote.length).replace(/^\\//, '');\n return [remote, request.startsWith('./') ? request : `./${request}`];\n};\n\nconst getMetadataUrl = (entry: string, filename: string): string => {\n const url = new URL(entry);\n url.pathname = `${url.pathname.slice(0, url.pathname.lastIndexOf('/') + 1)}${filename}`;\n url.pathname = url.pathname.replace('/ssr/', '/chunks/');\n return url.href;\n};\n\nconst getManifestUrl = (\n remoteInfo: RemoteInfo,\n configuredManifestUrl?: string,\n): string => {\n if (configuredManifestUrl) return configuredManifestUrl;\n return getMetadataUrl(remoteInfo.entry, 'mf-manifest.json');\n};\n\nconst getAssetBaseUrl = (metadataUrl: string): URL => {\n const baseUrl = new URL(metadataUrl);\n const staticPathIndex = baseUrl.pathname.indexOf('/static/');\n baseUrl.pathname =\n staticPathIndex === -1\n ? baseUrl.pathname.slice(0, baseUrl.pathname.lastIndexOf('/') + 1)\n : baseUrl.pathname.slice(0, staticPathIndex + 1);\n baseUrl.search = '';\n baseUrl.hash = '';\n return baseUrl;\n};\n\nconst fetchJson = async <T>(url: string): Promise<T> => {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Request failed with status ${response.status}`);\n }\n return response.json() as Promise<T>;\n};\n\nconst collectManifestAssets = (\n manifest: Manifest,\n manifestUrl: string,\n requests: Set<string>,\n): { chunks: string[]; missingRequests: Set<string> } => {\n const chunks = new Set<string>();\n const missingRequests = new Set(requests);\n let assetBaseUrl = getAssetBaseUrl(manifestUrl);\n const resourceBasePath = getResourceUrl(manifest.metaData, '');\n\n if (resourceBasePath !== 'auto') {\n const normalizedBasePath =\n resourceBasePath && !resourceBasePath.endsWith('/')\n ? `${resourceBasePath}/`\n : resourceBasePath || './';\n assetBaseUrl = new URL(normalizedBasePath, manifestUrl);\n }\n\n const resolveAssetUrl = (file: string) => new URL(file, assetBaseUrl).href;\n\n for (const expose of manifest.exposes) {\n const request = expose.path || `./${expose.name}`;\n if (!requests.has(request)) continue;\n\n const hasSyncAssets =\n expose.assets.js.sync.length > 0 || expose.assets.css.sync.length > 0;\n if (hasSyncAssets) missingRequests.delete(request);\n\n for (const file of expose.assets.js.sync) {\n chunks.add(resolveAssetUrl(file));\n }\n for (const file of expose.assets.css.sync) {\n chunks.add(resolveAssetUrl(file));\n }\n }\n\n return { chunks: Array.from(chunks), missingRequests };\n};\n\nconst collectLegacyAssets = (\n stats: LegacyFederatedStats,\n statsUrl: string,\n requests: Set<string>,\n): string[] => {\n const chunks = new Set<string>();\n const assetBaseUrl = getAssetBaseUrl(statsUrl);\n\n for (const federatedModule of stats.federatedModules || []) {\n for (const request of requests) {\n for (const file of federatedModule.exposes?.[request] || []) {\n chunks.add(new URL(file, assetBaseUrl).href);\n }\n }\n }\n\n return Array.from(chunks);\n};\n\nconst processRemote = async (\n remoteInfo: RemoteInfo,\n requests: Set<string>,\n configuredManifestUrl?: string,\n): Promise<string[]> => {\n const manifestUrl = getManifestUrl(remoteInfo, configuredManifestUrl);\n let manifestChunks: string[] = [];\n let legacyRequests = requests;\n\n try {\n const manifest = await fetchJson<Manifest>(manifestUrl);\n const { chunks, missingRequests } = collectManifestAssets(\n manifest,\n manifestUrl,\n requests,\n );\n manifestChunks = chunks;\n if (!missingRequests.size) return chunks;\n legacyRequests = missingRequests;\n } catch {\n // Older remotes may only expose federated-stats.json.\n }\n\n const statsUrl = getMetadataUrl(remoteInfo.entry, 'federated-stats.json');\n try {\n const stats = await fetchJson<LegacyFederatedStats>(statsUrl);\n return Array.from(\n new Set([\n ...manifestChunks,\n ...collectLegacyAssets(stats, statsUrl, legacyRequests),\n ]),\n );\n } catch (error) {\n if (!manifestChunks.length) console.error('flush error:', error);\n return manifestChunks;\n }\n};\n\n/**\n * Flush the chunks and return a deduplicated array of chunks.\n * @returns {Promise<Array>} A promise that resolves to an array of deduplicated chunks.\n */\nexport const flushChunks = async (): Promise<string[]> => {\n const knownRemotes = getAllKnownRemotes();\n const configuredManifestUrls = getConfiguredManifestUrls();\n const remoteNames = Object.keys(knownRemotes).sort(\n (left, right) => right.length - left.length,\n );\n const requestsByRemote = new Map<string, RemoteRequests>();\n\n for (const chunk of usedChunks) {\n const [remote, request] = parseUsedChunk(chunk, remoteNames);\n const remoteInfo = knownRemotes[remote];\n if (!remoteInfo) {\n console.error(\n `flush chunks: Remote ${remote} is not defined in the global config`,\n );\n continue;\n }\n\n const remoteRequests = requestsByRemote.get(remoteInfo.name) || {\n remoteInfo,\n manifestUrl:\n configuredManifestUrls.get(remote) ||\n configuredManifestUrls.get(remoteInfo.name),\n requests: new Set<string>(),\n };\n remoteRequests.requests.add(request);\n requestsByRemote.set(remoteInfo.name, remoteRequests);\n }\n usedChunks.clear();\n\n const allFlushed = await Promise.all(\n Array.from(\n requestsByRemote.values(),\n ({ remoteInfo, requests, manifestUrl }) =>\n processRemote(remoteInfo, requests, manifestUrl),\n ),\n );\n\n return Array.from(new Set(allFlushed.flat()));\n};\n"],"mappings":"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"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { getResourceUrl } from "@module-federation/sdk";
|
|
2
|
+
|
|
1
3
|
//#region src/utils/flush-chunks.ts
|
|
2
4
|
if (!globalThis.usedChunks) globalThis.usedChunks = /* @__PURE__ */ new Set();
|
|
3
5
|
/**
|
|
@@ -5,83 +7,107 @@ if (!globalThis.usedChunks) globalThis.usedChunks = /* @__PURE__ */ new Set();
|
|
|
5
7
|
* @type {Set}
|
|
6
8
|
*/
|
|
7
9
|
const { usedChunks } = globalThis;
|
|
8
|
-
|
|
9
|
-
* Load hostStats from the JSON file.
|
|
10
|
-
* @returns {object} hostStats - An object containing host stats data.
|
|
11
|
-
*/
|
|
12
|
-
const loadHostStats = () => {
|
|
13
|
-
try {
|
|
14
|
-
return __non_webpack_require__("../federated-stats.json");
|
|
15
|
-
} catch (e) {
|
|
16
|
-
return {};
|
|
17
|
-
}
|
|
18
|
-
};
|
|
10
|
+
const getFederationController = () => new Function("return globalThis")().__FEDERATION__;
|
|
19
11
|
const getAllKnownRemotes = function() {
|
|
20
|
-
const federationController =
|
|
12
|
+
const federationController = getFederationController();
|
|
21
13
|
if (!federationController || !federationController.__INSTANCES__) return {};
|
|
22
|
-
|
|
23
|
-
for (const instance of federationController.__INSTANCES__) for (const [
|
|
14
|
+
const collected = {};
|
|
15
|
+
for (const instance of federationController.__INSTANCES__) for (const [, cacheModule] of instance.moduleCache) if (cacheModule.remoteInfo) {
|
|
16
|
+
const remoteInfo = cacheModule.remoteInfo;
|
|
17
|
+
collected[remoteInfo.name] = remoteInfo;
|
|
18
|
+
if (remoteInfo.alias) collected[remoteInfo.alias] = remoteInfo;
|
|
19
|
+
}
|
|
24
20
|
return collected;
|
|
25
21
|
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
22
|
+
const getConfiguredManifestUrls = () => {
|
|
23
|
+
const manifestUrls = /* @__PURE__ */ new Map();
|
|
24
|
+
const federationController = getFederationController();
|
|
25
|
+
for (const instance of federationController?.__INSTANCES__ || []) for (const configuredRemote of instance.options?.remotes || []) {
|
|
26
|
+
if (!("entry" in configuredRemote)) continue;
|
|
27
|
+
try {
|
|
28
|
+
if (!new URL(configuredRemote.entry).pathname.endsWith(".json")) continue;
|
|
29
|
+
} catch {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
manifestUrls.set(configuredRemote.name, configuredRemote.entry);
|
|
33
|
+
if (configuredRemote.alias) manifestUrls.set(configuredRemote.alias, configuredRemote.entry);
|
|
34
|
+
}
|
|
35
|
+
return manifestUrls;
|
|
39
36
|
};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
37
|
+
const parseUsedChunk = (chunk, remoteNames) => {
|
|
38
|
+
const normalizedChunk = chunk.replace("->", "/");
|
|
39
|
+
const remote = remoteNames.find((name) => normalizedChunk === name || normalizedChunk.startsWith(`${name}/`)) || normalizedChunk.split("/", 1)[0];
|
|
40
|
+
const request = normalizedChunk.slice(remote.length).replace(/^\//, "");
|
|
41
|
+
return [remote, request.startsWith("./") ? request : `./${request}`];
|
|
42
|
+
};
|
|
43
|
+
const getMetadataUrl = (entry, filename) => {
|
|
44
|
+
const url = new URL(entry);
|
|
45
|
+
url.pathname = `${url.pathname.slice(0, url.pathname.lastIndexOf("/") + 1)}${filename}`;
|
|
46
|
+
url.pathname = url.pathname.replace("/ssr/", "/chunks/");
|
|
47
|
+
return url.href;
|
|
48
|
+
};
|
|
49
|
+
const getManifestUrl = (remoteInfo, configuredManifestUrl) => {
|
|
50
|
+
if (configuredManifestUrl) return configuredManifestUrl;
|
|
51
|
+
return getMetadataUrl(remoteInfo.entry, "mf-manifest.json");
|
|
52
|
+
};
|
|
53
|
+
const getAssetBaseUrl = (metadataUrl) => {
|
|
54
|
+
const baseUrl = new URL(metadataUrl);
|
|
55
|
+
const staticPathIndex = baseUrl.pathname.indexOf("/static/");
|
|
56
|
+
baseUrl.pathname = staticPathIndex === -1 ? baseUrl.pathname.slice(0, baseUrl.pathname.lastIndexOf("/") + 1) : baseUrl.pathname.slice(0, staticPathIndex + 1);
|
|
57
|
+
baseUrl.search = "";
|
|
58
|
+
baseUrl.hash = "";
|
|
59
|
+
return baseUrl;
|
|
60
|
+
};
|
|
61
|
+
const fetchJson = async (url) => {
|
|
62
|
+
const response = await fetch(url);
|
|
63
|
+
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
|
|
64
|
+
return response.json();
|
|
65
|
+
};
|
|
66
|
+
const collectManifestAssets = (manifest, manifestUrl, requests) => {
|
|
48
67
|
const chunks = /* @__PURE__ */ new Set();
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
68
|
+
const missingRequests = new Set(requests);
|
|
69
|
+
let assetBaseUrl = getAssetBaseUrl(manifestUrl);
|
|
70
|
+
const resourceBasePath = getResourceUrl(manifest.metaData, "");
|
|
71
|
+
if (resourceBasePath !== "auto") {
|
|
72
|
+
const normalizedBasePath = resourceBasePath && !resourceBasePath.endsWith("/") ? `${resourceBasePath}/` : resourceBasePath || "./";
|
|
73
|
+
assetBaseUrl = new URL(normalizedBasePath, manifestUrl);
|
|
74
|
+
}
|
|
75
|
+
const resolveAssetUrl = (file) => new URL(file, assetBaseUrl).href;
|
|
76
|
+
for (const expose of manifest.exposes) {
|
|
77
|
+
const request = expose.path || `./${expose.name}`;
|
|
78
|
+
if (!requests.has(request)) continue;
|
|
79
|
+
if (expose.assets.js.sync.length > 0 || expose.assets.css.sync.length > 0) missingRequests.delete(request);
|
|
80
|
+
for (const file of expose.assets.js.sync) chunks.add(resolveAssetUrl(file));
|
|
81
|
+
for (const file of expose.assets.css.sync) chunks.add(resolveAssetUrl(file));
|
|
58
82
|
}
|
|
83
|
+
return {
|
|
84
|
+
chunks: Array.from(chunks),
|
|
85
|
+
missingRequests
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
const collectLegacyAssets = (stats, statsUrl, requests) => {
|
|
89
|
+
const chunks = /* @__PURE__ */ new Set();
|
|
90
|
+
const assetBaseUrl = getAssetBaseUrl(statsUrl);
|
|
91
|
+
for (const federatedModule of stats.federatedModules || []) for (const request of requests) for (const file of federatedModule.exposes?.[request] || []) chunks.add(new URL(file, assetBaseUrl).href);
|
|
92
|
+
return Array.from(chunks);
|
|
93
|
+
};
|
|
94
|
+
const processRemote = async (remoteInfo, requests, configuredManifestUrl) => {
|
|
95
|
+
const manifestUrl = getManifestUrl(remoteInfo, configuredManifestUrl);
|
|
96
|
+
let manifestChunks = [];
|
|
97
|
+
let legacyRequests = requests;
|
|
59
98
|
try {
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
Object.values(chunk).forEach((chunk) => {
|
|
73
|
-
if (chunk.files) chunk.files.forEach((file) => {
|
|
74
|
-
chunks.add(prefix + file);
|
|
75
|
-
});
|
|
76
|
-
if (chunk.requiredModules) chunk.requiredModules.forEach((module) => {
|
|
77
|
-
if (shareMap[module]) {}
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
return Array.from(chunks);
|
|
83
|
-
} catch (e) {
|
|
84
|
-
console.error("flush error:", e);
|
|
99
|
+
const { chunks, missingRequests } = collectManifestAssets(await fetchJson(manifestUrl), manifestUrl, requests);
|
|
100
|
+
manifestChunks = chunks;
|
|
101
|
+
if (!missingRequests.size) return chunks;
|
|
102
|
+
legacyRequests = missingRequests;
|
|
103
|
+
} catch {}
|
|
104
|
+
const statsUrl = getMetadataUrl(remoteInfo.entry, "federated-stats.json");
|
|
105
|
+
try {
|
|
106
|
+
const stats = await fetchJson(statsUrl);
|
|
107
|
+
return Array.from(new Set([...manifestChunks, ...collectLegacyAssets(stats, statsUrl, legacyRequests)]));
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (!manifestChunks.length) console.error("flush error:", error);
|
|
110
|
+
return manifestChunks;
|
|
85
111
|
}
|
|
86
112
|
};
|
|
87
113
|
/**
|
|
@@ -89,12 +115,28 @@ const processChunk = async (chunk, shareMap, hostStats) => {
|
|
|
89
115
|
* @returns {Promise<Array>} A promise that resolves to an array of deduplicated chunks.
|
|
90
116
|
*/
|
|
91
117
|
const flushChunks = async () => {
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
const
|
|
118
|
+
const knownRemotes = getAllKnownRemotes();
|
|
119
|
+
const configuredManifestUrls = getConfiguredManifestUrls();
|
|
120
|
+
const remoteNames = Object.keys(knownRemotes).sort((left, right) => right.length - left.length);
|
|
121
|
+
const requestsByRemote = /* @__PURE__ */ new Map();
|
|
122
|
+
for (const chunk of usedChunks) {
|
|
123
|
+
const [remote, request] = parseUsedChunk(chunk, remoteNames);
|
|
124
|
+
const remoteInfo = knownRemotes[remote];
|
|
125
|
+
if (!remoteInfo) {
|
|
126
|
+
console.error(`flush chunks: Remote ${remote} is not defined in the global config`);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const remoteRequests = requestsByRemote.get(remoteInfo.name) || {
|
|
130
|
+
remoteInfo,
|
|
131
|
+
manifestUrl: configuredManifestUrls.get(remote) || configuredManifestUrls.get(remoteInfo.name),
|
|
132
|
+
requests: /* @__PURE__ */ new Set()
|
|
133
|
+
};
|
|
134
|
+
remoteRequests.requests.add(request);
|
|
135
|
+
requestsByRemote.set(remoteInfo.name, remoteRequests);
|
|
136
|
+
}
|
|
96
137
|
usedChunks.clear();
|
|
97
|
-
|
|
138
|
+
const allFlushed = await Promise.all(Array.from(requestsByRemote.values(), ({ remoteInfo, requests, manifestUrl }) => processRemote(remoteInfo, requests, manifestUrl)));
|
|
139
|
+
return Array.from(new Set(allFlushed.flat()));
|
|
98
140
|
};
|
|
99
141
|
|
|
100
142
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flush-chunks.mjs","names":[],"sources":["../../../src/utils/flush-chunks.ts"],"sourcesContent":["/* eslint-disable no-undef */\n\n// @ts-ignore\nif (!globalThis.usedChunks) {\n // @ts-ignore\n globalThis.usedChunks = new Set();\n}\n/**\n * Initialize usedChunks and share it globally.\n * @type {Set}\n */\n// @ts-ignore\nexport const { usedChunks } = globalThis;\n/**\n * Load hostStats from the JSON file.\n * @returns {object} hostStats - An object containing host stats data.\n */\nconst loadHostStats = () => {\n try {\n //@ts-ignore\n return __non_webpack_require__('../federated-stats.json');\n } catch (e) {\n return {};\n }\n};\n\nexport const getAllKnownRemotes = function () {\n // Attempt to access the global federation controller safely\n const federationController = new Function('return globalThis')()\n .__FEDERATION__;\n if (!federationController || !federationController.__INSTANCES__) {\n // If the federation controller or instances are not defined, return an empty object\n return {};\n }\n\n var collected = {};\n // Use a for...of loop to iterate over all federation instances\n for (const instance of federationController.__INSTANCES__) {\n // Use another for...of loop to iterate over the module cache Map entries\n for (const [key, cacheModule] of instance.moduleCache) {\n // Check if the cacheModule has remoteInfo and use it to collect remote names\n if (cacheModule.remoteInfo) {\n //@ts-ignore\n collected[cacheModule.remoteInfo.name] = cacheModule.remoteInfo;\n }\n }\n }\n return collected;\n};\n\n/**\n * Create a shareMap based on the loaded modules.\n * @returns {object} shareMap - An object containing the shareMap data.\n */\nconst createShareMap = () => {\n // Check if __webpack_share_scopes__ is defined and has a default property\n // @ts-ignore\n if (__webpack_share_scopes__?.default) {\n // Reduce the keys of the default property to create the share map\n // @ts-ignore\n return Object.keys(__webpack_share_scopes__.default).reduce((acc, key) => {\n // @ts-ignore\n const shareMap = __webpack_share_scopes__.default[key];\n // shareScope may equal undefined or null if it has unexpected value\n if (!shareMap || typeof shareMap !== 'object') {\n return acc;\n }\n // Get the loaded modules for the current key\n const loadedModules = Object.values(shareMap)\n // Filter out the modules that are not loaded\n // @ts-ignore\n .filter((sharedModule) => sharedModule.loaded)\n // Map the filtered modules to their 'from' properties\n // @ts-ignore\n .map((sharedModule) => sharedModule.from);\n\n // If there are any loaded modules, add them to the accumulator object\n if (loadedModules.length > 0) {\n // @ts-ignore\n acc[key] = loadedModules;\n }\n // Return the accumulator object for the next iteration\n return acc;\n }, {});\n }\n // If __webpack_share_scopes__ is not defined or doesn't have a default property, return an empty object\n return {};\n};\n\n/**\n * Process a single chunk and return an array of updated chunks.\n * @param {string} chunk - A chunk string containing remote and request data.\n * @param {object} shareMap - An object containing the shareMap data.\n * @param {object} hostStats - An object containing host stats data.\n * @returns {Promise<Array>} A promise that resolves to an array of updated chunks.\n */\n// @ts-ignore\nconst processChunk = async (chunk, shareMap, hostStats) => {\n const chunks = new Set();\n const normalizedChunk = chunk.includes('->')\n ? chunk.replace('->', '/')\n : chunk;\n const remoteSeparatorIndex = normalizedChunk.indexOf('/');\n const remote =\n remoteSeparatorIndex === -1\n ? normalizedChunk\n : normalizedChunk.slice(0, remoteSeparatorIndex);\n const req =\n remoteSeparatorIndex === -1\n ? ''\n : normalizedChunk.slice(remoteSeparatorIndex + 1);\n const request = req?.startsWith('./') ? req : './' + req;\n const knownRemotes = getAllKnownRemotes();\n //@ts-ignore\n if (!knownRemotes[remote]) {\n console.error(\n `flush chunks: Remote ${remote} is not defined in the global config`,\n );\n return;\n }\n\n try {\n //@ts-ignore\n const remoteName = new URL(knownRemotes[remote].entry).pathname\n .split('/')\n .pop();\n //@ts-ignore\n\n const statsFile = knownRemotes[remote].entry\n .replace(remoteName, 'federated-stats.json')\n .replace('ssr', 'chunks');\n let stats = {};\n\n try {\n stats = await fetch(statsFile).then((res) => res.json());\n } catch (e) {\n console.error('flush error', e);\n }\n //@ts-ignore\n\n const [prefix] = knownRemotes[remote].entry.split('static/');\n //@ts-ignore\n\n if (stats.federatedModules) {\n //@ts-ignore\n\n stats.federatedModules.forEach((modules) => {\n if (modules.exposes?.[request]) {\n //@ts-ignore\n\n modules.exposes[request].forEach((chunk) => {\n chunks.add([prefix, chunk].join(''));\n\n Object.values(chunk).forEach((chunk) => {\n //@ts-ignore\n\n if (chunk.files) {\n //@ts-ignore\n\n chunk.files.forEach((file) => {\n chunks.add(prefix + file);\n });\n }\n //@ts-ignore\n\n if (chunk.requiredModules) {\n //@ts-ignore\n\n chunk.requiredModules.forEach((module) => {\n if (shareMap[module]) {\n // If the module is from the host, log the host stats\n }\n });\n }\n });\n });\n }\n });\n }\n\n return Array.from(chunks);\n } catch (e) {\n console.error('flush error:', e);\n }\n};\n\n/**\n * Flush the chunks and return a deduplicated array of chunks.\n * @returns {Promise<Array>} A promise that resolves to an array of deduplicated chunks.\n */\nexport const flushChunks = async () => {\n const hostStats = loadHostStats();\n const shareMap = createShareMap();\n\n const allFlushed = await Promise.all(\n Array.from(usedChunks).map(async (chunk) =>\n processChunk(chunk, shareMap, hostStats),\n ),\n );\n\n // Deduplicate the chunks array\n const dedupe = Array.from(new Set([...allFlushed.flat()]));\n\n // Clear usedChunks\n usedChunks.clear();\n // Filter out any undefined or null values\n return dedupe.filter(Boolean);\n};\n"],"mappings":";AAGA,IAAI,CAAC,WAAW,WAEd,YAAW,6BAAa,IAAI,KAAK;;;;;AAOnC,MAAa,EAAE,eAAe;;;;;AAK9B,MAAM,sBAAsB;AAC1B,KAAI;AAEF,SAAO,wBAAwB,0BAA0B;UAClD,GAAG;AACV,SAAO,EAAE;;;AAIb,MAAa,qBAAqB,WAAY;CAE5C,MAAM,uBAAuB,IAAI,SAAS,oBAAoB,EAAE,CAC7D;AACH,KAAI,CAAC,wBAAwB,CAAC,qBAAqB,cAEjD,QAAO,EAAE;CAGX,IAAI,YAAY,EAAE;AAElB,MAAK,MAAM,YAAY,qBAAqB,cAE1C,MAAK,MAAM,CAAC,KAAK,gBAAgB,SAAS,YAExC,KAAI,YAAY,WAEd,WAAU,YAAY,WAAW,QAAQ,YAAY;AAI3D,QAAO;;;;;;AAOT,MAAM,uBAAuB;AAG3B,KAAI,0BAA0B,QAG5B,QAAO,OAAO,KAAK,yBAAyB,QAAQ,CAAC,QAAQ,KAAK,QAAQ;EAExE,MAAM,WAAW,yBAAyB,QAAQ;AAElD,MAAI,CAAC,YAAY,OAAO,aAAa,SACnC,QAAO;EAGT,MAAM,gBAAgB,OAAO,OAAO,SAAS,CAG1C,QAAQ,iBAAiB,aAAa,OAAO,CAG7C,KAAK,iBAAiB,aAAa,KAAK;AAG3C,MAAI,cAAc,SAAS,EAEzB,KAAI,OAAO;AAGb,SAAO;IACN,EAAE,CAAC;AAGR,QAAO,EAAE;;;;;;;;;AAWX,MAAM,eAAe,OAAO,OAAO,UAAU,cAAc;CACzD,MAAM,yBAAS,IAAI,KAAK;CACxB,MAAM,kBAAkB,MAAM,SAAS,KAAK,GACxC,MAAM,QAAQ,MAAM,IAAI,GACxB;CACJ,MAAM,uBAAuB,gBAAgB,QAAQ,IAAI;CACzD,MAAM,SACJ,yBAAyB,KACrB,kBACA,gBAAgB,MAAM,GAAG,qBAAqB;CACpD,MAAM,MACJ,yBAAyB,KACrB,KACA,gBAAgB,MAAM,uBAAuB,EAAE;CACrD,MAAM,UAAU,KAAK,WAAW,KAAK,GAAG,MAAM,OAAO;CACrD,MAAM,eAAe,oBAAoB;AAEzC,KAAI,CAAC,aAAa,SAAS;AACzB,UAAQ,MACN,wBAAwB,OAAO,sCAChC;AACD;;AAGF,KAAI;EAEF,MAAM,aAAa,IAAI,IAAI,aAAa,QAAQ,MAAM,CAAC,SACpD,MAAM,IAAI,CACV,KAAK;EAGR,MAAM,YAAY,aAAa,QAAQ,MACpC,QAAQ,YAAY,uBAAuB,CAC3C,QAAQ,OAAO,SAAS;EAC3B,IAAI,QAAQ,EAAE;AAEd,MAAI;AACF,WAAQ,MAAM,MAAM,UAAU,CAAC,MAAM,QAAQ,IAAI,MAAM,CAAC;WACjD,GAAG;AACV,WAAQ,MAAM,eAAe,EAAE;;EAIjC,MAAM,CAAC,UAAU,aAAa,QAAQ,MAAM,MAAM,UAAU;AAG5D,MAAI,MAAM,iBAGR,OAAM,iBAAiB,SAAS,YAAY;AAC1C,OAAI,QAAQ,UAAU,SAGpB,SAAQ,QAAQ,SAAS,SAAS,UAAU;AAC1C,WAAO,IAAI,CAAC,QAAQ,MAAM,CAAC,KAAK,GAAG,CAAC;AAEpC,WAAO,OAAO,MAAM,CAAC,SAAS,UAAU;AAGtC,SAAI,MAAM,MAGR,OAAM,MAAM,SAAS,SAAS;AAC5B,aAAO,IAAI,SAAS,KAAK;OACzB;AAIJ,SAAI,MAAM,gBAGR,OAAM,gBAAgB,SAAS,WAAW;AACxC,UAAI,SAAS,SAAS;OAGtB;MAEJ;KACF;IAEJ;AAGJ,SAAO,MAAM,KAAK,OAAO;UAClB,GAAG;AACV,UAAQ,MAAM,gBAAgB,EAAE;;;;;;;AAQpC,MAAa,cAAc,YAAY;CACrC,MAAM,YAAY,eAAe;CACjC,MAAM,WAAW,gBAAgB;CAEjC,MAAM,aAAa,MAAM,QAAQ,IAC/B,MAAM,KAAK,WAAW,CAAC,IAAI,OAAO,UAChC,aAAa,OAAO,UAAU,UAAU,CACzC,CACF;CAGD,MAAM,SAAS,MAAM,KAAK,IAAI,IAAI,CAAC,GAAG,WAAW,MAAM,CAAC,CAAC,CAAC;AAG1D,YAAW,OAAO;AAElB,QAAO,OAAO,OAAO,QAAQ"}
|
|
1
|
+
{"version":3,"file":"flush-chunks.mjs","names":[],"sources":["../../../src/utils/flush-chunks.ts"],"sourcesContent":["/* eslint-disable no-undef */\n\nimport { getResourceUrl, type Manifest } from '@module-federation/sdk';\nimport type { RemoteInfo } from '@module-federation/runtime/types';\n\ntype LegacyFederatedStats = {\n federatedModules?: Array<{\n exposes?: Record<string, string[]>;\n }>;\n};\n\ntype RemoteRequests = {\n remoteInfo: RemoteInfo;\n manifestUrl?: string;\n requests: Set<string>;\n};\n\n// @ts-ignore\nif (!globalThis.usedChunks) {\n // @ts-ignore\n globalThis.usedChunks = new Set();\n}\n/**\n * Initialize usedChunks and share it globally.\n * @type {Set}\n */\n// @ts-ignore\nexport const { usedChunks } = globalThis;\nconst getFederationController = () =>\n new Function('return globalThis')().__FEDERATION__;\n\nexport const getAllKnownRemotes = function (): Record<string, RemoteInfo> {\n const federationController = getFederationController();\n if (!federationController || !federationController.__INSTANCES__) {\n return {};\n }\n\n const collected: Record<string, RemoteInfo> = {};\n for (const instance of federationController.__INSTANCES__) {\n for (const [, cacheModule] of instance.moduleCache) {\n if (cacheModule.remoteInfo) {\n const remoteInfo = cacheModule.remoteInfo as RemoteInfo;\n collected[remoteInfo.name] = remoteInfo;\n if (remoteInfo.alias) collected[remoteInfo.alias] = remoteInfo;\n }\n }\n }\n return collected;\n};\n\nconst getConfiguredManifestUrls = (): Map<string, string> => {\n const manifestUrls = new Map<string, string>();\n const federationController = getFederationController();\n\n for (const instance of federationController?.__INSTANCES__ || []) {\n for (const configuredRemote of instance.options?.remotes || []) {\n if (!('entry' in configuredRemote)) continue;\n try {\n if (!new URL(configuredRemote.entry).pathname.endsWith('.json')) {\n continue;\n }\n } catch {\n continue;\n }\n manifestUrls.set(configuredRemote.name, configuredRemote.entry);\n if (configuredRemote.alias) {\n manifestUrls.set(configuredRemote.alias, configuredRemote.entry);\n }\n }\n }\n\n return manifestUrls;\n};\n\nconst parseUsedChunk = (\n chunk: string,\n remoteNames: string[],\n): [remote: string, request: string] => {\n const normalizedChunk = chunk.replace('->', '/');\n const remote =\n remoteNames.find(\n (name) =>\n normalizedChunk === name || normalizedChunk.startsWith(`${name}/`),\n ) || normalizedChunk.split('/', 1)[0];\n const request = normalizedChunk.slice(remote.length).replace(/^\\//, '');\n return [remote, request.startsWith('./') ? request : `./${request}`];\n};\n\nconst getMetadataUrl = (entry: string, filename: string): string => {\n const url = new URL(entry);\n url.pathname = `${url.pathname.slice(0, url.pathname.lastIndexOf('/') + 1)}${filename}`;\n url.pathname = url.pathname.replace('/ssr/', '/chunks/');\n return url.href;\n};\n\nconst getManifestUrl = (\n remoteInfo: RemoteInfo,\n configuredManifestUrl?: string,\n): string => {\n if (configuredManifestUrl) return configuredManifestUrl;\n return getMetadataUrl(remoteInfo.entry, 'mf-manifest.json');\n};\n\nconst getAssetBaseUrl = (metadataUrl: string): URL => {\n const baseUrl = new URL(metadataUrl);\n const staticPathIndex = baseUrl.pathname.indexOf('/static/');\n baseUrl.pathname =\n staticPathIndex === -1\n ? baseUrl.pathname.slice(0, baseUrl.pathname.lastIndexOf('/') + 1)\n : baseUrl.pathname.slice(0, staticPathIndex + 1);\n baseUrl.search = '';\n baseUrl.hash = '';\n return baseUrl;\n};\n\nconst fetchJson = async <T>(url: string): Promise<T> => {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Request failed with status ${response.status}`);\n }\n return response.json() as Promise<T>;\n};\n\nconst collectManifestAssets = (\n manifest: Manifest,\n manifestUrl: string,\n requests: Set<string>,\n): { chunks: string[]; missingRequests: Set<string> } => {\n const chunks = new Set<string>();\n const missingRequests = new Set(requests);\n let assetBaseUrl = getAssetBaseUrl(manifestUrl);\n const resourceBasePath = getResourceUrl(manifest.metaData, '');\n\n if (resourceBasePath !== 'auto') {\n const normalizedBasePath =\n resourceBasePath && !resourceBasePath.endsWith('/')\n ? `${resourceBasePath}/`\n : resourceBasePath || './';\n assetBaseUrl = new URL(normalizedBasePath, manifestUrl);\n }\n\n const resolveAssetUrl = (file: string) => new URL(file, assetBaseUrl).href;\n\n for (const expose of manifest.exposes) {\n const request = expose.path || `./${expose.name}`;\n if (!requests.has(request)) continue;\n\n const hasSyncAssets =\n expose.assets.js.sync.length > 0 || expose.assets.css.sync.length > 0;\n if (hasSyncAssets) missingRequests.delete(request);\n\n for (const file of expose.assets.js.sync) {\n chunks.add(resolveAssetUrl(file));\n }\n for (const file of expose.assets.css.sync) {\n chunks.add(resolveAssetUrl(file));\n }\n }\n\n return { chunks: Array.from(chunks), missingRequests };\n};\n\nconst collectLegacyAssets = (\n stats: LegacyFederatedStats,\n statsUrl: string,\n requests: Set<string>,\n): string[] => {\n const chunks = new Set<string>();\n const assetBaseUrl = getAssetBaseUrl(statsUrl);\n\n for (const federatedModule of stats.federatedModules || []) {\n for (const request of requests) {\n for (const file of federatedModule.exposes?.[request] || []) {\n chunks.add(new URL(file, assetBaseUrl).href);\n }\n }\n }\n\n return Array.from(chunks);\n};\n\nconst processRemote = async (\n remoteInfo: RemoteInfo,\n requests: Set<string>,\n configuredManifestUrl?: string,\n): Promise<string[]> => {\n const manifestUrl = getManifestUrl(remoteInfo, configuredManifestUrl);\n let manifestChunks: string[] = [];\n let legacyRequests = requests;\n\n try {\n const manifest = await fetchJson<Manifest>(manifestUrl);\n const { chunks, missingRequests } = collectManifestAssets(\n manifest,\n manifestUrl,\n requests,\n );\n manifestChunks = chunks;\n if (!missingRequests.size) return chunks;\n legacyRequests = missingRequests;\n } catch {\n // Older remotes may only expose federated-stats.json.\n }\n\n const statsUrl = getMetadataUrl(remoteInfo.entry, 'federated-stats.json');\n try {\n const stats = await fetchJson<LegacyFederatedStats>(statsUrl);\n return Array.from(\n new Set([\n ...manifestChunks,\n ...collectLegacyAssets(stats, statsUrl, legacyRequests),\n ]),\n );\n } catch (error) {\n if (!manifestChunks.length) console.error('flush error:', error);\n return manifestChunks;\n }\n};\n\n/**\n * Flush the chunks and return a deduplicated array of chunks.\n * @returns {Promise<Array>} A promise that resolves to an array of deduplicated chunks.\n */\nexport const flushChunks = async (): Promise<string[]> => {\n const knownRemotes = getAllKnownRemotes();\n const configuredManifestUrls = getConfiguredManifestUrls();\n const remoteNames = Object.keys(knownRemotes).sort(\n (left, right) => right.length - left.length,\n );\n const requestsByRemote = new Map<string, RemoteRequests>();\n\n for (const chunk of usedChunks) {\n const [remote, request] = parseUsedChunk(chunk, remoteNames);\n const remoteInfo = knownRemotes[remote];\n if (!remoteInfo) {\n console.error(\n `flush chunks: Remote ${remote} is not defined in the global config`,\n );\n continue;\n }\n\n const remoteRequests = requestsByRemote.get(remoteInfo.name) || {\n remoteInfo,\n manifestUrl:\n configuredManifestUrls.get(remote) ||\n configuredManifestUrls.get(remoteInfo.name),\n requests: new Set<string>(),\n };\n remoteRequests.requests.add(request);\n requestsByRemote.set(remoteInfo.name, remoteRequests);\n }\n usedChunks.clear();\n\n const allFlushed = await Promise.all(\n Array.from(\n requestsByRemote.values(),\n ({ remoteInfo, requests, manifestUrl }) =>\n processRemote(remoteInfo, requests, manifestUrl),\n ),\n );\n\n return Array.from(new Set(allFlushed.flat()));\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"public": true,
|
|
3
3
|
"name": "@module-federation/node",
|
|
4
|
-
"version": "2.7.
|
|
4
|
+
"version": "2.7.48",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
7
7
|
"module": "./dist/src/index.mjs",
|
|
@@ -111,9 +111,9 @@
|
|
|
111
111
|
"encoding": "0.1.13",
|
|
112
112
|
"node-fetch": "2.7.0",
|
|
113
113
|
"tapable": "2.3.0",
|
|
114
|
-
"@module-federation/
|
|
115
|
-
"@module-federation/
|
|
116
|
-
"@module-federation/
|
|
114
|
+
"@module-federation/runtime": "2.8.1",
|
|
115
|
+
"@module-federation/enhanced": "2.8.1",
|
|
116
|
+
"@module-federation/sdk": "2.8.1"
|
|
117
117
|
},
|
|
118
118
|
"peerDependencies": {
|
|
119
119
|
"webpack": "^5.40.0"
|