@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.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { createRequire } from "node:module";
|
|
|
2
2
|
import defu from "defu";
|
|
3
3
|
import * as fs from "fs";
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, writeFile, writeFileSync } from "fs";
|
|
5
|
+
import { createRequire as createRequire$1 } from "module";
|
|
5
6
|
import * as path$1 from "pathe";
|
|
6
7
|
import path, { basename, dirname, join, parse, resolve } from "pathe";
|
|
7
8
|
import MagicString from "magic-string";
|
|
@@ -9,7 +10,6 @@ import { createFilter } from "@rollup/pluginutils";
|
|
|
9
10
|
import { normalizeOptions } from "@module-federation/sdk";
|
|
10
11
|
import { consumeTypesAPI, generateTypesAPI, isTSProject, normalizeConsumeTypesOptions, normalizeDtsOptions, normalizeGenerateTypesOptions } from "@module-federation/dts-plugin";
|
|
11
12
|
import { rpc } from "@module-federation/dts-plugin/core";
|
|
12
|
-
import { createRequire as createRequire$1 } from "module";
|
|
13
13
|
import { fileURLToPath } from "url";
|
|
14
14
|
//#region \0rolldown/runtime.js
|
|
15
15
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
@@ -25,6 +25,104 @@ async function mapCodeToCodeWithSourcemap(code) {
|
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
//#endregion
|
|
28
|
+
//#region src/utils/htmlEntryUtils.ts
|
|
29
|
+
function sanitizeDevEntryPath(devEntryPath) {
|
|
30
|
+
return devEntryPath.replace(/^[^:]+:([/\\])[/\\]?/, "$1").replace(/\\\\?/g, "/");
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Inlines the federation init import into existing module script tags to fix
|
|
34
|
+
* the race condition (#396) where separate `<script type="module">` tags
|
|
35
|
+
* don't guarantee execution order with top-level await.
|
|
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>
|
|
45
|
+
*/
|
|
46
|
+
function inlineEntryScripts(html, initSrc) {
|
|
47
|
+
const src = sanitizeDevEntryPath(initSrc);
|
|
48
|
+
const scriptTagRegex = /<script\s+([^>]*\btype=["']module["'][^>]*\bsrc=["'][^"']+["'][^>]*)>/gi;
|
|
49
|
+
let hasEntry = false;
|
|
50
|
+
const result = html.replace(scriptTagRegex, (match, attrs) => {
|
|
51
|
+
const srcMatch = attrs.match(/\bsrc=["']([^"']+)["']/i);
|
|
52
|
+
if (!srcMatch) return match;
|
|
53
|
+
const originalSrc = srcMatch[1];
|
|
54
|
+
if (originalSrc.includes("@vite/client")) return match;
|
|
55
|
+
hasEntry = true;
|
|
56
|
+
return `<script ${attrs.replace(/\s*\bsrc=["'][^"']+["']/i, "")}>await import(${JSON.stringify(src)});await import(${JSON.stringify(originalSrc)});`;
|
|
57
|
+
});
|
|
58
|
+
if (hasEntry) return result;
|
|
59
|
+
return html.replace("<head>", `<head><script type="module" src=${JSON.stringify(src)}><\/script>`);
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/utils/packageUtils.ts
|
|
63
|
+
const dependencyPresenceCache = /* @__PURE__ */ new Map();
|
|
64
|
+
let packageDetectionCwd;
|
|
65
|
+
function getDependencyCacheKey(cwd, dependencyName) {
|
|
66
|
+
return `${cwd}:${dependencyName}`;
|
|
67
|
+
}
|
|
68
|
+
function setPackageDetectionCwd(cwd) {
|
|
69
|
+
packageDetectionCwd = cwd;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Escaping rules:
|
|
73
|
+
* Convert using the format __${mapping}__, where _ and $ are not allowed in npm package names but can be used in variable names.
|
|
74
|
+
* @ => 1
|
|
75
|
+
* / => 2
|
|
76
|
+
* - => 3
|
|
77
|
+
* . => 4
|
|
78
|
+
*/
|
|
79
|
+
/**
|
|
80
|
+
* Encodes a package name into a valid file name.
|
|
81
|
+
* @param {string} name - The package name, e.g., "@scope/xx-xx.xx".
|
|
82
|
+
* @returns {string} - The encoded file name.
|
|
83
|
+
*/
|
|
84
|
+
function packageNameEncode(name) {
|
|
85
|
+
if (typeof name !== "string") throw new Error("A string package name is required");
|
|
86
|
+
return name.replace(/@/g, "_mf_0_").replace(/\//g, "_mf_1_").replace(/-/g, "_mf_2_").replace(/\./g, "_mf_3_");
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Decodes an encoded file name back to the original package name.
|
|
90
|
+
* @param {string} encoded - The encoded file name, e.g., "_mf_0_scope_mf_1_xx_mf_2_xx_mf_3_xx".
|
|
91
|
+
* @returns {string} - The decoded package name.
|
|
92
|
+
*/
|
|
93
|
+
function packageNameDecode(encoded) {
|
|
94
|
+
if (typeof encoded !== "string") throw new Error("A string encoded file name is required");
|
|
95
|
+
return encoded.replace(/_mf_0_/g, "@").replace(/_mf_1_/g, "/").replace(/_mf_2_/g, "-").replace(/_mf_3_/g, ".");
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Removes any subpath from an npm package specifier and returns the package name only.
|
|
99
|
+
* @param {string} packageString - The package specifier, e.g., "@scope/pkg/runtime" or "react/jsx-runtime".
|
|
100
|
+
* @returns {string} - The base npm package name.
|
|
101
|
+
*/
|
|
102
|
+
function removePathFromNpmPackage(packageString) {
|
|
103
|
+
const match = packageString.match(/^(?:@[^/]+\/)?[^/]+/);
|
|
104
|
+
return match ? match[0] : packageString;
|
|
105
|
+
}
|
|
106
|
+
function hasPackageDependency(dependencyName, cwd = packageDetectionCwd || process.cwd()) {
|
|
107
|
+
const cacheKey = getDependencyCacheKey(cwd, dependencyName);
|
|
108
|
+
const cached = dependencyPresenceCache.get(cacheKey);
|
|
109
|
+
if (cached !== void 0) return cached;
|
|
110
|
+
try {
|
|
111
|
+
const packageJson = JSON.parse(readFileSync(path.join(cwd, "package.json"), "utf8"));
|
|
112
|
+
const hasDependency = [
|
|
113
|
+
packageJson.dependencies,
|
|
114
|
+
packageJson.devDependencies,
|
|
115
|
+
packageJson.peerDependencies,
|
|
116
|
+
packageJson.optionalDependencies
|
|
117
|
+
].some((deps) => !!deps?.[dependencyName]);
|
|
118
|
+
dependencyPresenceCache.set(cacheKey, hasDependency);
|
|
119
|
+
return hasDependency;
|
|
120
|
+
} catch {
|
|
121
|
+
dependencyPresenceCache.set(cacheKey, false);
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//#endregion
|
|
28
126
|
//#region src/plugins/pluginAddEntry.ts
|
|
29
127
|
function getFirstHtmlEntryFile(entryFiles) {
|
|
30
128
|
return entryFiles.find((file) => file.endsWith(".html"));
|
|
@@ -54,7 +152,7 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
54
152
|
viteConfig = config;
|
|
55
153
|
const resolvedEntryPath = getEntryPath();
|
|
56
154
|
devEntryPath = resolvedEntryPath.startsWith("virtual:mf") ? "@id/" + resolvedEntryPath : resolvedEntryPath;
|
|
57
|
-
devEntryPath = config.base + devEntryPath.replace(/\\\\?/g, "/").replace(
|
|
155
|
+
devEntryPath = config.base + devEntryPath.replace(/\\\\?/g, "/").replace(/^[^:]+:([/\\])[/\\]?/, "$1").replace(/^\//, "");
|
|
58
156
|
},
|
|
59
157
|
configureServer(server) {
|
|
60
158
|
server.middlewares.use((req, res, next) => {
|
|
@@ -69,14 +167,11 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
69
167
|
transformIndexHtml(c) {
|
|
70
168
|
if (!injectHtml()) return;
|
|
71
169
|
clientInjected = true;
|
|
72
|
-
return c
|
|
170
|
+
return inlineEntryScripts(c, devEntryPath);
|
|
73
171
|
},
|
|
74
172
|
transform(code, id) {
|
|
75
173
|
if (id.includes("node_modules") || inject !== "html" || htmlFilePath) return;
|
|
76
|
-
if (id.includes(".svelte-kit") && id.includes("internal.js"))
|
|
77
|
-
const src = devEntryPath.replace(/.+?\:([/\\])[/\\]?/, "$1").replace(/\\\\?/g, "/");
|
|
78
|
-
return code.replace(/<head>/g, "<head><script type=\\\"module\\\" src=\\\"" + src + "\\\"><\/script>");
|
|
79
|
-
}
|
|
174
|
+
if (id.includes(".svelte-kit") && id.includes("internal.js")) return code.replace(/<head>/g, "<head><script type=\\\"module\\\" src=\\\"" + sanitizeDevEntryPath(devEntryPath) + "\\\"><\/script>");
|
|
80
175
|
}
|
|
81
176
|
}, {
|
|
82
177
|
name: "add-entry",
|
|
@@ -89,6 +184,12 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
89
184
|
else if (Array.isArray(inputOptions)) entryFiles = inputOptions;
|
|
90
185
|
else if (typeof inputOptions === "object") entryFiles = Object.values(inputOptions);
|
|
91
186
|
if (entryFiles && entryFiles.length > 0) htmlFilePath = getFirstHtmlEntryFile(entryFiles);
|
|
187
|
+
if (_command === "serve" && htmlFilePath && fs.existsSync(htmlFilePath)) {
|
|
188
|
+
const htmlContent = fs.readFileSync(htmlFilePath, "utf-8");
|
|
189
|
+
const scriptRegex = /<script\s+[^>]*src=["']([^"']+)["'][^>]*>/gi;
|
|
190
|
+
let match;
|
|
191
|
+
while ((match = scriptRegex.exec(htmlContent)) !== null) entryFiles.push(match[1]);
|
|
192
|
+
}
|
|
92
193
|
},
|
|
93
194
|
buildStart() {
|
|
94
195
|
if (_command === "serve") return;
|
|
@@ -141,6 +242,15 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
141
242
|
}
|
|
142
243
|
},
|
|
143
244
|
transform(code, id) {
|
|
245
|
+
if (hasPackageDependency("vinext") && inject === "html" && (id.includes("virtual:vite-rsc/entry-browser") || id.includes("virtual:vinext-app-browser-entry"))) {
|
|
246
|
+
const injection = `import ${JSON.stringify(getEntryPath())};\n`;
|
|
247
|
+
if (code.includes(injection.trim())) {
|
|
248
|
+
clientInjected = true;
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
clientInjected = true;
|
|
252
|
+
return mapCodeToCodeWithSourcemap(injection + code);
|
|
253
|
+
}
|
|
144
254
|
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)) {
|
|
145
255
|
clientInjected = true;
|
|
146
256
|
return mapCodeToCodeWithSourcemap(`import ${JSON.stringify(getEntryPath())};\n` + code);
|
|
@@ -214,7 +324,9 @@ function PluginDevProxyModuleTopLevelAwait() {
|
|
|
214
324
|
throw new Error(`${id}: ${e}`);
|
|
215
325
|
}
|
|
216
326
|
const magicString = new MagicString(code);
|
|
217
|
-
|
|
327
|
+
const walk = await loadWalk();
|
|
328
|
+
const defaultExportExpression = hasPackageDependency("vinext") ? "(__mfproxy__awaitdefault?.default ?? __mfproxy__awaitdefault)" : "__mfproxy__awaitdefault";
|
|
329
|
+
walk(ast, { enter(node) {
|
|
218
330
|
if (node.type === "ExportNamedDeclaration" && node.specifiers) {
|
|
219
331
|
const exportSpecifiers = node.specifiers.map((specifier) => specifier.exported.name);
|
|
220
332
|
const proxyStatements = exportSpecifiers.map((name) => `
|
|
@@ -235,15 +347,15 @@ function PluginDevProxyModuleTopLevelAwait() {
|
|
|
235
347
|
let exportStatement = "default";
|
|
236
348
|
if (declaration.type === "Identifier") proxyStatement = `
|
|
237
349
|
const __mfproxy__awaitdefault = await ${declaration.name}();
|
|
238
|
-
const __mfproxy__default =
|
|
350
|
+
const __mfproxy__default = ${defaultExportExpression};
|
|
239
351
|
`;
|
|
240
352
|
else if (declaration.type === "CallExpression" || declaration.type === "FunctionDeclaration") proxyStatement = `
|
|
241
353
|
const __mfproxy__awaitdefault = await (${code.slice(declaration.start, declaration.end)});
|
|
242
|
-
const __mfproxy__default =
|
|
354
|
+
const __mfproxy__default = ${defaultExportExpression};
|
|
243
355
|
`;
|
|
244
356
|
else proxyStatement = `
|
|
245
357
|
const __mfproxy__awaitdefault = await (${code.slice(declaration.start, declaration.end)});
|
|
246
|
-
const __mfproxy__default =
|
|
358
|
+
const __mfproxy__default = ${defaultExportExpression};
|
|
247
359
|
`;
|
|
248
360
|
const replacement = `${proxyStatement}\nexport { __mfproxy__default as ${exportStatement} };`;
|
|
249
361
|
magicString.overwrite(start, end, replacement);
|
|
@@ -525,10 +637,6 @@ function normalizeRemoteItem(key, remote) {
|
|
|
525
637
|
entryGlobalName: key
|
|
526
638
|
}, remote);
|
|
527
639
|
}
|
|
528
|
-
function removePathFromNpmPackage(packageString) {
|
|
529
|
-
const match = packageString.match(/^(?:@[^/]+\/)?[^/]+/);
|
|
530
|
-
return match ? match[0] : packageString;
|
|
531
|
-
}
|
|
532
640
|
/**
|
|
533
641
|
* Tries to find the package.json's version of a shared package
|
|
534
642
|
* if `package.json` is not declared in `exports`
|
|
@@ -537,19 +645,23 @@ function removePathFromNpmPackage(packageString) {
|
|
|
537
645
|
*/
|
|
538
646
|
function searchPackageVersion(sharedName) {
|
|
539
647
|
try {
|
|
540
|
-
const sharedPath =
|
|
648
|
+
const sharedPath = createRequire(process.cwd()).resolve(sharedName);
|
|
541
649
|
let potentialPackageJsonDir = path$1.dirname(sharedPath);
|
|
542
650
|
const rootDir = path$1.parse(potentialPackageJsonDir).root;
|
|
543
651
|
while (path$1.parse(potentialPackageJsonDir).base !== "node_modules" && potentialPackageJsonDir !== rootDir) {
|
|
544
652
|
const potentialPackageJsonPath = path$1.join(potentialPackageJsonDir, "package.json");
|
|
545
653
|
if (fs.existsSync(potentialPackageJsonPath)) {
|
|
546
|
-
const potentialPackageJson =
|
|
654
|
+
const potentialPackageJson = JSON.parse(fs.readFileSync(potentialPackageJsonPath, "utf-8"));
|
|
547
655
|
if (typeof potentialPackageJson == "object" && potentialPackageJson !== null && typeof potentialPackageJson.version === "string" && potentialPackageJson.name === sharedName) return potentialPackageJson.version;
|
|
548
656
|
}
|
|
549
657
|
potentialPackageJsonDir = path$1.dirname(potentialPackageJsonDir);
|
|
550
658
|
}
|
|
551
659
|
} catch (_) {}
|
|
552
660
|
}
|
|
661
|
+
function inferVersionFromRequiredVersion(requiredVersion) {
|
|
662
|
+
if (!requiredVersion) return void 0;
|
|
663
|
+
return requiredVersion.match(/\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?/)?.[0];
|
|
664
|
+
}
|
|
553
665
|
function normalizeShareItem(key, shareItem) {
|
|
554
666
|
let version;
|
|
555
667
|
try {
|
|
@@ -580,7 +692,7 @@ function normalizeShareItem(key, shareItem) {
|
|
|
580
692
|
return {
|
|
581
693
|
name: key,
|
|
582
694
|
from: "",
|
|
583
|
-
version: shareItem.version || version,
|
|
695
|
+
version: shareItem.version || inferVersionFromRequiredVersion(shareItem.requiredVersion) || version,
|
|
584
696
|
scope: shareItem.shareScope || "default",
|
|
585
697
|
shareConfig: {
|
|
586
698
|
import: typeof shareItem === "object" ? shareItem.import : void 0,
|
|
@@ -654,34 +766,6 @@ function normalizeModuleFederationOptions(options) {
|
|
|
654
766
|
};
|
|
655
767
|
}
|
|
656
768
|
//#endregion
|
|
657
|
-
//#region src/utils/packageNameUtils.ts
|
|
658
|
-
/**
|
|
659
|
-
* Escaping rules:
|
|
660
|
-
* Convert using the format __${mapping}__, where _ and $ are not allowed in npm package names but can be used in variable names.
|
|
661
|
-
* @ => 1
|
|
662
|
-
* / => 2
|
|
663
|
-
* - => 3
|
|
664
|
-
* . => 4
|
|
665
|
-
*/
|
|
666
|
-
/**
|
|
667
|
-
* Encodes a package name into a valid file name.
|
|
668
|
-
* @param {string} name - The package name, e.g., "@scope/xx-xx.xx".
|
|
669
|
-
* @returns {string} - The encoded file name.
|
|
670
|
-
*/
|
|
671
|
-
function packageNameEncode(name) {
|
|
672
|
-
if (typeof name !== "string") throw new Error("A string package name is required");
|
|
673
|
-
return name.replace(/@/g, "_mf_0_").replace(/\//g, "_mf_1_").replace(/-/g, "_mf_2_").replace(/\./g, "_mf_3_");
|
|
674
|
-
}
|
|
675
|
-
/**
|
|
676
|
-
* Decodes an encoded file name back to the original package name.
|
|
677
|
-
* @param {string} encoded - The encoded file name, e.g., "_mf_0_scope_mf_1_xx_mf_2_xx_mf_3_xx".
|
|
678
|
-
* @returns {string} - The decoded package name.
|
|
679
|
-
*/
|
|
680
|
-
function packageNameDecode(encoded) {
|
|
681
|
-
if (typeof encoded !== "string") throw new Error("A string encoded file name is required");
|
|
682
|
-
return encoded.replace(/_mf_0_/g, "@").replace(/_mf_1_/g, "/").replace(/_mf_2_/g, "-").replace(/_mf_3_/g, ".");
|
|
683
|
-
}
|
|
684
|
-
//#endregion
|
|
685
769
|
//#region src/utils/localSharedImportMap_temp.ts
|
|
686
770
|
/**
|
|
687
771
|
* https://github.com/module-federation/vite/issues/68
|
|
@@ -875,12 +959,12 @@ function generateExposes(options) {
|
|
|
875
959
|
//#endregion
|
|
876
960
|
//#region src/virtualModules/virtualRuntimeInitStatus.ts
|
|
877
961
|
const virtualRuntimeInitStatus = new VirtualModule("runtimeInit");
|
|
878
|
-
function
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
const globalKey = ${JSON.stringify(
|
|
962
|
+
function getRuntimeInitGlobalKey() {
|
|
963
|
+
return `__mf_init__${virtualRuntimeInitStatus.getImportId()}__`;
|
|
964
|
+
}
|
|
965
|
+
function getRuntimeInitBootstrapCode() {
|
|
966
|
+
return `
|
|
967
|
+
const globalKey = ${JSON.stringify(getRuntimeInitGlobalKey())};
|
|
884
968
|
if (!globalThis[globalKey]) {
|
|
885
969
|
let initResolve, initReject;
|
|
886
970
|
const initPromise = new Promise((re, rj) => {
|
|
@@ -892,8 +976,6 @@ if (!globalThis[globalKey]) {
|
|
|
892
976
|
initResolve,
|
|
893
977
|
initReject,
|
|
894
978
|
};
|
|
895
|
-
// In SSR (no window), resolve immediately with a stub runtime
|
|
896
|
-
// so modules don't hang waiting for browser-only init
|
|
897
979
|
if (typeof window === 'undefined') {
|
|
898
980
|
initResolve({
|
|
899
981
|
loadRemote: function() { return Promise.resolve(undefined); },
|
|
@@ -901,6 +983,64 @@ if (!globalThis[globalKey]) {
|
|
|
901
983
|
});
|
|
902
984
|
}
|
|
903
985
|
}
|
|
986
|
+
`;
|
|
987
|
+
}
|
|
988
|
+
function getRuntimeInitPromiseBootstrapCode() {
|
|
989
|
+
return `
|
|
990
|
+
const __mfPromiseGlobalKey = ${JSON.stringify(getRuntimeInitGlobalKey())};
|
|
991
|
+
let __mfPromiseState = globalThis[__mfPromiseGlobalKey];
|
|
992
|
+
if (!__mfPromiseState) {
|
|
993
|
+
let initResolve, initReject;
|
|
994
|
+
const initPromise = new Promise((re, rj) => {
|
|
995
|
+
initResolve = re;
|
|
996
|
+
initReject = rj;
|
|
997
|
+
});
|
|
998
|
+
__mfPromiseState = globalThis[__mfPromiseGlobalKey] = {
|
|
999
|
+
initPromise,
|
|
1000
|
+
initResolve,
|
|
1001
|
+
initReject,
|
|
1002
|
+
};
|
|
1003
|
+
if (typeof window === 'undefined') {
|
|
1004
|
+
initResolve({
|
|
1005
|
+
loadRemote: function() { return Promise.resolve(undefined); },
|
|
1006
|
+
loadShare: function() { return Promise.resolve(undefined); },
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
const initPromise = __mfPromiseState.initPromise;
|
|
1011
|
+
`;
|
|
1012
|
+
}
|
|
1013
|
+
function getRuntimeInitResolveBootstrapCode() {
|
|
1014
|
+
return `
|
|
1015
|
+
const __mfResolveGlobalKey = ${JSON.stringify(getRuntimeInitGlobalKey())};
|
|
1016
|
+
let __mfResolveState = globalThis[__mfResolveGlobalKey];
|
|
1017
|
+
if (!__mfResolveState) {
|
|
1018
|
+
let initResolve, initReject;
|
|
1019
|
+
const initPromise = new Promise((re, rj) => {
|
|
1020
|
+
initResolve = re;
|
|
1021
|
+
initReject = rj;
|
|
1022
|
+
});
|
|
1023
|
+
__mfResolveState = globalThis[__mfResolveGlobalKey] = {
|
|
1024
|
+
initPromise,
|
|
1025
|
+
initResolve,
|
|
1026
|
+
initReject,
|
|
1027
|
+
};
|
|
1028
|
+
if (typeof window === 'undefined') {
|
|
1029
|
+
initResolve({
|
|
1030
|
+
loadRemote: function() { return Promise.resolve(undefined); },
|
|
1031
|
+
loadShare: function() { return Promise.resolve(undefined); },
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
const initResolve = __mfResolveState.initResolve;
|
|
1036
|
+
`;
|
|
1037
|
+
}
|
|
1038
|
+
function writeRuntimeInitStatus(command) {
|
|
1039
|
+
getRuntimeInitGlobalKey();
|
|
1040
|
+
const exportStatement = command === "build" ? `const { initPromise, initResolve, initReject } = globalThis[globalKey];
|
|
1041
|
+
export { initPromise, initResolve, initReject };` : `module.exports = globalThis[globalKey];`;
|
|
1042
|
+
virtualRuntimeInitStatus.writeSync(`
|
|
1043
|
+
${getRuntimeInitBootstrapCode()}
|
|
904
1044
|
${exportStatement}
|
|
905
1045
|
`);
|
|
906
1046
|
}
|
|
@@ -925,7 +1065,8 @@ function getUsedRemotesMap() {
|
|
|
925
1065
|
}
|
|
926
1066
|
function generateRemotes(id, command, isRolldown) {
|
|
927
1067
|
const useESM = command === "build" || isRolldown;
|
|
928
|
-
const importLine =
|
|
1068
|
+
const importLine = command === "build" ? getRuntimeInitPromiseBootstrapCode() : useESM ? `${getRuntimeInitBootstrapCode()}
|
|
1069
|
+
const { initPromise } = globalThis[globalKey];` : `const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")`;
|
|
929
1070
|
const awaitOrPlaceholder = useESM ? "await " : "/*mf top-level-await placeholder replacement mf*/";
|
|
930
1071
|
const exportLine = command === "serve" && useESM ? "export default exportModule.default ?? exportModule" : useESM ? "export default exportModule" : "module.exports = exportModule";
|
|
931
1072
|
return `
|
|
@@ -955,6 +1096,14 @@ function getPackageNamedExports(pkg) {
|
|
|
955
1096
|
return [];
|
|
956
1097
|
}
|
|
957
1098
|
}
|
|
1099
|
+
function getLocalProviderImportPath(pkg) {
|
|
1100
|
+
try {
|
|
1101
|
+
const resolved = createRequire$1(new URL("file://" + process.cwd() + "/package.json")).resolve(pkg);
|
|
1102
|
+
return resolved.includes("/node_modules/") || resolved.includes("\\node_modules\\") ? void 0 : resolved;
|
|
1103
|
+
} catch {
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
958
1107
|
const preBuildCacheMap = {};
|
|
959
1108
|
const PREBUILD_TAG = "__prebuild__";
|
|
960
1109
|
function writePreBuildLibPath(pkg) {
|
|
@@ -974,8 +1123,11 @@ function getLoadShareModulePath(pkg, isRolldown, command) {
|
|
|
974
1123
|
function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
975
1124
|
if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, isRolldown || command === "build" ? ".mjs" : ".js");
|
|
976
1125
|
const useESM = command === "build" || isRolldown;
|
|
977
|
-
const importLine =
|
|
1126
|
+
const importLine = command === "build" ? getRuntimeInitPromiseBootstrapCode() : useESM ? `${getRuntimeInitBootstrapCode()}
|
|
1127
|
+
const { initPromise } = globalThis[globalKey];` : `const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")`;
|
|
978
1128
|
const awaitOrPlaceholder = useESM ? "await " : "/*mf top-level-await placeholder replacement mf*/";
|
|
1129
|
+
const useSsrProviderFallback = hasPackageDependency("vinext") && command === "build" && pkg === "react";
|
|
1130
|
+
const providerImportId = getLocalProviderImportPath(pkg) || getPreBuildLibImportId(pkg);
|
|
979
1131
|
const namedExports = getPackageNamedExports(pkg);
|
|
980
1132
|
let exportLine;
|
|
981
1133
|
if (namedExports.length > 0) {
|
|
@@ -987,6 +1139,9 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
|
987
1139
|
import ${JSON.stringify(getPreBuildLibImportId(pkg))};
|
|
988
1140
|
${command !== "build" ? `;() => import(${JSON.stringify(pkg)}).catch(() => {});` : ""}
|
|
989
1141
|
${importLine}
|
|
1142
|
+
${useSsrProviderFallback ? `const providerModulePromise = typeof window === "undefined"
|
|
1143
|
+
? import(${JSON.stringify(providerImportId)})
|
|
1144
|
+
: undefined` : ""}
|
|
990
1145
|
const res = initPromise.then(runtime => runtime.loadShare(${JSON.stringify(pkg)}, {
|
|
991
1146
|
customShareInfo: {shareConfig:{
|
|
992
1147
|
singleton: ${shareItem.shareConfig.singleton},
|
|
@@ -994,7 +1149,9 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
|
994
1149
|
requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)}
|
|
995
1150
|
}}
|
|
996
1151
|
}))
|
|
997
|
-
const exportModule = ${
|
|
1152
|
+
const exportModule = ${useSsrProviderFallback ? `(typeof window === "undefined"
|
|
1153
|
+
? ((await providerModulePromise)?.default ?? await providerModulePromise)
|
|
1154
|
+
: ${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory)))` : `${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory))`}
|
|
998
1155
|
${exportLine}
|
|
999
1156
|
`);
|
|
1000
1157
|
}
|
|
@@ -1011,15 +1168,16 @@ new VirtualModule("localSharedImportMap");
|
|
|
1011
1168
|
function getLocalSharedImportMapPath() {
|
|
1012
1169
|
return getLocalSharedImportMapPath_temp();
|
|
1013
1170
|
}
|
|
1014
|
-
let
|
|
1171
|
+
let prevLocalSharedImportMapContent;
|
|
1015
1172
|
function writeLocalSharedImportMap() {
|
|
1016
|
-
const
|
|
1017
|
-
if (
|
|
1018
|
-
|
|
1019
|
-
writeLocalSharedImportMap_temp(
|
|
1173
|
+
const nextContent = generateLocalSharedImportMap();
|
|
1174
|
+
if (prevLocalSharedImportMapContent !== nextContent) {
|
|
1175
|
+
prevLocalSharedImportMapContent = nextContent;
|
|
1176
|
+
writeLocalSharedImportMap_temp(nextContent);
|
|
1020
1177
|
}
|
|
1021
1178
|
}
|
|
1022
1179
|
function generateLocalSharedImportMap() {
|
|
1180
|
+
const isVinext = hasPackageDependency("vinext");
|
|
1023
1181
|
const options = getNormalizeModuleFederationOptions();
|
|
1024
1182
|
return `
|
|
1025
1183
|
import {loadShare} from "@module-federation/runtime";
|
|
@@ -1028,7 +1186,8 @@ function generateLocalSharedImportMap() {
|
|
|
1028
1186
|
const shareItem = getNormalizeShareItem(pkg);
|
|
1029
1187
|
return `
|
|
1030
1188
|
${JSON.stringify(pkg)}: async () => {
|
|
1031
|
-
${shareItem?.shareConfig.import === false ? `throw new Error(\`Shared module '\${${JSON.stringify(pkg)}}' must be provided by host\`);` : `let pkg = await import("
|
|
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("${getPreBuildLibImportId(pkg)}");
|
|
1032
1191
|
return pkg;`}
|
|
1033
1192
|
}
|
|
1034
1193
|
`;
|
|
@@ -1052,7 +1211,9 @@ function generateLocalSharedImportMap() {
|
|
|
1052
1211
|
usedShared[${JSON.stringify(key)}].loaded = true
|
|
1053
1212
|
const {${JSON.stringify(key)}: pkgDynamicImport} = importMap
|
|
1054
1213
|
const res = await pkgDynamicImport()
|
|
1055
|
-
const exportModule = {
|
|
1214
|
+
const exportModule = ${JSON.stringify(isVinext)} && ${JSON.stringify(key)} === "react"
|
|
1215
|
+
? (res?.default ?? res)
|
|
1216
|
+
: {...res}
|
|
1056
1217
|
// All npm packages pre-built by vite will be converted to esm
|
|
1057
1218
|
Object.defineProperty(exportModule, "__esModule", {
|
|
1058
1219
|
value: true,
|
|
@@ -1095,7 +1256,7 @@ const REMOTE_ENTRY_ID = "virtual:mf-REMOTE_ENTRY_ID";
|
|
|
1095
1256
|
function getRemoteEntryId(options) {
|
|
1096
1257
|
return `${REMOTE_ENTRY_ID}:${`${options.name}__${options.filename}`.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
|
|
1097
1258
|
}
|
|
1098
|
-
function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(options)) {
|
|
1259
|
+
function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(options), command = "build") {
|
|
1099
1260
|
const pluginImportNames = options.runtimePlugins.map((p, i) => {
|
|
1100
1261
|
if (typeof p === "string") return [
|
|
1101
1262
|
`$runtimePlugin_${i}`,
|
|
@@ -1111,15 +1272,25 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1111
1272
|
return `
|
|
1112
1273
|
import {init as runtimeInit, loadRemote} from "@module-federation/runtime";
|
|
1113
1274
|
${pluginImportNames.map((item) => item[1]).join("\n")}
|
|
1114
|
-
|
|
1115
|
-
import {usedShared, usedRemotes} from "${getLocalSharedImportMapPath()}"
|
|
1116
|
-
import {
|
|
1117
|
-
initResolve
|
|
1118
|
-
} from "${virtualRuntimeInitStatus.getImportId()}"
|
|
1275
|
+
${command === "build" ? getRuntimeInitResolveBootstrapCode() : getRuntimeInitBootstrapCode() + "\n const { initResolve } = globalThis[globalKey];"}
|
|
1119
1276
|
const initTokens = {}
|
|
1120
1277
|
const shareScopeName = ${JSON.stringify(options.shareScope)}
|
|
1121
1278
|
const mfName = ${JSON.stringify(options.name)}
|
|
1279
|
+
let localSharedImportMapPromise
|
|
1280
|
+
let exposesMapPromise
|
|
1281
|
+
|
|
1282
|
+
async function getLocalSharedImportMap() {
|
|
1283
|
+
localSharedImportMapPromise ??= import("${getLocalSharedImportMapPath()}")
|
|
1284
|
+
return localSharedImportMapPromise
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
async function getExposesMap() {
|
|
1288
|
+
exposesMapPromise ??= import("${virtualExposesId}").then((mod) => mod.default ?? mod)
|
|
1289
|
+
return exposesMapPromise
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1122
1292
|
async function init(shared = {}, initScope = []) {
|
|
1293
|
+
const {usedShared, usedRemotes} = await getLocalSharedImportMap()
|
|
1123
1294
|
const initRes = runtimeInit({
|
|
1124
1295
|
name: mfName,
|
|
1125
1296
|
remotes: usedRemotes,
|
|
@@ -1134,6 +1305,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1134
1305
|
if (initScope.indexOf(initToken) >= 0) return;
|
|
1135
1306
|
initScope.push(initToken);
|
|
1136
1307
|
initRes.initShareScopeMap('${options.shareScope}', shared);
|
|
1308
|
+
initResolve(initRes)
|
|
1137
1309
|
try {
|
|
1138
1310
|
await Promise.all(await initRes.initializeSharing('${options.shareScope}', {
|
|
1139
1311
|
strategy: '${options.shareStrategy}',
|
|
@@ -1143,11 +1315,11 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1143
1315
|
} catch (e) {
|
|
1144
1316
|
console.error(e)
|
|
1145
1317
|
}
|
|
1146
|
-
initResolve(initRes)
|
|
1147
1318
|
return initRes
|
|
1148
1319
|
}
|
|
1149
1320
|
|
|
1150
|
-
function getExposes(moduleName) {
|
|
1321
|
+
async function getExposes(moduleName) {
|
|
1322
|
+
const exposesMap = await getExposesMap()
|
|
1151
1323
|
if (!(moduleName in exposesMap)) throw new Error(\`Module \${moduleName} does not exist in container.\`)
|
|
1152
1324
|
return (exposesMap[moduleName])().then(res => () => res)
|
|
1153
1325
|
}
|
|
@@ -1160,13 +1332,8 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1160
1332
|
const hostAutoInitModule = new VirtualModule("hostAutoInit", "__H_A_I__");
|
|
1161
1333
|
function writeHostAutoInit(remoteEntryId = REMOTE_ENTRY_ID) {
|
|
1162
1334
|
hostAutoInitModule.writeSync(`
|
|
1163
|
-
const
|
|
1164
|
-
|
|
1165
|
-
Promise.resolve(remoteEntryPromise)
|
|
1166
|
-
.then(remoteEntry => {
|
|
1167
|
-
return Promise.resolve(remoteEntry.__tla)
|
|
1168
|
-
.then(remoteEntry.init).catch(remoteEntry.init)
|
|
1169
|
-
})
|
|
1335
|
+
const remoteEntry = await import("${remoteEntryId}");
|
|
1336
|
+
await remoteEntry.init();
|
|
1170
1337
|
`);
|
|
1171
1338
|
}
|
|
1172
1339
|
function getHostAutoInitImportId() {
|
|
@@ -1189,13 +1356,21 @@ function initVirtualModules(command, remoteEntryId) {
|
|
|
1189
1356
|
* If Rollup's deconflict renamed the alias but didn't update references
|
|
1190
1357
|
* in the code body, fall back to proxyLocal so they stay in sync.
|
|
1191
1358
|
*/
|
|
1192
|
-
function resolveProxyAlias(binding, proxyLocal, code, fullImport) {
|
|
1359
|
+
function resolveProxyAlias(binding, proxyLocal, code, fullImport, claimedLocals = /* @__PURE__ */ new Set()) {
|
|
1193
1360
|
const codeWithoutImport = code.replace(fullImport, "");
|
|
1194
1361
|
const escapedLocal = binding.local.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1195
1362
|
const localUsedInCode = new RegExp(`\\b${escapedLocal}\\b`).test(codeWithoutImport);
|
|
1363
|
+
const claimedImportLocals = /* @__PURE__ */ new Set();
|
|
1364
|
+
const importRe = /import\s*\{([^}]+)\}\s*from\s*["'][^"']+["']\s*;?/g;
|
|
1365
|
+
let match;
|
|
1366
|
+
while ((match = importRe.exec(codeWithoutImport)) !== null) for (const spec of match[1].split(",")) {
|
|
1367
|
+
const parts = spec.trim().split(/\s+as\s+/);
|
|
1368
|
+
claimedImportLocals.add((parts[1] || parts[0]).trim());
|
|
1369
|
+
}
|
|
1370
|
+
const local = !localUsedInCode && !claimedLocals.has(proxyLocal) && !claimedImportLocals.has(proxyLocal) ? proxyLocal : binding.local;
|
|
1196
1371
|
return {
|
|
1197
1372
|
imported: binding.imported,
|
|
1198
|
-
local
|
|
1373
|
+
local
|
|
1199
1374
|
};
|
|
1200
1375
|
}
|
|
1201
1376
|
function findRemoteEntryFile(filename, bundle) {
|
|
@@ -1650,14 +1825,14 @@ function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposes
|
|
|
1650
1825
|
}
|
|
1651
1826
|
},
|
|
1652
1827
|
load(id) {
|
|
1653
|
-
if (id === remoteEntryId) return parsePromise.then((_) => generateRemoteEntry(options, virtualExposesId));
|
|
1828
|
+
if (id === remoteEntryId) return parsePromise.then((_) => generateRemoteEntry(options, virtualExposesId, _command));
|
|
1654
1829
|
if (id === virtualExposesId) return generateExposes(options);
|
|
1655
1830
|
if (_command === "serve" && id.includes(getHostAutoInitPath())) return id;
|
|
1656
1831
|
},
|
|
1657
1832
|
transform(code, id) {
|
|
1658
1833
|
return mapCodeToCodeWithSourcemap((() => {
|
|
1659
1834
|
if (!filter(id)) return;
|
|
1660
|
-
if (id.includes(remoteEntryId)) return parsePromise.then((_) => generateRemoteEntry(options, virtualExposesId));
|
|
1835
|
+
if (id.includes(remoteEntryId)) return parsePromise.then((_) => generateRemoteEntry(options, virtualExposesId, _command));
|
|
1661
1836
|
if (id === virtualExposesId) return generateExposes(options);
|
|
1662
1837
|
if (id.includes(getHostAutoInitPath())) {
|
|
1663
1838
|
if (_command === "serve") {
|
|
@@ -1745,6 +1920,7 @@ function proxySharedModule(options) {
|
|
|
1745
1920
|
const { shared = {} } = options;
|
|
1746
1921
|
let _config;
|
|
1747
1922
|
let _command = "serve";
|
|
1923
|
+
let isVinext = false;
|
|
1748
1924
|
const savePrebuild = new PromiseStore();
|
|
1749
1925
|
return [{
|
|
1750
1926
|
name: "generateLocalSharedImportMap",
|
|
@@ -1759,9 +1935,11 @@ function proxySharedModule(options) {
|
|
|
1759
1935
|
name: "proxyPreBuildShared",
|
|
1760
1936
|
enforce: "post",
|
|
1761
1937
|
config(config, { command }) {
|
|
1938
|
+
setPackageDetectionCwd(config.root || process.cwd());
|
|
1939
|
+
isVinext = hasPackageDependency("vinext");
|
|
1762
1940
|
const isRolldown = !!this?.meta?.rolldownVersion;
|
|
1763
1941
|
_command = command;
|
|
1764
|
-
config.resolve.alias.push(...Object.keys(shared).map((key) => {
|
|
1942
|
+
config.resolve.alias.push(...Object.keys(shared).filter((key) => !(isVinext && key === "react")).map((key) => {
|
|
1765
1943
|
const keyBase = key.endsWith("/") ? key.slice(0, -1) : key;
|
|
1766
1944
|
const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1767
1945
|
const escapedKeyBase = escapeRegex(keyBase);
|
|
@@ -1771,6 +1949,7 @@ function proxySharedModule(options) {
|
|
|
1771
1949
|
replacement: "$1",
|
|
1772
1950
|
customResolver(source, importer) {
|
|
1773
1951
|
if (/\.css$/.test(source)) return;
|
|
1952
|
+
if (isVinext && source === "react") return;
|
|
1774
1953
|
if (importer && importer.includes("localSharedImportMap")) return;
|
|
1775
1954
|
if (key.endsWith("/") && source !== key.slice(0, -1)) return;
|
|
1776
1955
|
const loadSharePath = getLoadShareModulePath(source, isRolldown, command);
|
|
@@ -1782,7 +1961,7 @@ function proxySharedModule(options) {
|
|
|
1782
1961
|
}
|
|
1783
1962
|
};
|
|
1784
1963
|
}));
|
|
1785
|
-
config.resolve.alias.push(...Object.keys(shared).map((key) => {
|
|
1964
|
+
config.resolve.alias.push(...Object.keys(shared).filter((key) => !(isVinext && key === "react")).map((key) => {
|
|
1786
1965
|
return command === "build" ? {
|
|
1787
1966
|
find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
|
|
1788
1967
|
replacement: function($1) {
|
|
@@ -1805,6 +1984,10 @@ function proxySharedModule(options) {
|
|
|
1805
1984
|
const isRolldown = !!config.experimental?.rolldownDev;
|
|
1806
1985
|
Object.keys(shared).forEach((key) => {
|
|
1807
1986
|
if (key.endsWith("/")) return;
|
|
1987
|
+
if (isVinext && key === "react") {
|
|
1988
|
+
addUsedShares(key);
|
|
1989
|
+
return;
|
|
1990
|
+
}
|
|
1808
1991
|
writeLoadShareModule(key, shared[key], _command, isRolldown);
|
|
1809
1992
|
writePreBuildLibPath(key);
|
|
1810
1993
|
addUsedShares(key);
|
|
@@ -1908,6 +2091,58 @@ var aliasToArrayPlugin_default = {
|
|
|
1908
2091
|
}
|
|
1909
2092
|
};
|
|
1910
2093
|
//#endregion
|
|
2094
|
+
//#region src/utils/controlChunkSanitizer.ts
|
|
2095
|
+
const FEDERATION_CONTROL_CHUNK_HINTS = [
|
|
2096
|
+
"hostInit",
|
|
2097
|
+
"virtualExposes",
|
|
2098
|
+
"localSharedImportMap"
|
|
2099
|
+
];
|
|
2100
|
+
function stripEmptyPreloadCalls(code) {
|
|
2101
|
+
const helperImportRegex = /import\s*\{\s*_\s*as\s*(\w+)\s*\}\s*from\s*["'][^"']+["']\s*;?/g;
|
|
2102
|
+
const helperAliases = [...code.matchAll(helperImportRegex)].map((match) => match[1]);
|
|
2103
|
+
let nextCode = code;
|
|
2104
|
+
for (const alias of helperAliases) {
|
|
2105
|
+
const marker = `${alias}(()=>`;
|
|
2106
|
+
let start = nextCode.indexOf(marker);
|
|
2107
|
+
while (start !== -1) {
|
|
2108
|
+
const exprStart = start + marker.length;
|
|
2109
|
+
let depth = 0;
|
|
2110
|
+
let cursor = exprStart;
|
|
2111
|
+
let replacementEnd = -1;
|
|
2112
|
+
while (cursor < nextCode.length) {
|
|
2113
|
+
const char = nextCode[cursor];
|
|
2114
|
+
if (char === "(") depth++;
|
|
2115
|
+
else if (char === ")") depth--;
|
|
2116
|
+
else if (depth === 0 && nextCode.startsWith(",[],import.meta.url)", cursor)) {
|
|
2117
|
+
replacementEnd = cursor;
|
|
2118
|
+
break;
|
|
2119
|
+
}
|
|
2120
|
+
cursor++;
|
|
2121
|
+
}
|
|
2122
|
+
if (replacementEnd === -1) break;
|
|
2123
|
+
const expression = nextCode.slice(exprStart, replacementEnd);
|
|
2124
|
+
nextCode = nextCode.slice(0, start) + expression + nextCode.slice(replacementEnd + 20);
|
|
2125
|
+
start = nextCode.indexOf(marker, start + expression.length);
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
nextCode = nextCode.replace(/import\s*["'][^"']*__loadShare__[^"']*["']\s*;?/g, "");
|
|
2129
|
+
nextCode = nextCode.replace(helperImportRegex, (statement, local) => {
|
|
2130
|
+
return new RegExp(`\\b${local}\\s*\\(`).test(nextCode.replace(statement, "")) ? statement : "";
|
|
2131
|
+
});
|
|
2132
|
+
return nextCode;
|
|
2133
|
+
}
|
|
2134
|
+
function isFederationControlChunk(fileName, filename) {
|
|
2135
|
+
return fileName.includes(filename) || FEDERATION_CONTROL_CHUNK_HINTS.some((hint) => fileName.includes(hint));
|
|
2136
|
+
}
|
|
2137
|
+
function sanitizeFederationControlChunk(code, fileName, filename) {
|
|
2138
|
+
let nextCode = stripEmptyPreloadCalls(code);
|
|
2139
|
+
if (fileName.includes("localSharedImportMap")) {
|
|
2140
|
+
const remoteEntryImportRegex = new RegExp(`import\\s*["'][^"']*${filename.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']\\s*;?`, "g");
|
|
2141
|
+
nextCode = nextCode.replace(remoteEntryImportRegex, "");
|
|
2142
|
+
}
|
|
2143
|
+
return nextCode;
|
|
2144
|
+
}
|
|
2145
|
+
//#endregion
|
|
1911
2146
|
//#region src/utils/normalizeOptimizeDeps.ts
|
|
1912
2147
|
var normalizeOptimizeDeps_default = {
|
|
1913
2148
|
name: "normalizeOptimizeDeps",
|
|
@@ -1936,6 +2171,8 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
1936
2171
|
enforce: "pre",
|
|
1937
2172
|
config(config, { command: _command }) {
|
|
1938
2173
|
const root = config.root || process.cwd();
|
|
2174
|
+
setPackageDetectionCwd(root);
|
|
2175
|
+
const isVinext = hasPackageDependency("vinext");
|
|
1939
2176
|
initVirtualModuleInfrastructure(root, virtualModuleDir);
|
|
1940
2177
|
VirtualModule.setRoot(root);
|
|
1941
2178
|
VirtualModule.ensureVirtualPackageExists();
|
|
@@ -1950,6 +2187,10 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
1950
2187
|
for (const key of Object.keys(shared)) {
|
|
1951
2188
|
if (key.endsWith("/")) continue;
|
|
1952
2189
|
const shareItem = shared[key];
|
|
2190
|
+
if (isVinext && key === "react") {
|
|
2191
|
+
addUsedShares(key);
|
|
2192
|
+
continue;
|
|
2193
|
+
}
|
|
1953
2194
|
getLoadShareModulePath(key, isRolldown);
|
|
1954
2195
|
writeLoadShareModule(key, shareItem, _command, isRolldown);
|
|
1955
2196
|
writePreBuildLibPath(key);
|
|
@@ -1963,6 +2204,7 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
1963
2204
|
}
|
|
1964
2205
|
function federation(mfUserOptions) {
|
|
1965
2206
|
const options = normalizeModuleFederationOptions(mfUserOptions);
|
|
2207
|
+
const isVinext = hasPackageDependency("vinext");
|
|
1966
2208
|
const { name, remotes, shared, filename, hostInitInjectLocation } = options;
|
|
1967
2209
|
if (!name) throw new Error("name is required");
|
|
1968
2210
|
const remoteEntryId = getRemoteEntryId(options);
|
|
@@ -1970,6 +2212,23 @@ function federation(mfUserOptions) {
|
|
|
1970
2212
|
let command;
|
|
1971
2213
|
return [
|
|
1972
2214
|
createEarlyVirtualModulesPlugin(options),
|
|
2215
|
+
...isVinext ? [{
|
|
2216
|
+
name: "module-federation-vinext-react-server-build-alias",
|
|
2217
|
+
apply: "build",
|
|
2218
|
+
enforce: "pre",
|
|
2219
|
+
resolveId(id) {
|
|
2220
|
+
const reactServerEntryMap = {
|
|
2221
|
+
"react/jsx-runtime": "react/cjs/react-jsx-runtime.production.js",
|
|
2222
|
+
"react/jsx-dev-runtime": "react/cjs/react-jsx-dev-runtime.production.js"
|
|
2223
|
+
};
|
|
2224
|
+
if (!(id in reactServerEntryMap)) return;
|
|
2225
|
+
const environmentName = this?.environment?.name;
|
|
2226
|
+
if (!environmentName || environmentName === "client") return;
|
|
2227
|
+
const target = reactServerEntryMap[id];
|
|
2228
|
+
const reactPackageJson = createRequire$1(new URL(`file://${process.cwd()}/package.json`)).resolve("react/package.json");
|
|
2229
|
+
return path.join(path.dirname(reactPackageJson), target.replace(/^react\//, ""));
|
|
2230
|
+
}
|
|
2231
|
+
}] : [],
|
|
1973
2232
|
{
|
|
1974
2233
|
name: "vite:module-federation-config",
|
|
1975
2234
|
enforce: "pre",
|
|
@@ -2021,9 +2280,19 @@ function federation(mfUserOptions) {
|
|
|
2021
2280
|
config(config) {
|
|
2022
2281
|
const runtimeInitId = virtualRuntimeInitStatus.getImportId();
|
|
2023
2282
|
config.build = config.build || {};
|
|
2024
|
-
config.build.
|
|
2025
|
-
|
|
2026
|
-
const
|
|
2283
|
+
if (config.build.modulePreload !== false) {
|
|
2284
|
+
const currentModulePreload = config.build.modulePreload && typeof config.build.modulePreload === "object" ? config.build.modulePreload : {};
|
|
2285
|
+
const existingResolveDependencies = currentModulePreload.resolveDependencies;
|
|
2286
|
+
config.build.modulePreload = {
|
|
2287
|
+
...currentModulePreload,
|
|
2288
|
+
resolveDependencies(filename, deps, context) {
|
|
2289
|
+
const resolvedDeps = existingResolveDependencies ? existingResolveDependencies(filename, deps, context) : deps;
|
|
2290
|
+
const hostFile = path.basename(context.hostId);
|
|
2291
|
+
return context.hostType === "js" && (hostFile === options.filename || hostFile.includes("hostInit") || hostFile.includes("virtualExposes") || hostFile.includes("localSharedImportMap")) ? [] : resolvedDeps;
|
|
2292
|
+
}
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
const applyManualChunks = (output) => {
|
|
2027
2296
|
const existingManualChunks = output.manualChunks;
|
|
2028
2297
|
output.manualChunks = function(id) {
|
|
2029
2298
|
if (id.includes(runtimeInitId)) return "runtimeInit";
|
|
@@ -2036,7 +2305,12 @@ function federation(mfUserOptions) {
|
|
|
2036
2305
|
for (const [key, ids] of Object.entries(existingManualChunks)) if (Array.isArray(ids) && ids.some((v) => id.includes(v))) return key;
|
|
2037
2306
|
}
|
|
2038
2307
|
};
|
|
2039
|
-
}
|
|
2308
|
+
};
|
|
2309
|
+
config.build.rollupOptions = config.build.rollupOptions || {};
|
|
2310
|
+
if (!Array.isArray(config.build.rollupOptions.output)) applyManualChunks(config.build.rollupOptions.output ||= {});
|
|
2311
|
+
const buildWithRolldown = config.build;
|
|
2312
|
+
buildWithRolldown.rolldownOptions = buildWithRolldown.rolldownOptions || {};
|
|
2313
|
+
if (!Array.isArray(buildWithRolldown.rolldownOptions.output)) applyManualChunks(buildWithRolldown.rolldownOptions.output ||= {});
|
|
2040
2314
|
},
|
|
2041
2315
|
load(id) {
|
|
2042
2316
|
if (id.startsWith("\0")) return;
|
|
@@ -2068,6 +2342,11 @@ function federation(mfUserOptions) {
|
|
|
2068
2342
|
}
|
|
2069
2343
|
},
|
|
2070
2344
|
generateBundle(_, bundle) {
|
|
2345
|
+
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
2346
|
+
if (chunk.type !== "chunk") continue;
|
|
2347
|
+
if (!isFederationControlChunk(fileName, filename)) continue;
|
|
2348
|
+
chunk.code = sanitizeFederationControlChunk(chunk.code, fileName, filename);
|
|
2349
|
+
}
|
|
2071
2350
|
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
2072
2351
|
if (chunk.type !== "chunk") continue;
|
|
2073
2352
|
if (fileName.includes("__loadShare__")) continue;
|
|
@@ -2105,12 +2384,12 @@ function federation(mfUserOptions) {
|
|
|
2105
2384
|
fileName
|
|
2106
2385
|
});
|
|
2107
2386
|
}
|
|
2108
|
-
if (proxyChunks.size
|
|
2109
|
-
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
2387
|
+
if (proxyChunks.size > 0) for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
2110
2388
|
if (chunk.type !== "chunk") continue;
|
|
2111
2389
|
if (fileName.includes("__loadShare__")) continue;
|
|
2112
2390
|
let code = chunk.code;
|
|
2113
2391
|
let modified = false;
|
|
2392
|
+
const claimedLocals = /* @__PURE__ */ new Set();
|
|
2114
2393
|
for (const [proxyFileName, proxyInfo] of proxyChunks) {
|
|
2115
2394
|
const proxyBaseName = proxyFileName.replace(/^.*\//, "").replace(/\.js$/, "").replace(/-[A-Za-z0-9_-]+$/, "");
|
|
2116
2395
|
const importMatch = new RegExp(`import\\s*\\{([^}]+)\\}\\s*from\\s*["']([^"']*${proxyBaseName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[^"']*)["']\\s*;?`).exec(code);
|
|
@@ -2133,9 +2412,12 @@ function federation(mfUserOptions) {
|
|
|
2133
2412
|
}
|
|
2134
2413
|
const inlineable = [];
|
|
2135
2414
|
const nonInlineable = [];
|
|
2415
|
+
const pendingLocals = new Set(bindings.map((binding) => binding.local));
|
|
2136
2416
|
for (const b of bindings) {
|
|
2417
|
+
pendingLocals.delete(b.local);
|
|
2137
2418
|
const proxyLocal = exportMap[b.imported];
|
|
2138
2419
|
if (!proxyLocal) {
|
|
2420
|
+
claimedLocals.add(b.local);
|
|
2139
2421
|
nonInlineable.push(b);
|
|
2140
2422
|
continue;
|
|
2141
2423
|
}
|
|
@@ -2157,7 +2439,14 @@ function federation(mfUserOptions) {
|
|
|
2157
2439
|
local: b.local,
|
|
2158
2440
|
funcBody: renamedFunc
|
|
2159
2441
|
});
|
|
2160
|
-
|
|
2442
|
+
claimedLocals.add(b.local);
|
|
2443
|
+
} else {
|
|
2444
|
+
const unavailableLocals = new Set(claimedLocals);
|
|
2445
|
+
pendingLocals.forEach((local) => unavailableLocals.add(local));
|
|
2446
|
+
const resolvedBinding = resolveProxyAlias(b, proxyLocal, code, fullImport, unavailableLocals);
|
|
2447
|
+
claimedLocals.add(resolvedBinding.local);
|
|
2448
|
+
nonInlineable.push(resolvedBinding);
|
|
2449
|
+
}
|
|
2161
2450
|
}
|
|
2162
2451
|
const hasRenamedAlias = nonInlineable.some((b) => bindings.find((ob) => ob.imported === b.imported)?.local !== b.local);
|
|
2163
2452
|
if (inlineable.length === 0 && !hasRenamedAlias) continue;
|
|
@@ -2171,6 +2460,28 @@ function federation(mfUserOptions) {
|
|
|
2171
2460
|
}
|
|
2172
2461
|
}
|
|
2173
2462
|
},
|
|
2463
|
+
{
|
|
2464
|
+
name: "module-federation-strip-empty-preload-helper",
|
|
2465
|
+
enforce: "post",
|
|
2466
|
+
apply: "build",
|
|
2467
|
+
renderChunk(code, chunk) {
|
|
2468
|
+
if (!isFederationControlChunk(chunk.fileName, filename)) return;
|
|
2469
|
+
const nextCode = sanitizeFederationControlChunk(code, chunk.fileName, filename);
|
|
2470
|
+
return nextCode === code ? null : {
|
|
2471
|
+
code: nextCode,
|
|
2472
|
+
map: null
|
|
2473
|
+
};
|
|
2474
|
+
},
|
|
2475
|
+
writeBundle(outputOptions, bundle) {
|
|
2476
|
+
if (!outputOptions.dir) return;
|
|
2477
|
+
for (const chunk of Object.values(bundle)) {
|
|
2478
|
+
if (chunk.type !== "chunk") continue;
|
|
2479
|
+
if (!isFederationControlChunk(chunk.fileName, filename)) continue;
|
|
2480
|
+
const outputPath = path.join(outputOptions.dir, chunk.fileName);
|
|
2481
|
+
writeFileSync(outputPath, sanitizeFederationControlChunk(readFileSync(outputPath, "utf-8"), chunk.fileName, filename));
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
},
|
|
2174
2485
|
{
|
|
2175
2486
|
name: "module-federation-dev-await-shared-init",
|
|
2176
2487
|
apply: "serve",
|
|
@@ -2205,7 +2516,7 @@ function federation(mfUserOptions) {
|
|
|
2205
2516
|
config(config, { command: _command }) {
|
|
2206
2517
|
const isRolldown = !!this?.meta?.rolldownVersion;
|
|
2207
2518
|
let implementation = options.implementation;
|
|
2208
|
-
if (isRolldown) implementation = implementation.replace(/\.cjs\.
|
|
2519
|
+
if (isRolldown) implementation = implementation.replace(/\.cjs(\.js)?$/, ".js");
|
|
2209
2520
|
config.resolve.alias.push({
|
|
2210
2521
|
find: "@module-federation/runtime",
|
|
2211
2522
|
replacement: implementation
|