@module-federation/vite 1.13.1 → 1.13.3
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/lib/index.cjs +429 -83
- package/lib/index.mjs +429 -83
- package/package.json +7 -5
package/lib/index.mjs
CHANGED
|
@@ -27,38 +27,60 @@ async function mapCodeToCodeWithSourcemap(code) {
|
|
|
27
27
|
//#endregion
|
|
28
28
|
//#region src/utils/htmlEntryUtils.ts
|
|
29
29
|
function sanitizeDevEntryPath(devEntryPath) {
|
|
30
|
-
return devEntryPath.replace(
|
|
30
|
+
return devEntryPath.replace(/\\\\?/g, "/");
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* If no entry scripts are found, falls back to injecting a separate script tag.
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* // Before (two separate scripts, race condition):
|
|
41
|
-
* // <script type="module" src="/__mf__virtual/hostAutoInit.js"><\/script>
|
|
42
|
-
* // <script type="module" src="/src/main.js"><\/script>
|
|
43
|
-
* // After (single inline script, sequential execution):
|
|
44
|
-
* // <script type="module">await import("/__mf__virtual/hostAutoInit.js");await import("/src/main.js");<\/script>
|
|
33
|
+
* Rewrites entry module script tags to point at an external wrapper module.
|
|
34
|
+
* The wrapper can then sequence federation init before the app entry without
|
|
35
|
+
* relying on CSP-breaking inline `<script type="module">`.
|
|
45
36
|
*/
|
|
46
|
-
function
|
|
47
|
-
|
|
48
|
-
const scriptTagRegex = /<script\s+([^>]*\btype=["']module["'][^>]*\bsrc=["'][^"']+["'][^>]*)>/gi;
|
|
49
|
-
let hasEntry = false;
|
|
50
|
-
const result = html.replace(scriptTagRegex, (match, attrs) => {
|
|
37
|
+
function rewriteEntryScripts(html, createProxySrc) {
|
|
38
|
+
return html.replace(/<script\s+([^>]*\btype=["']module["'][^>]*\bsrc=["'][^"']+["'][^>]*)>/gi, (match, attrs) => {
|
|
51
39
|
const srcMatch = attrs.match(/\bsrc=["']([^"']+)["']/i);
|
|
52
40
|
if (!srcMatch) return match;
|
|
53
41
|
const originalSrc = srcMatch[1];
|
|
54
42
|
if (originalSrc.includes("@vite/client")) return match;
|
|
55
|
-
|
|
56
|
-
return
|
|
43
|
+
const proxySrc = createProxySrc(originalSrc);
|
|
44
|
+
return match.replace(srcMatch[0], `src=${JSON.stringify(proxySrc)}`);
|
|
57
45
|
});
|
|
58
|
-
|
|
46
|
+
}
|
|
47
|
+
function injectEntryScript(html, initSrc) {
|
|
48
|
+
const src = sanitizeDevEntryPath(initSrc);
|
|
59
49
|
return html.replace("<head>", `<head><script type="module" src=${JSON.stringify(src)}><\/script>`);
|
|
60
50
|
}
|
|
61
51
|
//#endregion
|
|
52
|
+
//#region src/utils/logger.ts
|
|
53
|
+
const MODULE_FEDERATION_LOG_PREFIX = "[Module Federation]";
|
|
54
|
+
function formatModuleFederationMessage(message) {
|
|
55
|
+
return `${MODULE_FEDERATION_LOG_PREFIX} ${message}`;
|
|
56
|
+
}
|
|
57
|
+
function createModuleFederationError(message) {
|
|
58
|
+
return new Error(formatModuleFederationMessage(message));
|
|
59
|
+
}
|
|
60
|
+
function toConsoleArgs(message, rest = []) {
|
|
61
|
+
if (typeof message === "string") return [formatModuleFederationMessage(message), ...rest];
|
|
62
|
+
if (message === void 0) return [MODULE_FEDERATION_LOG_PREFIX, ...rest];
|
|
63
|
+
return [
|
|
64
|
+
MODULE_FEDERATION_LOG_PREFIX,
|
|
65
|
+
message,
|
|
66
|
+
...rest
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
const moduleFederationConsole = {
|
|
70
|
+
log(message, ...rest) {
|
|
71
|
+
console.log(...toConsoleArgs(message, rest));
|
|
72
|
+
},
|
|
73
|
+
warn(message, ...rest) {
|
|
74
|
+
console.warn(...toConsoleArgs(message, rest));
|
|
75
|
+
},
|
|
76
|
+
error(message, ...rest) {
|
|
77
|
+
console.error(...toConsoleArgs(message, rest));
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
moduleFederationConsole.log;
|
|
81
|
+
const mfWarn = moduleFederationConsole.warn;
|
|
82
|
+
const mfError = moduleFederationConsole.error;
|
|
83
|
+
//#endregion
|
|
62
84
|
//#region src/utils/packageUtils.ts
|
|
63
85
|
const dependencyPresenceCache = /* @__PURE__ */ new Map();
|
|
64
86
|
let packageDetectionCwd;
|
|
@@ -68,6 +90,9 @@ function getDependencyCacheKey(cwd, dependencyName) {
|
|
|
68
90
|
function setPackageDetectionCwd(cwd) {
|
|
69
91
|
packageDetectionCwd = cwd;
|
|
70
92
|
}
|
|
93
|
+
function getPackageDetectionCwd() {
|
|
94
|
+
return packageDetectionCwd || process.cwd();
|
|
95
|
+
}
|
|
71
96
|
/**
|
|
72
97
|
* Escaping rules:
|
|
73
98
|
* Convert using the format __${mapping}__, where _ and $ are not allowed in npm package names but can be used in variable names.
|
|
@@ -82,7 +107,7 @@ function setPackageDetectionCwd(cwd) {
|
|
|
82
107
|
* @returns {string} - The encoded file name.
|
|
83
108
|
*/
|
|
84
109
|
function packageNameEncode(name) {
|
|
85
|
-
if (typeof name !== "string") throw
|
|
110
|
+
if (typeof name !== "string") throw createModuleFederationError("A string package name is required");
|
|
86
111
|
return name.replace(/@/g, "_mf_0_").replace(/\//g, "_mf_1_").replace(/-/g, "_mf_2_").replace(/\./g, "_mf_3_");
|
|
87
112
|
}
|
|
88
113
|
/**
|
|
@@ -91,7 +116,7 @@ function packageNameEncode(name) {
|
|
|
91
116
|
* @returns {string} - The decoded package name.
|
|
92
117
|
*/
|
|
93
118
|
function packageNameDecode(encoded) {
|
|
94
|
-
if (typeof encoded !== "string") throw
|
|
119
|
+
if (typeof encoded !== "string") throw createModuleFederationError("A string encoded file name is required");
|
|
95
120
|
return encoded.replace(/_mf_0_/g, "@").replace(/_mf_1_/g, "/").replace(/_mf_2_/g, "-").replace(/_mf_3_/g, ".");
|
|
96
121
|
}
|
|
97
122
|
/**
|
|
@@ -103,6 +128,13 @@ function removePathFromNpmPackage(packageString) {
|
|
|
103
128
|
const match = packageString.match(/^(?:@[^/]+\/)?[^/]+/);
|
|
104
129
|
return match ? match[0] : packageString;
|
|
105
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Detect whether the current bundler is Rolldown (Vite 8+) by checking
|
|
133
|
+
* for `meta.rolldownVersion` on the plugin hook context.
|
|
134
|
+
*/
|
|
135
|
+
function getIsRolldown(ctx) {
|
|
136
|
+
return !!ctx?.meta?.rolldownVersion;
|
|
137
|
+
}
|
|
106
138
|
function hasPackageDependency(dependencyName, cwd = packageDetectionCwd || process.cwd()) {
|
|
107
139
|
const cacheKey = getDependencyCacheKey(cwd, dependencyName);
|
|
108
140
|
const cached = dependencyPresenceCache.get(cacheKey);
|
|
@@ -128,6 +160,7 @@ function getFirstHtmlEntryFile(entryFiles) {
|
|
|
128
160
|
return entryFiles.find((file) => file.endsWith(".html"));
|
|
129
161
|
}
|
|
130
162
|
const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
163
|
+
const DEV_HTML_PROXY_PREFIX = "virtual:mf-html-entry-proxy?";
|
|
131
164
|
const getEntryPath = () => typeof entryPath === "function" ? entryPath() : entryPath;
|
|
132
165
|
let devEntryPath = "";
|
|
133
166
|
let entryFiles = [];
|
|
@@ -151,8 +184,13 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
151
184
|
configResolved(config) {
|
|
152
185
|
viteConfig = config;
|
|
153
186
|
const resolvedEntryPath = getEntryPath();
|
|
154
|
-
|
|
155
|
-
|
|
187
|
+
if (resolvedEntryPath.startsWith("virtual:mf")) devEntryPath = config.base + "@id/" + resolvedEntryPath;
|
|
188
|
+
else {
|
|
189
|
+
const normalized = resolvedEntryPath.replace(/\\\\?/g, "/");
|
|
190
|
+
const root = config.root.replace(/\\\\?/g, "/").replace(/\/$/, "");
|
|
191
|
+
const relativePath = normalized.startsWith(root + "/") ? normalized.slice(root.length) : "/" + normalized.replace(/^[A-Za-z]:[\\/]/, "");
|
|
192
|
+
devEntryPath = config.base + relativePath.replace(/^\//, "");
|
|
193
|
+
}
|
|
156
194
|
},
|
|
157
195
|
configureServer(server) {
|
|
158
196
|
server.middlewares.use((req, res, next) => {
|
|
@@ -167,7 +205,29 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
167
205
|
transformIndexHtml(c) {
|
|
168
206
|
if (!injectHtml()) return;
|
|
169
207
|
clientInjected = true;
|
|
170
|
-
|
|
208
|
+
const html = rewriteEntryScripts(c, (originalSrc) => {
|
|
209
|
+
const query = new URLSearchParams({
|
|
210
|
+
init: sanitizeDevEntryPath(devEntryPath),
|
|
211
|
+
entry: originalSrc
|
|
212
|
+
}).toString();
|
|
213
|
+
return `${viteConfig.base}@id/${DEV_HTML_PROXY_PREFIX}${query}`;
|
|
214
|
+
});
|
|
215
|
+
return html === c ? injectEntryScript(c, devEntryPath) : html;
|
|
216
|
+
},
|
|
217
|
+
resolveId(id) {
|
|
218
|
+
if (id.startsWith(DEV_HTML_PROXY_PREFIX)) return id;
|
|
219
|
+
},
|
|
220
|
+
load(id) {
|
|
221
|
+
if (!id.startsWith(DEV_HTML_PROXY_PREFIX)) return;
|
|
222
|
+
const params = new URLSearchParams(id.slice(28));
|
|
223
|
+
const initSrc = params.get("init");
|
|
224
|
+
const entrySrc = params.get("entry");
|
|
225
|
+
if (!initSrc || !entrySrc) return;
|
|
226
|
+
return `
|
|
227
|
+
const baseUrl = document.baseURI || window.location.href;
|
|
228
|
+
await import(new URL(${JSON.stringify(initSrc)}, baseUrl).href);
|
|
229
|
+
await import(new URL(${JSON.stringify(entrySrc)}, baseUrl).href);
|
|
230
|
+
`;
|
|
171
231
|
},
|
|
172
232
|
transform(code, id) {
|
|
173
233
|
if (id.includes("node_modules") || inject !== "html" || htmlFilePath) return;
|
|
@@ -223,7 +283,7 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
223
283
|
if (typeof result === "string") return result;
|
|
224
284
|
if (result && typeof result === "object") {
|
|
225
285
|
if ("runtime" in result) {
|
|
226
|
-
|
|
286
|
+
mfWarn("renderBuiltUrl returned runtime code for HTML injection. Runtime code cannot be used in <script src=\"\">. Falling back to base path.");
|
|
227
287
|
return viteConfig.base + file;
|
|
228
288
|
}
|
|
229
289
|
if (result.relative) return file;
|
|
@@ -288,11 +348,11 @@ function checkAliasConflicts(options) {
|
|
|
288
348
|
});
|
|
289
349
|
}
|
|
290
350
|
if (conflicts.length > 0) {
|
|
291
|
-
|
|
351
|
+
mfWarn("Detected alias conflicts with shared modules:");
|
|
292
352
|
conflicts.forEach(({ sharedModule, alias, target }) => {
|
|
293
|
-
|
|
353
|
+
mfWarn(`Shared module "${sharedModule}" is aliased by "${alias}" to "${target}"`);
|
|
294
354
|
});
|
|
295
|
-
|
|
355
|
+
mfWarn("This may cause runtime errors as the shared module will bypass Module Federation's sharing mechanism.");
|
|
296
356
|
}
|
|
297
357
|
}
|
|
298
358
|
};
|
|
@@ -321,7 +381,7 @@ function PluginDevProxyModuleTopLevelAwait() {
|
|
|
321
381
|
try {
|
|
322
382
|
ast = this.parse(code, { allowReturnOutsideFunction: true });
|
|
323
383
|
} catch (e) {
|
|
324
|
-
throw
|
|
384
|
+
throw createModuleFederationError(`${id}: ${e}`);
|
|
325
385
|
}
|
|
326
386
|
const magicString = new MagicString(code);
|
|
327
387
|
const walk = await loadWalk();
|
|
@@ -449,7 +509,7 @@ const normalizeDevDtsOptions = (dts, context) => {
|
|
|
449
509
|
const logDtsError = (error, dtsOptions) => {
|
|
450
510
|
if (dtsOptions === false) return;
|
|
451
511
|
if (typeof dtsOptions === "object" && dtsOptions && dtsOptions.displayErrorInTerminal === false) return;
|
|
452
|
-
|
|
512
|
+
mfError(error);
|
|
453
513
|
};
|
|
454
514
|
function pluginDts(options) {
|
|
455
515
|
if (options.dts === false) return [];
|
|
@@ -477,7 +537,7 @@ function pluginDts(options) {
|
|
|
477
537
|
if (!normalizedDevOptions || !resolvedConfig) return;
|
|
478
538
|
const devOptions = normalizedDevOptions;
|
|
479
539
|
if (devOptions.disableDynamicRemoteTypeHints && devOptions.disableHotTypesReload && devOptions.disableLiveReload) return;
|
|
480
|
-
if (!options.name) throw
|
|
540
|
+
if (!options.name) throw createModuleFederationError("name is required if you want to enable dev server!");
|
|
481
541
|
const outputDir = resolveOutputDir(resolvedConfig);
|
|
482
542
|
const normalizedDtsOptions = normalizeDevDtsOptions(options.dts, resolvedConfig.root);
|
|
483
543
|
if (typeof normalizedDtsOptions !== "object") return;
|
|
@@ -672,11 +732,11 @@ function normalizeShareItem(key, shareItem) {
|
|
|
672
732
|
version = __require(path$1.join(process.cwd(), "node_modules", removePathFromNpmPackage(key), "package.json")).version;
|
|
673
733
|
} catch (e2) {
|
|
674
734
|
version = searchPackageVersion(key);
|
|
675
|
-
if (!version)
|
|
735
|
+
if (!version) mfError(e1);
|
|
676
736
|
}
|
|
677
737
|
}
|
|
678
738
|
} catch (e) {
|
|
679
|
-
|
|
739
|
+
mfError(`Unexpected error resolving version for ${key}:`, e);
|
|
680
740
|
}
|
|
681
741
|
if (typeof shareItem === "string") return {
|
|
682
742
|
name: shareItem,
|
|
@@ -737,7 +797,7 @@ function getNormalizeShareItem(key) {
|
|
|
737
797
|
return options.shared[key] || options.shared[removePathFromNpmPackage(key)] || options.shared[removePathFromNpmPackage(key) + "/"];
|
|
738
798
|
}
|
|
739
799
|
function normalizeModuleFederationOptions(options) {
|
|
740
|
-
if (options.virtualModuleDir && options.virtualModuleDir.includes("/")) throw
|
|
800
|
+
if (options.virtualModuleDir && options.virtualModuleDir.includes("/")) throw createModuleFederationError(`Invalid virtualModuleDir: "${options.virtualModuleDir}". The virtualModuleDir option cannot contain slashes (/). Please use a single directory name like '__mf__virtual__your_app_name'.`);
|
|
741
801
|
return config = {
|
|
742
802
|
exposes: normalizeExposes(options.exposes),
|
|
743
803
|
filename: options.filename || "remoteEntry-[hash]",
|
|
@@ -872,7 +932,7 @@ const cacheMap = {};
|
|
|
872
932
|
*/
|
|
873
933
|
function assertModuleFound(tag, str = "") {
|
|
874
934
|
const module = VirtualModule.findModule(tag, str);
|
|
875
|
-
if (!module) throw
|
|
935
|
+
if (!module) throw createModuleFederationError(`Module Federation shared module '${str}' not found. Please ensure it's installed as a dependency in your package.json.`);
|
|
876
936
|
return module;
|
|
877
937
|
}
|
|
878
938
|
var VirtualModule = class {
|
|
@@ -933,15 +993,61 @@ var VirtualModule = class {
|
|
|
933
993
|
};
|
|
934
994
|
//#endregion
|
|
935
995
|
//#region src/virtualModules/virtualExposes.ts
|
|
996
|
+
const EXPOSES_CSS_MAP_PLACEHOLDER = "__MF_EXPOSES_CSS_MAP__";
|
|
997
|
+
function getExposesCssMapPlaceholder() {
|
|
998
|
+
return EXPOSES_CSS_MAP_PLACEHOLDER;
|
|
999
|
+
}
|
|
936
1000
|
function getVirtualExposesId(options) {
|
|
937
1001
|
return `virtual:mf-exposes:${`${options.name}__${options.filename}`.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
|
|
938
1002
|
}
|
|
939
1003
|
function generateExposes(options) {
|
|
940
1004
|
return `
|
|
1005
|
+
const cssAssetMap = ${JSON.stringify(options.bundleAllCSS ? EXPOSES_CSS_MAP_PLACEHOLDER : {})};
|
|
1006
|
+
const injectedCssHrefs = new Set();
|
|
1007
|
+
|
|
1008
|
+
async function injectCssAssets(exposeKey) {
|
|
1009
|
+
if (typeof document === "undefined") {
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// Replaced at build time with expose -> css asset paths.
|
|
1014
|
+
const cssAssets = cssAssetMap[exposeKey] || [];
|
|
1015
|
+
|
|
1016
|
+
await Promise.all(
|
|
1017
|
+
cssAssets.map((cssAsset) => {
|
|
1018
|
+
const href = new URL(cssAsset, import.meta.url).href;
|
|
1019
|
+
|
|
1020
|
+
// Same expose can be resolved multiple times in one page.
|
|
1021
|
+
if (injectedCssHrefs.has(href)) {
|
|
1022
|
+
return Promise.resolve();
|
|
1023
|
+
}
|
|
1024
|
+
injectedCssHrefs.add(href);
|
|
1025
|
+
|
|
1026
|
+
const existingLink = document.querySelector(
|
|
1027
|
+
\`link[rel="stylesheet"][data-mf-href="\${href}"]\`
|
|
1028
|
+
);
|
|
1029
|
+
if (existingLink) {
|
|
1030
|
+
return Promise.resolve();
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
return new Promise((resolve, reject) => {
|
|
1034
|
+
const link = document.createElement("link");
|
|
1035
|
+
link.rel = "stylesheet";
|
|
1036
|
+
link.href = href;
|
|
1037
|
+
link.setAttribute("data-mf-href", href);
|
|
1038
|
+
link.onload = () => resolve();
|
|
1039
|
+
link.onerror = () => reject(new Error(\`[Module Federation] Failed to load CSS asset: \${href}\`));
|
|
1040
|
+
document.head.appendChild(link);
|
|
1041
|
+
});
|
|
1042
|
+
})
|
|
1043
|
+
);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
941
1046
|
export default {
|
|
942
1047
|
${Object.keys(options.exposes).map((key) => {
|
|
943
1048
|
return `
|
|
944
1049
|
${JSON.stringify(key)}: async () => {
|
|
1050
|
+
await injectCssAssets(${JSON.stringify(key)})
|
|
945
1051
|
const importModule = await import(${JSON.stringify(options.exposes[key].import)})
|
|
946
1052
|
const exportModule = {}
|
|
947
1053
|
Object.assign(exportModule, importModule)
|
|
@@ -1088,36 +1194,167 @@ function generateRemotes(id, command, isRolldown) {
|
|
|
1088
1194
|
* 1. __prebuild__: export shareModule (pre-built source code of modules such as vue, react, etc.)
|
|
1089
1195
|
* 2. __loadShare__: load shareModule (mfRuntime.loadShare('vue'))
|
|
1090
1196
|
*/
|
|
1197
|
+
function escapeGeneratedStringLiteral(value) {
|
|
1198
|
+
return JSON.stringify(value).replace(/[<>\u2028\u2029]/g, (char) => {
|
|
1199
|
+
switch (char) {
|
|
1200
|
+
case "<": return "\\u003C";
|
|
1201
|
+
case ">": return "\\u003E";
|
|
1202
|
+
case "\u2028": return "\\u2028";
|
|
1203
|
+
case "\u2029": return "\\u2029";
|
|
1204
|
+
default: return char;
|
|
1205
|
+
}
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1208
|
+
const localRequire = createRequire$1(import.meta.url);
|
|
1209
|
+
function resolvePackageEntryFromProjectRoot(pkg) {
|
|
1210
|
+
try {
|
|
1211
|
+
return createRequire$1(new URL(`file://${path.join(getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
|
|
1212
|
+
} catch {
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
function getInstalledPackageJsonPath(pkg) {
|
|
1217
|
+
try {
|
|
1218
|
+
const packageName = removePathFromNpmPackage(pkg);
|
|
1219
|
+
const projectRequire = createRequire$1(new URL(`file://${path.join(getPackageDetectionCwd(), "package.json")}`));
|
|
1220
|
+
let resolvedPath;
|
|
1221
|
+
try {
|
|
1222
|
+
resolvedPath = projectRequire.resolve(pkg);
|
|
1223
|
+
} catch {
|
|
1224
|
+
resolvedPath = projectRequire.resolve(packageName);
|
|
1225
|
+
}
|
|
1226
|
+
let currentDir = path.dirname(resolvedPath);
|
|
1227
|
+
const rootDir = path.parse(currentDir).root;
|
|
1228
|
+
while (currentDir !== rootDir) {
|
|
1229
|
+
const packageJsonPath = path.join(currentDir, "package.json");
|
|
1230
|
+
if (existsSync(packageJsonPath)) {
|
|
1231
|
+
if (JSON.parse(readFileSync(packageJsonPath, "utf-8")).name === packageName) return packageJsonPath;
|
|
1232
|
+
}
|
|
1233
|
+
currentDir = path.dirname(currentDir);
|
|
1234
|
+
}
|
|
1235
|
+
const rootPackageJsonPath = path.join(rootDir, "package.json");
|
|
1236
|
+
if (existsSync(rootPackageJsonPath)) {
|
|
1237
|
+
if (JSON.parse(readFileSync(rootPackageJsonPath, "utf-8")).name === packageName) return rootPackageJsonPath;
|
|
1238
|
+
}
|
|
1239
|
+
} catch {
|
|
1240
|
+
const packageName = removePathFromNpmPackage(pkg);
|
|
1241
|
+
let currentDir = getPackageDetectionCwd();
|
|
1242
|
+
const rootDir = path.parse(currentDir).root;
|
|
1243
|
+
while (currentDir !== rootDir) {
|
|
1244
|
+
const packageJsonPath = path.join(currentDir, "node_modules", packageName, "package.json");
|
|
1245
|
+
if (existsSync(packageJsonPath)) return packageJsonPath;
|
|
1246
|
+
currentDir = path.dirname(currentDir);
|
|
1247
|
+
}
|
|
1248
|
+
const rootPackageJsonPath = path.join(rootDir, "node_modules", packageName, "package.json");
|
|
1249
|
+
return existsSync(rootPackageJsonPath) ? rootPackageJsonPath : void 0;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
function resolveImportTarget(exportsField) {
|
|
1253
|
+
if (typeof exportsField === "string") return exportsField;
|
|
1254
|
+
if (!exportsField || typeof exportsField !== "object") return void 0;
|
|
1255
|
+
const record = exportsField;
|
|
1256
|
+
for (const condition of [
|
|
1257
|
+
"import",
|
|
1258
|
+
"module",
|
|
1259
|
+
"default"
|
|
1260
|
+
]) {
|
|
1261
|
+
const target = resolveImportTarget(record[condition]);
|
|
1262
|
+
if (target) return target;
|
|
1263
|
+
}
|
|
1264
|
+
for (const target of Object.values(record)) {
|
|
1265
|
+
const resolved = resolveImportTarget(target);
|
|
1266
|
+
if (resolved) return resolved;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
function getPackageEsmEntryPath(pkg) {
|
|
1270
|
+
try {
|
|
1271
|
+
const resolvedEntryPath = resolvePackageEntryFromProjectRoot(pkg);
|
|
1272
|
+
const packageJsonPath = getInstalledPackageJsonPath(pkg);
|
|
1273
|
+
if (!packageJsonPath) return resolvedEntryPath;
|
|
1274
|
+
const packageName = removePathFromNpmPackage(pkg);
|
|
1275
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
1276
|
+
const subpath = pkg === packageName ? "." : `.${pkg.slice(packageName.length)}`;
|
|
1277
|
+
const target = resolveImportTarget(typeof packageJson.exports === "string" ? subpath === "." ? packageJson.exports : void 0 : packageJson.exports?.[subpath] ?? (subpath === "." ? packageJson.exports?.["."] ?? (packageJson.exports && !Object.keys(packageJson.exports).some((key) => key.startsWith(".")) ? packageJson.exports : void 0) : void 0)) || packageJson.module;
|
|
1278
|
+
if (!target) return resolvedEntryPath;
|
|
1279
|
+
return path.resolve(path.dirname(packageJsonPath), target);
|
|
1280
|
+
} catch {
|
|
1281
|
+
return resolvePackageEntryFromProjectRoot(pkg);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
function getEsmNamedExports(pkg) {
|
|
1285
|
+
try {
|
|
1286
|
+
const entryPath = getPackageEsmEntryPath(pkg);
|
|
1287
|
+
if (!entryPath) return [];
|
|
1288
|
+
const { initSync, parse } = localRequire("es-module-lexer");
|
|
1289
|
+
initSync();
|
|
1290
|
+
const [, exports] = parse(readFileSync(entryPath, "utf-8"), entryPath);
|
|
1291
|
+
return exports.map((item) => item.n).filter((name) => !!name && name !== "default" && name !== "__esModule" && /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name));
|
|
1292
|
+
} catch {
|
|
1293
|
+
return [];
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1091
1296
|
function getPackageNamedExports(pkg) {
|
|
1092
1297
|
try {
|
|
1093
|
-
const mod = createRequire$1(new URL(
|
|
1298
|
+
const mod = createRequire$1(new URL(`file://${path.join(getPackageDetectionCwd(), "package.json")}`))(pkg);
|
|
1094
1299
|
return Object.keys(mod).filter((k) => k !== "default" && k !== "__esModule" && /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(k));
|
|
1095
1300
|
} catch {
|
|
1096
|
-
return
|
|
1301
|
+
return getEsmNamedExports(pkg);
|
|
1097
1302
|
}
|
|
1098
1303
|
}
|
|
1099
1304
|
function getLocalProviderImportPath(pkg) {
|
|
1100
1305
|
try {
|
|
1101
|
-
const resolved = createRequire$1(new URL(
|
|
1306
|
+
const resolved = createRequire$1(new URL(`file://${path.join(getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
|
|
1102
1307
|
return resolved.includes("/node_modules/") || resolved.includes("\\node_modules\\") ? void 0 : resolved;
|
|
1103
1308
|
} catch {
|
|
1104
1309
|
return;
|
|
1105
1310
|
}
|
|
1106
1311
|
}
|
|
1312
|
+
function tryResolveImportFromPackageRoot(pkg, root) {
|
|
1313
|
+
try {
|
|
1314
|
+
return createRequire$1(new URL(`file://${path.join(root, "package.json")}`)).resolve(pkg);
|
|
1315
|
+
} catch {
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
function getConcreteSharedImportSource(pkg, shareItem) {
|
|
1320
|
+
const configuredImport = shareItem?.shareConfig.import;
|
|
1321
|
+
if (typeof configuredImport === "string") return configuredImport;
|
|
1322
|
+
const projectRoot = getPackageDetectionCwd();
|
|
1323
|
+
if (tryResolveImportFromPackageRoot(pkg, projectRoot)) return;
|
|
1324
|
+
let currentDir = path.dirname(projectRoot);
|
|
1325
|
+
while (currentDir !== path.dirname(currentDir)) {
|
|
1326
|
+
const resolved = tryResolveImportFromPackageRoot(pkg, currentDir);
|
|
1327
|
+
if (resolved) return resolved;
|
|
1328
|
+
currentDir = path.dirname(currentDir);
|
|
1329
|
+
}
|
|
1330
|
+
return tryResolveImportFromPackageRoot(pkg, currentDir);
|
|
1331
|
+
}
|
|
1107
1332
|
const preBuildCacheMap = {};
|
|
1333
|
+
const preBuildShareItemMap = {};
|
|
1108
1334
|
const PREBUILD_TAG = "__prebuild__";
|
|
1109
|
-
function writePreBuildLibPath(pkg) {
|
|
1335
|
+
function writePreBuildLibPath(pkg, shareItem) {
|
|
1110
1336
|
if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
|
|
1111
|
-
|
|
1337
|
+
preBuildShareItemMap[pkg] = shareItem;
|
|
1338
|
+
preBuildCacheMap[pkg].writeSync("", true);
|
|
1112
1339
|
}
|
|
1113
1340
|
function getPreBuildLibImportId(pkg) {
|
|
1114
1341
|
if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
|
|
1115
1342
|
return preBuildCacheMap[pkg].getImportId();
|
|
1116
1343
|
}
|
|
1344
|
+
function getPreBuildShareItem(pkg) {
|
|
1345
|
+
return preBuildShareItemMap[pkg];
|
|
1346
|
+
}
|
|
1347
|
+
function getSharedImportSource(pkg, shareItem) {
|
|
1348
|
+
return getConcreteSharedImportSource(pkg, shareItem) || getPreBuildLibImportId(pkg);
|
|
1349
|
+
}
|
|
1117
1350
|
const LOAD_SHARE_TAG = "__loadShare__";
|
|
1118
1351
|
const loadShareCacheMap = {};
|
|
1119
|
-
function
|
|
1352
|
+
function getLoadShareImportId(pkg, isRolldown, command) {
|
|
1120
1353
|
if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, isRolldown || command === "build" ? ".mjs" : ".js");
|
|
1354
|
+
return loadShareCacheMap[pkg].getImportId();
|
|
1355
|
+
}
|
|
1356
|
+
function getLoadShareModulePath(pkg, isRolldown, command) {
|
|
1357
|
+
if (!loadShareCacheMap[pkg]) getLoadShareImportId(pkg, isRolldown, command);
|
|
1121
1358
|
return loadShareCacheMap[pkg].getPath();
|
|
1122
1359
|
}
|
|
1123
1360
|
function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
@@ -1127,22 +1364,25 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
|
1127
1364
|
const { initPromise } = globalThis[globalKey];` : `const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")`;
|
|
1128
1365
|
const awaitOrPlaceholder = useESM ? "await " : "/*mf top-level-await placeholder replacement mf*/";
|
|
1129
1366
|
const useSsrProviderFallback = hasPackageDependency("vinext") && command === "build" && pkg === "react";
|
|
1130
|
-
const
|
|
1367
|
+
const concreteSharedImportSource = getConcreteSharedImportSource(pkg, shareItem);
|
|
1368
|
+
const sharedImportSource = concreteSharedImportSource || getPreBuildLibImportId(pkg);
|
|
1369
|
+
const devImportSource = concreteSharedImportSource || pkg;
|
|
1370
|
+
const providerImportId = getLocalProviderImportPath(pkg) || concreteSharedImportSource || sharedImportSource;
|
|
1131
1371
|
const namedExports = getPackageNamedExports(pkg);
|
|
1132
1372
|
let exportLine;
|
|
1133
1373
|
if (namedExports.length > 0) {
|
|
1134
1374
|
const destructure = `const { ${namedExports.map((name, i) => `${name}: __mf_${i}`).join(", ")} } = exportModule;`;
|
|
1135
1375
|
const namedExportLine = `export { ${namedExports.map((name, i) => `__mf_${i} as ${name}`).join(", ")} };`;
|
|
1136
|
-
exportLine = useESM ? `export default exportModule;\n ${destructure}\n ${namedExportLine}` : `module.exports = exportModule;\n ${destructure}\n Object.assign(module.exports, { ${namedExports.map((name, i) => `"${name}": __mf_${i}`).join(", ")} });`;
|
|
1137
|
-
} else exportLine = useESM ? `export default exportModule\n export * from ${
|
|
1376
|
+
exportLine = useESM ? `export default exportModule.default ?? exportModule;\n ${destructure}\n ${namedExportLine}` : `module.exports = exportModule;\n ${destructure}\n Object.assign(module.exports, { ${namedExports.map((name, i) => `"${name}": __mf_${i}`).join(", ")} });`;
|
|
1377
|
+
} else exportLine = useESM ? `export default exportModule.default ?? exportModule\n export * from ${escapeGeneratedStringLiteral(sharedImportSource)}` : "module.exports = exportModule";
|
|
1138
1378
|
loadShareCacheMap[pkg].writeSync(`
|
|
1139
|
-
import ${
|
|
1140
|
-
${command !== "build" ? `;() => import(${
|
|
1379
|
+
import ${escapeGeneratedStringLiteral(sharedImportSource)};
|
|
1380
|
+
${command !== "build" ? `;() => import(${escapeGeneratedStringLiteral(devImportSource)}).catch(() => {});` : ""}
|
|
1141
1381
|
${importLine}
|
|
1142
1382
|
${useSsrProviderFallback ? `const providerModulePromise = typeof window === "undefined"
|
|
1143
|
-
? import(${
|
|
1383
|
+
? import(${escapeGeneratedStringLiteral(providerImportId)})
|
|
1144
1384
|
: undefined` : ""}
|
|
1145
|
-
const res = initPromise.then(runtime => runtime.loadShare(${
|
|
1385
|
+
const res = initPromise.then(runtime => runtime.loadShare(${escapeGeneratedStringLiteral(pkg)}, {
|
|
1146
1386
|
customShareInfo: {shareConfig:{
|
|
1147
1387
|
singleton: ${shareItem.shareConfig.singleton},
|
|
1148
1388
|
strictVersion: ${shareItem.shareConfig.strictVersion},
|
|
@@ -1153,7 +1393,7 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
|
1153
1393
|
? ((await providerModulePromise)?.default ?? await providerModulePromise)
|
|
1154
1394
|
: ${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory)))` : `${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory))`}
|
|
1155
1395
|
${exportLine}
|
|
1156
|
-
|
|
1396
|
+
`, true);
|
|
1157
1397
|
}
|
|
1158
1398
|
//#endregion
|
|
1159
1399
|
//#region src/virtualModules/virtualRemoteEntry.ts
|
|
@@ -1186,8 +1426,8 @@ function generateLocalSharedImportMap() {
|
|
|
1186
1426
|
const shareItem = getNormalizeShareItem(pkg);
|
|
1187
1427
|
return `
|
|
1188
1428
|
${JSON.stringify(pkg)}: async () => {
|
|
1189
|
-
${shareItem?.shareConfig.import === false ? `throw new Error(\`Shared module '\${${JSON.stringify(pkg)}}' must be provided by host\`);` : isVinext && pkg === "react" ? `let pkg = await import("react");
|
|
1190
|
-
return pkg;` : `let pkg = await import(
|
|
1429
|
+
${shareItem?.shareConfig.import === false ? `throw new Error(\`[Module Federation] Shared module '\${${JSON.stringify(pkg)}}' must be provided by host\`);` : isVinext && pkg === "react" ? `let pkg = await import("react");
|
|
1430
|
+
return pkg;` : `let pkg = await import(${JSON.stringify(getSharedImportSource(pkg, shareItem))});
|
|
1191
1431
|
return pkg;`}
|
|
1192
1432
|
}
|
|
1193
1433
|
`;
|
|
@@ -1206,7 +1446,7 @@ function generateLocalSharedImportMap() {
|
|
|
1206
1446
|
from: ${JSON.stringify(options.name)},
|
|
1207
1447
|
async get () {
|
|
1208
1448
|
if (${shareItem.shareConfig.import === false}) {
|
|
1209
|
-
throw new Error(\`Shared module '\${${JSON.stringify(key)}}' must be provided by host\`);
|
|
1449
|
+
throw new Error(\`[Module Federation] Shared module '\${${JSON.stringify(key)}}' must be provided by host\`);
|
|
1210
1450
|
}
|
|
1211
1451
|
usedShared[${JSON.stringify(key)}].loaded = true
|
|
1212
1452
|
const {${JSON.stringify(key)}: pkgDynamicImport} = importMap
|
|
@@ -1313,14 +1553,14 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1313
1553
|
initScope
|
|
1314
1554
|
}));
|
|
1315
1555
|
} catch (e) {
|
|
1316
|
-
console.error(e)
|
|
1556
|
+
console.error('[Module Federation]', e)
|
|
1317
1557
|
}
|
|
1318
1558
|
return initRes
|
|
1319
1559
|
}
|
|
1320
1560
|
|
|
1321
1561
|
async function getExposes(moduleName) {
|
|
1322
1562
|
const exposesMap = await getExposesMap()
|
|
1323
|
-
if (!(moduleName in exposesMap)) throw new Error(\`Module \${moduleName} does not exist in container.\`)
|
|
1563
|
+
if (!(moduleName in exposesMap)) throw new Error(\`[Module Federation] Module \${moduleName} does not exist in container.\`)
|
|
1324
1564
|
return (exposesMap[moduleName])().then(res => () => res)
|
|
1325
1565
|
}
|
|
1326
1566
|
export {
|
|
@@ -1469,6 +1709,18 @@ const processModuleAssets = (bundle, filesMap, moduleMatcher) => {
|
|
|
1469
1709
|
}
|
|
1470
1710
|
};
|
|
1471
1711
|
/**
|
|
1712
|
+
* Adds global CSS assets to all module exports
|
|
1713
|
+
* @param filesMap - The preload map to update
|
|
1714
|
+
* @param cssAssets - Set of CSS asset filenames to add
|
|
1715
|
+
*/
|
|
1716
|
+
const addCssAssetsToAllExports = (filesMap, cssAssets) => {
|
|
1717
|
+
Object.keys(filesMap).forEach((key) => {
|
|
1718
|
+
cssAssets.forEach((cssAsset) => {
|
|
1719
|
+
trackAsset(filesMap, key, cssAsset, false, "css");
|
|
1720
|
+
});
|
|
1721
|
+
});
|
|
1722
|
+
};
|
|
1723
|
+
/**
|
|
1472
1724
|
* Deduplicates assets in the files map
|
|
1473
1725
|
* @param filesMap - The preload map to deduplicate
|
|
1474
1726
|
* @returns New deduplicated preload map
|
|
@@ -1737,14 +1989,14 @@ const promise = new Promise((resolve, reject) => {
|
|
|
1737
1989
|
});
|
|
1738
1990
|
function setParseTimeout(timeout) {
|
|
1739
1991
|
if (!_parseTimeout) _parseTimeout = setTimeout(() => {
|
|
1740
|
-
|
|
1992
|
+
mfWarn(`Parse timeout (${timeout}s) - forcing resolve`);
|
|
1741
1993
|
_resolve(1);
|
|
1742
1994
|
}, timeout * 1e3);
|
|
1743
1995
|
}
|
|
1744
1996
|
function resetIdleTimeout(timeout) {
|
|
1745
1997
|
clearTimeout(_parseTimeout);
|
|
1746
1998
|
_parseTimeout = setTimeout(() => {
|
|
1747
|
-
|
|
1999
|
+
mfWarn(`moduleParseIdleTimeout: no module activity for ${timeout}s, forcing resolve. Some shared/remote dependencies may be missing. Consider increasing moduleParseIdleTimeout.`);
|
|
1748
2000
|
_resolve(1);
|
|
1749
2001
|
}, timeout * 1e3);
|
|
1750
2002
|
}
|
|
@@ -1794,12 +2046,13 @@ function pluginModuleParseEnd_default(excludeFn, options) {
|
|
|
1794
2046
|
//#region src/plugins/pluginProxyRemoteEntry.ts
|
|
1795
2047
|
const filter = createFilter();
|
|
1796
2048
|
function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposesId }) {
|
|
1797
|
-
let viteConfig, _command;
|
|
2049
|
+
let viteConfig, _command, root;
|
|
1798
2050
|
return {
|
|
1799
2051
|
name: "proxyRemoteEntry",
|
|
1800
2052
|
enforce: "post",
|
|
1801
2053
|
configResolved(config) {
|
|
1802
2054
|
viteConfig = config;
|
|
2055
|
+
root = config.root;
|
|
1803
2056
|
},
|
|
1804
2057
|
config(config, { command }) {
|
|
1805
2058
|
_command = command;
|
|
@@ -1854,6 +2107,51 @@ function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposes
|
|
|
1854
2107
|
return code;
|
|
1855
2108
|
}
|
|
1856
2109
|
})());
|
|
2110
|
+
},
|
|
2111
|
+
generateBundle(_, bundle) {
|
|
2112
|
+
if (_command !== "build") return;
|
|
2113
|
+
const filesMap = {};
|
|
2114
|
+
const exposeEntries = Object.entries(options.exposes);
|
|
2115
|
+
const allCssAssets = options.bundleAllCSS ? collectCssAssets(bundle) : /* @__PURE__ */ new Set();
|
|
2116
|
+
processModuleAssets(bundle, filesMap, (modulePath) => {
|
|
2117
|
+
const absoluteModulePath = path$1.resolve(root, modulePath);
|
|
2118
|
+
return exposeEntries.find(([_, exposeOptions]) => {
|
|
2119
|
+
const exposePath = path$1.resolve(root, exposeOptions.import);
|
|
2120
|
+
if (absoluteModulePath === exposePath) return true;
|
|
2121
|
+
const stripKnownJsExt = (filePath) => {
|
|
2122
|
+
const ext = path$1.extname(filePath);
|
|
2123
|
+
return [
|
|
2124
|
+
".ts",
|
|
2125
|
+
".tsx",
|
|
2126
|
+
".jsx",
|
|
2127
|
+
".mjs",
|
|
2128
|
+
".cjs"
|
|
2129
|
+
].includes(ext) ? path$1.join(path$1.dirname(filePath), path$1.basename(filePath, ext)) : filePath;
|
|
2130
|
+
};
|
|
2131
|
+
return stripKnownJsExt(absoluteModulePath) === stripKnownJsExt(exposePath);
|
|
2132
|
+
})?.[1].import;
|
|
2133
|
+
});
|
|
2134
|
+
if (options.bundleAllCSS) addCssAssetsToAllExports(filesMap, allCssAssets);
|
|
2135
|
+
const ensureRelativeImportPath = (fromFile, toFile) => {
|
|
2136
|
+
let relativePath = path$1.relative(path$1.dirname(fromFile), toFile);
|
|
2137
|
+
if (!relativePath.startsWith(".")) relativePath = `./${relativePath}`;
|
|
2138
|
+
return relativePath;
|
|
2139
|
+
};
|
|
2140
|
+
const placeholderValue = getExposesCssMapPlaceholder();
|
|
2141
|
+
const placeholderPatterns = [
|
|
2142
|
+
JSON.stringify(placeholderValue),
|
|
2143
|
+
`'${placeholderValue}'`,
|
|
2144
|
+
`\`${placeholderValue}\``
|
|
2145
|
+
];
|
|
2146
|
+
for (const file of Object.values(bundle)) {
|
|
2147
|
+
if (file.type !== "chunk" || !file.code.includes(placeholderValue)) continue;
|
|
2148
|
+
const cssAssetMap = exposeEntries.reduce((acc, [exposeKey, expose]) => {
|
|
2149
|
+
const assets = filesMap[expose.import] || createEmptyAssetMap();
|
|
2150
|
+
acc[exposeKey] = [...assets.css.sync, ...assets.css.async].map((cssAsset) => ensureRelativeImportPath(file.fileName, cssAsset));
|
|
2151
|
+
return acc;
|
|
2152
|
+
}, {});
|
|
2153
|
+
for (const placeholderPattern of placeholderPatterns) file.code = file.code.replace(placeholderPattern, JSON.stringify(cssAssetMap));
|
|
2154
|
+
}
|
|
1857
2155
|
}
|
|
1858
2156
|
};
|
|
1859
2157
|
}
|
|
@@ -1865,7 +2163,7 @@ function pluginProxyRemotes_default(options) {
|
|
|
1865
2163
|
return {
|
|
1866
2164
|
name: "proxyRemotes",
|
|
1867
2165
|
config(config, { command: _command }) {
|
|
1868
|
-
const isRolldown =
|
|
2166
|
+
const isRolldown = getIsRolldown(this);
|
|
1869
2167
|
Object.keys(remotes).forEach((key) => {
|
|
1870
2168
|
const remote = remotes[key];
|
|
1871
2169
|
config.resolve.alias.push({
|
|
@@ -1916,6 +2214,9 @@ var PromiseStore = class {
|
|
|
1916
2214
|
};
|
|
1917
2215
|
//#endregion
|
|
1918
2216
|
//#region src/plugins/pluginProxySharedModule_preBuild.ts
|
|
2217
|
+
function getPrebuildResolutionSource(pkgName, shareItem) {
|
|
2218
|
+
return getConcreteSharedImportSource(pkgName, shareItem) || pkgName;
|
|
2219
|
+
}
|
|
1919
2220
|
function proxySharedModule(options) {
|
|
1920
2221
|
const { shared = {} } = options;
|
|
1921
2222
|
let _config;
|
|
@@ -1937,7 +2238,7 @@ function proxySharedModule(options) {
|
|
|
1937
2238
|
config(config, { command }) {
|
|
1938
2239
|
setPackageDetectionCwd(config.root || process.cwd());
|
|
1939
2240
|
isVinext = hasPackageDependency("vinext");
|
|
1940
|
-
const isRolldown =
|
|
2241
|
+
const isRolldown = getIsRolldown(this);
|
|
1941
2242
|
_command = command;
|
|
1942
2243
|
config.resolve.alias.push(...Object.keys(shared).filter((key) => !(isVinext && key === "react")).map((key) => {
|
|
1943
2244
|
const keyBase = key.endsWith("/") ? key.slice(0, -1) : key;
|
|
@@ -1954,7 +2255,7 @@ function proxySharedModule(options) {
|
|
|
1954
2255
|
if (key.endsWith("/") && source !== key.slice(0, -1)) return;
|
|
1955
2256
|
const loadSharePath = getLoadShareModulePath(source, isRolldown, command);
|
|
1956
2257
|
writeLoadShareModule(source, shared[key], command, isRolldown);
|
|
1957
|
-
writePreBuildLibPath(source);
|
|
2258
|
+
writePreBuildLibPath(source, shared[key]);
|
|
1958
2259
|
addUsedShares(source);
|
|
1959
2260
|
writeLocalSharedImportMap();
|
|
1960
2261
|
return this.resolve(loadSharePath, importer);
|
|
@@ -1965,14 +2266,18 @@ function proxySharedModule(options) {
|
|
|
1965
2266
|
return command === "build" ? {
|
|
1966
2267
|
find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
|
|
1967
2268
|
replacement: function($1) {
|
|
1968
|
-
|
|
2269
|
+
const pkgName = assertModuleFound(PREBUILD_TAG, $1).name;
|
|
2270
|
+
return getPrebuildResolutionSource(pkgName, getPreBuildShareItem(pkgName));
|
|
1969
2271
|
}
|
|
1970
2272
|
} : {
|
|
1971
2273
|
find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
|
|
1972
2274
|
replacement: "$1",
|
|
1973
2275
|
async customResolver(source, importer) {
|
|
1974
2276
|
const pkgName = assertModuleFound(PREBUILD_TAG, source).name;
|
|
1975
|
-
const
|
|
2277
|
+
const importSource = getPrebuildResolutionSource(pkgName, getPreBuildShareItem(pkgName));
|
|
2278
|
+
const resolved = await this.resolve(importSource, importer);
|
|
2279
|
+
if (!resolved?.id) return;
|
|
2280
|
+
const result = resolved.id;
|
|
1976
2281
|
if (_config && !result.includes(_config.cacheDir)) savePrebuild.set(pkgName, Promise.resolve(result));
|
|
1977
2282
|
return await this.resolve(await savePrebuild.get(pkgName), importer);
|
|
1978
2283
|
}
|
|
@@ -1989,7 +2294,7 @@ function proxySharedModule(options) {
|
|
|
1989
2294
|
return;
|
|
1990
2295
|
}
|
|
1991
2296
|
writeLoadShareModule(key, shared[key], _command, isRolldown);
|
|
1992
|
-
writePreBuildLibPath(key);
|
|
2297
|
+
writePreBuildLibPath(key, shared[key]);
|
|
1993
2298
|
addUsedShares(key);
|
|
1994
2299
|
});
|
|
1995
2300
|
writeLocalSharedImportMap();
|
|
@@ -2017,7 +2322,6 @@ const VarRemoteEntry = () => {
|
|
|
2017
2322
|
if (req.url?.replace(/\?.*/, "") === (viteConfig.base + varFilename).replace(/^\/?/, "/")) {
|
|
2018
2323
|
res.setHeader("Content-Type", "text/javascript");
|
|
2019
2324
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
2020
|
-
console.log({ filename });
|
|
2021
2325
|
res.end(generateVarRemoteEntry(filename));
|
|
2022
2326
|
} else next();
|
|
2023
2327
|
});
|
|
@@ -2033,9 +2337,9 @@ const VarRemoteEntry = () => {
|
|
|
2033
2337
|
},
|
|
2034
2338
|
async generateBundle(options, bundle) {
|
|
2035
2339
|
if (!varFilename) return;
|
|
2036
|
-
if (!isValidVarName(name))
|
|
2340
|
+
if (!isValidVarName(name)) mfWarn(`Provided remote name "${name}" is not valid for "var" remoteEntry type, thus it's placed in globalThis['${name}'].\nIt may cause problems, so you would better want to use valid var name (see https://www.w3schools.com/js/js_variables.asp).`);
|
|
2037
2341
|
const remoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
|
|
2038
|
-
if (!remoteEntryFile) throw
|
|
2342
|
+
if (!remoteEntryFile) throw createModuleFederationError(`Couldn't find a remoteEntry chunk file for ${mfOptions.filename}, can't generate varRemoteEntry file`);
|
|
2039
2343
|
this.emitFile({
|
|
2040
2344
|
type: "asset",
|
|
2041
2345
|
fileName: varFilename,
|
|
@@ -2060,7 +2364,7 @@ const VarRemoteEntry = () => {
|
|
|
2060
2364
|
function getScriptUrl() {
|
|
2061
2365
|
const currentScript = document.currentScript;
|
|
2062
2366
|
if (!currentScript) {
|
|
2063
|
-
console.error("[
|
|
2367
|
+
console.error("[Module Federation] ${varFilename} script should be called from sync <script> tag (document.currentScript is undefined)")
|
|
2064
2368
|
return '/';
|
|
2065
2369
|
}
|
|
2066
2370
|
return document.currentScript.src.replace(/\\/[^/]*$/, '/');
|
|
@@ -2112,14 +2416,19 @@ function stripEmptyPreloadCalls(code) {
|
|
|
2112
2416
|
while (cursor < nextCode.length) {
|
|
2113
2417
|
const char = nextCode[cursor];
|
|
2114
2418
|
if (char === "(") depth++;
|
|
2115
|
-
else if (char === ")")
|
|
2116
|
-
|
|
2419
|
+
else if (char === ")") {
|
|
2420
|
+
depth--;
|
|
2421
|
+
if (depth < 0) break;
|
|
2422
|
+
} else if (depth === 0 && nextCode.startsWith(",[],import.meta.url)", cursor)) {
|
|
2117
2423
|
replacementEnd = cursor;
|
|
2118
2424
|
break;
|
|
2119
2425
|
}
|
|
2120
2426
|
cursor++;
|
|
2121
2427
|
}
|
|
2122
|
-
if (replacementEnd === -1)
|
|
2428
|
+
if (replacementEnd === -1) {
|
|
2429
|
+
start = nextCode.indexOf(marker, start + marker.length);
|
|
2430
|
+
continue;
|
|
2431
|
+
}
|
|
2123
2432
|
const expression = nextCode.slice(exprStart, replacementEnd);
|
|
2124
2433
|
nextCode = nextCode.slice(0, start) + expression + nextCode.slice(replacementEnd + 20);
|
|
2125
2434
|
start = nextCode.indexOf(marker, start + expression.length);
|
|
@@ -2159,6 +2468,25 @@ var normalizeOptimizeDeps_default = {
|
|
|
2159
2468
|
};
|
|
2160
2469
|
//#endregion
|
|
2161
2470
|
//#region src/index.ts
|
|
2471
|
+
const UNSAFE_JS_SOURCE_CHAR_MAP = {
|
|
2472
|
+
"<": "\\u003C",
|
|
2473
|
+
">": "\\u003E",
|
|
2474
|
+
"/": "\\u002F",
|
|
2475
|
+
"\\": "\\\\",
|
|
2476
|
+
"\b": "\\b",
|
|
2477
|
+
"\f": "\\f",
|
|
2478
|
+
"\n": "\\n",
|
|
2479
|
+
"\r": "\\r",
|
|
2480
|
+
" ": "\\t",
|
|
2481
|
+
"\0": "\\0",
|
|
2482
|
+
"\u2028": "\\u2028",
|
|
2483
|
+
"\u2029": "\\u2029"
|
|
2484
|
+
};
|
|
2485
|
+
function escapeUnsafeJsSourceChars(str) {
|
|
2486
|
+
return str.replace(/[<>/\\\b\f\n\r\t\0\u2028\u2029]/g, (char) => {
|
|
2487
|
+
return UNSAFE_JS_SOURCE_CHAR_MAP[char] ?? char;
|
|
2488
|
+
});
|
|
2489
|
+
}
|
|
2162
2490
|
/**
|
|
2163
2491
|
* Plugin that runs FIRST to create virtual module files in the config hook.
|
|
2164
2492
|
* This prevents 504 "Outdated Optimize Dep" errors by ensuring files exist
|
|
@@ -2177,13 +2505,14 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
2177
2505
|
VirtualModule.setRoot(root);
|
|
2178
2506
|
VirtualModule.ensureVirtualPackageExists();
|
|
2179
2507
|
initVirtualModules(_command, getRemoteEntryId(options));
|
|
2180
|
-
|
|
2181
|
-
const isRolldown = !!this?.meta?.rolldownVersion;
|
|
2508
|
+
const isRolldown = getIsRolldown(this);
|
|
2182
2509
|
if (remotes && Object.keys(remotes).length > 0) for (const key of Object.keys(remotes)) addUsedRemote(key, key);
|
|
2183
2510
|
if (shared && Object.keys(shared).length > 0) {
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2511
|
+
if (_command === "serve") {
|
|
2512
|
+
config.optimizeDeps = config.optimizeDeps || {};
|
|
2513
|
+
config.optimizeDeps.include = config.optimizeDeps.include || [];
|
|
2514
|
+
config.optimizeDeps.include.push(virtualRuntimeInitStatus.getImportId());
|
|
2515
|
+
}
|
|
2187
2516
|
for (const key of Object.keys(shared)) {
|
|
2188
2517
|
if (key.endsWith("/")) continue;
|
|
2189
2518
|
const shareItem = shared[key];
|
|
@@ -2193,9 +2522,12 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
2193
2522
|
}
|
|
2194
2523
|
getLoadShareModulePath(key, isRolldown);
|
|
2195
2524
|
writeLoadShareModule(key, shareItem, _command, isRolldown);
|
|
2196
|
-
writePreBuildLibPath(key);
|
|
2525
|
+
writePreBuildLibPath(key, shareItem);
|
|
2197
2526
|
addUsedShares(key);
|
|
2198
|
-
|
|
2527
|
+
if (_command === "serve") {
|
|
2528
|
+
if (!isRolldown) config.optimizeDeps.include.push(getLoadShareImportId(key, isRolldown, _command));
|
|
2529
|
+
config.optimizeDeps.include.push(getPreBuildLibImportId(key));
|
|
2530
|
+
}
|
|
2199
2531
|
}
|
|
2200
2532
|
writeLocalSharedImportMap();
|
|
2201
2533
|
}
|
|
@@ -2206,7 +2538,7 @@ function federation(mfUserOptions) {
|
|
|
2206
2538
|
const options = normalizeModuleFederationOptions(mfUserOptions);
|
|
2207
2539
|
const isVinext = hasPackageDependency("vinext");
|
|
2208
2540
|
const { name, remotes, shared, filename, hostInitInjectLocation } = options;
|
|
2209
|
-
if (!name) throw
|
|
2541
|
+
if (!name) throw createModuleFederationError("name is required");
|
|
2210
2542
|
const remoteEntryId = getRemoteEntryId(options);
|
|
2211
2543
|
const virtualExposesId = getVirtualExposesId(options);
|
|
2212
2544
|
let command;
|
|
@@ -2292,7 +2624,16 @@ function federation(mfUserOptions) {
|
|
|
2292
2624
|
}
|
|
2293
2625
|
};
|
|
2294
2626
|
}
|
|
2627
|
+
let warnedAboutCodeSplitting = false;
|
|
2628
|
+
const ensureCodeSplitting = (output) => {
|
|
2629
|
+
if (output?.codeSplitting !== false) return;
|
|
2630
|
+
delete output.codeSplitting;
|
|
2631
|
+
if (warnedAboutCodeSplitting) return;
|
|
2632
|
+
warnedAboutCodeSplitting = true;
|
|
2633
|
+
mfWarn("Ignoring `build.rolldownOptions.output.codeSplitting = false` because module federation requires chunk splitting.");
|
|
2634
|
+
};
|
|
2295
2635
|
const applyManualChunks = (output) => {
|
|
2636
|
+
ensureCodeSplitting(output);
|
|
2296
2637
|
const existingManualChunks = output.manualChunks;
|
|
2297
2638
|
output.manualChunks = function(id) {
|
|
2298
2639
|
if (id.includes(runtimeInitId)) return "runtimeInit";
|
|
@@ -2514,7 +2855,7 @@ function federation(mfUserOptions) {
|
|
|
2514
2855
|
enforce: "post",
|
|
2515
2856
|
_options: options,
|
|
2516
2857
|
config(config, { command: _command }) {
|
|
2517
|
-
const isRolldown =
|
|
2858
|
+
const isRolldown = getIsRolldown(this);
|
|
2518
2859
|
let implementation = options.implementation;
|
|
2519
2860
|
if (isRolldown) implementation = implementation.replace(/\.cjs(\.js)?$/, ".js");
|
|
2520
2861
|
config.resolve.alias.push({
|
|
@@ -2543,7 +2884,7 @@ function federation(mfUserOptions) {
|
|
|
2543
2884
|
const resolvedTarget = options.target ?? (config.build?.ssr ? "node" : "web");
|
|
2544
2885
|
if (!config.define) config.define = {};
|
|
2545
2886
|
if (!("ENV_TARGET" in config.define)) config.define["ENV_TARGET"] = JSON.stringify(resolvedTarget);
|
|
2546
|
-
if (options.target && "ENV_TARGET" in config.define && config.define["ENV_TARGET"] !== JSON.stringify(options.target))
|
|
2887
|
+
if (options.target && "ENV_TARGET" in config.define && config.define["ENV_TARGET"] !== JSON.stringify(options.target)) mfWarn(`ENV_TARGET define (${config.define["ENV_TARGET"]}) differs from target option ("${options.target}"). ENV_TARGET will not be overridden.`);
|
|
2547
2888
|
}
|
|
2548
2889
|
},
|
|
2549
2890
|
...Manifest(),
|
|
@@ -2556,13 +2897,18 @@ function federation(mfUserOptions) {
|
|
|
2556
2897
|
for (const chunk of Object.values(bundle)) {
|
|
2557
2898
|
if (chunk.type !== "chunk") continue;
|
|
2558
2899
|
if (!chunk.code.includes("modulepreload")) continue;
|
|
2559
|
-
const
|
|
2900
|
+
const chunkDir = path.dirname(chunk.fileName);
|
|
2901
|
+
const prefixToRoot = chunkDir === "." ? "" : `${path.relative(chunkDir, ".")}/`;
|
|
2902
|
+
const replacementExpr = prefixToRoot ? `${escapeUnsafeJsSourceChars(JSON.stringify(prefixToRoot))}+$1` : "$1";
|
|
2903
|
+
const replacement = `=function($1){return new URL(${replacementExpr},import.meta.url).href}`;
|
|
2560
2904
|
const replaced = chunk.code.replace(/=\(?(\w+)(?:,\w+)?\)?\s*=>\s*["'`][^"'`]*["'`]\s*\+\s*\1/, replacement);
|
|
2561
2905
|
if (replaced !== chunk.code) {
|
|
2562
2906
|
chunk.code = replaced;
|
|
2563
2907
|
continue;
|
|
2564
2908
|
}
|
|
2565
2909
|
chunk.code = chunk.code.replace(/=function\((\w+)(?:,\w+)?\)\{return\s*["'`][^"'`]*["'`]\s*\+\s*\1\s*\}/, replacement);
|
|
2910
|
+
chunk.code = chunk.code.replace(/=function\((\w+)(?:,\w+)?\)\{return new URL\("\.\.\/"\+\1,import\.meta\.url\)\.href\}/, replacement);
|
|
2911
|
+
chunk.code = chunk.code.replace(/new URL\("\.\.\/"\+(\w+),import\.meta\.url\)\.href/g, `new URL(${replacementExpr},import.meta.url).href`);
|
|
2566
2912
|
}
|
|
2567
2913
|
}
|
|
2568
2914
|
}] : []
|