@module-federation/vite 1.16.10 → 1.16.12

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/README.md CHANGED
@@ -6,6 +6,23 @@
6
6
 
7
7
  [Read the announcement](https://www.linkedin.com/posts/voidzero_github-module-federationvite-vite-plugin-activity-7449452398202241024-JyAL).
8
8
 
9
+ <div align="center">
10
+ <h2>Gold Sponsor</h2>
11
+ <a href="https://www.zephyr-cloud.io/">
12
+ <img src="./docs/sponsors/zephyr-logo.png" alt="Zephyr Cloud" width="360" />
13
+ </a>
14
+
15
+ <h3>Sponsors</h3>
16
+ <p>
17
+ <a href="https://github.com/thecoder93">
18
+ <img src="https://github.com/thecoder93.png?size=96" alt="thecoder93" width="64" height="64" />
19
+ </a>
20
+ <a href="https://github.com/stephanelgrg">
21
+ <img src="https://github.com/stephanelgrg.png?size=96" alt="stephanelgrg" width="64" height="64" />
22
+ </a>
23
+ </p>
24
+ </div>
25
+
9
26
  ## Reason why 🤔
10
27
 
11
28
  [Microservices](https://martinfowler.com/articles/microservices.html) nowadays is a well-known concept and maybe you are using it in your current company.
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { _ as mfWarn, a as getIsRolldown, c as getPackageNameFromNodeModulePath, d as isNuxtProjectRoot, f as packageNameDecode, g as createModuleFederationError, h as setPackageDetectionCwd, i as getInstalledPackageJson, l as getSharedCacheKey, m as resolveImportPath, o as getPackageDetectionCwd, p as packageNameEncode, r as getInstalledPackageEntry, s as getPackageName, u as hasPackageDependency, v as normalizePathForImport, y as rebaseImport } from "./pluginDts-CrSsDUnT.js";
1
+ import { _ as createModuleFederationError, a as getIsRolldown, b as rebaseImport, c as getPackageNameFromNodeModulePath, d as isNuxtProjectRoot, f as packageNameDecode, g as sharedCacheHelperCode, h as setPackageDetectionCwd, i as getInstalledPackageJson, l as getSharedCacheDescriptor, m as resolveImportPath, o as getPackageDetectionCwd, p as packageNameEncode, r as getInstalledPackageEntry, s as getPackageName, u as hasPackageDependency, v as mfWarn, y as normalizePathForImport } from "./pluginDts-CTAHkt4C.js";
2
2
  import { createRequire } from "node:module";
3
- import * as fs$1 from "fs";
3
+ import * as fs$2 from "fs";
4
4
  import { existsSync, readFileSync, realpathSync, statSync, writeFileSync } from "fs";
5
5
  import { createRequire as createRequire$1 } from "module";
6
6
  import * as path$1 from "node:path";
@@ -8,6 +8,7 @@ import path, { basename } from "node:path";
8
8
  import { fileURLToPath, pathToFileURL } from "url";
9
9
  import { version } from "vite";
10
10
  import { createHash } from "node:crypto";
11
+ import * as fs$1 from "node:fs";
11
12
  import { existsSync as existsSync$1, readFileSync as readFileSync$1 } from "node:fs";
12
13
  import { pathToFileURL as pathToFileURL$1 } from "node:url";
13
14
  //#region src/utils/codeRewriter.ts
@@ -360,7 +361,7 @@ function normalizeShared(shared) {
360
361
  const result = {};
361
362
  const packageJsonPath = path$1.join(getPackageDetectionCwd(), "package.json");
362
363
  try {
363
- const packageJson = JSON.parse(fs$1.readFileSync(packageJsonPath, "utf-8"));
364
+ const packageJson = JSON.parse(fs$2.readFileSync(packageJsonPath, "utf-8"));
364
365
  if (packageJson.name === "@module-federation/vite") return result;
365
366
  Object.keys(packageJson.dependencies || {}).filter((key) => shouldAutoShareDependency(key)).forEach((key) => {
366
367
  result[key] = normalizeShareItem(key, {
@@ -434,7 +435,7 @@ function resolveRuntimeImplementation() {
434
435
  const fallback = resolveImportPath("@module-federation/runtime");
435
436
  try {
436
437
  const packageJsonPath = resolveImportPath("@module-federation/runtime/package.json");
437
- const packageJson = JSON.parse(fs$1.readFileSync(packageJsonPath, "utf-8"));
438
+ const packageJson = JSON.parse(fs$2.readFileSync(packageJsonPath, "utf-8"));
438
439
  const importExport = packageJson.exports?.["."];
439
440
  const exportImport = typeof importExport === "object" ? typeof importExport.import === "string" ? importExport.import : importExport.import?.default : void 0;
440
441
  const esmEntry = packageJson.module || exportImport;
@@ -573,6 +574,27 @@ var VirtualModule = class VirtualModule {
573
574
  }
574
575
  };
575
576
  //#endregion
577
+ //#region src/utils/ssrCapabilities.ts
578
+ /** A browser-safe generated expression that is true only in Node.js. */
579
+ const SERVER_ENV_GUARD = "typeof process !== 'undefined' && !!process.versions && !!process.versions.node";
580
+ /**
581
+ * Single source of truth for SSR-related feature gates.
582
+ *
583
+ * - Vite 8+ dev: ModuleRunner + FetchableDevEnvironment for `/__mf_ssr__/` entries.
584
+ * - Any Vite major on build/preview: HTTP fetch + temp-file import via ssrEntryLoader.
585
+ */
586
+ function getSsrCapabilities(viteMajor, command, hasRemotes) {
587
+ if (!hasRemotes) return {
588
+ enableSsrInitBootstrap: false,
589
+ injectSsrEntryLoader: false
590
+ };
591
+ const supported = command === "build" || command === "serve" && viteMajor >= 8;
592
+ return {
593
+ enableSsrInitBootstrap: supported,
594
+ injectSsrEntryLoader: supported
595
+ };
596
+ }
597
+ //#endregion
576
598
  //#region src/utils/serializeRuntimeOptions.ts
577
599
  /**
578
600
  * Serializes a JavaScript object into a string of source code that can be evaluated.
@@ -722,7 +744,7 @@ function setSsrRemotes(remotes) {
722
744
  }
723
745
  function getSsrNoopResolveCode(enableSsrInit, hostInitImportId, initResolveExpression = "initResolve") {
724
746
  if (!enableSsrInit) return "";
725
- return `if (typeof window === 'undefined') {
747
+ return `if (${SERVER_ENV_GUARD}) {
726
748
  var _noop = { loadRemote: function() { return Promise.resolve(undefined); }, loadShare: function() { return Promise.resolve(undefined); } };
727
749
  ${hostInitImportId ? `import(${JSON.stringify(hostInitImportId)})
728
750
  .then(function(mod) { return mod.hostInitPromise; })
@@ -781,7 +803,7 @@ globalThis[globalKey] = {
781
803
  };
782
804
  }
783
805
  ${enableSsrInit ? `
784
- if (typeof window === 'undefined' && !globalThis[globalKey].ssrInitStarted) {
806
+ if (${SERVER_ENV_GUARD} && !globalThis[globalKey].ssrInitStarted) {
785
807
  globalThis[globalKey].ssrInitStarted = true;
786
808
  ${getSsrNoopResolveCode(enableSsrInit, hostInitImportId, "globalThis[globalKey].initResolve")}
787
809
  }` : ""}
@@ -862,6 +884,9 @@ function escapeGeneratedStringLiteral(value) {
862
884
  }
863
885
  });
864
886
  }
887
+ function getSharedCacheDescriptorLiteral(pkg, shareItem) {
888
+ return JSON.stringify(getSharedCacheDescriptor(pkg, shareItem));
889
+ }
865
890
  function isValidJsIdentifier(name) {
866
891
  return JS_IDENTIFIER_REGEX.test(name);
867
892
  }
@@ -1031,7 +1056,7 @@ function getSharedNamedExports(pkg, shareItem) {
1031
1056
  }
1032
1057
  function getLocalProviderImportPath(pkg) {
1033
1058
  try {
1034
- const resolved = createRequire$1(pathToFileURL(path$1.join(getPackageDetectionCwd(), "package.json"))).resolve(pkg);
1059
+ const resolved = resolveWorkspaceEsmEntry(pkg, createRequire$1(pathToFileURL(path$1.join(getPackageDetectionCwd(), "package.json"))).resolve(pkg));
1035
1060
  return isWorkspaceFilePath(resolved) ? resolved : void 0;
1036
1061
  } catch {
1037
1062
  const resolved = getInstalledPackageEntry(pkg, {
@@ -1052,7 +1077,7 @@ function getProjectResolvedImportPath(pkg) {
1052
1077
  if (esmEntry) return esmEntry;
1053
1078
  }
1054
1079
  try {
1055
- return createRequire$1(pathToFileURL(path$1.join(getPackageDetectionCwd(), "package.json"))).resolve(pkg);
1080
+ return resolveWorkspaceEsmEntry(pkg, createRequire$1(pathToFileURL(path$1.join(getPackageDetectionCwd(), "package.json"))).resolve(pkg));
1056
1081
  } catch {
1057
1082
  return;
1058
1083
  }
@@ -1065,6 +1090,30 @@ function isWorkspaceFilePath(resolved) {
1065
1090
  } catch {}
1066
1091
  return !realResolved.includes("/node_modules/") && !realResolved.includes("\\node_modules\\");
1067
1092
  }
1093
+ /**
1094
+ * When createRequire resolves a workspace package to a CJS entry (e.g. dist/index.cjs),
1095
+ * re-resolve via getInstalledPackageEntry with ESM-preferring conditions.
1096
+ *
1097
+ * Workspace packages produce browser code, so they must use the ESM build — CJS files
1098
+ * contain `module.exports` which is undefined in the browser. createRequire().resolve()
1099
+ * follows Node.js CJS conditions ["node", "require"], which matches exports["."].require.default
1100
+ * and returns the .cjs path for packages with dual ESM/CJS exports.
1101
+ */
1102
+ function resolveWorkspaceEsmEntry(pkg, resolved, cwd = getPackageDetectionCwd()) {
1103
+ if (!isWorkspaceFilePath(resolved)) return resolved;
1104
+ const esmEntry = getInstalledPackageEntry(pkg, {
1105
+ cwd,
1106
+ conditions: [
1107
+ "browser",
1108
+ "import",
1109
+ "module",
1110
+ "default"
1111
+ ],
1112
+ resolveSubpathWithRequire: false
1113
+ });
1114
+ if (esmEntry && isWorkspaceFilePath(esmEntry)) return esmEntry;
1115
+ return resolved;
1116
+ }
1068
1117
  function isWorkspacePackageEntry(pkg, resolved) {
1069
1118
  if (!resolved || !path$1.isAbsolute(resolved) || !isWorkspaceFilePath(resolved)) return false;
1070
1119
  return !!getInstalledPackageJson(pkg, {
@@ -1117,7 +1166,7 @@ function isWorkspaceSingletonConsumedByPeer(pkg) {
1117
1166
  }
1118
1167
  function tryResolveImportFromPackageRoot(pkg, root) {
1119
1168
  try {
1120
- return createRequire$1(pathToFileURL(path$1.join(root, "package.json"))).resolve(pkg);
1169
+ return resolveWorkspaceEsmEntry(pkg, createRequire$1(pathToFileURL(path$1.join(root, "package.json"))).resolve(pkg), root);
1121
1170
  } catch {
1122
1171
  return;
1123
1172
  }
@@ -1143,11 +1192,18 @@ function writePreBuildLibPath(pkg, shareItem) {
1143
1192
  preBuildShareItemMap[pkg] = shareItem;
1144
1193
  const importSource = getConcreteSharedImportSource(pkg, shareItem) || pkg;
1145
1194
  if (pkg === "react/compiler-runtime") {
1195
+ const reactCacheDescriptor = getSharedCacheDescriptorLiteral("react", shareItem ?? {
1196
+ name: "react",
1197
+ from: "",
1198
+ scope: "default",
1199
+ shareConfig: { singleton: true }
1200
+ });
1146
1201
  preBuildCacheMap[pkg].writeSync(`
1202
+ ${sharedCacheHelperCode}
1147
1203
  const __mfCacheGlobalKey = "__mf_module_cache__";
1148
1204
  export const c = function(size) {
1149
1205
  const cache = globalThis[__mfCacheGlobalKey]?.share;
1150
- const sharedReact = cache?.['react'];
1206
+ const sharedReact = cache && __mfReadSharedCache(cache, ${reactCacheDescriptor});
1151
1207
  const reactExports = sharedReact?.default ?? sharedReact;
1152
1208
  const internals = reactExports?.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
1153
1209
  return internals?.H?.useMemoCache(size);
@@ -1244,34 +1300,36 @@ function materializeCachedLoadShareModule(options) {
1244
1300
  options.addUsedShares(pkg);
1245
1301
  options.writeLocalSharedImportMap();
1246
1302
  }
1247
- function generateEagerWorkspaceSingletonExports(namedExports, importSource, cacheKey) {
1248
- const namedExportLine = namedExports.length > 0 ? `\n export { ${namedExports.join(", ")} } from ${escapeGeneratedStringLiteral(importSource)};` : "";
1303
+ function generateEagerWorkspaceSingletonExports(namedExports, importSource, cacheDescriptor) {
1304
+ const namedExportVars = namedExports.map((_name, i) => `__mf_${i}`);
1305
+ const namedExportAssignments = namedExports.length > 0 ? `\n ${namedExports.map((name, i) => `const ${namedExportVars[i]} = exportModule[${escapeGeneratedStringLiteral(name)}];`).join("\n ")}` : "";
1306
+ const namedExportLine = namedExports.length > 0 ? `\n export { ${namedExports.map((name, i) => `${namedExportVars[i]} as ${name}`).join(", ")} };` : "";
1249
1307
  return `import * as __mfLocalShare from ${escapeGeneratedStringLiteral(importSource)};
1250
- let exportModule = __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}];
1308
+ let exportModule = __mfReadSharedCache(__mfModuleCache.share, ${cacheDescriptor});
1251
1309
  if (exportModule === undefined) {
1252
1310
  Promise.resolve().then(() => {
1253
- if (__mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}] === undefined) {
1254
- __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}] = __mfNormalizeShareModule(__mfLocalShare);
1311
+ if (__mfReadSharedCache(__mfModuleCache.share, ${cacheDescriptor}) === undefined) {
1312
+ __mfWriteSharedCache(__mfModuleCache.share, ${cacheDescriptor}, __mfNormalizeShareModule(__mfLocalShare));
1255
1313
  }
1256
1314
  });
1257
1315
  exportModule = __mfLocalShare;
1258
1316
  }
1259
- const __mf_default = exportModule.default ?? exportModule;
1317
+ const __mf_default = exportModule.default ?? exportModule;${namedExportAssignments}
1260
1318
  export { __mf_default as default };${namedExportLine}`;
1261
1319
  }
1262
- function generateLazyWorkspaceSingletonExports(namedExports, importSource, cacheKey, eagerLocalFallback) {
1320
+ function generateLazyWorkspaceSingletonExports(namedExports, importSource, cacheDescriptor, eagerLocalFallback) {
1263
1321
  const namedExportVars = namedExports.map((_name, i) => `__mf_${i}`);
1264
1322
  const declarations = namedExports.length > 0 ? ["let __mf_default;", ...namedExportVars.map((name) => `let ${name};`)].join("\n ") : "let __mf_default;";
1265
1323
  const assignments = namedExports.length > 0 ? [...namedExports.map((name, i) => `${namedExportVars[i]} = mod[${escapeGeneratedStringLiteral(name)}];`), "__mf_default = mod.default ?? mod;"].join("\n ") : "__mf_default = mod.default ?? mod;";
1266
1324
  const namedExportLine = namedExports.length > 0 ? `\n export { ${namedExports.map((name, i) => `${namedExportVars[i]} as ${name}`).join(", ")} };` : "";
1267
1325
  const applyLocalFallback = `exportModule = __mfNormalizeShareModule(__mfLocalShare);
1268
- __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}] = exportModule;
1326
+ __mfWriteSharedCache(__mfModuleCache.share, ${cacheDescriptor}, exportModule);
1269
1327
  __mfApplyLazyShareExports(exportModule);`;
1270
1328
  const body = `${declarations}
1271
1329
  const __mfApplyLazyShareExports = (mod) => {
1272
1330
  ${assignments}
1273
1331
  };
1274
- let exportModule = __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}];
1332
+ let exportModule = __mfReadSharedCache(__mfModuleCache.share, ${cacheDescriptor});
1275
1333
  if (exportModule === undefined) {
1276
1334
  ${eagerLocalFallback ? applyLocalFallback : `if (import.meta.env.SSR) {
1277
1335
  ${applyLocalFallback}
@@ -1279,7 +1337,7 @@ function generateLazyWorkspaceSingletonExports(namedExports, importSource, cache
1279
1337
  initPromise.then(() =>
1280
1338
  import(${escapeGeneratedStringLiteral(importSource)}).then((mod) => {
1281
1339
  exportModule = __mfNormalizeShareModule(mod);
1282
- __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}] = exportModule;
1340
+ __mfWriteSharedCache(__mfModuleCache.share, ${cacheDescriptor}, exportModule);
1283
1341
  __mfApplyLazyShareExports(exportModule);
1284
1342
  })
1285
1343
  );
@@ -1301,19 +1359,16 @@ function prependWorkspaceSingletonSsrImport(code) {
1301
1359
  const quote = importMatch[1];
1302
1360
  return `import * as __mfLocalShare from ${quote}${importMatch[2]}${quote};\n${code}`;
1303
1361
  }
1304
- function generateDeferredHostProvidedExports(namedExports, pkg, cacheKey) {
1362
+ function generateDeferredHostProvidedExports(namedExports, pkg, cacheDescriptor) {
1305
1363
  const namedExportVars = namedExports.map((_name, i) => `__mf_${i}`);
1306
- const declarations = ["let __mf_default;", ...namedExportVars.map((name) => `let ${name};`)].join("\n ");
1307
- const assignments = [...namedExports.map((name, i) => `${namedExportVars[i]} = exportModule[${escapeGeneratedStringLiteral(name)}];`), "__mf_default = exportModule.default ?? exportModule;"].join("\n ");
1308
- const namedExportLine = namedExports.length > 0 ? `\n export { ${namedExports.map((name, i) => `${namedExportVars[i]} as ${name}`).join(", ")} };` : "";
1309
- return `${declarations}
1364
+ return `${["let __mf_default;", ...namedExportVars.map((name) => `let ${name};`)].join("\n ")}
1310
1365
  const __mfApplyHostProvidedExports = (exportModule) => {
1311
- ${assignments}
1366
+ ${[...namedExports.map((name, i) => `${namedExportVars[i]} = exportModule[${escapeGeneratedStringLiteral(name)}];`), "__mf_default = exportModule.default ?? exportModule;"].join("\n ")}
1312
1367
  };
1313
- let exportModule = __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}];
1368
+ let exportModule = __mfReadSharedCache(__mfModuleCache.share, ${cacheDescriptor});
1314
1369
  if (exportModule === undefined) {
1315
1370
  initPromise.then(() => {
1316
- exportModule = __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}];
1371
+ exportModule = __mfReadSharedCache(__mfModuleCache.share, ${cacheDescriptor});
1317
1372
  if (exportModule === undefined) {
1318
1373
  throw new Error("[Module Federation] Shared module ${pkg} was imported before federation bootstrap finished.");
1319
1374
  }
@@ -1322,7 +1377,7 @@ function generateDeferredHostProvidedExports(namedExports, pkg, cacheKey) {
1322
1377
  } else {
1323
1378
  __mfApplyHostProvidedExports(exportModule);
1324
1379
  }
1325
- export { __mf_default as default };${namedExportLine}`;
1380
+ export { __mf_default as default };${namedExports.length > 0 ? `\n export { ${namedExports.map((name, i) => `${namedExportVars[i]} as ${name}`).join(", ")} };` : ""}`;
1326
1381
  }
1327
1382
  function generateShareModuleUnwrapCode({ source, preserveNamedExports, stopWithReturn }) {
1328
1383
  return `let current = ${source};
@@ -1344,18 +1399,19 @@ const normalizeLocalShareModuleCode = `const __mfNormalizeShareModule = (mod) =>
1344
1399
  function writeLoadShareModule(pkg, shareItem, command, _isRolldown) {
1345
1400
  if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, ".js");
1346
1401
  let importLine = getRuntimeModuleCacheBootstrapCode();
1347
- const cacheKey = getSharedCacheKey(pkg, shareItem);
1402
+ const cacheDescriptor = getSharedCacheDescriptorLiteral(pkg, shareItem);
1348
1403
  if (shareItem.shareConfig.import === false) {
1349
1404
  const namedExports = getPackageNamedExports(pkg);
1350
1405
  let exportLine;
1351
- if (namedExports.length > 0) exportLine = generateDeferredHostProvidedExports(namedExports, pkg, cacheKey);
1406
+ if (namedExports.length > 0) exportLine = generateDeferredHostProvidedExports(namedExports, pkg, cacheDescriptor);
1352
1407
  else {
1353
1408
  mfWarn(`Shared dependency "${pkg}" has import: false but is not installed locally.\n Named imports (e.g. import { ... } from '${pkg}') will not work in production builds.\n Install it as a devDependency to enable named export detection.`);
1354
- exportLine = generateDeferredHostProvidedExports([], pkg, cacheKey);
1409
+ exportLine = generateDeferredHostProvidedExports([], pkg, cacheDescriptor);
1355
1410
  }
1356
1411
  loadShareCacheMap[pkg].writeSync(`
1357
1412
  ${getRuntimeInitPromiseBootstrapCode()}
1358
1413
  ${importLine}
1414
+ ${sharedCacheHelperCode}
1359
1415
  ${exportLine}
1360
1416
  `, true);
1361
1417
  return;
@@ -1372,10 +1428,10 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown) {
1372
1428
  const namedExports = getSharedNamedExports(pkg, shareItem);
1373
1429
  let exportLine;
1374
1430
  let initBlock = "";
1375
- if (usesEagerWorkspaceFallback) exportLine = generateEagerWorkspaceSingletonExports(namedExports, lazyLocalFallbackSource, cacheKey);
1431
+ if (usesEagerWorkspaceFallback) exportLine = generateEagerWorkspaceSingletonExports(namedExports, lazyLocalFallbackSource, cacheDescriptor);
1376
1432
  else if (isWorkspaceSingleton) {
1377
1433
  importLine = `${getRuntimeInitPromiseBootstrapCode()}\n ${importLine}`;
1378
- exportLine = generateLazyWorkspaceSingletonExports(namedExports, lazyLocalFallbackSource, cacheKey, command !== "build");
1434
+ exportLine = generateLazyWorkspaceSingletonExports(namedExports, lazyLocalFallbackSource, cacheDescriptor, command !== "build");
1379
1435
  } else if (namedExports.length > 0) {
1380
1436
  const destructure = `const { ${namedExports.map((name, i) => `${name}: __mf_${i}`).join(", ")} } = exportModule;`;
1381
1437
  const namedExportLine = `export { ${namedExports.map((name, i) => `__mf_${i} as ${name}`).join(", ")} };`;
@@ -1390,11 +1446,11 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown) {
1390
1446
  ${destructure}
1391
1447
  ${namedExportLine}`;
1392
1448
  initBlock = `exportModule = __mfNormalizeShareModule(__mfLocalShare);
1393
- __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}] = exportModule;`;
1449
+ __mfWriteSharedCache(__mfModuleCache.share, ${cacheDescriptor}, exportModule);`;
1394
1450
  } else {
1395
1451
  exportLine = `export default exportModule.default ?? exportModule\n export * from ${escapeGeneratedStringLiteral(sharedImportSource)}`;
1396
1452
  initBlock = `exportModule = __mfNormalizeShareModule(__mfLocalShare);
1397
- __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}] = exportModule;`;
1453
+ __mfWriteSharedCache(__mfModuleCache.share, ${cacheDescriptor}, exportModule);`;
1398
1454
  }
1399
1455
  const prebuildImportLine = isWorkspaceSingleton || isWorkspacePackage && command !== "build" ? "" : `import * as __mfLocalShare from ${escapeGeneratedStringLiteral(skipServePrebuildWarmup ? devImportSource : sharedImportSource)};`;
1400
1456
  const devDynamicImportLine = isWorkspacePackage ? "" : command !== "build" && !skipServePrebuildWarmup ? `;() => import(${escapeGeneratedStringLiteral(devImportSource)}).catch(() => {});` : "";
@@ -1402,14 +1458,16 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown) {
1402
1458
  ${prebuildImportLine}
1403
1459
  ${devDynamicImportLine}
1404
1460
  ${importLine}
1461
+ ${sharedCacheHelperCode}
1405
1462
  ${normalizeLocalShareModuleCode}
1406
1463
  ${exportLine}
1407
1464
  ` : `
1408
1465
  ${prebuildImportLine}
1409
1466
  ${devDynamicImportLine}
1410
1467
  ${importLine}
1468
+ ${sharedCacheHelperCode}
1411
1469
  ${normalizeLocalShareModuleCode}
1412
- let exportModule = __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}]
1470
+ let exportModule = __mfReadSharedCache(__mfModuleCache.share, ${cacheDescriptor})
1413
1471
  if (exportModule === undefined) {
1414
1472
  ${initBlock}
1415
1473
  }
@@ -1596,8 +1654,8 @@ function getShareItemForPreload(pkg) {
1596
1654
  if (isExplicitSharedKey(wildcardKey)) return shared[wildcardKey];
1597
1655
  }
1598
1656
  function generateSharedCacheSeedItem(pkg, shareItem, importPath) {
1599
- const cacheKey = getSharedCacheKey(pkg, shareItem);
1600
- return `if (__mfModuleCache.share[${JSON.stringify(cacheKey)}] === undefined) {
1657
+ const cacheDescriptor = getSharedCacheDescriptor(pkg, shareItem);
1658
+ return `if (__mfReadSharedCache(__mfModuleCache.share, ${JSON.stringify(cacheDescriptor)}) === undefined) {
1601
1659
  const mod = await import(${JSON.stringify(importPath)});
1602
1660
  ${normalizeRuntimeShareCode}
1603
1661
  const normalizedModule = __mfNormalizeRuntimeShare(mod);
@@ -1606,14 +1664,9 @@ function generateSharedCacheSeedItem(pkg, shareItem, importPath) {
1606
1664
  value: true,
1607
1665
  enumerable: false
1608
1666
  });
1609
- __mfModuleCache.share[${JSON.stringify(cacheKey)}] = exportModule;
1667
+ __mfWriteSharedCache(__mfModuleCache.share, ${JSON.stringify(cacheDescriptor)}, exportModule);
1610
1668
  }`;
1611
1669
  }
1612
- const sharedCacheKeyHelperCode = `const __mfGetSharedCacheKey = (pkg, singleton, version, scope) => {
1613
- const normalizedScope = Array.isArray(scope) ? scope[0] : scope;
1614
- const prefix = (normalizedScope || "default") + ":";
1615
- return singleton || !version ? prefix + pkg : prefix + pkg + "@" + version;
1616
- };`;
1617
1670
  const normalizeRuntimeShareCode = `const __mfNormalizeRuntimeShare = (mod) => {
1618
1671
  let current = mod;
1619
1672
  for (let i = 0; i < 5; i++) {
@@ -1767,7 +1820,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1767
1820
  }
1768
1821
 
1769
1822
  async function init(shared = {}, initScope = []) {
1770
- ${sharedCacheKeyHelperCode}
1823
+ ${sharedCacheHelperCode}
1771
1824
  const {usedShared, usedRemotes} = await getLocalSharedImportMap()
1772
1825
  try {
1773
1826
  const allInstances = globalThis.__FEDERATION__?.__SHARE__;
@@ -1786,16 +1839,16 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1786
1839
  : Object.entries(versionMap);
1787
1840
  for (const [version, provider] of providerEntries) {
1788
1841
  if (!provider.lib) continue;
1789
- const cacheKey = __mfGetSharedCacheKey(pkg, provider.shareConfig?.singleton, version, ${JSON.stringify(options.shareScope)});
1790
- if (__mfModuleCache.share[cacheKey] !== undefined) continue;
1842
+ const cacheDescriptor = __mfGetSharedCacheDescriptor(pkg, provider.shareConfig?.singleton, version, ${JSON.stringify(options.shareScope)});
1843
+ if (__mfReadSharedCache(__mfModuleCache.share, cacheDescriptor) !== undefined) continue;
1791
1844
  const mod = typeof provider.lib === "function" ? provider.lib() : provider.lib;
1792
1845
  const resolved = await Promise.resolve(mod);
1793
1846
  const normalized = __mfNormalizeRuntimeShare(resolved);
1794
- __mfModuleCache.share[cacheKey] = normalized;
1847
+ __mfWriteSharedCache(__mfModuleCache.share, cacheDescriptor, normalized);
1795
1848
  if (provider.shareConfig?.singleton && usedShare) {
1796
- const usedCacheKey = __mfGetSharedCacheKey(pkg, usedShare.shareConfig?.singleton, usedShare.version, usedShare.scope);
1797
- if (__mfModuleCache.share[usedCacheKey] === undefined) {
1798
- __mfModuleCache.share[usedCacheKey] = normalized;
1849
+ const usedCacheDescriptor = __mfGetSharedCacheDescriptor(pkg, usedShare.shareConfig?.singleton, usedShare.version, usedShare.scope);
1850
+ if (__mfReadSharedCache(__mfModuleCache.share, usedCacheDescriptor) === undefined) {
1851
+ __mfWriteSharedCache(__mfModuleCache.share, usedCacheDescriptor, normalized);
1799
1852
  }
1800
1853
  }
1801
1854
  }
@@ -1806,11 +1859,12 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1806
1859
  console.error('[Module Federation] Failed to bridge external shared modules', e)
1807
1860
  }
1808
1861
  for (const [pkg, share] of Object.entries(usedShared)) {
1809
- const cacheKey = __mfGetSharedCacheKey(pkg, share.shareConfig?.singleton, share.version, share.scope);
1810
- if (__mfModuleCache.share[cacheKey] !== undefined) continue;
1811
- const singletonCacheKey = __mfGetSharedCacheKey(pkg, true, share.version, share.scope);
1812
- if (__mfModuleCache.share[singletonCacheKey] !== undefined) {
1813
- __mfModuleCache.share[cacheKey] = __mfModuleCache.share[singletonCacheKey];
1862
+ const cacheDescriptor = __mfGetSharedCacheDescriptor(pkg, share.shareConfig?.singleton, share.version, share.scope);
1863
+ if (__mfReadSharedCache(__mfModuleCache.share, cacheDescriptor) !== undefined) continue;
1864
+ const singletonCacheDescriptor = __mfGetSharedCacheDescriptor(pkg, true, share.version, share.scope);
1865
+ const singletonModule = __mfReadSharedCache(__mfModuleCache.share, singletonCacheDescriptor);
1866
+ if (singletonModule !== undefined) {
1867
+ __mfWriteSharedCache(__mfModuleCache.share, cacheDescriptor, singletonModule);
1814
1868
  }
1815
1869
  }
1816
1870
  ${generateDirectSharedCacheSeedCode(command)}
@@ -1849,8 +1903,8 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1849
1903
  console.error('[Module Federation]', e)
1850
1904
  }
1851
1905
  for (const [pkg, share] of Object.entries(usedShared)) {
1852
- const cacheKey = __mfGetSharedCacheKey(pkg, share.shareConfig?.singleton, share.version, share.scope);
1853
- if (share.shareConfig?.import !== false || __mfModuleCache.share[cacheKey] !== undefined) continue;
1906
+ const cacheDescriptor = __mfGetSharedCacheDescriptor(pkg, share.shareConfig?.singleton, share.version, share.scope);
1907
+ if (share.shareConfig?.import !== false || __mfReadSharedCache(__mfModuleCache.share, cacheDescriptor) !== undefined) continue;
1854
1908
  ${normalizeRuntimeShareCode}
1855
1909
  const versions = shared?.[pkg];
1856
1910
  const provider = __mfSelectSharedProvider(versions, pkg, share, '${options.shareStrategy}');
@@ -1858,7 +1912,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1858
1912
  const factory = provider.lib || (provider.loading ? await provider.loading : await provider.get?.());
1859
1913
  const mod = typeof factory === "function" ? factory() : factory;
1860
1914
  const resolved = await Promise.resolve(mod);
1861
- __mfModuleCache.share[cacheKey] = __mfNormalizeRuntimeShare(resolved);
1915
+ __mfWriteSharedCache(__mfModuleCache.share, cacheDescriptor, __mfNormalizeRuntimeShare(resolved));
1862
1916
  }
1863
1917
  return initRes
1864
1918
  }
@@ -1885,16 +1939,16 @@ function generateHostAutoInitCode(remoteEntryImport, _command = "build") {
1885
1939
  async function initHost() {
1886
1940
  if (!hostInitPromise) {
1887
1941
  hostInitPromise = (async () => {
1942
+ ${sharedCacheHelperCode}
1888
1943
  ${generateHostAutoInitSharedCacheSeedCode(_command)}
1889
1944
  const remoteEntry = await import(${remoteEntryImport});
1890
1945
  const runtime = await remoteEntry.init();
1891
1946
  const usedShared = ${generateUsedSharedPreloadConfig()};
1892
- ${sharedCacheKeyHelperCode}
1893
1947
  ${normalizeRuntimeShareCode}
1894
1948
  ${shouldPreloadShares ? `
1895
1949
  for (const [pkg, share] of Object.entries(usedShared)) {
1896
- const cacheKey = __mfGetSharedCacheKey(pkg, share.shareConfig?.singleton, share.version, share.scope);
1897
- if (__mfModuleCache.share[cacheKey] !== undefined) {
1950
+ const cacheDescriptor = __mfGetSharedCacheDescriptor(pkg, share.shareConfig?.singleton, share.version, share.scope);
1951
+ if (__mfReadSharedCache(__mfModuleCache.share, cacheDescriptor) !== undefined) {
1898
1952
  continue;
1899
1953
  }
1900
1954
  await runtime.loadShare(pkg, {
@@ -1902,7 +1956,7 @@ function generateHostAutoInitCode(remoteEntryImport, _command = "build") {
1902
1956
  }).then((factory) => {
1903
1957
  const mod = typeof factory === "function" ? factory() : factory;
1904
1958
  return Promise.resolve(mod).then((resolved) => {
1905
- __mfModuleCache.share[cacheKey] = __mfNormalizeRuntimeShare(resolved);
1959
+ __mfWriteSharedCache(__mfModuleCache.share, cacheDescriptor, __mfNormalizeRuntimeShare(resolved));
1906
1960
  });
1907
1961
  });
1908
1962
  }
@@ -2162,7 +2216,7 @@ function generateRemotes(id, command, enableSsrInit = false, consumer = "unified
2162
2216
  const eagerLoadClientRemote = shouldEagerLoadClientRemoteInDev(command, enableSsrInit);
2163
2217
  const eagerClientInit = eagerLoadClientRemote ? getEagerDeferredClientInit() : deferredClientInit;
2164
2218
  const loadedFirstClientInit = eagerLoadClientRemote ? getEagerDeferredClientInit() : deferredClientInit;
2165
- const environmentSplitInit = (clientInit, serverInit) => consumer === "client" ? clientInit : consumer === "server" ? serverInit : `if (typeof window === "undefined") {
2219
+ const environmentSplitInit = (clientInit, serverInit) => consumer === "client" ? clientInit : consumer === "server" ? serverInit : `if (${SERVER_ENV_GUARD}) {
2166
2220
  ${serverInit}
2167
2221
  } else {
2168
2222
  ${clientInit}
@@ -2221,6 +2275,12 @@ function getFirstHtmlEntryFile(entryFiles) {
2221
2275
  function stripQueryAndHash(file) {
2222
2276
  return file.split(/[?#]/)[0];
2223
2277
  }
2278
+ function resolveDevHashEntryFileName(fileName) {
2279
+ if (!fileName.includes("[hash")) return fileName;
2280
+ const normalized = fileName.replace(/(?:[._-]?\[hash(?::\d+)?\])/g, "");
2281
+ const baseName = path$1.basename(normalized);
2282
+ return path$1.extname(baseName) ? normalized : `${normalized}.js`;
2283
+ }
2224
2284
  function getBuildInput(config) {
2225
2285
  return config.build?.rollupOptions?.input ?? config.build?.rolldownOptions?.input;
2226
2286
  }
@@ -2292,8 +2352,8 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
2292
2352
  });
2293
2353
  }
2294
2354
  function walkFiles(dir, predicate) {
2295
- if (!fs$1.existsSync(dir)) return [];
2296
- return fs$1.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
2355
+ if (!fs$2.existsSync(dir)) return [];
2356
+ return fs$2.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
2297
2357
  const entryPath = path$1.join(dir, entry.name);
2298
2358
  if (entry.isDirectory()) return walkFiles(entryPath, predicate);
2299
2359
  return entry.isFile() && predicate(entry.name) ? [entryPath] : [];
@@ -2309,17 +2369,17 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
2309
2369
  function patchSvelteKitStaticHtml() {
2310
2370
  const buildDir = path$1.resolve(viteConfig.root, "build");
2311
2371
  let initFile = emittedFileName ? path$1.resolve(buildDir, emittedFileName) : void 0;
2312
- if (!initFile || !fs$1.existsSync(initFile)) initFile = walkFiles(buildDir, (fileName) => fileName.endsWith(".js")).find((file) => {
2313
- const code = fs$1.readFileSync(file, "utf-8");
2372
+ if (!initFile || !fs$2.existsSync(initFile)) initFile = walkFiles(buildDir, (fileName) => fileName.endsWith(".js")).find((file) => {
2373
+ const code = fs$2.readFileSync(file, "utf-8");
2314
2374
  return code.includes("hostInitPromise") && code.includes("initHost");
2315
2375
  });
2316
2376
  if (!initFile) return false;
2317
2377
  let patched = false;
2318
2378
  for (const htmlFile of walkHtmlFiles(buildDir)) {
2319
- const html = fs$1.readFileSync(htmlFile, "utf-8");
2379
+ const html = fs$2.readFileSync(htmlFile, "utf-8");
2320
2380
  const rewritten = rewriteSvelteKitInlineStart(html, toRelativeImport(htmlFile, initFile));
2321
2381
  if (rewritten !== html) {
2322
- fs$1.writeFileSync(htmlFile, rewritten);
2382
+ fs$2.writeFileSync(htmlFile, rewritten);
2323
2383
  patched = true;
2324
2384
  }
2325
2385
  }
@@ -2396,8 +2456,8 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
2396
2456
  if (!entryFiles.includes(normalized)) entryFiles.push(normalized);
2397
2457
  }
2398
2458
  function addHtmlScriptEntries(htmlPath) {
2399
- if (!fs$1.existsSync(htmlPath)) return;
2400
- const htmlContent = fs$1.readFileSync(htmlPath, "utf-8");
2459
+ if (!fs$2.existsSync(htmlPath)) return;
2460
+ const htmlContent = fs$2.readFileSync(htmlPath, "utf-8");
2401
2461
  const scriptRegex = /<script\b(?=[^>]*\btype=["']module["'])(?=[^>]*\bsrc=["']([^"']+)["'])[^>]*>/gi;
2402
2462
  let match;
2403
2463
  while ((match = scriptRegex.exec(htmlContent)) !== null) {
@@ -2444,6 +2504,8 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
2444
2504
  next();
2445
2505
  return;
2446
2506
  }
2507
+ const devFileName = resolveDevHashEntryFileName(fileName);
2508
+ if (devFileName !== fileName && req.url?.startsWith((viteConfig.base + devFileName).replace(/^\/?/, "/"))) req.url = req.url.replace(devFileName, fileName);
2447
2509
  if (req.url && req.url.startsWith((viteConfig.base + fileName).replace(/^\/?/, "/"))) req.url = devEntryPath;
2448
2510
  next();
2449
2511
  });
@@ -2626,9 +2688,9 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
2626
2688
  const injection = `await import(${JSON.stringify(getEntryPath())}).then(({ initHost }) => initHost());\n `;
2627
2689
  return mapCodeToCodeWithSourcemap(code.replace("vueApp.mount(vueAppRootContainer);", `${injection}vueApp.mount(vueAppRootContainer);`));
2628
2690
  }
2629
- const isHydrationEntryFallback = inject === "entry" && entryFiles.length === 0 && (!htmlFilePath || !fs$1.existsSync(htmlFilePath)) && !clientInjected && !isFederationInternalVirtualId(id) && !id.includes("node_modules") && (id.startsWith("\0") || /\.(js|ts|mjs|vue|jsx|tsx)(\?|$)/.test(id)) && (/hydrateRoot|createRoot|ReactDOM\.render/.test(code) || /\.mount\s*\(\s*['"#]/.test(code) || /\.mount\s*\(/.test(code) && /createSSRApp|createApp/.test(code));
2691
+ const isHydrationEntryFallback = inject === "entry" && entryFiles.length === 0 && (!htmlFilePath || !fs$2.existsSync(htmlFilePath)) && !clientInjected && !isFederationInternalVirtualId(id) && !id.includes("node_modules") && (id.startsWith("\0") || /\.(js|ts|mjs|vue|jsx|tsx)(\?|$)/.test(id)) && (/hydrateRoot|createRoot|ReactDOM\.render/.test(code) || /\.mount\s*\(\s*['"#]/.test(code) || /\.mount\s*\(/.test(code) && /createSSRApp|createApp/.test(code));
2630
2692
  const isNuxtEntryAsyncModule = /(?:^|\/)nuxt\/dist\/app\/entry\.async\.js(?:\?|$)/.test(id) && code.includes("entry();");
2631
- const isNuxtClientEntryFallback = _command === "serve" && inject === "entry" && (!htmlFilePath || !fs$1.existsSync(htmlFilePath)) && !clientInjected && !hasEntryBootstrapParam(id) && !id.includes("node_modules/.vite") && isNuxtEntryAsyncModule && !entryFiles.some((file) => projectId === file);
2693
+ const isNuxtClientEntryFallback = _command === "serve" && inject === "entry" && (!htmlFilePath || !fs$2.existsSync(htmlFilePath)) && !clientInjected && !hasEntryBootstrapParam(id) && !id.includes("node_modules/.vite") && isNuxtEntryAsyncModule && !entryFiles.some((file) => projectId === file);
2632
2694
  if (!(_command === "serve" && isNuxtEntryAsyncModule) && (injectedTransformIds.has(projectId) || injectEntry() && entryFiles.some((file) => projectId === file) || _command === "serve" && inject === "html" && !isVinext && !clientInjected && !skipHtmlDevFallback && !id.startsWith("\0") && !id.includes("node_modules") && /\.(js|ts|mjs|vue|jsx|tsx)(\?|$)/.test(id) || isHydrationEntryFallback || isNuxtClientEntryFallback)) {
2633
2695
  clientInjected = true;
2634
2696
  injectedTransformIds.add(projectId);
@@ -3349,7 +3411,13 @@ function rewriteSystemProxyConsumers(code, systemProxyInfo) {
3349
3411
  return nextCode;
3350
3412
  }
3351
3413
  function findRemoteEntryFile(filename, bundle) {
3352
- for (const [_, fileData] of Object.entries(bundle)) if (filename.replace(/[\[\]]/g, "_").replace(/\.[^/.]+$/, "") === fileData.name || fileData.name === "remoteEntry") return fileData.fileName;
3414
+ const strippedName = filename.replace(/[\[\]]/g, "_").replace(/\.[^/.]+$/, "");
3415
+ let fallback;
3416
+ for (const fileData of Object.values(bundle)) {
3417
+ if (fileData.fileName === filename) return fileData.fileName;
3418
+ if (fallback === void 0 && (strippedName === fileData.name || fileData.name === "remoteEntry")) fallback = fileData.fileName;
3419
+ }
3420
+ return fallback;
3353
3421
  }
3354
3422
  //#endregion
3355
3423
  //#region src/utils/cssModuleHelpers.ts
@@ -3699,13 +3767,13 @@ const Manifest = () => {
3699
3767
  },
3700
3768
  configureServer(server) {
3701
3769
  server.middlewares.use((req, res, next) => {
3702
- if (!mfManifestName) {
3770
+ const devRemoteEntryFile = resolveDevRemoteEntryFileName(filename);
3771
+ if (devRemoteEntryFile !== filename && Object.keys(mfOptions.exposes).length > 0 && req.url?.startsWith((viteConfig.base + devRemoteEntryFile).replace(/^\/?/, "/"))) {
3772
+ req.url = req.url.replace(devRemoteEntryFile, filename);
3703
3773
  next();
3704
3774
  return;
3705
3775
  }
3706
- const devRemoteEntryFile = resolveDevRemoteEntryFileName(filename);
3707
- if (devRemoteEntryFile !== filename && req.url?.startsWith((viteConfig.base + devRemoteEntryFile).replace(/^\/?/, "/"))) {
3708
- req.url = req.url.replace(devRemoteEntryFile, filename);
3776
+ if (!mfManifestName) {
3709
3777
  next();
3710
3778
  return;
3711
3779
  }
@@ -3769,6 +3837,7 @@ const Manifest = () => {
3769
3837
  },
3770
3838
  async generateBundle(_options, bundle) {
3771
3839
  if (!mfManifestName) return;
3840
+ if (this.environment?.name === "ssr") return;
3772
3841
  let filesMap = {};
3773
3842
  const foundRemoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
3774
3843
  const expectedSsrRemoteEntryFile = getSsrRemoteEntryFileName(foundRemoteEntryFile || mfOptions.filename);
@@ -4131,25 +4200,6 @@ function resolveRemoteConsumer(ctx, hasMultiEnvironment) {
4131
4200
  return "server";
4132
4201
  }
4133
4202
  //#endregion
4134
- //#region src/utils/ssrCapabilities.ts
4135
- /**
4136
- * Single source of truth for SSR-related feature gates.
4137
- *
4138
- * - Vite 8+ dev: ModuleRunner + FetchableDevEnvironment for `/__mf_ssr__/` entries.
4139
- * - Any Vite major on build/preview: HTTP fetch + temp-file import via ssrEntryLoader.
4140
- */
4141
- function getSsrCapabilities(viteMajor, command, hasRemotes) {
4142
- if (!hasRemotes) return {
4143
- enableSsrInitBootstrap: false,
4144
- injectSsrEntryLoader: false
4145
- };
4146
- const supported = command === "build" || command === "serve" && viteMajor >= 8;
4147
- return {
4148
- enableSsrInitBootstrap: supported,
4149
- injectSsrEntryLoader: supported
4150
- };
4151
- }
4152
- //#endregion
4153
4203
  //#region src/plugins/pluginProxyRemotes.ts
4154
4204
  function isNodeModulesImporter(importer) {
4155
4205
  return importer?.includes("/node_modules/") || importer?.includes("\\node_modules\\");
@@ -4482,7 +4532,6 @@ function proxySharedModule(options) {
4482
4532
  //#endregion
4483
4533
  //#region src/plugins/pluginRemoteNamedExports.ts
4484
4534
  const JS_EXTENSIONS_RE = /\.(?:[mc]?[jt]sx?|vue|svelte)(?:\?|$)/;
4485
- const REGEX_FALLBACK_EXTENSIONS_RE = /\.(?:[mc]?[jt]sx?)(?:\?|$)/;
4486
4535
  function isAstNode(value) {
4487
4536
  return !!value && typeof value === "object" && typeof value.type === "string";
4488
4537
  }
@@ -4679,10 +4728,12 @@ async function collectFromAST(ast, code, isRemoteImport) {
4679
4728
  }
4680
4729
  function collectFromRegex(code, isRemoteImport) {
4681
4730
  const result = [];
4731
+ const codePositions = createCodePositionMap(code);
4682
4732
  const importAttributes = String.raw`(?:\s+(?:with|assert)\s+\{[^;]*\})?`;
4683
4733
  const staticRe = new RegExp(String.raw`^\s*import\s+([\s\S]*?)\s+from\s+(['"])([^'"]+)\2${importAttributes}\s*;?`, "gm");
4684
4734
  for (const match of code.matchAll(staticRe)) {
4685
4735
  const [full, specifiersPartRaw, , source] = match;
4736
+ if (!codePositions[match.index]) continue;
4686
4737
  if (!isRemoteImport(source)) continue;
4687
4738
  const specifiersPart = specifiersPartRaw.trim();
4688
4739
  if (/^type\s/.test(specifiersPart)) continue;
@@ -4715,6 +4766,7 @@ function collectFromRegex(code, isRemoteImport) {
4715
4766
  const reexportRe = new RegExp(String.raw`^\s*export\s+\{([\s\S]*?)\}\s+from\s+(['"])([^'"]+)\2${importAttributes}\s*;?`, "gm");
4716
4767
  for (const match of code.matchAll(reexportRe)) {
4717
4768
  const [full, specifiersRaw, , source] = match;
4769
+ if (!codePositions[match.index]) continue;
4718
4770
  if (!isRemoteImport(source)) continue;
4719
4771
  const specifiers = parseNamedSpecifiers(specifiersRaw, "export");
4720
4772
  if (specifiers.length === 0) continue;
@@ -4729,6 +4781,7 @@ function collectFromRegex(code, isRemoteImport) {
4729
4781
  const exportAllRe = new RegExp(String.raw`^\s*export\s+\*\s+from\s+(['"])([^'"]+)\1${importAttributes}\s*;?`, "gm");
4730
4782
  for (const match of code.matchAll(exportAllRe)) {
4731
4783
  const [full, , source] = match;
4784
+ if (!codePositions[match.index]) continue;
4732
4785
  if (!isRemoteImport(source)) continue;
4733
4786
  result.push({
4734
4787
  kind: "export-all",
@@ -4739,6 +4792,7 @@ function collectFromRegex(code, isRemoteImport) {
4739
4792
  }
4740
4793
  for (const match of code.matchAll(/import\(\s*(?:\/\*[\s\S]*?\*\/\s*)?(['"])([^'"]+)\1\s*\)/g)) {
4741
4794
  const [full, , source] = match;
4795
+ if (!codePositions[match.index]) continue;
4742
4796
  if (!isRemoteImport(source)) continue;
4743
4797
  result.push({
4744
4798
  kind: "dynamic",
@@ -4749,6 +4803,50 @@ function collectFromRegex(code, isRemoteImport) {
4749
4803
  }
4750
4804
  return result.length > 0 ? result : void 0;
4751
4805
  }
4806
+ function createCodePositionMap(code) {
4807
+ const positions = Array(code.length).fill(true);
4808
+ function mask(start, end) {
4809
+ for (let i = start; i < end; i++) positions[i] = false;
4810
+ }
4811
+ for (let i = 0; i < code.length;) {
4812
+ const char = code[i];
4813
+ const next = code[i + 1];
4814
+ if (char === "/" && next === "/") {
4815
+ const start = i;
4816
+ i += 2;
4817
+ while (i < code.length && code[i] !== "\n" && code[i] !== "\r") i++;
4818
+ mask(start, i);
4819
+ continue;
4820
+ }
4821
+ if (char === "/" && next === "*") {
4822
+ const start = i;
4823
+ i += 2;
4824
+ while (i < code.length && !(code[i] === "*" && code[i + 1] === "/")) i++;
4825
+ i = Math.min(code.length, i + 2);
4826
+ mask(start, i);
4827
+ continue;
4828
+ }
4829
+ if (char === "\"" || char === "'" || char === "`") {
4830
+ const quote = char;
4831
+ const start = i++;
4832
+ while (i < code.length) {
4833
+ if (code[i] === "\\") {
4834
+ i += 2;
4835
+ continue;
4836
+ }
4837
+ if (code[i] === quote) {
4838
+ i++;
4839
+ break;
4840
+ }
4841
+ i++;
4842
+ }
4843
+ mask(start, i);
4844
+ continue;
4845
+ }
4846
+ i++;
4847
+ }
4848
+ return positions;
4849
+ }
4752
4850
  function pluginRemoteNamedExports(options) {
4753
4851
  const remoteNames = Object.keys(options.remotes);
4754
4852
  const isNodeModulesId = (id) => id.includes("/node_modules/") || id.includes("\\node_modules\\");
@@ -4775,7 +4873,6 @@ function pluginRemoteNamedExports(options) {
4775
4873
  if ((id.includes(".vue") || id.includes(".svelte")) && /^\s*</.test(code)) return;
4776
4874
  imports = collectFromRegex(code, matchesRemoteImport);
4777
4875
  }
4778
- if ((!imports || imports.length === 0) && REGEX_FALLBACK_EXTENSIONS_RE.test(id)) imports = collectFromRegex(code, matchesRemoteImport);
4779
4876
  if (!imports) return;
4780
4877
  return applyRewrites(code, imports, id);
4781
4878
  }
@@ -4800,6 +4897,9 @@ function pluginSSRRemoteEntry(options) {
4800
4897
  const virtualExposesSSRId = getVirtualExposesSSRId(options);
4801
4898
  let isRolldown = false;
4802
4899
  let ssrOutputFilename = "";
4900
+ let ssrOutputFiles = /* @__PURE__ */ new Set();
4901
+ let ssrOutputDir = "";
4902
+ let clientOutputDir = "";
4803
4903
  const ssrOnlyExternals = [
4804
4904
  "@module-federation/runtime",
4805
4905
  "@module-federation/runtime-core",
@@ -4851,6 +4951,7 @@ function pluginSSRRemoteEntry(options) {
4851
4951
  }
4852
4952
  }, {
4853
4953
  name: "mf:ssr-remote-entry",
4954
+ sharedDuringBuild: true,
4854
4955
  configResolved(config) {
4855
4956
  viteConfig = config;
4856
4957
  isNuxtProject = isNuxtProjectRoot(config.root);
@@ -4980,11 +5081,62 @@ function pluginSSRRemoteEntry(options) {
4980
5081
  const exposesChunk = findNuxtExposesChunk(bundle);
4981
5082
  const ssrAsset = bundle[ssrOutputFilename];
4982
5083
  if (exposesChunk && ssrAsset?.type === "asset" && typeof ssrAsset.source === "string") ssrAsset.source = ssrAsset.source.replace(/import\("virtual:mf-exposes-ssr:[^"]+"\)/g, `import("./${exposesChunk}")`);
5084
+ if (this.environment?.name === "ssr") ssrOutputFiles = collectEntryOutputFiles(bundle, ssrOutputFilename);
4983
5085
  if (!isRolldown) return;
4984
5086
  const chunk = bundle[ssrOutputFilename];
4985
5087
  if (!chunk || chunk.type !== "chunk") return;
5088
+ },
5089
+ writeBundle(outputOptions) {
5090
+ const environmentName = this.environment?.name;
5091
+ if (environmentName === "ssr" && outputOptions.dir) ssrOutputDir = outputOptions.dir;
5092
+ else if (environmentName === "client" && outputOptions.dir) clientOutputDir = outputOptions.dir;
5093
+ publishSsrOutputFiles(ssrOutputDir, clientOutputDir || viteConfig?.environments?.client?.build?.outDir);
4986
5094
  }
4987
5095
  }];
5096
+ function publishSsrOutputFiles(ssrOutDir, clientOutDir) {
5097
+ if (ssrOutputFiles.size === 0 || !ssrOutDir || !clientOutDir) return;
5098
+ const root = viteConfig?.root ?? process.cwd();
5099
+ const ssrDir = path$1.resolve(root, ssrOutDir);
5100
+ const clientDir = path$1.resolve(root, clientOutDir);
5101
+ if (ssrDir === clientDir || !fs$1.existsSync(ssrDir)) return;
5102
+ fs$1.mkdirSync(clientDir, { recursive: true });
5103
+ for (const fileName of ssrOutputFiles) {
5104
+ const source = path$1.resolve(ssrDir, fileName);
5105
+ const destination = path$1.resolve(clientDir, fileName);
5106
+ if (!isWithinDirectory(source, ssrDir) || !isWithinDirectory(destination, clientDir)) continue;
5107
+ if (!fs$1.existsSync(source) || fs$1.existsSync(destination)) continue;
5108
+ fs$1.mkdirSync(path$1.dirname(destination), { recursive: true });
5109
+ fs$1.copyFileSync(source, destination);
5110
+ }
5111
+ }
5112
+ }
5113
+ const RELATIVE_IMPORT_RE = /(?:\bfrom|\bimport\s*(?:\(\s*)?|\bexport\s*\*\s*from)\s*["'`](\.\.?\/[^"'`]+)["'`]/g;
5114
+ function collectEntryOutputFiles(bundle, entryFileName) {
5115
+ const files = /* @__PURE__ */ new Set();
5116
+ const visit = (fileName) => {
5117
+ if (files.has(fileName)) return;
5118
+ const file = bundle[fileName];
5119
+ if (!file) return;
5120
+ files.add(fileName);
5121
+ const dependencies = new Set([
5122
+ ...file.imports || [],
5123
+ ...file.dynamicImports || [],
5124
+ ...file.implicitlyLoadedBefore || [],
5125
+ ...file.referencedFiles || []
5126
+ ]);
5127
+ const source = typeof file.code === "string" ? file.code : typeof file.source === "string" ? file.source : "";
5128
+ if (source) {
5129
+ const directory = path$1.posix.dirname(fileName);
5130
+ for (const match of source.matchAll(RELATIVE_IMPORT_RE)) dependencies.add(path$1.posix.normalize(path$1.posix.join(directory, match[1])));
5131
+ }
5132
+ for (const dependency of dependencies) visit(dependency);
5133
+ };
5134
+ visit(entryFileName);
5135
+ return files;
5136
+ }
5137
+ function isWithinDirectory(filePath, directory) {
5138
+ const relative = path$1.relative(directory, filePath);
5139
+ return relative !== "" && !relative.startsWith(`..${path$1.sep}`) && relative !== "..";
4988
5140
  }
4989
5141
  //#endregion
4990
5142
  //#region src/plugins/pluginVarRemoteEntry.ts
@@ -5180,18 +5332,21 @@ function normalizeVinextRscPreloadHints(code) {
5180
5332
  }
5181
5333
  function ignoreFederationGeneratedFiles(config, options) {
5182
5334
  config.server ??= {};
5183
- config.server.watch ??= {};
5335
+ const watch = config.server.watch;
5336
+ if (watch === false || watch === null) return;
5337
+ const watchOptions = watch === true || watch === void 0 ? {} : watch;
5338
+ config.server.watch = watchOptions;
5184
5339
  const federationIgnore = (file) => shouldIgnoreFile(file, options);
5185
- const ignored = config.server.watch.ignored;
5340
+ const ignored = watchOptions.ignored;
5186
5341
  if (!ignored) {
5187
- config.server.watch.ignored = federationIgnore;
5342
+ watchOptions.ignored = federationIgnore;
5188
5343
  return;
5189
5344
  }
5190
5345
  if (Array.isArray(ignored)) {
5191
5346
  ignored.push(federationIgnore);
5192
5347
  return;
5193
5348
  }
5194
- config.server.watch.ignored = [ignored, federationIgnore];
5349
+ watchOptions.ignored = [ignored, federationIgnore];
5195
5350
  }
5196
5351
  function isSharedResolverInternalImporter(importer) {
5197
5352
  return !!importer && (importer.includes("__loadShare__") || importer.includes("__prebuild__"));
@@ -5303,14 +5458,32 @@ function createEarlyVirtualModulesPlugin(options) {
5303
5458
  optimizeDeps.rolldownOptions.plugins ??= [];
5304
5459
  optimizeDeps.rolldownOptions.plugins.push({
5305
5460
  name: "module-federation:optimize-shared-resolver",
5461
+ load(id) {
5462
+ if (id !== "module-federation:optimized-require-react") return;
5463
+ const optimizedLoadSharePath = toViteOptimizedDepVirtualId(getLoadShareModulePath("react", isRolldown));
5464
+ const source = JSON.stringify(optimizedLoadSharePath);
5465
+ return "import * as __mfShared from " + source + ";\nexport * from " + source + ";\nexport default __mfShared.default ?? __mfShared;";
5466
+ },
5306
5467
  resolveId(source, importer, options) {
5307
- if (options?.kind?.startsWith("require")) return;
5468
+ if (createViteEncodedIdPrefixRegExp("virtual:mf:").test(source)) return {
5469
+ id: source,
5470
+ external: true
5471
+ };
5308
5472
  if (isSharedResolverInternalImporter(importer)) return;
5309
- if (isCommonJsImporter(importer)) return;
5310
5473
  const key = findSharedKey(source, shared);
5311
5474
  if (!key) return;
5312
5475
  if (source.endsWith(".css")) return;
5313
5476
  const shareItem = shared[key];
5477
+ const isReactSingleton = source === "react" && key === "react" && shareItem.shareConfig?.singleton === true;
5478
+ const isReactRequire = options?.kind?.startsWith("require") && isReactSingleton;
5479
+ if (options?.kind?.startsWith("require") && !isReactSingleton) return;
5480
+ if (isCommonJsImporter(importer) && !isReactSingleton) return;
5481
+ if (isReactRequire) {
5482
+ writeLoadShareModule(source, shareItem, _command, isRolldown);
5483
+ if (shareItem.shareConfig?.import !== false) writePreBuildLibPath(source, shareItem);
5484
+ addUsedShares(source);
5485
+ return { id: "module-federation:optimized-require-react" };
5486
+ }
5314
5487
  const loadSharePath = getLoadShareModulePath(source, isRolldown);
5315
5488
  writeLoadShareModule(source, shareItem, _command, isRolldown);
5316
5489
  if (shareItem.shareConfig?.import !== false) writePreBuildLibPath(source, shareItem);
@@ -5391,7 +5564,7 @@ export default __mfShared.default ?? __mfShared;`
5391
5564
  const optimizeDeps = config.optimizeDeps ??= {};
5392
5565
  optimizeDeps.include ??= [];
5393
5566
  optimizeDeps.exclude ??= [];
5394
- const shouldBypassOptimizeDep = isLitShare(key) || key === "react" && hasPackageDependency("react-redux", root);
5567
+ const shouldBypassOptimizeDep = isLitShare(key) || key === "react" && shareItem.shareConfig?.singleton === true;
5395
5568
  if (optimizeDeps.include.includes(key)) optimizeDeps.exclude = optimizeDeps.exclude.filter((dep) => dep !== key);
5396
5569
  else if (shouldBypassOptimizeDep) optimizeDeps.exclude.push(key);
5397
5570
  else optimizeDeps.include.push(key);
@@ -5446,7 +5619,7 @@ export default __mfShared.default ?? __mfShared;`
5446
5619
  const SSR_ONLY_PLUGINS = new Set(["@module-federation/vite/ssrEntryLoader"]);
5447
5620
  function loadPluginDts(options) {
5448
5621
  if (options.dts === false) return [];
5449
- return [import("./pluginDts-CrSsDUnT.js").then((n) => n.n).then(({ default: pluginDts }) => pluginDts(options))];
5622
+ return [import("./pluginDts-CTAHkt4C.js").then((n) => n.n).then(({ default: pluginDts }) => pluginDts(options))];
5450
5623
  }
5451
5624
  function federation(mfUserOptions) {
5452
5625
  if (isTestEnv()) return [];
@@ -193,10 +193,56 @@ function getPackageNameFromNodeModulePath(source) {
193
193
  if (parts[0].startsWith("@")) return parts[1] ? `${parts[0]}/${parts[1]}` : void 0;
194
194
  return parts[0];
195
195
  }
196
- function getSharedCacheKey(pkg, shareItem) {
197
- const prefix = `${shareItem.scope || "default"}:`;
198
- return shareItem.shareConfig.singleton || !shareItem.version ? `${prefix}${pkg}` : `${prefix}${pkg}@${shareItem.version}`;
196
+ function getSharedCacheKeyParts(input) {
197
+ const scope = (Array.isArray(input.scope) ? input.scope[0] : input.scope) || "default";
198
+ const id = input.singleton || !input.version ? input.pkg : `${input.pkg}@${input.version}`;
199
+ return {
200
+ scope,
201
+ id,
202
+ key: `${scope}:${id}`
203
+ };
204
+ }
205
+ function getSharedCacheDescriptor(pkg, shareItem) {
206
+ const parts = getSharedCacheKeyParts({
207
+ pkg,
208
+ singleton: shareItem.shareConfig.singleton,
209
+ version: shareItem.version,
210
+ scope: shareItem.scope
211
+ });
212
+ return {
213
+ canonical: parts.key,
214
+ ...parts.scope === "default" ? { aliases: [parts.id] } : {}
215
+ };
199
216
  }
217
+ const sharedCacheHelperCode = `const __mfGetSharedCacheDescriptor = (pkg, singleton, version, scope) => {
218
+ const normalizedScope = Array.isArray(scope) ? scope[0] : scope;
219
+ const scopeName = normalizedScope || "default";
220
+ const id = singleton || !version ? pkg : pkg + "@" + version;
221
+ const descriptor = { canonical: scopeName + ":" + id };
222
+ if (scopeName === "default") descriptor.aliases = [id];
223
+ return descriptor;
224
+ };
225
+ const __mfReadSharedCache = (cache, descriptor) => {
226
+ const value = cache[descriptor.canonical];
227
+ if (value !== undefined) return value;
228
+ const aliases = descriptor.aliases || [];
229
+ for (const alias of aliases) {
230
+ const aliasValue = cache[alias];
231
+ if (aliasValue !== undefined) {
232
+ cache[descriptor.canonical] = aliasValue;
233
+ return aliasValue;
234
+ }
235
+ }
236
+ return undefined;
237
+ };
238
+ const __mfWriteSharedCache = (cache, descriptor, value) => {
239
+ cache[descriptor.canonical] = value;
240
+ const aliases = descriptor.aliases || [];
241
+ for (const alias of aliases) {
242
+ if (cache[alias] === undefined) cache[alias] = value;
243
+ }
244
+ return value;
245
+ };`;
200
246
  function getInstalledPackageJson(pkg, opts) {
201
247
  const cwd = opts?.cwd || getPackageDetectionCwd();
202
248
  const packageName = opts?.packageName || getPackageName(pkg);
@@ -630,4 +676,4 @@ function pluginDts(options) {
630
676
  }];
631
677
  }
632
678
  //#endregion
633
- export { mfWarn as _, getIsRolldown as a, getPackageNameFromNodeModulePath as c, isNuxtProjectRoot as d, packageNameDecode as f, createModuleFederationError as g, setPackageDetectionCwd as h, getInstalledPackageJson as i, getSharedCacheKey as l, resolveImportPath as m, pluginDts_exports as n, getPackageDetectionCwd as o, packageNameEncode as p, getInstalledPackageEntry as r, getPackageName as s, DEFAULT_PUBLIC_TYPES_FOLDER as t, hasPackageDependency as u, normalizePathForImport as v, rebaseImport as y };
679
+ export { createModuleFederationError as _, getIsRolldown as a, rebaseImport as b, getPackageNameFromNodeModulePath as c, isNuxtProjectRoot as d, packageNameDecode as f, sharedCacheHelperCode as g, setPackageDetectionCwd as h, getInstalledPackageJson as i, getSharedCacheDescriptor as l, resolveImportPath as m, pluginDts_exports as n, getPackageDetectionCwd as o, packageNameEncode as p, getInstalledPackageEntry as r, getPackageName as s, DEFAULT_PUBLIC_TYPES_FOLDER as t, hasPackageDependency as u, mfWarn as v, normalizePathForImport as y };
@@ -8,7 +8,7 @@
8
8
  * `loadScriptNode` — if the hook returns a value, the runtime uses it directly.
9
9
  *
10
10
  * Strategy:
11
- * - In Node (typeof window === 'undefined'), fetch the remote's mf-manifest.json
11
+ * - In Node (detected through process.versions.node), fetch the remote's mf-manifest.json
12
12
  * to discover the ssrRemoteEntry URL and its type.
13
13
  * - ESM entry: use a dynamic `import()` — the SSR entry has no browser
14
14
  * globals and all shared packages are external.
@@ -8,7 +8,7 @@
8
8
  * `loadScriptNode` — if the hook returns a value, the runtime uses it directly.
9
9
  *
10
10
  * Strategy:
11
- * - In Node (typeof window === 'undefined'), fetch the remote's mf-manifest.json
11
+ * - In Node (detected through process.versions.node), fetch the remote's mf-manifest.json
12
12
  * to discover the ssrRemoteEntry URL and its type.
13
13
  * - ESM entry: use a dynamic `import()` — the SSR entry has no browser
14
14
  * globals and all shared packages are external.
@@ -34,6 +34,7 @@ async function nodeImport(id) {
34
34
  ));
35
35
  return importCache.get(id);
36
36
  }
37
+ const isNodeServer = () => typeof globalThis.process?.versions?.node === "string";
37
38
  const runnerCache = /* @__PURE__ */ new Map();
38
39
  /**
39
40
  * Import `vite/module-runner` dynamically. Returns null on Vite < 8 where the
@@ -362,7 +363,7 @@ function ssrEntryLoaderPlugin(options = {}) {
362
363
  return {
363
364
  name: "mf-vite:ssr-entry-loader",
364
365
  async loadEntry({ remoteInfo }) {
365
- if (typeof globalThis.window !== "undefined") return;
366
+ if (!isNodeServer()) return;
366
367
  const ssrEntry = await getSSREntry(remoteInfo.entry);
367
368
  if (!ssrEntry) return;
368
369
  const mod = await loadSSRRemoteEntry(ssrEntry, resolvedShared);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/vite",
3
- "version": "1.16.10",
3
+ "version": "1.16.12",
4
4
  "description": "Vite plugin for Module Federation",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -70,9 +70,9 @@
70
70
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
71
71
  },
72
72
  "dependencies": {
73
- "@module-federation/dts-plugin": "2.5.1",
74
- "@module-federation/runtime": "2.5.1",
75
- "@module-federation/sdk": "2.5.1"
73
+ "@module-federation/dts-plugin": "2.6.0",
74
+ "@module-federation/runtime": "2.6.0",
75
+ "@module-federation/sdk": "2.6.0"
76
76
  },
77
77
  "devDependencies": {
78
78
  "@playwright/test": "1.58.2",
@@ -83,7 +83,7 @@
83
83
  "rollup": "4.47.1",
84
84
  "tsdown": "0.21.0",
85
85
  "typescript": "5.9.3",
86
- "vite": "8.0.10",
86
+ "vite": "8.1.0",
87
87
  "vitest": "4.0.18"
88
88
  }
89
89
  }