@module-federation/vite 1.12.3 → 1.13.1
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 +405 -93
- package/lib/index.d.cts +1 -1
- package/lib/index.d.mts +1 -1
- package/lib/index.mjs +404 -93
- package/package.json +6 -6
package/lib/index.cjs
CHANGED
|
@@ -25,6 +25,7 @@ let defu = require("defu");
|
|
|
25
25
|
defu = __toESM(defu);
|
|
26
26
|
let fs = require("fs");
|
|
27
27
|
fs = __toESM(fs);
|
|
28
|
+
let module$1 = require("module");
|
|
28
29
|
let pathe = require("pathe");
|
|
29
30
|
pathe = __toESM(pathe);
|
|
30
31
|
let magic_string = require("magic-string");
|
|
@@ -33,7 +34,7 @@ let _rollup_pluginutils = require("@rollup/pluginutils");
|
|
|
33
34
|
let _module_federation_sdk = require("@module-federation/sdk");
|
|
34
35
|
let _module_federation_dts_plugin = require("@module-federation/dts-plugin");
|
|
35
36
|
let _module_federation_dts_plugin_core = require("@module-federation/dts-plugin/core");
|
|
36
|
-
let
|
|
37
|
+
let node_module = require("node:module");
|
|
37
38
|
let url = require("url");
|
|
38
39
|
//#region src/utils/mapCodeToCodeWithSourcemap.ts
|
|
39
40
|
async function mapCodeToCodeWithSourcemap(code) {
|
|
@@ -46,6 +47,104 @@ async function mapCodeToCodeWithSourcemap(code) {
|
|
|
46
47
|
};
|
|
47
48
|
}
|
|
48
49
|
//#endregion
|
|
50
|
+
//#region src/utils/htmlEntryUtils.ts
|
|
51
|
+
function sanitizeDevEntryPath(devEntryPath) {
|
|
52
|
+
return devEntryPath.replace(/^[^:]+:([/\\])[/\\]?/, "$1").replace(/\\\\?/g, "/");
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Inlines the federation init import into existing module script tags to fix
|
|
56
|
+
* the race condition (#396) where separate `<script type="module">` tags
|
|
57
|
+
* don't guarantee execution order with top-level await.
|
|
58
|
+
*
|
|
59
|
+
* If no entry scripts are found, falls back to injecting a separate script tag.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* // Before (two separate scripts, race condition):
|
|
63
|
+
* // <script type="module" src="/__mf__virtual/hostAutoInit.js"><\/script>
|
|
64
|
+
* // <script type="module" src="/src/main.js"><\/script>
|
|
65
|
+
* // After (single inline script, sequential execution):
|
|
66
|
+
* // <script type="module">await import("/__mf__virtual/hostAutoInit.js");await import("/src/main.js");<\/script>
|
|
67
|
+
*/
|
|
68
|
+
function inlineEntryScripts(html, initSrc) {
|
|
69
|
+
const src = sanitizeDevEntryPath(initSrc);
|
|
70
|
+
const scriptTagRegex = /<script\s+([^>]*\btype=["']module["'][^>]*\bsrc=["'][^"']+["'][^>]*)>/gi;
|
|
71
|
+
let hasEntry = false;
|
|
72
|
+
const result = html.replace(scriptTagRegex, (match, attrs) => {
|
|
73
|
+
const srcMatch = attrs.match(/\bsrc=["']([^"']+)["']/i);
|
|
74
|
+
if (!srcMatch) return match;
|
|
75
|
+
const originalSrc = srcMatch[1];
|
|
76
|
+
if (originalSrc.includes("@vite/client")) return match;
|
|
77
|
+
hasEntry = true;
|
|
78
|
+
return `<script ${attrs.replace(/\s*\bsrc=["'][^"']+["']/i, "")}>await import(${JSON.stringify(src)});await import(${JSON.stringify(originalSrc)});`;
|
|
79
|
+
});
|
|
80
|
+
if (hasEntry) return result;
|
|
81
|
+
return html.replace("<head>", `<head><script type="module" src=${JSON.stringify(src)}><\/script>`);
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/utils/packageUtils.ts
|
|
85
|
+
const dependencyPresenceCache = /* @__PURE__ */ new Map();
|
|
86
|
+
let packageDetectionCwd;
|
|
87
|
+
function getDependencyCacheKey(cwd, dependencyName) {
|
|
88
|
+
return `${cwd}:${dependencyName}`;
|
|
89
|
+
}
|
|
90
|
+
function setPackageDetectionCwd(cwd) {
|
|
91
|
+
packageDetectionCwd = cwd;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Escaping rules:
|
|
95
|
+
* Convert using the format __${mapping}__, where _ and $ are not allowed in npm package names but can be used in variable names.
|
|
96
|
+
* @ => 1
|
|
97
|
+
* / => 2
|
|
98
|
+
* - => 3
|
|
99
|
+
* . => 4
|
|
100
|
+
*/
|
|
101
|
+
/**
|
|
102
|
+
* Encodes a package name into a valid file name.
|
|
103
|
+
* @param {string} name - The package name, e.g., "@scope/xx-xx.xx".
|
|
104
|
+
* @returns {string} - The encoded file name.
|
|
105
|
+
*/
|
|
106
|
+
function packageNameEncode(name) {
|
|
107
|
+
if (typeof name !== "string") throw new Error("A string package name is required");
|
|
108
|
+
return name.replace(/@/g, "_mf_0_").replace(/\//g, "_mf_1_").replace(/-/g, "_mf_2_").replace(/\./g, "_mf_3_");
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Decodes an encoded file name back to the original package name.
|
|
112
|
+
* @param {string} encoded - The encoded file name, e.g., "_mf_0_scope_mf_1_xx_mf_2_xx_mf_3_xx".
|
|
113
|
+
* @returns {string} - The decoded package name.
|
|
114
|
+
*/
|
|
115
|
+
function packageNameDecode(encoded) {
|
|
116
|
+
if (typeof encoded !== "string") throw new Error("A string encoded file name is required");
|
|
117
|
+
return encoded.replace(/_mf_0_/g, "@").replace(/_mf_1_/g, "/").replace(/_mf_2_/g, "-").replace(/_mf_3_/g, ".");
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Removes any subpath from an npm package specifier and returns the package name only.
|
|
121
|
+
* @param {string} packageString - The package specifier, e.g., "@scope/pkg/runtime" or "react/jsx-runtime".
|
|
122
|
+
* @returns {string} - The base npm package name.
|
|
123
|
+
*/
|
|
124
|
+
function removePathFromNpmPackage(packageString) {
|
|
125
|
+
const match = packageString.match(/^(?:@[^/]+\/)?[^/]+/);
|
|
126
|
+
return match ? match[0] : packageString;
|
|
127
|
+
}
|
|
128
|
+
function hasPackageDependency(dependencyName, cwd = packageDetectionCwd || process.cwd()) {
|
|
129
|
+
const cacheKey = getDependencyCacheKey(cwd, dependencyName);
|
|
130
|
+
const cached = dependencyPresenceCache.get(cacheKey);
|
|
131
|
+
if (cached !== void 0) return cached;
|
|
132
|
+
try {
|
|
133
|
+
const packageJson = JSON.parse((0, fs.readFileSync)(pathe.default.join(cwd, "package.json"), "utf8"));
|
|
134
|
+
const hasDependency = [
|
|
135
|
+
packageJson.dependencies,
|
|
136
|
+
packageJson.devDependencies,
|
|
137
|
+
packageJson.peerDependencies,
|
|
138
|
+
packageJson.optionalDependencies
|
|
139
|
+
].some((deps) => !!deps?.[dependencyName]);
|
|
140
|
+
dependencyPresenceCache.set(cacheKey, hasDependency);
|
|
141
|
+
return hasDependency;
|
|
142
|
+
} catch {
|
|
143
|
+
dependencyPresenceCache.set(cacheKey, false);
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
49
148
|
//#region src/plugins/pluginAddEntry.ts
|
|
50
149
|
function getFirstHtmlEntryFile(entryFiles) {
|
|
51
150
|
return entryFiles.find((file) => file.endsWith(".html"));
|
|
@@ -75,7 +174,7 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
75
174
|
viteConfig = config;
|
|
76
175
|
const resolvedEntryPath = getEntryPath();
|
|
77
176
|
devEntryPath = resolvedEntryPath.startsWith("virtual:mf") ? "@id/" + resolvedEntryPath : resolvedEntryPath;
|
|
78
|
-
devEntryPath = config.base + devEntryPath.replace(/\\\\?/g, "/").replace(
|
|
177
|
+
devEntryPath = config.base + devEntryPath.replace(/\\\\?/g, "/").replace(/^[^:]+:([/\\])[/\\]?/, "$1").replace(/^\//, "");
|
|
79
178
|
},
|
|
80
179
|
configureServer(server) {
|
|
81
180
|
server.middlewares.use((req, res, next) => {
|
|
@@ -90,14 +189,11 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
90
189
|
transformIndexHtml(c) {
|
|
91
190
|
if (!injectHtml()) return;
|
|
92
191
|
clientInjected = true;
|
|
93
|
-
return c
|
|
192
|
+
return inlineEntryScripts(c, devEntryPath);
|
|
94
193
|
},
|
|
95
194
|
transform(code, id) {
|
|
96
195
|
if (id.includes("node_modules") || inject !== "html" || htmlFilePath) return;
|
|
97
|
-
if (id.includes(".svelte-kit") && id.includes("internal.js"))
|
|
98
|
-
const src = devEntryPath.replace(/.+?\:([/\\])[/\\]?/, "$1").replace(/\\\\?/g, "/");
|
|
99
|
-
return code.replace(/<head>/g, "<head><script type=\\\"module\\\" src=\\\"" + src + "\\\"><\/script>");
|
|
100
|
-
}
|
|
196
|
+
if (id.includes(".svelte-kit") && id.includes("internal.js")) return code.replace(/<head>/g, "<head><script type=\\\"module\\\" src=\\\"" + sanitizeDevEntryPath(devEntryPath) + "\\\"><\/script>");
|
|
101
197
|
}
|
|
102
198
|
}, {
|
|
103
199
|
name: "add-entry",
|
|
@@ -110,6 +206,12 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
110
206
|
else if (Array.isArray(inputOptions)) entryFiles = inputOptions;
|
|
111
207
|
else if (typeof inputOptions === "object") entryFiles = Object.values(inputOptions);
|
|
112
208
|
if (entryFiles && entryFiles.length > 0) htmlFilePath = getFirstHtmlEntryFile(entryFiles);
|
|
209
|
+
if (_command === "serve" && htmlFilePath && fs.existsSync(htmlFilePath)) {
|
|
210
|
+
const htmlContent = fs.readFileSync(htmlFilePath, "utf-8");
|
|
211
|
+
const scriptRegex = /<script\s+[^>]*src=["']([^"']+)["'][^>]*>/gi;
|
|
212
|
+
let match;
|
|
213
|
+
while ((match = scriptRegex.exec(htmlContent)) !== null) entryFiles.push(match[1]);
|
|
214
|
+
}
|
|
113
215
|
},
|
|
114
216
|
buildStart() {
|
|
115
217
|
if (_command === "serve") return;
|
|
@@ -162,6 +264,15 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
162
264
|
}
|
|
163
265
|
},
|
|
164
266
|
transform(code, id) {
|
|
267
|
+
if (hasPackageDependency("vinext") && inject === "html" && (id.includes("virtual:vite-rsc/entry-browser") || id.includes("virtual:vinext-app-browser-entry"))) {
|
|
268
|
+
const injection = `import ${JSON.stringify(getEntryPath())};\n`;
|
|
269
|
+
if (code.includes(injection.trim())) {
|
|
270
|
+
clientInjected = true;
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
clientInjected = true;
|
|
274
|
+
return mapCodeToCodeWithSourcemap(injection + code);
|
|
275
|
+
}
|
|
165
276
|
if (injectEntry() && entryFiles.some((file) => id.endsWith(file)) || _command === "serve" && inject === "html" && !clientInjected && !id.includes("node_modules") && /\.(js|ts|mjs|vue|jsx|tsx)(\?|$)/.test(id)) {
|
|
166
277
|
clientInjected = true;
|
|
167
278
|
return mapCodeToCodeWithSourcemap(`import ${JSON.stringify(getEntryPath())};\n` + code);
|
|
@@ -235,7 +346,9 @@ function PluginDevProxyModuleTopLevelAwait() {
|
|
|
235
346
|
throw new Error(`${id}: ${e}`);
|
|
236
347
|
}
|
|
237
348
|
const magicString = new magic_string.default(code);
|
|
238
|
-
|
|
349
|
+
const walk = await loadWalk();
|
|
350
|
+
const defaultExportExpression = hasPackageDependency("vinext") ? "(__mfproxy__awaitdefault?.default ?? __mfproxy__awaitdefault)" : "__mfproxy__awaitdefault";
|
|
351
|
+
walk(ast, { enter(node) {
|
|
239
352
|
if (node.type === "ExportNamedDeclaration" && node.specifiers) {
|
|
240
353
|
const exportSpecifiers = node.specifiers.map((specifier) => specifier.exported.name);
|
|
241
354
|
const proxyStatements = exportSpecifiers.map((name) => `
|
|
@@ -256,15 +369,15 @@ function PluginDevProxyModuleTopLevelAwait() {
|
|
|
256
369
|
let exportStatement = "default";
|
|
257
370
|
if (declaration.type === "Identifier") proxyStatement = `
|
|
258
371
|
const __mfproxy__awaitdefault = await ${declaration.name}();
|
|
259
|
-
const __mfproxy__default =
|
|
372
|
+
const __mfproxy__default = ${defaultExportExpression};
|
|
260
373
|
`;
|
|
261
374
|
else if (declaration.type === "CallExpression" || declaration.type === "FunctionDeclaration") proxyStatement = `
|
|
262
375
|
const __mfproxy__awaitdefault = await (${code.slice(declaration.start, declaration.end)});
|
|
263
|
-
const __mfproxy__default =
|
|
376
|
+
const __mfproxy__default = ${defaultExportExpression};
|
|
264
377
|
`;
|
|
265
378
|
else proxyStatement = `
|
|
266
379
|
const __mfproxy__awaitdefault = await (${code.slice(declaration.start, declaration.end)});
|
|
267
|
-
const __mfproxy__default =
|
|
380
|
+
const __mfproxy__default = ${defaultExportExpression};
|
|
268
381
|
`;
|
|
269
382
|
const replacement = `${proxyStatement}\nexport { __mfproxy__default as ${exportStatement} };`;
|
|
270
383
|
magicString.overwrite(start, end, replacement);
|
|
@@ -546,10 +659,6 @@ function normalizeRemoteItem(key, remote) {
|
|
|
546
659
|
entryGlobalName: key
|
|
547
660
|
}, remote);
|
|
548
661
|
}
|
|
549
|
-
function removePathFromNpmPackage(packageString) {
|
|
550
|
-
const match = packageString.match(/^(?:@[^/]+\/)?[^/]+/);
|
|
551
|
-
return match ? match[0] : packageString;
|
|
552
|
-
}
|
|
553
662
|
/**
|
|
554
663
|
* Tries to find the package.json's version of a shared package
|
|
555
664
|
* if `package.json` is not declared in `exports`
|
|
@@ -558,19 +667,23 @@ function removePathFromNpmPackage(packageString) {
|
|
|
558
667
|
*/
|
|
559
668
|
function searchPackageVersion(sharedName) {
|
|
560
669
|
try {
|
|
561
|
-
const sharedPath =
|
|
670
|
+
const sharedPath = (0, node_module.createRequire)(process.cwd()).resolve(sharedName);
|
|
562
671
|
let potentialPackageJsonDir = pathe.dirname(sharedPath);
|
|
563
672
|
const rootDir = pathe.parse(potentialPackageJsonDir).root;
|
|
564
673
|
while (pathe.parse(potentialPackageJsonDir).base !== "node_modules" && potentialPackageJsonDir !== rootDir) {
|
|
565
674
|
const potentialPackageJsonPath = pathe.join(potentialPackageJsonDir, "package.json");
|
|
566
675
|
if (fs.existsSync(potentialPackageJsonPath)) {
|
|
567
|
-
const potentialPackageJson =
|
|
676
|
+
const potentialPackageJson = JSON.parse(fs.readFileSync(potentialPackageJsonPath, "utf-8"));
|
|
568
677
|
if (typeof potentialPackageJson == "object" && potentialPackageJson !== null && typeof potentialPackageJson.version === "string" && potentialPackageJson.name === sharedName) return potentialPackageJson.version;
|
|
569
678
|
}
|
|
570
679
|
potentialPackageJsonDir = pathe.dirname(potentialPackageJsonDir);
|
|
571
680
|
}
|
|
572
681
|
} catch (_) {}
|
|
573
682
|
}
|
|
683
|
+
function inferVersionFromRequiredVersion(requiredVersion) {
|
|
684
|
+
if (!requiredVersion) return void 0;
|
|
685
|
+
return requiredVersion.match(/\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?/)?.[0];
|
|
686
|
+
}
|
|
574
687
|
function normalizeShareItem(key, shareItem) {
|
|
575
688
|
let version;
|
|
576
689
|
try {
|
|
@@ -602,7 +715,7 @@ function normalizeShareItem(key, shareItem) {
|
|
|
602
715
|
return {
|
|
603
716
|
name: key,
|
|
604
717
|
from: "",
|
|
605
|
-
version: shareItem.version || version,
|
|
718
|
+
version: shareItem.version || inferVersionFromRequiredVersion(shareItem.requiredVersion) || version,
|
|
606
719
|
scope: shareItem.shareScope || "default",
|
|
607
720
|
shareConfig: {
|
|
608
721
|
import: typeof shareItem === "object" ? shareItem.import : void 0,
|
|
@@ -676,34 +789,6 @@ function normalizeModuleFederationOptions(options) {
|
|
|
676
789
|
};
|
|
677
790
|
}
|
|
678
791
|
//#endregion
|
|
679
|
-
//#region src/utils/packageNameUtils.ts
|
|
680
|
-
/**
|
|
681
|
-
* Escaping rules:
|
|
682
|
-
* Convert using the format __${mapping}__, where _ and $ are not allowed in npm package names but can be used in variable names.
|
|
683
|
-
* @ => 1
|
|
684
|
-
* / => 2
|
|
685
|
-
* - => 3
|
|
686
|
-
* . => 4
|
|
687
|
-
*/
|
|
688
|
-
/**
|
|
689
|
-
* Encodes a package name into a valid file name.
|
|
690
|
-
* @param {string} name - The package name, e.g., "@scope/xx-xx.xx".
|
|
691
|
-
* @returns {string} - The encoded file name.
|
|
692
|
-
*/
|
|
693
|
-
function packageNameEncode(name) {
|
|
694
|
-
if (typeof name !== "string") throw new Error("A string package name is required");
|
|
695
|
-
return name.replace(/@/g, "_mf_0_").replace(/\//g, "_mf_1_").replace(/-/g, "_mf_2_").replace(/\./g, "_mf_3_");
|
|
696
|
-
}
|
|
697
|
-
/**
|
|
698
|
-
* Decodes an encoded file name back to the original package name.
|
|
699
|
-
* @param {string} encoded - The encoded file name, e.g., "_mf_0_scope_mf_1_xx_mf_2_xx_mf_3_xx".
|
|
700
|
-
* @returns {string} - The decoded package name.
|
|
701
|
-
*/
|
|
702
|
-
function packageNameDecode(encoded) {
|
|
703
|
-
if (typeof encoded !== "string") throw new Error("A string encoded file name is required");
|
|
704
|
-
return encoded.replace(/_mf_0_/g, "@").replace(/_mf_1_/g, "/").replace(/_mf_2_/g, "-").replace(/_mf_3_/g, ".");
|
|
705
|
-
}
|
|
706
|
-
//#endregion
|
|
707
792
|
//#region src/utils/localSharedImportMap_temp.ts
|
|
708
793
|
/**
|
|
709
794
|
* https://github.com/module-federation/vite/issues/68
|
|
@@ -897,12 +982,12 @@ function generateExposes(options) {
|
|
|
897
982
|
//#endregion
|
|
898
983
|
//#region src/virtualModules/virtualRuntimeInitStatus.ts
|
|
899
984
|
const virtualRuntimeInitStatus = new VirtualModule("runtimeInit");
|
|
900
|
-
function
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
const globalKey = ${JSON.stringify(
|
|
985
|
+
function getRuntimeInitGlobalKey() {
|
|
986
|
+
return `__mf_init__${virtualRuntimeInitStatus.getImportId()}__`;
|
|
987
|
+
}
|
|
988
|
+
function getRuntimeInitBootstrapCode() {
|
|
989
|
+
return `
|
|
990
|
+
const globalKey = ${JSON.stringify(getRuntimeInitGlobalKey())};
|
|
906
991
|
if (!globalThis[globalKey]) {
|
|
907
992
|
let initResolve, initReject;
|
|
908
993
|
const initPromise = new Promise((re, rj) => {
|
|
@@ -914,8 +999,6 @@ if (!globalThis[globalKey]) {
|
|
|
914
999
|
initResolve,
|
|
915
1000
|
initReject,
|
|
916
1001
|
};
|
|
917
|
-
// In SSR (no window), resolve immediately with a stub runtime
|
|
918
|
-
// so modules don't hang waiting for browser-only init
|
|
919
1002
|
if (typeof window === 'undefined') {
|
|
920
1003
|
initResolve({
|
|
921
1004
|
loadRemote: function() { return Promise.resolve(undefined); },
|
|
@@ -923,6 +1006,64 @@ if (!globalThis[globalKey]) {
|
|
|
923
1006
|
});
|
|
924
1007
|
}
|
|
925
1008
|
}
|
|
1009
|
+
`;
|
|
1010
|
+
}
|
|
1011
|
+
function getRuntimeInitPromiseBootstrapCode() {
|
|
1012
|
+
return `
|
|
1013
|
+
const __mfPromiseGlobalKey = ${JSON.stringify(getRuntimeInitGlobalKey())};
|
|
1014
|
+
let __mfPromiseState = globalThis[__mfPromiseGlobalKey];
|
|
1015
|
+
if (!__mfPromiseState) {
|
|
1016
|
+
let initResolve, initReject;
|
|
1017
|
+
const initPromise = new Promise((re, rj) => {
|
|
1018
|
+
initResolve = re;
|
|
1019
|
+
initReject = rj;
|
|
1020
|
+
});
|
|
1021
|
+
__mfPromiseState = globalThis[__mfPromiseGlobalKey] = {
|
|
1022
|
+
initPromise,
|
|
1023
|
+
initResolve,
|
|
1024
|
+
initReject,
|
|
1025
|
+
};
|
|
1026
|
+
if (typeof window === 'undefined') {
|
|
1027
|
+
initResolve({
|
|
1028
|
+
loadRemote: function() { return Promise.resolve(undefined); },
|
|
1029
|
+
loadShare: function() { return Promise.resolve(undefined); },
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
const initPromise = __mfPromiseState.initPromise;
|
|
1034
|
+
`;
|
|
1035
|
+
}
|
|
1036
|
+
function getRuntimeInitResolveBootstrapCode() {
|
|
1037
|
+
return `
|
|
1038
|
+
const __mfResolveGlobalKey = ${JSON.stringify(getRuntimeInitGlobalKey())};
|
|
1039
|
+
let __mfResolveState = globalThis[__mfResolveGlobalKey];
|
|
1040
|
+
if (!__mfResolveState) {
|
|
1041
|
+
let initResolve, initReject;
|
|
1042
|
+
const initPromise = new Promise((re, rj) => {
|
|
1043
|
+
initResolve = re;
|
|
1044
|
+
initReject = rj;
|
|
1045
|
+
});
|
|
1046
|
+
__mfResolveState = globalThis[__mfResolveGlobalKey] = {
|
|
1047
|
+
initPromise,
|
|
1048
|
+
initResolve,
|
|
1049
|
+
initReject,
|
|
1050
|
+
};
|
|
1051
|
+
if (typeof window === 'undefined') {
|
|
1052
|
+
initResolve({
|
|
1053
|
+
loadRemote: function() { return Promise.resolve(undefined); },
|
|
1054
|
+
loadShare: function() { return Promise.resolve(undefined); },
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
const initResolve = __mfResolveState.initResolve;
|
|
1059
|
+
`;
|
|
1060
|
+
}
|
|
1061
|
+
function writeRuntimeInitStatus(command) {
|
|
1062
|
+
getRuntimeInitGlobalKey();
|
|
1063
|
+
const exportStatement = command === "build" ? `const { initPromise, initResolve, initReject } = globalThis[globalKey];
|
|
1064
|
+
export { initPromise, initResolve, initReject };` : `module.exports = globalThis[globalKey];`;
|
|
1065
|
+
virtualRuntimeInitStatus.writeSync(`
|
|
1066
|
+
${getRuntimeInitBootstrapCode()}
|
|
926
1067
|
${exportStatement}
|
|
927
1068
|
`);
|
|
928
1069
|
}
|
|
@@ -947,7 +1088,8 @@ function getUsedRemotesMap() {
|
|
|
947
1088
|
}
|
|
948
1089
|
function generateRemotes(id, command, isRolldown) {
|
|
949
1090
|
const useESM = command === "build" || isRolldown;
|
|
950
|
-
const importLine =
|
|
1091
|
+
const importLine = command === "build" ? getRuntimeInitPromiseBootstrapCode() : useESM ? `${getRuntimeInitBootstrapCode()}
|
|
1092
|
+
const { initPromise } = globalThis[globalKey];` : `const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")`;
|
|
951
1093
|
const awaitOrPlaceholder = useESM ? "await " : "/*mf top-level-await placeholder replacement mf*/";
|
|
952
1094
|
const exportLine = command === "serve" && useESM ? "export default exportModule.default ?? exportModule" : useESM ? "export default exportModule" : "module.exports = exportModule";
|
|
953
1095
|
return `
|
|
@@ -977,6 +1119,14 @@ function getPackageNamedExports(pkg) {
|
|
|
977
1119
|
return [];
|
|
978
1120
|
}
|
|
979
1121
|
}
|
|
1122
|
+
function getLocalProviderImportPath(pkg) {
|
|
1123
|
+
try {
|
|
1124
|
+
const resolved = (0, module$1.createRequire)(new URL("file://" + process.cwd() + "/package.json")).resolve(pkg);
|
|
1125
|
+
return resolved.includes("/node_modules/") || resolved.includes("\\node_modules\\") ? void 0 : resolved;
|
|
1126
|
+
} catch {
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
980
1130
|
const preBuildCacheMap = {};
|
|
981
1131
|
const PREBUILD_TAG = "__prebuild__";
|
|
982
1132
|
function writePreBuildLibPath(pkg) {
|
|
@@ -996,8 +1146,11 @@ function getLoadShareModulePath(pkg, isRolldown, command) {
|
|
|
996
1146
|
function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
997
1147
|
if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, isRolldown || command === "build" ? ".mjs" : ".js");
|
|
998
1148
|
const useESM = command === "build" || isRolldown;
|
|
999
|
-
const importLine =
|
|
1149
|
+
const importLine = command === "build" ? getRuntimeInitPromiseBootstrapCode() : useESM ? `${getRuntimeInitBootstrapCode()}
|
|
1150
|
+
const { initPromise } = globalThis[globalKey];` : `const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")`;
|
|
1000
1151
|
const awaitOrPlaceholder = useESM ? "await " : "/*mf top-level-await placeholder replacement mf*/";
|
|
1152
|
+
const useSsrProviderFallback = hasPackageDependency("vinext") && command === "build" && pkg === "react";
|
|
1153
|
+
const providerImportId = getLocalProviderImportPath(pkg) || getPreBuildLibImportId(pkg);
|
|
1001
1154
|
const namedExports = getPackageNamedExports(pkg);
|
|
1002
1155
|
let exportLine;
|
|
1003
1156
|
if (namedExports.length > 0) {
|
|
@@ -1009,6 +1162,9 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
|
1009
1162
|
import ${JSON.stringify(getPreBuildLibImportId(pkg))};
|
|
1010
1163
|
${command !== "build" ? `;() => import(${JSON.stringify(pkg)}).catch(() => {});` : ""}
|
|
1011
1164
|
${importLine}
|
|
1165
|
+
${useSsrProviderFallback ? `const providerModulePromise = typeof window === "undefined"
|
|
1166
|
+
? import(${JSON.stringify(providerImportId)})
|
|
1167
|
+
: undefined` : ""}
|
|
1012
1168
|
const res = initPromise.then(runtime => runtime.loadShare(${JSON.stringify(pkg)}, {
|
|
1013
1169
|
customShareInfo: {shareConfig:{
|
|
1014
1170
|
singleton: ${shareItem.shareConfig.singleton},
|
|
@@ -1016,7 +1172,9 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
|
1016
1172
|
requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)}
|
|
1017
1173
|
}}
|
|
1018
1174
|
}))
|
|
1019
|
-
const exportModule = ${
|
|
1175
|
+
const exportModule = ${useSsrProviderFallback ? `(typeof window === "undefined"
|
|
1176
|
+
? ((await providerModulePromise)?.default ?? await providerModulePromise)
|
|
1177
|
+
: ${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory)))` : `${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory))`}
|
|
1020
1178
|
${exportLine}
|
|
1021
1179
|
`);
|
|
1022
1180
|
}
|
|
@@ -1033,15 +1191,16 @@ new VirtualModule("localSharedImportMap");
|
|
|
1033
1191
|
function getLocalSharedImportMapPath() {
|
|
1034
1192
|
return getLocalSharedImportMapPath_temp();
|
|
1035
1193
|
}
|
|
1036
|
-
let
|
|
1194
|
+
let prevLocalSharedImportMapContent;
|
|
1037
1195
|
function writeLocalSharedImportMap() {
|
|
1038
|
-
const
|
|
1039
|
-
if (
|
|
1040
|
-
|
|
1041
|
-
writeLocalSharedImportMap_temp(
|
|
1196
|
+
const nextContent = generateLocalSharedImportMap();
|
|
1197
|
+
if (prevLocalSharedImportMapContent !== nextContent) {
|
|
1198
|
+
prevLocalSharedImportMapContent = nextContent;
|
|
1199
|
+
writeLocalSharedImportMap_temp(nextContent);
|
|
1042
1200
|
}
|
|
1043
1201
|
}
|
|
1044
1202
|
function generateLocalSharedImportMap() {
|
|
1203
|
+
const isVinext = hasPackageDependency("vinext");
|
|
1045
1204
|
const options = getNormalizeModuleFederationOptions();
|
|
1046
1205
|
return `
|
|
1047
1206
|
import {loadShare} from "@module-federation/runtime";
|
|
@@ -1050,7 +1209,8 @@ function generateLocalSharedImportMap() {
|
|
|
1050
1209
|
const shareItem = getNormalizeShareItem(pkg);
|
|
1051
1210
|
return `
|
|
1052
1211
|
${JSON.stringify(pkg)}: async () => {
|
|
1053
|
-
${shareItem?.shareConfig.import === false ? `throw new Error(\`Shared module '\${${JSON.stringify(pkg)}}' must be provided by host\`);` : `let pkg = await import("
|
|
1212
|
+
${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");
|
|
1213
|
+
return pkg;` : `let pkg = await import("${getPreBuildLibImportId(pkg)}");
|
|
1054
1214
|
return pkg;`}
|
|
1055
1215
|
}
|
|
1056
1216
|
`;
|
|
@@ -1074,7 +1234,9 @@ function generateLocalSharedImportMap() {
|
|
|
1074
1234
|
usedShared[${JSON.stringify(key)}].loaded = true
|
|
1075
1235
|
const {${JSON.stringify(key)}: pkgDynamicImport} = importMap
|
|
1076
1236
|
const res = await pkgDynamicImport()
|
|
1077
|
-
const exportModule = {
|
|
1237
|
+
const exportModule = ${JSON.stringify(isVinext)} && ${JSON.stringify(key)} === "react"
|
|
1238
|
+
? (res?.default ?? res)
|
|
1239
|
+
: {...res}
|
|
1078
1240
|
// All npm packages pre-built by vite will be converted to esm
|
|
1079
1241
|
Object.defineProperty(exportModule, "__esModule", {
|
|
1080
1242
|
value: true,
|
|
@@ -1117,7 +1279,7 @@ const REMOTE_ENTRY_ID = "virtual:mf-REMOTE_ENTRY_ID";
|
|
|
1117
1279
|
function getRemoteEntryId(options) {
|
|
1118
1280
|
return `${REMOTE_ENTRY_ID}:${`${options.name}__${options.filename}`.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
|
|
1119
1281
|
}
|
|
1120
|
-
function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(options)) {
|
|
1282
|
+
function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(options), command = "build") {
|
|
1121
1283
|
const pluginImportNames = options.runtimePlugins.map((p, i) => {
|
|
1122
1284
|
if (typeof p === "string") return [
|
|
1123
1285
|
`$runtimePlugin_${i}`,
|
|
@@ -1133,15 +1295,25 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1133
1295
|
return `
|
|
1134
1296
|
import {init as runtimeInit, loadRemote} from "@module-federation/runtime";
|
|
1135
1297
|
${pluginImportNames.map((item) => item[1]).join("\n")}
|
|
1136
|
-
|
|
1137
|
-
import {usedShared, usedRemotes} from "${getLocalSharedImportMapPath()}"
|
|
1138
|
-
import {
|
|
1139
|
-
initResolve
|
|
1140
|
-
} from "${virtualRuntimeInitStatus.getImportId()}"
|
|
1298
|
+
${command === "build" ? getRuntimeInitResolveBootstrapCode() : getRuntimeInitBootstrapCode() + "\n const { initResolve } = globalThis[globalKey];"}
|
|
1141
1299
|
const initTokens = {}
|
|
1142
1300
|
const shareScopeName = ${JSON.stringify(options.shareScope)}
|
|
1143
1301
|
const mfName = ${JSON.stringify(options.name)}
|
|
1302
|
+
let localSharedImportMapPromise
|
|
1303
|
+
let exposesMapPromise
|
|
1304
|
+
|
|
1305
|
+
async function getLocalSharedImportMap() {
|
|
1306
|
+
localSharedImportMapPromise ??= import("${getLocalSharedImportMapPath()}")
|
|
1307
|
+
return localSharedImportMapPromise
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
async function getExposesMap() {
|
|
1311
|
+
exposesMapPromise ??= import("${virtualExposesId}").then((mod) => mod.default ?? mod)
|
|
1312
|
+
return exposesMapPromise
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1144
1315
|
async function init(shared = {}, initScope = []) {
|
|
1316
|
+
const {usedShared, usedRemotes} = await getLocalSharedImportMap()
|
|
1145
1317
|
const initRes = runtimeInit({
|
|
1146
1318
|
name: mfName,
|
|
1147
1319
|
remotes: usedRemotes,
|
|
@@ -1156,6 +1328,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1156
1328
|
if (initScope.indexOf(initToken) >= 0) return;
|
|
1157
1329
|
initScope.push(initToken);
|
|
1158
1330
|
initRes.initShareScopeMap('${options.shareScope}', shared);
|
|
1331
|
+
initResolve(initRes)
|
|
1159
1332
|
try {
|
|
1160
1333
|
await Promise.all(await initRes.initializeSharing('${options.shareScope}', {
|
|
1161
1334
|
strategy: '${options.shareStrategy}',
|
|
@@ -1165,11 +1338,11 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1165
1338
|
} catch (e) {
|
|
1166
1339
|
console.error(e)
|
|
1167
1340
|
}
|
|
1168
|
-
initResolve(initRes)
|
|
1169
1341
|
return initRes
|
|
1170
1342
|
}
|
|
1171
1343
|
|
|
1172
|
-
function getExposes(moduleName) {
|
|
1344
|
+
async function getExposes(moduleName) {
|
|
1345
|
+
const exposesMap = await getExposesMap()
|
|
1173
1346
|
if (!(moduleName in exposesMap)) throw new Error(\`Module \${moduleName} does not exist in container.\`)
|
|
1174
1347
|
return (exposesMap[moduleName])().then(res => () => res)
|
|
1175
1348
|
}
|
|
@@ -1182,13 +1355,8 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1182
1355
|
const hostAutoInitModule = new VirtualModule("hostAutoInit", "__H_A_I__");
|
|
1183
1356
|
function writeHostAutoInit(remoteEntryId = REMOTE_ENTRY_ID) {
|
|
1184
1357
|
hostAutoInitModule.writeSync(`
|
|
1185
|
-
const
|
|
1186
|
-
|
|
1187
|
-
Promise.resolve(remoteEntryPromise)
|
|
1188
|
-
.then(remoteEntry => {
|
|
1189
|
-
return Promise.resolve(remoteEntry.__tla)
|
|
1190
|
-
.then(remoteEntry.init).catch(remoteEntry.init)
|
|
1191
|
-
})
|
|
1358
|
+
const remoteEntry = await import("${remoteEntryId}");
|
|
1359
|
+
await remoteEntry.init();
|
|
1192
1360
|
`);
|
|
1193
1361
|
}
|
|
1194
1362
|
function getHostAutoInitImportId() {
|
|
@@ -1211,13 +1379,21 @@ function initVirtualModules(command, remoteEntryId) {
|
|
|
1211
1379
|
* If Rollup's deconflict renamed the alias but didn't update references
|
|
1212
1380
|
* in the code body, fall back to proxyLocal so they stay in sync.
|
|
1213
1381
|
*/
|
|
1214
|
-
function resolveProxyAlias(binding, proxyLocal, code, fullImport) {
|
|
1382
|
+
function resolveProxyAlias(binding, proxyLocal, code, fullImport, claimedLocals = /* @__PURE__ */ new Set()) {
|
|
1215
1383
|
const codeWithoutImport = code.replace(fullImport, "");
|
|
1216
1384
|
const escapedLocal = binding.local.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1217
1385
|
const localUsedInCode = new RegExp(`\\b${escapedLocal}\\b`).test(codeWithoutImport);
|
|
1386
|
+
const claimedImportLocals = /* @__PURE__ */ new Set();
|
|
1387
|
+
const importRe = /import\s*\{([^}]+)\}\s*from\s*["'][^"']+["']\s*;?/g;
|
|
1388
|
+
let match;
|
|
1389
|
+
while ((match = importRe.exec(codeWithoutImport)) !== null) for (const spec of match[1].split(",")) {
|
|
1390
|
+
const parts = spec.trim().split(/\s+as\s+/);
|
|
1391
|
+
claimedImportLocals.add((parts[1] || parts[0]).trim());
|
|
1392
|
+
}
|
|
1393
|
+
const local = !localUsedInCode && !claimedLocals.has(proxyLocal) && !claimedImportLocals.has(proxyLocal) ? proxyLocal : binding.local;
|
|
1218
1394
|
return {
|
|
1219
1395
|
imported: binding.imported,
|
|
1220
|
-
local
|
|
1396
|
+
local
|
|
1221
1397
|
};
|
|
1222
1398
|
}
|
|
1223
1399
|
function findRemoteEntryFile(filename, bundle) {
|
|
@@ -1672,14 +1848,14 @@ function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposes
|
|
|
1672
1848
|
}
|
|
1673
1849
|
},
|
|
1674
1850
|
load(id) {
|
|
1675
|
-
if (id === remoteEntryId) return parsePromise.then((_) => generateRemoteEntry(options, virtualExposesId));
|
|
1851
|
+
if (id === remoteEntryId) return parsePromise.then((_) => generateRemoteEntry(options, virtualExposesId, _command));
|
|
1676
1852
|
if (id === virtualExposesId) return generateExposes(options);
|
|
1677
1853
|
if (_command === "serve" && id.includes(getHostAutoInitPath())) return id;
|
|
1678
1854
|
},
|
|
1679
1855
|
transform(code, id) {
|
|
1680
1856
|
return mapCodeToCodeWithSourcemap((() => {
|
|
1681
1857
|
if (!filter(id)) return;
|
|
1682
|
-
if (id.includes(remoteEntryId)) return parsePromise.then((_) => generateRemoteEntry(options, virtualExposesId));
|
|
1858
|
+
if (id.includes(remoteEntryId)) return parsePromise.then((_) => generateRemoteEntry(options, virtualExposesId, _command));
|
|
1683
1859
|
if (id === virtualExposesId) return generateExposes(options);
|
|
1684
1860
|
if (id.includes(getHostAutoInitPath())) {
|
|
1685
1861
|
if (_command === "serve") {
|
|
@@ -1767,6 +1943,7 @@ function proxySharedModule(options) {
|
|
|
1767
1943
|
const { shared = {} } = options;
|
|
1768
1944
|
let _config;
|
|
1769
1945
|
let _command = "serve";
|
|
1946
|
+
let isVinext = false;
|
|
1770
1947
|
const savePrebuild = new PromiseStore();
|
|
1771
1948
|
return [{
|
|
1772
1949
|
name: "generateLocalSharedImportMap",
|
|
@@ -1781,9 +1958,11 @@ function proxySharedModule(options) {
|
|
|
1781
1958
|
name: "proxyPreBuildShared",
|
|
1782
1959
|
enforce: "post",
|
|
1783
1960
|
config(config, { command }) {
|
|
1961
|
+
setPackageDetectionCwd(config.root || process.cwd());
|
|
1962
|
+
isVinext = hasPackageDependency("vinext");
|
|
1784
1963
|
const isRolldown = !!this?.meta?.rolldownVersion;
|
|
1785
1964
|
_command = command;
|
|
1786
|
-
config.resolve.alias.push(...Object.keys(shared).map((key) => {
|
|
1965
|
+
config.resolve.alias.push(...Object.keys(shared).filter((key) => !(isVinext && key === "react")).map((key) => {
|
|
1787
1966
|
const keyBase = key.endsWith("/") ? key.slice(0, -1) : key;
|
|
1788
1967
|
const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1789
1968
|
const escapedKeyBase = escapeRegex(keyBase);
|
|
@@ -1793,6 +1972,7 @@ function proxySharedModule(options) {
|
|
|
1793
1972
|
replacement: "$1",
|
|
1794
1973
|
customResolver(source, importer) {
|
|
1795
1974
|
if (/\.css$/.test(source)) return;
|
|
1975
|
+
if (isVinext && source === "react") return;
|
|
1796
1976
|
if (importer && importer.includes("localSharedImportMap")) return;
|
|
1797
1977
|
if (key.endsWith("/") && source !== key.slice(0, -1)) return;
|
|
1798
1978
|
const loadSharePath = getLoadShareModulePath(source, isRolldown, command);
|
|
@@ -1804,7 +1984,7 @@ function proxySharedModule(options) {
|
|
|
1804
1984
|
}
|
|
1805
1985
|
};
|
|
1806
1986
|
}));
|
|
1807
|
-
config.resolve.alias.push(...Object.keys(shared).map((key) => {
|
|
1987
|
+
config.resolve.alias.push(...Object.keys(shared).filter((key) => !(isVinext && key === "react")).map((key) => {
|
|
1808
1988
|
return command === "build" ? {
|
|
1809
1989
|
find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
|
|
1810
1990
|
replacement: function($1) {
|
|
@@ -1827,6 +2007,10 @@ function proxySharedModule(options) {
|
|
|
1827
2007
|
const isRolldown = !!config.experimental?.rolldownDev;
|
|
1828
2008
|
Object.keys(shared).forEach((key) => {
|
|
1829
2009
|
if (key.endsWith("/")) return;
|
|
2010
|
+
if (isVinext && key === "react") {
|
|
2011
|
+
addUsedShares(key);
|
|
2012
|
+
return;
|
|
2013
|
+
}
|
|
1830
2014
|
writeLoadShareModule(key, shared[key], _command, isRolldown);
|
|
1831
2015
|
writePreBuildLibPath(key);
|
|
1832
2016
|
addUsedShares(key);
|
|
@@ -1930,6 +2114,58 @@ var aliasToArrayPlugin_default = {
|
|
|
1930
2114
|
}
|
|
1931
2115
|
};
|
|
1932
2116
|
//#endregion
|
|
2117
|
+
//#region src/utils/controlChunkSanitizer.ts
|
|
2118
|
+
const FEDERATION_CONTROL_CHUNK_HINTS = [
|
|
2119
|
+
"hostInit",
|
|
2120
|
+
"virtualExposes",
|
|
2121
|
+
"localSharedImportMap"
|
|
2122
|
+
];
|
|
2123
|
+
function stripEmptyPreloadCalls(code) {
|
|
2124
|
+
const helperImportRegex = /import\s*\{\s*_\s*as\s*(\w+)\s*\}\s*from\s*["'][^"']+["']\s*;?/g;
|
|
2125
|
+
const helperAliases = [...code.matchAll(helperImportRegex)].map((match) => match[1]);
|
|
2126
|
+
let nextCode = code;
|
|
2127
|
+
for (const alias of helperAliases) {
|
|
2128
|
+
const marker = `${alias}(()=>`;
|
|
2129
|
+
let start = nextCode.indexOf(marker);
|
|
2130
|
+
while (start !== -1) {
|
|
2131
|
+
const exprStart = start + marker.length;
|
|
2132
|
+
let depth = 0;
|
|
2133
|
+
let cursor = exprStart;
|
|
2134
|
+
let replacementEnd = -1;
|
|
2135
|
+
while (cursor < nextCode.length) {
|
|
2136
|
+
const char = nextCode[cursor];
|
|
2137
|
+
if (char === "(") depth++;
|
|
2138
|
+
else if (char === ")") depth--;
|
|
2139
|
+
else if (depth === 0 && nextCode.startsWith(",[],import.meta.url)", cursor)) {
|
|
2140
|
+
replacementEnd = cursor;
|
|
2141
|
+
break;
|
|
2142
|
+
}
|
|
2143
|
+
cursor++;
|
|
2144
|
+
}
|
|
2145
|
+
if (replacementEnd === -1) break;
|
|
2146
|
+
const expression = nextCode.slice(exprStart, replacementEnd);
|
|
2147
|
+
nextCode = nextCode.slice(0, start) + expression + nextCode.slice(replacementEnd + 20);
|
|
2148
|
+
start = nextCode.indexOf(marker, start + expression.length);
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
nextCode = nextCode.replace(/import\s*["'][^"']*__loadShare__[^"']*["']\s*;?/g, "");
|
|
2152
|
+
nextCode = nextCode.replace(helperImportRegex, (statement, local) => {
|
|
2153
|
+
return new RegExp(`\\b${local}\\s*\\(`).test(nextCode.replace(statement, "")) ? statement : "";
|
|
2154
|
+
});
|
|
2155
|
+
return nextCode;
|
|
2156
|
+
}
|
|
2157
|
+
function isFederationControlChunk(fileName, filename) {
|
|
2158
|
+
return fileName.includes(filename) || FEDERATION_CONTROL_CHUNK_HINTS.some((hint) => fileName.includes(hint));
|
|
2159
|
+
}
|
|
2160
|
+
function sanitizeFederationControlChunk(code, fileName, filename) {
|
|
2161
|
+
let nextCode = stripEmptyPreloadCalls(code);
|
|
2162
|
+
if (fileName.includes("localSharedImportMap")) {
|
|
2163
|
+
const remoteEntryImportRegex = new RegExp(`import\\s*["'][^"']*${filename.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']\\s*;?`, "g");
|
|
2164
|
+
nextCode = nextCode.replace(remoteEntryImportRegex, "");
|
|
2165
|
+
}
|
|
2166
|
+
return nextCode;
|
|
2167
|
+
}
|
|
2168
|
+
//#endregion
|
|
1933
2169
|
//#region src/utils/normalizeOptimizeDeps.ts
|
|
1934
2170
|
var normalizeOptimizeDeps_default = {
|
|
1935
2171
|
name: "normalizeOptimizeDeps",
|
|
@@ -1958,6 +2194,8 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
1958
2194
|
enforce: "pre",
|
|
1959
2195
|
config(config, { command: _command }) {
|
|
1960
2196
|
const root = config.root || process.cwd();
|
|
2197
|
+
setPackageDetectionCwd(root);
|
|
2198
|
+
const isVinext = hasPackageDependency("vinext");
|
|
1961
2199
|
initVirtualModuleInfrastructure(root, virtualModuleDir);
|
|
1962
2200
|
VirtualModule.setRoot(root);
|
|
1963
2201
|
VirtualModule.ensureVirtualPackageExists();
|
|
@@ -1972,6 +2210,10 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
1972
2210
|
for (const key of Object.keys(shared)) {
|
|
1973
2211
|
if (key.endsWith("/")) continue;
|
|
1974
2212
|
const shareItem = shared[key];
|
|
2213
|
+
if (isVinext && key === "react") {
|
|
2214
|
+
addUsedShares(key);
|
|
2215
|
+
continue;
|
|
2216
|
+
}
|
|
1975
2217
|
getLoadShareModulePath(key, isRolldown);
|
|
1976
2218
|
writeLoadShareModule(key, shareItem, _command, isRolldown);
|
|
1977
2219
|
writePreBuildLibPath(key);
|
|
@@ -1985,6 +2227,7 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
1985
2227
|
}
|
|
1986
2228
|
function federation(mfUserOptions) {
|
|
1987
2229
|
const options = normalizeModuleFederationOptions(mfUserOptions);
|
|
2230
|
+
const isVinext = hasPackageDependency("vinext");
|
|
1988
2231
|
const { name, remotes, shared, filename, hostInitInjectLocation } = options;
|
|
1989
2232
|
if (!name) throw new Error("name is required");
|
|
1990
2233
|
const remoteEntryId = getRemoteEntryId(options);
|
|
@@ -1992,6 +2235,23 @@ function federation(mfUserOptions) {
|
|
|
1992
2235
|
let command;
|
|
1993
2236
|
return [
|
|
1994
2237
|
createEarlyVirtualModulesPlugin(options),
|
|
2238
|
+
...isVinext ? [{
|
|
2239
|
+
name: "module-federation-vinext-react-server-build-alias",
|
|
2240
|
+
apply: "build",
|
|
2241
|
+
enforce: "pre",
|
|
2242
|
+
resolveId(id) {
|
|
2243
|
+
const reactServerEntryMap = {
|
|
2244
|
+
"react/jsx-runtime": "react/cjs/react-jsx-runtime.production.js",
|
|
2245
|
+
"react/jsx-dev-runtime": "react/cjs/react-jsx-dev-runtime.production.js"
|
|
2246
|
+
};
|
|
2247
|
+
if (!(id in reactServerEntryMap)) return;
|
|
2248
|
+
const environmentName = this?.environment?.name;
|
|
2249
|
+
if (!environmentName || environmentName === "client") return;
|
|
2250
|
+
const target = reactServerEntryMap[id];
|
|
2251
|
+
const reactPackageJson = (0, module$1.createRequire)(new URL(`file://${process.cwd()}/package.json`)).resolve("react/package.json");
|
|
2252
|
+
return pathe.default.join(pathe.default.dirname(reactPackageJson), target.replace(/^react\//, ""));
|
|
2253
|
+
}
|
|
2254
|
+
}] : [],
|
|
1995
2255
|
{
|
|
1996
2256
|
name: "vite:module-federation-config",
|
|
1997
2257
|
enforce: "pre",
|
|
@@ -2043,9 +2303,19 @@ function federation(mfUserOptions) {
|
|
|
2043
2303
|
config(config) {
|
|
2044
2304
|
const runtimeInitId = virtualRuntimeInitStatus.getImportId();
|
|
2045
2305
|
config.build = config.build || {};
|
|
2046
|
-
config.build.
|
|
2047
|
-
|
|
2048
|
-
const
|
|
2306
|
+
if (config.build.modulePreload !== false) {
|
|
2307
|
+
const currentModulePreload = config.build.modulePreload && typeof config.build.modulePreload === "object" ? config.build.modulePreload : {};
|
|
2308
|
+
const existingResolveDependencies = currentModulePreload.resolveDependencies;
|
|
2309
|
+
config.build.modulePreload = {
|
|
2310
|
+
...currentModulePreload,
|
|
2311
|
+
resolveDependencies(filename, deps, context) {
|
|
2312
|
+
const resolvedDeps = existingResolveDependencies ? existingResolveDependencies(filename, deps, context) : deps;
|
|
2313
|
+
const hostFile = pathe.default.basename(context.hostId);
|
|
2314
|
+
return context.hostType === "js" && (hostFile === options.filename || hostFile.includes("hostInit") || hostFile.includes("virtualExposes") || hostFile.includes("localSharedImportMap")) ? [] : resolvedDeps;
|
|
2315
|
+
}
|
|
2316
|
+
};
|
|
2317
|
+
}
|
|
2318
|
+
const applyManualChunks = (output) => {
|
|
2049
2319
|
const existingManualChunks = output.manualChunks;
|
|
2050
2320
|
output.manualChunks = function(id) {
|
|
2051
2321
|
if (id.includes(runtimeInitId)) return "runtimeInit";
|
|
@@ -2058,7 +2328,12 @@ function federation(mfUserOptions) {
|
|
|
2058
2328
|
for (const [key, ids] of Object.entries(existingManualChunks)) if (Array.isArray(ids) && ids.some((v) => id.includes(v))) return key;
|
|
2059
2329
|
}
|
|
2060
2330
|
};
|
|
2061
|
-
}
|
|
2331
|
+
};
|
|
2332
|
+
config.build.rollupOptions = config.build.rollupOptions || {};
|
|
2333
|
+
if (!Array.isArray(config.build.rollupOptions.output)) applyManualChunks(config.build.rollupOptions.output ||= {});
|
|
2334
|
+
const buildWithRolldown = config.build;
|
|
2335
|
+
buildWithRolldown.rolldownOptions = buildWithRolldown.rolldownOptions || {};
|
|
2336
|
+
if (!Array.isArray(buildWithRolldown.rolldownOptions.output)) applyManualChunks(buildWithRolldown.rolldownOptions.output ||= {});
|
|
2062
2337
|
},
|
|
2063
2338
|
load(id) {
|
|
2064
2339
|
if (id.startsWith("\0")) return;
|
|
@@ -2090,6 +2365,11 @@ function federation(mfUserOptions) {
|
|
|
2090
2365
|
}
|
|
2091
2366
|
},
|
|
2092
2367
|
generateBundle(_, bundle) {
|
|
2368
|
+
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
2369
|
+
if (chunk.type !== "chunk") continue;
|
|
2370
|
+
if (!isFederationControlChunk(fileName, filename)) continue;
|
|
2371
|
+
chunk.code = sanitizeFederationControlChunk(chunk.code, fileName, filename);
|
|
2372
|
+
}
|
|
2093
2373
|
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
2094
2374
|
if (chunk.type !== "chunk") continue;
|
|
2095
2375
|
if (fileName.includes("__loadShare__")) continue;
|
|
@@ -2127,12 +2407,12 @@ function federation(mfUserOptions) {
|
|
|
2127
2407
|
fileName
|
|
2128
2408
|
});
|
|
2129
2409
|
}
|
|
2130
|
-
if (proxyChunks.size
|
|
2131
|
-
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
2410
|
+
if (proxyChunks.size > 0) for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
2132
2411
|
if (chunk.type !== "chunk") continue;
|
|
2133
2412
|
if (fileName.includes("__loadShare__")) continue;
|
|
2134
2413
|
let code = chunk.code;
|
|
2135
2414
|
let modified = false;
|
|
2415
|
+
const claimedLocals = /* @__PURE__ */ new Set();
|
|
2136
2416
|
for (const [proxyFileName, proxyInfo] of proxyChunks) {
|
|
2137
2417
|
const proxyBaseName = proxyFileName.replace(/^.*\//, "").replace(/\.js$/, "").replace(/-[A-Za-z0-9_-]+$/, "");
|
|
2138
2418
|
const importMatch = new RegExp(`import\\s*\\{([^}]+)\\}\\s*from\\s*["']([^"']*${proxyBaseName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[^"']*)["']\\s*;?`).exec(code);
|
|
@@ -2155,9 +2435,12 @@ function federation(mfUserOptions) {
|
|
|
2155
2435
|
}
|
|
2156
2436
|
const inlineable = [];
|
|
2157
2437
|
const nonInlineable = [];
|
|
2438
|
+
const pendingLocals = new Set(bindings.map((binding) => binding.local));
|
|
2158
2439
|
for (const b of bindings) {
|
|
2440
|
+
pendingLocals.delete(b.local);
|
|
2159
2441
|
const proxyLocal = exportMap[b.imported];
|
|
2160
2442
|
if (!proxyLocal) {
|
|
2443
|
+
claimedLocals.add(b.local);
|
|
2161
2444
|
nonInlineable.push(b);
|
|
2162
2445
|
continue;
|
|
2163
2446
|
}
|
|
@@ -2179,7 +2462,14 @@ function federation(mfUserOptions) {
|
|
|
2179
2462
|
local: b.local,
|
|
2180
2463
|
funcBody: renamedFunc
|
|
2181
2464
|
});
|
|
2182
|
-
|
|
2465
|
+
claimedLocals.add(b.local);
|
|
2466
|
+
} else {
|
|
2467
|
+
const unavailableLocals = new Set(claimedLocals);
|
|
2468
|
+
pendingLocals.forEach((local) => unavailableLocals.add(local));
|
|
2469
|
+
const resolvedBinding = resolveProxyAlias(b, proxyLocal, code, fullImport, unavailableLocals);
|
|
2470
|
+
claimedLocals.add(resolvedBinding.local);
|
|
2471
|
+
nonInlineable.push(resolvedBinding);
|
|
2472
|
+
}
|
|
2183
2473
|
}
|
|
2184
2474
|
const hasRenamedAlias = nonInlineable.some((b) => bindings.find((ob) => ob.imported === b.imported)?.local !== b.local);
|
|
2185
2475
|
if (inlineable.length === 0 && !hasRenamedAlias) continue;
|
|
@@ -2193,6 +2483,28 @@ function federation(mfUserOptions) {
|
|
|
2193
2483
|
}
|
|
2194
2484
|
}
|
|
2195
2485
|
},
|
|
2486
|
+
{
|
|
2487
|
+
name: "module-federation-strip-empty-preload-helper",
|
|
2488
|
+
enforce: "post",
|
|
2489
|
+
apply: "build",
|
|
2490
|
+
renderChunk(code, chunk) {
|
|
2491
|
+
if (!isFederationControlChunk(chunk.fileName, filename)) return;
|
|
2492
|
+
const nextCode = sanitizeFederationControlChunk(code, chunk.fileName, filename);
|
|
2493
|
+
return nextCode === code ? null : {
|
|
2494
|
+
code: nextCode,
|
|
2495
|
+
map: null
|
|
2496
|
+
};
|
|
2497
|
+
},
|
|
2498
|
+
writeBundle(outputOptions, bundle) {
|
|
2499
|
+
if (!outputOptions.dir) return;
|
|
2500
|
+
for (const chunk of Object.values(bundle)) {
|
|
2501
|
+
if (chunk.type !== "chunk") continue;
|
|
2502
|
+
if (!isFederationControlChunk(chunk.fileName, filename)) continue;
|
|
2503
|
+
const outputPath = pathe.default.join(outputOptions.dir, chunk.fileName);
|
|
2504
|
+
(0, fs.writeFileSync)(outputPath, sanitizeFederationControlChunk((0, fs.readFileSync)(outputPath, "utf-8"), chunk.fileName, filename));
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
},
|
|
2196
2508
|
{
|
|
2197
2509
|
name: "module-federation-dev-await-shared-init",
|
|
2198
2510
|
apply: "serve",
|
|
@@ -2227,7 +2539,7 @@ function federation(mfUserOptions) {
|
|
|
2227
2539
|
config(config, { command: _command }) {
|
|
2228
2540
|
const isRolldown = !!this?.meta?.rolldownVersion;
|
|
2229
2541
|
let implementation = options.implementation;
|
|
2230
|
-
if (isRolldown) implementation = implementation.replace(/\.cjs\.
|
|
2542
|
+
if (isRolldown) implementation = implementation.replace(/\.cjs(\.js)?$/, ".js");
|
|
2231
2543
|
config.resolve.alias.push({
|
|
2232
2544
|
find: "@module-federation/runtime",
|
|
2233
2545
|
replacement: implementation
|