@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 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 module$1 = require("module");
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(/.+?\:([/\\])[/\\]?/, "$1").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.replace("<head>", `<head><script type="module" src=${JSON.stringify(devEntryPath.replace(/.+?\:([/\\])[/\\]?/, "$1").replace(/\\\\?/g, "/"))}><\/script>`);
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
- (await loadWalk())(ast, { enter(node) {
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 = __mfproxy__awaitdefault;
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 = __mfproxy__awaitdefault;
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 = __mfproxy__awaitdefault;
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 = require.resolve(sharedName);
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 = require(potentialPackageJsonPath);
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 writeRuntimeInitStatus(command) {
901
- const globalKey = `__mf_init__${virtualRuntimeInitStatus.getImportId()}__`;
902
- const exportStatement = command === "build" ? `const { initPromise, initResolve, initReject } = globalThis[globalKey];
903
- export { initPromise, initResolve, initReject };` : `module.exports = globalThis[globalKey];`;
904
- virtualRuntimeInitStatus.writeSync(`
905
- const globalKey = ${JSON.stringify(globalKey)};
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 = useESM ? `import { initPromise } from "${virtualRuntimeInitStatus.getImportId()}"` : `const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")`;
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 = useESM ? `import { initPromise } from "${virtualRuntimeInitStatus.getImportId()}"` : `const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")`;
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 = ${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory))
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 prevSharedCount;
1194
+ let prevLocalSharedImportMapContent;
1037
1195
  function writeLocalSharedImportMap() {
1038
- const sharedCount = getUsedShares().size;
1039
- if (prevSharedCount !== sharedCount) {
1040
- prevSharedCount = sharedCount;
1041
- writeLocalSharedImportMap_temp(generateLocalSharedImportMap());
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("${getPreBuildLibImportId(pkg)}");
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 = {...res}
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
- import exposesMap from "${virtualExposesId}"
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 remoteEntryPromise = import("${remoteEntryId}")
1186
- // __tla only serves as a hack for vite-plugin-top-level-await.
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: localUsedInCode ? binding.local : proxyLocal
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.rollupOptions = config.build.rollupOptions || {};
2047
- if (!Array.isArray(config.build.rollupOptions.output)) {
2048
- const output = config.build.rollupOptions.output ||= {};
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 === 0) return;
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
- } else nonInlineable.push(resolveProxyAlias(b, proxyLocal, code, fullImport));
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\.cjs$/, ".esm.js");
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