@module-federation/vite 1.20.2 → 1.20.4

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.
@@ -0,0 +1,47 @@
1
+ //#region src/utils/buildPaths.ts
2
+ /**
3
+ * Rebase an import path for a bootstrap file that moved from root into `dir`.
4
+ *
5
+ * When entryFileNames places entries in a subdirectory (e.g. `static/js/`),
6
+ * the bootstrap file moves there too. Paths that resolved from the HTML root
7
+ * must resolve from the new directory instead.
8
+ *
9
+ * Cases: `/static/js/hostInit.js` → `./hostInit.js` (strip dir prefix)
10
+ * `./src/main.tsx` → `../../src/main.tsx` (climb back up for each dir level)
11
+ * `https://cdn.example.com` → unchanged (absolute URL)
12
+ */
13
+ function rebaseImport(importSrc, dir) {
14
+ if (!dir) return importSrc;
15
+ if (isAbsoluteUrl(importSrc)) return importSrc;
16
+ const normalizedDir = dir.replace(/^\/+|\/+$/g, "");
17
+ if (!normalizedDir) return importSrc;
18
+ const stripDirPrefix = (src, prefix) => {
19
+ if (src === prefix) return "";
20
+ if (src.startsWith(prefix + "/")) return src.slice(prefix.length);
21
+ };
22
+ const absoluteRemainder = stripDirPrefix(importSrc, "/" + normalizedDir);
23
+ if (absoluteRemainder !== void 0) {
24
+ const remainder = absoluteRemainder.replace(/^\/+/, "");
25
+ return remainder ? "./" + remainder : "./";
26
+ }
27
+ const relativeRemainder = stripDirPrefix(importSrc, normalizedDir);
28
+ if (relativeRemainder !== void 0) {
29
+ const remainder = relativeRemainder.replace(/^\/+/, "");
30
+ return remainder ? "./" + remainder : "./";
31
+ }
32
+ const upLevels = normalizedDir.split("/").filter(Boolean).length;
33
+ const prefix = upLevels > 0 ? "../".repeat(upLevels) : "./";
34
+ if (importSrc.startsWith("./")) return prefix + importSrc.slice(2);
35
+ if (importSrc.startsWith("/")) return prefix + importSrc.slice(1);
36
+ return prefix + importSrc;
37
+ }
38
+ function normalizePathForImport(path) {
39
+ return path.replace(/\\/g, "/");
40
+ }
41
+ const EXTERNAL_URL_RE = /^(?:[a-z]+:|\/\/)/i;
42
+ function isAbsoluteUrl(src) {
43
+ if (/^[a-z]:[\\/]/i.test(src)) return false;
44
+ return EXTERNAL_URL_RE.test(src);
45
+ }
46
+ //#endregion
47
+ export { normalizePathForImport as n, rebaseImport as r, EXTERNAL_URL_RE as t };
package/lib/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { n as normalizePathForImport, r as rebaseImport } from "./buildPaths-BkaQHrd2.js";
2
+ import { a as getCommonSharedSubpaths, c as isNodeModulePath, d as normalizeNodeModulePath, f as resolvePublicPath, i as getCommonSharedSubpathFromNodeModulePath, l as isNuxtClientBase, n as filterId, o as getMatchingNodeModuleSubpath, r as getBasePath$2, s as isAssetLikeImport, t as ensureTrailingSlash, u as isViteOptimizableEntry } from "./pathNormalization-DvgU8LIp.js";
1
3
  import { createRequire } from "node:module";
2
4
  import * as fs$2 from "fs";
3
5
  import fs, { existsSync, readFileSync, readdirSync, realpathSync, statSync, writeFileSync } from "fs";
@@ -25,52 +27,6 @@ var __exportAll = (all, no_symbols) => {
25
27
  return target;
26
28
  };
27
29
  //#endregion
28
- //#region src/utils/buildPaths.ts
29
- /**
30
- * Rebase an import path for a bootstrap file that moved from root into `dir`.
31
- *
32
- * When entryFileNames places entries in a subdirectory (e.g. `static/js/`),
33
- * the bootstrap file moves there too. Paths that resolved from the HTML root
34
- * must resolve from the new directory instead.
35
- *
36
- * Cases: `/static/js/hostInit.js` → `./hostInit.js` (strip dir prefix)
37
- * `./src/main.tsx` → `../../src/main.tsx` (climb back up for each dir level)
38
- * `https://cdn.example.com` → unchanged (absolute URL)
39
- */
40
- function rebaseImport(importSrc, dir) {
41
- if (!dir) return importSrc;
42
- if (isAbsoluteUrl(importSrc)) return importSrc;
43
- const normalizedDir = dir.replace(/^\/+|\/+$/g, "");
44
- if (!normalizedDir) return importSrc;
45
- const stripDirPrefix = (src, prefix) => {
46
- if (src === prefix) return "";
47
- if (src.startsWith(prefix + "/")) return src.slice(prefix.length);
48
- };
49
- const absoluteRemainder = stripDirPrefix(importSrc, "/" + normalizedDir);
50
- if (absoluteRemainder !== void 0) {
51
- const remainder = absoluteRemainder.replace(/^\/+/, "");
52
- return remainder ? "./" + remainder : "./";
53
- }
54
- const relativeRemainder = stripDirPrefix(importSrc, normalizedDir);
55
- if (relativeRemainder !== void 0) {
56
- const remainder = relativeRemainder.replace(/^\/+/, "");
57
- return remainder ? "./" + remainder : "./";
58
- }
59
- const upLevels = normalizedDir.split("/").filter(Boolean).length;
60
- const prefix = upLevels > 0 ? "../".repeat(upLevels) : "./";
61
- if (importSrc.startsWith("./")) return prefix + importSrc.slice(2);
62
- if (importSrc.startsWith("/")) return prefix + importSrc.slice(1);
63
- return prefix + importSrc;
64
- }
65
- function normalizePathForImport(path) {
66
- return path.replace(/\\/g, "/");
67
- }
68
- const EXTERNAL_URL_RE = /^(?:[a-z]+:|\/\/)/i;
69
- function isAbsoluteUrl(src) {
70
- if (/^[a-z]:[\\/]/i.test(src)) return false;
71
- return EXTERNAL_URL_RE.test(src);
72
- }
73
- //#endregion
74
30
  //#region src/utils/codeRewriter.ts
75
31
  const BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
76
32
  var CodeRewriter = class {
@@ -851,124 +807,6 @@ function hasPackageDependency(dependencyName, cwd = packageDetectionCwd || proce
851
807
  }
852
808
  }
853
809
  //#endregion
854
- //#region src/utils/pathNormalization.ts
855
- const COMMON_SHARED_SUBPATHS = {
856
- react: [
857
- "react/jsx-runtime",
858
- "react/jsx-dev-runtime",
859
- "react/compiler-runtime"
860
- ],
861
- "react-dom": [
862
- "react-dom/client",
863
- "react-dom/server",
864
- "react-dom/server.browser"
865
- ],
866
- "solid-js": [
867
- "solid-js/web",
868
- "solid-js/store",
869
- "solid-js/html",
870
- "solid-js/h"
871
- ],
872
- zustand: ["zustand/vanilla", "zustand/react"]
873
- };
874
- const VITE_DEFAULT_ASSET_TYPES = [
875
- "apng",
876
- "bmp",
877
- "png",
878
- "jpe?g",
879
- "jfif",
880
- "pjpeg",
881
- "pjp",
882
- "gif",
883
- "svg",
884
- "ico",
885
- "webp",
886
- "avif",
887
- "cur",
888
- "jxl",
889
- "mp4",
890
- "webm",
891
- "ogg",
892
- "mp3",
893
- "wav",
894
- "flac",
895
- "aac",
896
- "opus",
897
- "mov",
898
- "m4a",
899
- "vtt",
900
- "woff2?",
901
- "eot",
902
- "ttf",
903
- "otf",
904
- "webmanifest",
905
- "pdf",
906
- "txt"
907
- ];
908
- const ASSET_LIKE_IMPORT_RE = new RegExp(`\\.(${[...[
909
- "css",
910
- "scss",
911
- "sass",
912
- "less",
913
- "styl",
914
- "stylus"
915
- ], ...VITE_DEFAULT_ASSET_TYPES].join("|")})(?:[?#].*)?$`, "i");
916
- function isAssetLikeImport(source) {
917
- return ASSET_LIKE_IMPORT_RE.test(source);
918
- }
919
- const VITE_OPTIMIZABLE_ENTRY_RE = /\.[cm]?[jt]s$/;
920
- function isViteOptimizableEntry(resolvedPath) {
921
- return VITE_OPTIMIZABLE_ENTRY_RE.test(resolvedPath);
922
- }
923
- function removeTrailingSlash(value) {
924
- return value.endsWith("/") ? value.slice(0, -1) : value;
925
- }
926
- function ensureTrailingSlash(value) {
927
- return `${removeTrailingSlash(value)}/`;
928
- }
929
- function getBasePath$2(base) {
930
- return removeTrailingSlash(base || "/");
931
- }
932
- function isNuxtClientBase(base) {
933
- return getBasePath$2(base).endsWith("/_nuxt");
934
- }
935
- function normalizeNodeModulePath(source) {
936
- const queryIndex = source.indexOf("?");
937
- return (queryIndex === -1 ? source : source.slice(0, queryIndex)).replace(/\\/g, "/");
938
- }
939
- function isNodeModulePath(source) {
940
- return source.includes("/node_modules/") || source.includes("\\node_modules\\");
941
- }
942
- function filterId(id) {
943
- return typeof id === "string" && !id.includes("\0");
944
- }
945
- function getMatchingNodeModuleSubpath(source, candidates) {
946
- const normalized = normalizeNodeModulePath(source);
947
- return [...candidates].sort((a, b) => b.length - a.length).find((candidate) => normalized.includes(`/node_modules/${candidate}/`) || normalized.includes(`/node_modules/${candidate}.`));
948
- }
949
- function getCommonSharedSubpaths(sharedKey) {
950
- return COMMON_SHARED_SUBPATHS[removeTrailingSlash(sharedKey)] || [];
951
- }
952
- function getCommonSharedSubpathFromNodeModulePath(source, sharedKey) {
953
- return getMatchingNodeModuleSubpath(source, getCommonSharedSubpaths(removeTrailingSlash(sharedKey)));
954
- }
955
- /**
956
- * Resolves the public path for remote entries
957
- * @param options - Module Federation options
958
- * @param viteBase - Vite's base config value
959
- * @param originalBase - Original base config before any transformations
960
- * @returns The resolved public path
961
- */
962
- function resolvePublicPath(options, viteBase, originalBase) {
963
- if (options.publicPath && options.publicPath !== "auto") return options.publicPath;
964
- if (!originalBase) return "auto";
965
- if (viteBase) {
966
- if (viteBase === "./") return "auto";
967
- return ensureTrailingSlash(viteBase);
968
- }
969
- return "auto";
970
- }
971
- //#endregion
972
810
  //#region src/utils/normalizeModuleFederationOptions.ts
973
811
  const INTERNAL_NAME_PREFIX = "__mfe_internal__";
974
812
  function toInternalModuleFederationName(name) {
@@ -1236,6 +1074,7 @@ function normalizeModuleFederationOptions(options) {
1236
1074
  moduleParseIdleTimeout: options.moduleParseIdleTimeout,
1237
1075
  varFilename: options.varFilename,
1238
1076
  target: options.target,
1077
+ ssrExternals: options.ssrExternals,
1239
1078
  disableRemote: options.disableRemote,
1240
1079
  disableShared: options.disableShared,
1241
1080
  disableSnapshot: options.disableSnapshot,
@@ -1914,6 +1753,24 @@ ${exportStatement}
1914
1753
  `);
1915
1754
  }
1916
1755
  //#endregion
1756
+ //#region src/plugins/pluginReactMixedModeGuard.ts
1757
+ function createReactMixedModeRuntimeGuard() {
1758
+ return `const __mfReactInternals = mod["__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE"];
1759
+ if (__mfReactInternals && "A" in __mfReactInternals) {
1760
+ let __mfReactDispatcher = __mfReactInternals.A;
1761
+ Object.defineProperty(__mfReactInternals, "A", {
1762
+ configurable: true,
1763
+ enumerable: true,
1764
+ get: () => __mfReactDispatcher,
1765
+ set: (next) => {
1766
+ if (next && typeof next.getOwner !== "function") next.getOwner = () => null;
1767
+ __mfReactDispatcher = next;
1768
+ },
1769
+ });
1770
+ __mfReactInternals.A = __mfReactDispatcher;
1771
+ }`;
1772
+ }
1773
+ //#endregion
1917
1774
  //#region src/utils/treeShaking.ts
1918
1775
  function shouldAnalyzeSharedExports(shareItem) {
1919
1776
  return !!(shareItem && (shareItem.shareConfig.treeShaking || shareItem.shareConfig.import === false));
@@ -2476,32 +2333,55 @@ function resolveReExportModule(filePath, specifier, exportConditions) {
2476
2333
  return;
2477
2334
  }
2478
2335
  }
2479
- function hasTopLevelDeclaratorComma(source, start, codePositions) {
2336
+ /** Marks a template-literal frame whose text (not its interpolation) is being scanned. */
2337
+ const TEMPLATE_TEXT = Symbol("templateText");
2338
+ function getAdditionalTopLevelDeclaratorNames(source, start, codePositions) {
2339
+ const names = [];
2480
2340
  let depth = 0;
2481
2341
  let quote;
2482
2342
  let escaped = false;
2483
2343
  let canStartRegex = true;
2344
+ const templateFrames = [];
2345
+ const inTemplateText = () => templateFrames[templateFrames.length - 1] === TEMPLATE_TEXT;
2484
2346
  for (let index = start; index < source.length; index++) {
2485
2347
  const char = source[index];
2348
+ if (inTemplateText()) {
2349
+ if (escaped) escaped = false;
2350
+ else if (char === "\\") escaped = true;
2351
+ else if (char === "$" && source[index + 1] === "{") {
2352
+ templateFrames.push(depth);
2353
+ index++;
2354
+ canStartRegex = true;
2355
+ } else if (char === "`") {
2356
+ templateFrames.pop();
2357
+ canStartRegex = false;
2358
+ }
2359
+ continue;
2360
+ }
2486
2361
  if (quote) {
2487
2362
  if (escaped) escaped = false;
2488
2363
  else if (char === "\\") escaped = true;
2489
2364
  else if (char === quote) quote = void 0;
2490
2365
  continue;
2491
2366
  }
2492
- if (char === "\"" || char === "'" || char === "`") {
2367
+ if (char === "`") {
2368
+ templateFrames.push(TEMPLATE_TEXT);
2369
+ canStartRegex = false;
2370
+ continue;
2371
+ }
2372
+ if (char === "\"" || char === "'") {
2493
2373
  quote = char;
2494
2374
  canStartRegex = false;
2495
2375
  continue;
2496
2376
  }
2497
2377
  if (char === "/" && source[index + 1] === "/") {
2498
2378
  index = source.indexOf("\n", index + 2);
2499
- if (index === -1) return false;
2379
+ if (index === -1) return names;
2500
2380
  continue;
2501
2381
  }
2502
2382
  if (char === "/" && source[index + 1] === "*") {
2503
2383
  const commentEnd = source.indexOf("*/", index + 2);
2504
- if (commentEnd === -1) return true;
2384
+ if (commentEnd === -1) return void 0;
2505
2385
  index = commentEnd + 1;
2506
2386
  continue;
2507
2387
  }
@@ -2532,9 +2412,9 @@ function hasTopLevelDeclaratorComma(source, start, codePositions) {
2532
2412
  while (/[$_\p{ID_Continue}]/u.test(source[index + 1] || "")) index++;
2533
2413
  break;
2534
2414
  }
2535
- if (regexChar === "\n" || regexChar === "\r") return true;
2415
+ if (regexChar === "\n" || regexChar === "\r") return void 0;
2536
2416
  }
2537
- if (!closed) return true;
2417
+ if (!closed) return void 0;
2538
2418
  canStartRegex = false;
2539
2419
  continue;
2540
2420
  }
@@ -2573,15 +2453,29 @@ function hasTopLevelDeclaratorComma(source, start, codePositions) {
2573
2453
  continue;
2574
2454
  }
2575
2455
  if (char === ")" || char === "]" || char === "}") {
2456
+ if (char === "}" && templateFrames.length > 0 && templateFrames[templateFrames.length - 1] === depth) {
2457
+ templateFrames.pop();
2458
+ canStartRegex = false;
2459
+ continue;
2460
+ }
2576
2461
  depth = Math.max(0, depth - 1);
2577
2462
  canStartRegex = false;
2578
2463
  continue;
2579
2464
  }
2580
- if (depth === 0 && char === ",") return true;
2581
- if (depth === 0 && char === ";") return false;
2465
+ if (templateFrames.length === 0 && depth === 0 && char === ",") {
2466
+ let bindingStart = index + 1;
2467
+ while (/\s/.test(source[bindingStart] || "")) bindingStart++;
2468
+ const binding = source.slice(bindingStart).match(new RegExp(`^(${JS_IDENTIFIER_PATTERN})`, "u"));
2469
+ if (!binding || !isValidEsmExportName(binding[1])) return void 0;
2470
+ names.push(binding[1]);
2471
+ index = bindingStart + binding[1].length - 1;
2472
+ canStartRegex = false;
2473
+ continue;
2474
+ }
2475
+ if (templateFrames.length === 0 && depth === 0 && char === ";") return names;
2582
2476
  if (!/\s/.test(char)) canStartRegex = char !== ".";
2583
2477
  }
2584
- return false;
2478
+ return names;
2585
2479
  }
2586
2480
  function hasUnsupportedBindingPattern(source, start) {
2587
2481
  const opening = source[start];
@@ -2624,7 +2518,9 @@ function getNamedExportsViaRegex(source, filePath, visited, scanState = { comple
2624
2518
  const exportedVariableDeclarationRegex = /export\s+(?:const|let|var)\s+/g;
2625
2519
  while ((match = exportedVariableDeclarationRegex.exec(source)) !== null) {
2626
2520
  if (!codePositions[match.index]) continue;
2627
- if (hasTopLevelDeclaratorComma(source, exportedVariableDeclarationRegex.lastIndex, codePositions)) scanState.complete = false;
2521
+ const additionalNames = getAdditionalTopLevelDeclaratorNames(source, exportedVariableDeclarationRegex.lastIndex, codePositions);
2522
+ if (additionalNames === void 0) scanState.complete = false;
2523
+ else for (const name of additionalNames) names.add(name);
2628
2524
  if (hasUnsupportedBindingPattern(source, exportedVariableDeclarationRegex.lastIndex)) scanState.complete = false;
2629
2525
  }
2630
2526
  if (hasCodeMatch(source, /export\s+import\s+/g, codePositions) || hasCodeMatch(source, /export\s*=/g, codePositions)) scanState.complete = false;
@@ -3372,12 +3268,13 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown, options, exp
3372
3268
  const hasCompleteExportCoverage = detectedNamedExports !== void 0;
3373
3269
  const isWorkspaceSingleton = isWorkspacePackage && shareItem.shareConfig.singleton === true;
3374
3270
  const isDefaultShareScope = shareItem.scope === void 0 || shareItem.scope === "default" || Array.isArray(shareItem.scope) && shareItem.scope[0] === "default";
3375
- const usesDeferredSingletonFallback = hasCompleteExportCoverage && (isWorkspaceSingleton || command !== "build" && isRemoteOnlyContainer(resolvedOptions) && shareItem.shareConfig.singleton === true || command === "build" && isRemoteOnlyContainer(resolvedOptions) && shareItem.shareConfig.singleton === true && !isDefaultShareScope);
3271
+ const usesDeferredSingletonFallback = hasCompleteExportCoverage && (isWorkspacePackage || command !== "build" && isRemoteOnlyContainer(resolvedOptions) && shareItem.shareConfig.singleton === true || command === "build" && isRemoteOnlyContainer(resolvedOptions) && (shareItem.shareConfig.singleton === true ? !isDefaultShareScope : isDefaultShareScope));
3376
3272
  const servesRemoteSingletonFallback = command !== "build" && isRemoteOnlyContainer(resolvedOptions) && shareItem.shareConfig.singleton === true;
3377
3273
  const isConsumedByPeerSingleton = isSharedSingletonConsumedByPeer(pkg, resolvedOptions);
3378
3274
  const usesEntryInjectedRemoteFallback = hasCompleteExportCoverage && command !== "build" && !isWorkspaceSingleton && isRemoteOnlyContainer(resolvedOptions) && shareItem.shareConfig.singleton === true && resolvedOptions.hostInitInjectLocation === "entry" && isConsumedByPeerSingleton;
3379
- const usesEagerWorkspaceFallback = hasCompleteExportCoverage && isWorkspaceSingleton && isConsumedByPeerSingleton;
3275
+ const usesEagerWorkspaceFallback = hasCompleteExportCoverage && isWorkspaceSingleton && (isConsumedByPeerSingleton || shareItem.shareConfig.eager === true);
3380
3276
  const usesDeferredTreeShakingFallback = hasCompleteExportCoverage && Boolean(treeShakingConsumer);
3277
+ const reactMixedModeGuard = pkg === "react" ? createReactMixedModeRuntimeGuard() : "";
3381
3278
  let exportLine;
3382
3279
  let initBlock = "";
3383
3280
  if (usesDeferredTreeShakingFallback) {
@@ -3403,13 +3300,17 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown, options, exp
3403
3300
  const namedExportVars = copiedNamedExports.map((_name, i) => `__mf_${i}`);
3404
3301
  exportLine = `${["let __mfDefaultExport;", ...namedExportVars.map((name) => `let ${name};`)].join("\n ")}
3405
3302
  const __mfApplySharedExports = (mod) => {
3406
- ${[...copiedNamedExports.map((name, i) => `${namedExportVars[i]} = mod[${escapeGeneratedStringLiteral(name)}];`), `__mfDefaultExport = (() => {
3303
+ ${[
3304
+ ...reactMixedModeGuard ? [reactMixedModeGuard] : [],
3305
+ ...copiedNamedExports.map((name, i) => `${namedExportVars[i]} = mod[${escapeGeneratedStringLiteral(name)}];`),
3306
+ `__mfDefaultExport = (() => {
3407
3307
  ${generateShareModuleUnwrapCode({
3408
- source: "mod",
3409
- preserveNamedExports: false,
3410
- stopWithReturn: "defaultExport ?? current"
3411
- })}
3412
- })();`].join("\n ")}
3308
+ source: "mod",
3309
+ preserveNamedExports: false,
3310
+ stopWithReturn: "defaultExport ?? current"
3311
+ })}
3312
+ })();`
3313
+ ].join("\n ")}
3413
3314
  };
3414
3315
  __mfSubscribeSharedCache(__mfModuleCache.share, ${cacheDescriptor}, __mfApplySharedExports);
3415
3316
  __mfApplySharedExports(exportModule);
@@ -3437,6 +3338,7 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown, options, exp
3437
3338
  } else if (shareItem.shareConfig.singleton === true) {
3438
3339
  exportLine = `let __mfDefaultExport;
3439
3340
  const __mfApplySharedDefaultExport = (mod) => {
3341
+ ${reactMixedModeGuard}
3440
3342
  __mfDefaultExport = mod.default ?? mod;
3441
3343
  };
3442
3344
  __mfSubscribeSharedCache(__mfModuleCache.share, ${cacheDescriptor}, __mfApplySharedDefaultExport);
@@ -3979,7 +3881,6 @@ function generateRuntimeSharedCacheSeedCode(shareStrategy) {
3979
3881
  : __mfReadSharedCache(__mfModuleCache.share, cacheDescriptor);
3980
3882
  if (cachedShare !== undefined) return false;
3981
3883
  if (share.treeShaking || share.shareConfig?.import === false) return true;
3982
- if (!share.shareConfig?.singleton) return false;
3983
3884
  if (typeof __mfSelectExternalSharedProvider !== 'function') return false;
3984
3885
  return Boolean(__mfSelectExternalSharedProvider(
3985
3886
  initialShared[pkg],
@@ -4193,7 +4094,6 @@ function generateTreeShakingSnapshotPluginCode(enabled) {
4193
4094
  function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(options), command = "build") {
4194
4095
  const needsSharedProviderSelectionHelper = Object.keys(options.shared ?? {}).length > 0;
4195
4096
  const hasTreeShakingShared = Object.values(options.shared ?? {}).some((share) => !!share?.shareConfig.treeShaking);
4196
- const hasEagerShared = Object.values(options.shared ?? {}).some((share) => share?.shareConfig.eager === true && share.shareConfig.import !== false);
4197
4097
  const hasMultipleShareScopes = Array.isArray(options.shareScope);
4198
4098
  const runtimeImports = [
4199
4099
  "init as runtimeInit",
@@ -4246,7 +4146,6 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
4246
4146
  globalThis.__VUE_HMR_RUNTIME__ = { createRecord() {}, rerender() {}, reload() {} };
4247
4147
  }
4248
4148
  import {${runtimeImports}} from "@module-federation/runtime";
4249
- ${hasEagerShared ? `import * as __mfLocalSharedImportMap from "${getLocalSharedImportMapPath(options)}";` : ""}
4250
4149
  ${runtimeHelperImports.length ? `import {${runtimeHelperImports.join(", ")}} from "@module-federation/runtime/helpers";` : ""}
4251
4150
  ${pluginImportNames.filter((item) => !isSsrOnlyPlugin(item[1])).map((item) => item[1]).join("\n")}
4252
4151
  ${command === "build" ? getRuntimeInitResolveBootstrapCode(false, options ? getRuntimeInitStatusImportId(options) : void 0) : getRuntimeInitBootstrapCode(false, options ? getRuntimeInitStatusImportId(options) : void 0) + "\n const { initResolve } = globalThis[globalKey];"}
@@ -4281,12 +4180,11 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
4281
4180
  ${needsSharedProviderSelectionHelper ? externalSharedProviderSelectionHelperCode : ""}
4282
4181
 
4283
4182
  async function getLocalSharedImportMap() {
4284
- ${hasEagerShared ? "return __mfLocalSharedImportMap;" : ""}
4285
- ${hasEagerShared ? "" : `if (!localSharedImportMapPromise) {
4183
+ if (!localSharedImportMapPromise) {
4286
4184
  localSharedImportMapPromise = retrySharedInit(() => import("${getLocalSharedImportMapPath(options)}"))
4287
4185
  .catch((e) => { localSharedImportMapPromise = undefined; throw e; });
4288
4186
  }
4289
- return localSharedImportMapPromise`}
4187
+ return localSharedImportMapPromise
4290
4188
  }
4291
4189
 
4292
4190
  async function getExposesMap() {
@@ -4721,6 +4619,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
4721
4619
  if (!providerEntry) return;
4722
4620
  const selectedLocalProvider = __mfMatchesSharedProvider(selectedRuntimeProvider, usedShare);
4723
4621
  const { version } = providerEntry;
4622
+ if (!usedShare.shareConfig?.singleton && version !== usedShare.version) return;
4724
4623
  const passedProvider = passedVersionMap?.[version];
4725
4624
  const resolvedExternalProvider = __mfResolveExternalSharedProvider(
4726
4625
  federationInstances,
@@ -4738,10 +4637,6 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
4738
4637
  provider: selectedRuntimeProvider,
4739
4638
  scopeRootProvider: undefined
4740
4639
  };
4741
- // Non-singleton proxies may have already snapshotted their local exports while
4742
- // seeding shared dependencies. Late cache replacement is safe only for the
4743
- // live-bound singleton proxies.
4744
- if (!usedShare.shareConfig?.singleton) return;
4745
4640
  if (usedShare.canLiveRebind === false) return;
4746
4641
  // Preserve a singleton already selected by another container. The bridge may
4747
4642
  // only replace the provisional local fallback seeded by this container.
@@ -8004,6 +7899,11 @@ function resolveDevHashEntryFileName(fileName) {
8004
7899
  const baseName = path$1.basename(normalized);
8005
7900
  return path$1.extname(baseName) ? normalized : `${normalized}.js`;
8006
7901
  }
7902
+ function resolveAbsoluteDevRemoteEntryUrl(publicPath, fileName) {
7903
+ const base = new URL(publicPath);
7904
+ base.pathname = ensureTrailingSlash(base.pathname);
7905
+ return new URL(fileName, base).href;
7906
+ }
8007
7907
  function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposesId, getParsePromise = () => Promise.resolve() }) {
8008
7908
  let viteConfig, _command, root, originalConfigBase;
8009
7909
  let exposeRemoteDependencies = {};
@@ -8133,12 +8033,15 @@ function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposes
8133
8033
  if (_command === "serve") {
8134
8034
  const host = typeof viteConfig.server?.host === "string" && viteConfig.server.host !== "0.0.0.0" ? viteConfig.server.host : "localhost";
8135
8035
  const resolvedPublicPath = resolvePublicPath(options, viteConfig.base, originalConfigBase);
8136
- const publicPath = JSON.stringify((resolvedPublicPath === "auto" ? "/" : resolvedPublicPath) + resolveDevHashEntryFileName(options.filename));
8036
+ const devPublicPath = resolvedPublicPath === "auto" ? "/" : resolvedPublicPath;
8037
+ const remoteEntryFileName = resolveDevHashEntryFileName(options.filename);
8038
+ const isAbsolutePublicPath = /^https?:\/\//i.test(devPublicPath);
8039
+ const remoteEntryUrl = JSON.stringify(isAbsolutePublicPath ? resolveAbsoluteDevRemoteEntryUrl(devPublicPath, remoteEntryFileName) : `${ensureTrailingSlash(devPublicPath)}${remoteEntryFileName}`);
8137
8040
  const fallbackOrigin = `//${host}:${viteConfig.server?.port}`;
8138
8041
  const ssrRemoteEntry = "data:text/javascript," + encodeURIComponent("export async function init(){return {loadRemote:async()=>({}),loadShare:async()=>({})}}");
8139
8042
  return `
8140
8043
  const origin = typeof window !== 'undefined' && (${!options.ignoreOrigin}) ? window.origin : ${JSON.stringify(fallbackOrigin)};
8141
- const remoteEntryImport = typeof window !== 'undefined' ? origin + ${publicPath} : ${JSON.stringify(ssrRemoteEntry)};
8044
+ const remoteEntryImport = typeof window !== 'undefined' ? ${isAbsolutePublicPath ? remoteEntryUrl : `origin + ${remoteEntryUrl}`} : ${JSON.stringify(ssrRemoteEntry)};
8142
8045
  ${generateHostAutoInitCode("remoteEntryImport", "serve", options)}
8143
8046
  `;
8144
8047
  }
@@ -8281,41 +8184,6 @@ function pluginProxyRemotes_default(options) {
8281
8184
  };
8282
8185
  }
8283
8186
  //#endregion
8284
- //#region src/plugins/pluginReactMixedModeGuard.ts
8285
- const REACT_DEVELOPMENT_RUNTIME = /[\\/]react[\\/]cjs[\\/]react(?:-jsx-(?:dev-)?runtime)?\.development\.js$/;
8286
- const UNSAFE_GET_OWNER = "return null === dispatcher ? null : dispatcher.getOwner();";
8287
- const SAFE_GET_OWNER = "return typeof dispatcher?.getOwner === \"function\" ? dispatcher.getOwner() : null;";
8288
- const REACT_MIXED_MODE_ROLLDOWN_PLUGIN = "module-federation:react-mixed-mode-rolldown";
8289
- const REACT_MIXED_MODE_ESBUILD_PLUGIN = "module-federation:react-mixed-mode-esbuild";
8290
- function patchReactDevelopmentRuntime(code, id) {
8291
- if (!REACT_DEVELOPMENT_RUNTIME.test(id)) return;
8292
- const patched = code.replaceAll(UNSAFE_GET_OWNER, SAFE_GET_OWNER);
8293
- return patched === code ? void 0 : patched;
8294
- }
8295
- function createRolldownReactMixedModeGuard() {
8296
- return {
8297
- name: REACT_MIXED_MODE_ROLLDOWN_PLUGIN,
8298
- transform(code, id) {
8299
- return patchReactDevelopmentRuntime(code, id);
8300
- }
8301
- };
8302
- }
8303
- function createEsbuildReactMixedModeGuard() {
8304
- return {
8305
- name: REACT_MIXED_MODE_ESBUILD_PLUGIN,
8306
- setup(build) {
8307
- build.onLoad({ filter: REACT_DEVELOPMENT_RUNTIME }, (args) => {
8308
- const patched = patchReactDevelopmentRuntime(readFileSync$1(args.path, "utf8"), args.path);
8309
- if (patched === void 0) return;
8310
- return {
8311
- contents: patched,
8312
- loader: "js"
8313
- };
8314
- });
8315
- }
8316
- };
8317
- }
8318
- //#endregion
8319
8187
  //#region src/utils/PromiseStore.ts
8320
8188
  /**
8321
8189
  * example:
@@ -9242,12 +9110,8 @@ function pluginSSRRemoteEntry(options) {
9242
9110
  ssrOutputFilename = getSsrRemoteEntryFileName(options.filename);
9243
9111
  const environmentName = this.environment?.name;
9244
9112
  const hasSsrEnvironment = Boolean(viteConfig?.environments?.ssr);
9245
- const isLegacySsrBuild = Boolean(this.environment?.config?.build?.ssr);
9246
- if (hasSsrEnvironment) {
9247
- if (isNuxtProject) {
9248
- if (environmentName === "ssr") return;
9249
- } else if (environmentName !== "ssr") return;
9250
- } else if (isLegacySsrBuild) {} else if (environmentName && environmentName !== "client") return;
9113
+ const isLegacySsrBuild = Boolean(this.environment?.config?.build?.ssr ?? viteConfig?.build?.ssr);
9114
+ if (hasSsrEnvironment && environmentName !== "ssr" || !hasSsrEnvironment && !isLegacySsrBuild) return;
9251
9115
  if (Object.keys(options.exposes).length === 0) return;
9252
9116
  if (isRolldown) this.emitFile({
9253
9117
  type: "chunk",
@@ -9481,7 +9345,7 @@ function stripEmptyPreloadCalls(code) {
9481
9345
  }
9482
9346
  nextCode = nextCode.replace(/import\s*["'][^"']*__loadShare__[^"']*["']\s*;?/g, "");
9483
9347
  nextCode = nextCode.replace(helperImportRegex, (statement, local) => {
9484
- return new RegExp(`\\b${local}\\s*\\(`).test(nextCode.replace(statement, "")) ? statement : "";
9348
+ return new RegExp(`\\b${local}\\b`).test(nextCode.replace(statement, "")) ? statement : "";
9485
9349
  });
9486
9350
  return nextCode;
9487
9351
  }
@@ -9787,7 +9651,6 @@ function includeLinkedSharedEntries(optimizeDeps, shared, projectRoot, exposes,
9787
9651
  function createEarlyVirtualModulesPlugin(options) {
9788
9652
  const { shared, remotes } = options;
9789
9653
  const isLitShare = (pkg) => pkg === "lit" || pkg.startsWith("lit/");
9790
- const shouldGuardReactMixedMode = Object.keys(remotes ?? {}).length > 0 && shared?.react?.shareConfig.singleton === true;
9791
9654
  return {
9792
9655
  name: "vite:module-federation-early-init",
9793
9656
  enforce: "pre",
@@ -9815,7 +9678,6 @@ function createEarlyVirtualModulesPlugin(options) {
9815
9678
  if (isRolldown) {
9816
9679
  optimizeDeps.rolldownOptions ??= {};
9817
9680
  optimizeDeps.rolldownOptions.plugins ??= [];
9818
- if (shouldGuardReactMixedMode) optimizeDeps.rolldownOptions.plugins.push(createRolldownReactMixedModeGuard());
9819
9681
  optimizeDeps.rolldownOptions.plugins.push({
9820
9682
  name: "module-federation:optimize-shared-resolver",
9821
9683
  load(id) {
@@ -9860,7 +9722,6 @@ function createEarlyVirtualModulesPlugin(options) {
9860
9722
  } else {
9861
9723
  optimizeDeps.esbuildOptions ??= {};
9862
9724
  optimizeDeps.esbuildOptions.plugins ??= [];
9863
- if (shouldGuardReactMixedMode) optimizeDeps.esbuildOptions.plugins.push(createEsbuildReactMixedModeGuard());
9864
9725
  optimizeDeps.esbuildOptions.plugins.push({
9865
9726
  name: "module-federation:optimize-shared-proxy",
9866
9727
  setup(build) {
@@ -9935,7 +9796,7 @@ export default __mfShared.default ?? __mfShared;`
9935
9796
  else optimizeDeps.include.push(key);
9936
9797
  for (const subpath of getCommonSharedSubpaths(key)) {
9937
9798
  const canResolveSubpath = canResolveSharedSubpath(subpath, root);
9938
- if (subpath === "react/compiler-runtime" && !canResolveSubpath) {
9799
+ if (["react/compiler-runtime", "react-dom/client"].includes(subpath) && !canResolveSubpath) {
9939
9800
  optimizeDeps.exclude.push(subpath);
9940
9801
  continue;
9941
9802
  }
@@ -10289,6 +10150,7 @@ function federation(mfUserOptions) {
10289
10150
  patchedManualChunks.add(mfChunkName);
10290
10151
  if (!useCodeSplitting) {
10291
10152
  const mfManualChunks = function(id) {
10153
+ if (PRELOAD_HELPER_TEST.test(id)) return PRELOAD_HELPER_CHUNK;
10292
10154
  return mfChunkName(id) ?? void 0;
10293
10155
  };
10294
10156
  patchedManualChunks.add(mfManualChunks);
@@ -0,0 +1,119 @@
1
+ //#region src/utils/pathNormalization.ts
2
+ const COMMON_SHARED_SUBPATHS = {
3
+ react: [
4
+ "react/jsx-runtime",
5
+ "react/jsx-dev-runtime",
6
+ "react/compiler-runtime"
7
+ ],
8
+ "react-dom": [
9
+ "react-dom/client",
10
+ "react-dom/server",
11
+ "react-dom/server.browser"
12
+ ],
13
+ "solid-js": [
14
+ "solid-js/web",
15
+ "solid-js/store",
16
+ "solid-js/html",
17
+ "solid-js/h"
18
+ ],
19
+ zustand: ["zustand/vanilla", "zustand/react"]
20
+ };
21
+ const VITE_DEFAULT_ASSET_TYPES = [
22
+ "apng",
23
+ "bmp",
24
+ "png",
25
+ "jpe?g",
26
+ "jfif",
27
+ "pjpeg",
28
+ "pjp",
29
+ "gif",
30
+ "svg",
31
+ "ico",
32
+ "webp",
33
+ "avif",
34
+ "cur",
35
+ "jxl",
36
+ "mp4",
37
+ "webm",
38
+ "ogg",
39
+ "mp3",
40
+ "wav",
41
+ "flac",
42
+ "aac",
43
+ "opus",
44
+ "mov",
45
+ "m4a",
46
+ "vtt",
47
+ "woff2?",
48
+ "eot",
49
+ "ttf",
50
+ "otf",
51
+ "webmanifest",
52
+ "pdf",
53
+ "txt"
54
+ ];
55
+ const ASSET_LIKE_IMPORT_RE = new RegExp(`\\.(${[...[
56
+ "css",
57
+ "scss",
58
+ "sass",
59
+ "less",
60
+ "styl",
61
+ "stylus"
62
+ ], ...VITE_DEFAULT_ASSET_TYPES].join("|")})(?:[?#].*)?$`, "i");
63
+ function isAssetLikeImport(source) {
64
+ return ASSET_LIKE_IMPORT_RE.test(source);
65
+ }
66
+ const VITE_OPTIMIZABLE_ENTRY_RE = /\.[cm]?[jt]s$/;
67
+ function isViteOptimizableEntry(resolvedPath) {
68
+ return VITE_OPTIMIZABLE_ENTRY_RE.test(resolvedPath);
69
+ }
70
+ function removeTrailingSlash(value) {
71
+ return value.endsWith("/") ? value.slice(0, -1) : value;
72
+ }
73
+ function ensureTrailingSlash(value) {
74
+ return `${removeTrailingSlash(value)}/`;
75
+ }
76
+ function getBasePath(base) {
77
+ return removeTrailingSlash(base || "/");
78
+ }
79
+ function isNuxtClientBase(base) {
80
+ return getBasePath(base).endsWith("/_nuxt");
81
+ }
82
+ function normalizeNodeModulePath(source) {
83
+ const queryIndex = source.indexOf("?");
84
+ return (queryIndex === -1 ? source : source.slice(0, queryIndex)).replace(/\\/g, "/");
85
+ }
86
+ function isNodeModulePath(source) {
87
+ return source.includes("/node_modules/") || source.includes("\\node_modules\\");
88
+ }
89
+ function filterId(id) {
90
+ return typeof id === "string" && !id.includes("\0");
91
+ }
92
+ function getMatchingNodeModuleSubpath(source, candidates) {
93
+ const normalized = normalizeNodeModulePath(source);
94
+ return [...candidates].sort((a, b) => b.length - a.length).find((candidate) => normalized.includes(`/node_modules/${candidate}/`) || normalized.includes(`/node_modules/${candidate}.`));
95
+ }
96
+ function getCommonSharedSubpaths(sharedKey) {
97
+ return COMMON_SHARED_SUBPATHS[removeTrailingSlash(sharedKey)] || [];
98
+ }
99
+ function getCommonSharedSubpathFromNodeModulePath(source, sharedKey) {
100
+ return getMatchingNodeModuleSubpath(source, getCommonSharedSubpaths(removeTrailingSlash(sharedKey)));
101
+ }
102
+ /**
103
+ * Resolves the public path for remote entries
104
+ * @param options - Module Federation options
105
+ * @param viteBase - Vite's base config value
106
+ * @param originalBase - Original base config before any transformations
107
+ * @returns The resolved public path
108
+ */
109
+ function resolvePublicPath(options, viteBase, originalBase) {
110
+ if (options.publicPath && options.publicPath !== "auto") return options.publicPath;
111
+ if (!originalBase) return "auto";
112
+ if (viteBase) {
113
+ if (viteBase === "./") return "auto";
114
+ return ensureTrailingSlash(viteBase);
115
+ }
116
+ return "auto";
117
+ }
118
+ //#endregion
119
+ export { getCommonSharedSubpaths as a, isNodeModulePath as c, normalizeNodeModulePath as d, resolvePublicPath as f, getCommonSharedSubpathFromNodeModulePath as i, isNuxtClientBase as l, filterId as n, getMatchingNodeModuleSubpath as o, getBasePath as r, isAssetLikeImport as s, ensureTrailingSlash as t, isViteOptimizableEntry as u };
@@ -1,3 +1,4 @@
1
+ import { t as EXTERNAL_URL_RE } from "./buildPaths-BkaQHrd2.js";
1
2
  //#region src/utils/fetchWithTimeout.ts
2
3
  const DEFAULT_SSR_FETCH_TIMEOUT_MS = 1e4;
3
4
  const DEFAULT_SSR_FETCH_MAX_BYTES = 10 * 1024 * 1024;
@@ -116,11 +117,10 @@ async function readResponseTextBounded(res, maxBytes = DEFAULT_SSR_FETCH_MAX_BYT
116
117
  * module source through Vite's plugin pipeline, avoiding serialisation which
117
118
  * cannot faithfully represent React components or closures.
118
119
  *
119
- * Dev mode on Vite < 8 is NOT supported `ModuleRunner` and
120
- * `FetchableDevEnvironment` are Vite 8+ APIs. If you need dev-mode SSR on
121
- * an older Vite version, implement an alternative loader in `loadSSRRemoteEntry`
122
- * for the `isDevSsrEntry` branch and expose a corresponding server endpoint
123
- * from `pluginSSRRemoteEntry.configureServer`.
120
+ * Dev mode on Vite < 8 is NOT supported by this integration because the
121
+ * cross-process `fetchModule` proxy uses Vite 8's environment APIs.
122
+ * `ModuleRunner` itself is available in earlier Vite versions, but an older
123
+ * remote needs a different transport and server endpoint.
124
124
  *
125
125
  * Exported as a plain factory function so it can be serialised into the
126
126
  * generated runtimePlugins list in virtualRemotes.ts.
@@ -135,9 +135,12 @@ async function nodeImport(id) {
135
135
  }
136
136
  const isNodeServer = () => typeof globalThis.process?.versions?.node === "string";
137
137
  const runnerCache = /* @__PURE__ */ new Map();
138
+ function getSortedRecordEntries(record) {
139
+ return Object.entries(record).sort(([left], [right]) => left.localeCompare(right));
140
+ }
138
141
  /**
139
- * Load `vite/module-runner`. Returns null on Vite < 8 where the subpath doesn't
140
- * exist.
142
+ * Load `vite/module-runner`. Returns null when the installed Vite does not
143
+ * expose the module-runner entry point.
141
144
  */
142
145
  async function getModuleRunnerModule() {
143
146
  const moduleRunnerId = ["vite", "module-runner"].join("/");
@@ -156,11 +159,33 @@ async function getModuleRunnerModule() {
156
159
  * `/__mf_runner__` endpoint. Each HTTP POST carries a `fetchModule` invoke
157
160
  * payload; the remote responds with the transformed module source as JSON.
158
161
  *
159
- * This is Vite 8+ only older versions don't expose `vite/module-runner` or
160
- * the `/__mf_runner__` proxy endpoint.
162
+ * The cross-process transport is Vite 8+ only because older versions do not
163
+ * expose the `/__mf_runner__` environment proxy used here.
161
164
  */
162
- async function getOrCreateRunner(remoteOrigin, fetchTimeoutMs, fetchMaxBytes) {
163
- const cacheKey = `${fetchTimeoutMs}::${fetchMaxBytes}::${remoteOrigin}`;
165
+ function getRunnerCacheKey(remoteOrigin, resolvedShared, fetchTimeoutMs, fetchMaxBytes) {
166
+ return JSON.stringify([
167
+ remoteOrigin,
168
+ fetchTimeoutMs,
169
+ fetchMaxBytes,
170
+ getSortedRecordEntries(resolvedShared)
171
+ ]);
172
+ }
173
+ async function resolveSharedExternal(id, resolvedShared) {
174
+ if (typeof id !== "string") return null;
175
+ const resolved = resolvedShared[id];
176
+ if (!resolved) return null;
177
+ if (EXTERNAL_URL_RE.test(resolved)) return {
178
+ externalize: resolved,
179
+ type: "module"
180
+ };
181
+ const { pathToFileURL } = await _url();
182
+ return {
183
+ externalize: pathToFileURL(resolved).href,
184
+ type: "module"
185
+ };
186
+ }
187
+ async function getOrCreateRunner(remoteOrigin, resolvedShared, fetchTimeoutMs, fetchMaxBytes) {
188
+ const cacheKey = getRunnerCacheKey(remoteOrigin, resolvedShared, fetchTimeoutMs, fetchMaxBytes);
164
189
  if (runnerCache.has(cacheKey)) return runnerCache.get(cacheKey);
165
190
  const promise = (async () => {
166
191
  const viteRunner = await getModuleRunnerModule();
@@ -171,6 +196,10 @@ async function getOrCreateRunner(remoteOrigin, fetchTimeoutMs, fetchMaxBytes) {
171
196
  return new ModuleRunner({
172
197
  hmr: false,
173
198
  transport: { async invoke(payload) {
199
+ if (payload.data.name === "fetchModule") {
200
+ const sharedExternal = await resolveSharedExternal(payload.data.data[0], resolvedShared);
201
+ if (sharedExternal) return { result: sharedExternal };
202
+ }
174
203
  const text = await readResponseTextBounded(await fetchWithTimeout(runnerEndpoint, {
175
204
  method: "POST",
176
205
  headers: { "Content-Type": "application/json" },
@@ -190,6 +219,7 @@ const _path = () => nodeImport("path");
190
219
  const _fs = () => nodeImport("fs");
191
220
  const _crypto = () => nodeImport("crypto");
192
221
  const _module = () => nodeImport("module");
222
+ const _url = () => nodeImport("url");
193
223
  /**
194
224
  * Version key for a resolved SSR entry. Derived from the remote's manifest
195
225
  * content so a redeploy at the same URL produces a different key, which in
@@ -449,7 +479,7 @@ function revalidate(remoteEntryUrl) {
449
479
  const tempFileCache = /* @__PURE__ */ new Map();
450
480
  const tempFilePathCache = /* @__PURE__ */ new Map();
451
481
  function getSsrTransformContextKey(resolvedShared, shareScopeName) {
452
- return JSON.stringify([shareScopeName, Object.entries(resolvedShared).sort(([left], [right]) => left.localeCompare(right))]);
482
+ return JSON.stringify([shareScopeName, getSortedRecordEntries(resolvedShared)]);
453
483
  }
454
484
  let ssrCacheDirPromise;
455
485
  async function getSSRCacheDir() {
@@ -573,7 +603,7 @@ async function importTempModule(filePath, versionKey) {
573
603
  }
574
604
  let warnedVmUnavailable = false;
575
605
  async function tryVmStrategy(ssrEntry, options) {
576
- const { loadViaVmStrategy, isVmStrategyAvailable } = await import("./ssrVmStrategy-B34y11HE.js");
606
+ const { loadViaVmStrategy, isVmStrategyAvailable } = await import("./ssrVmStrategy-DTJITp2Z.js");
577
607
  if (!await isVmStrategyAvailable()) {
578
608
  if (!warnedVmUnavailable) {
579
609
  warnedVmUnavailable = true;
@@ -605,7 +635,7 @@ async function loadSSRRemoteEntry(ssrEntry, options) {
605
635
  const urlObj = new URL(url);
606
636
  if (urlObj.pathname.includes("/__mf_ssr__/")) {
607
637
  const remoteOrigin = urlObj.origin;
608
- const runner = await getOrCreateRunner(remoteOrigin, options.fetchTimeoutMs, options.fetchMaxBytes);
638
+ const runner = await getOrCreateRunner(remoteOrigin, resolvedShared, options.fetchTimeoutMs, options.fetchMaxBytes);
609
639
  if (!runner) {
610
640
  if (process.env.NODE_ENV !== "production") return null;
611
641
  } else try {
@@ -1,4 +1,5 @@
1
- import { c as readResponseTextBounded, n as neutralizeBrowserPreloadHelpers, s as fetchWithTimeout, t as SsrEntryHttpError } from "./ssrEntryLoader-gVPDPAE8.js";
1
+ import { a as getCommonSharedSubpaths } from "./pathNormalization-DvgU8LIp.js";
2
+ import { c as readResponseTextBounded, n as neutralizeBrowserPreloadHelpers, s as fetchWithTimeout, t as SsrEntryHttpError } from "./ssrEntryLoader-Ccr0zMrr.js";
2
3
  //#region src/utils/ssrVmStrategy.ts
3
4
  /**
4
5
  * vm.SourceTextModule strategy for loading remote SSR entries.
@@ -39,6 +40,22 @@ async function getVmApi() {
39
40
  async function isVmStrategyAvailable() {
40
41
  return await getVmApi() !== null;
41
42
  }
43
+ function findVmSharedKey(specifier, shared) {
44
+ if (!shared) return;
45
+ const keys = Object.keys(shared);
46
+ if (Object.prototype.hasOwnProperty.call(shared, specifier)) return specifier;
47
+ const vueKey = keys.find((key) => key.endsWith("/") ? key.slice(0, -1) === "vue" : key === "vue");
48
+ if (vueKey && (specifier === "vue/dist/vue.esm-bundler.js" || specifier === "vue/dist/vue.runtime.esm-bundler.js")) return vueKey;
49
+ const commonSubpathKey = keys.find((key) => {
50
+ return getCommonSharedSubpaths(key.endsWith("/") ? key.slice(0, -1) : key).includes(specifier);
51
+ });
52
+ if (commonSubpathKey) return commonSubpathKey;
53
+ return keys.find((key) => {
54
+ if (!key.endsWith("/")) return false;
55
+ const keyBase = key.slice(0, -1);
56
+ return specifier === keyBase || specifier.startsWith(`${keyBase}/`);
57
+ });
58
+ }
42
59
  function getFederationInstances() {
43
60
  return globalThis.__FEDERATION__?.__INSTANCES__ ?? [];
44
61
  }
@@ -51,9 +68,11 @@ async function loadBareModule(specifier, options) {
51
68
  const instances = owner ? [owner] : getFederationInstances();
52
69
  for (const instance of instances) {
53
70
  if (typeof instance?.loadShare !== "function") continue;
54
- const shared = instance.options?.shared?.[specifier];
55
- if (!shared) continue;
56
- if (!(Array.isArray(shared.scope) ? shared.scope : [shared.scope ?? "default"]).includes(options.shareScopeName)) continue;
71
+ const shared = instance.options?.shared;
72
+ const sharedKey = findVmSharedKey(specifier, shared);
73
+ const shareConfig = sharedKey ? shared?.[sharedKey] : void 0;
74
+ if (!shareConfig) continue;
75
+ if (!(Array.isArray(shareConfig.scope) ? shareConfig.scope : [shareConfig.scope ?? "default"]).includes(options.shareScopeName)) continue;
57
76
  try {
58
77
  const factory = await instance.loadShare(specifier);
59
78
  if (typeof factory === "function") {
@@ -1,3 +1,4 @@
1
+ import runtimePackage from "@module-federation/runtime/package.json" with { type: "json" };
1
2
  import * as runtimeCore from "@module-federation/runtime/core";
2
3
  //#region src/utils/injectExternalRuntimeCorePlugin.ts
3
4
  /**
@@ -8,8 +9,7 @@ import * as runtimeCore from "@module-federation/runtime/core";
8
9
  * Mirrors `@module-federation/inject-external-runtime-core-plugin` without
9
10
  * adding that package (or `runtime-tools`) as a dependency of this plugin.
10
11
  */
11
- /** Keep in sync with the `@module-federation/runtime` dependency version. */
12
- const PLUGIN_VERSION = "2.8.0";
12
+ const PLUGIN_VERSION = runtimePackage.version;
13
13
  function getFederationGlobal() {
14
14
  const globalRef = runtimeCore.Global;
15
15
  if (!globalRef || typeof globalRef !== "object") return void 0;
@@ -17,11 +17,10 @@
17
17
  * module source through Vite's plugin pipeline, avoiding serialisation which
18
18
  * cannot faithfully represent React components or closures.
19
19
  *
20
- * Dev mode on Vite < 8 is NOT supported `ModuleRunner` and
21
- * `FetchableDevEnvironment` are Vite 8+ APIs. If you need dev-mode SSR on
22
- * an older Vite version, implement an alternative loader in `loadSSRRemoteEntry`
23
- * for the `isDevSsrEntry` branch and expose a corresponding server endpoint
24
- * from `pluginSSRRemoteEntry.configureServer`.
20
+ * Dev mode on Vite < 8 is NOT supported by this integration because the
21
+ * cross-process `fetchModule` proxy uses Vite 8's environment APIs.
22
+ * `ModuleRunner` itself is available in earlier Vite versions, but an older
23
+ * remote needs a different transport and server endpoint.
25
24
  *
26
25
  * Exported as a plain factory function so it can be serialised into the
27
26
  * generated runtimePlugins list in virtualRemotes.ts.
@@ -1,2 +1,2 @@
1
- import { i as ssrEntryLoaderPlugin, n as neutralizeBrowserPreloadHelpers, r as revalidate, t as SsrEntryHttpError } from "../ssrEntryLoader-gVPDPAE8.js";
1
+ import { i as ssrEntryLoaderPlugin, n as neutralizeBrowserPreloadHelpers, r as revalidate, t as SsrEntryHttpError } from "../ssrEntryLoader-Ccr0zMrr.js";
2
2
  export { SsrEntryHttpError, ssrEntryLoaderPlugin as default, neutralizeBrowserPreloadHelpers, revalidate };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/vite",
3
- "version": "1.20.2",
3
+ "version": "1.20.4",
4
4
  "description": "Vite plugin for Module Federation",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -77,9 +77,9 @@
77
77
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
78
78
  },
79
79
  "dependencies": {
80
- "@module-federation/dts-plugin": "2.8.1",
81
- "@module-federation/runtime": "2.8.1",
82
- "@module-federation/sdk": "2.8.1"
80
+ "@module-federation/dts-plugin": "2.8.2",
81
+ "@module-federation/runtime": "2.8.2",
82
+ "@module-federation/sdk": "2.8.2"
83
83
  },
84
84
  "devDependencies": {
85
85
  "@playwright/test": "1.62.0",
@@ -92,39 +92,5 @@
92
92
  "typescript": "7.0.2",
93
93
  "vite": "8.2.0",
94
94
  "vitest": "4.1.10"
95
- },
96
- "pnpm": {
97
- "overrides": {
98
- "@babel/core@<7.29.6": "7.29.6",
99
- "@babel/helpers@<7.26.10": "7.29.7",
100
- "@babel/plugin-transform-modules-systemjs@<7.29.4": "7.29.4",
101
- "@babel/runtime@<7.26.10": "7.29.7",
102
- "adm-zip@<0.6.0": "0.6.0",
103
- "ajv@>=6.0.0 <6.14.0": "6.14.0",
104
- "ajv@>=8.0.0 <8.18.0": "8.20.0",
105
- "body-parser@<1.20.6": "1.20.6",
106
- "cross-spawn@<7.0.5": "7.0.6",
107
- "esbuild@<0.28.1": "0.28.1",
108
- "fast-uri@>=3.0.0 <3.1.4": "3.1.4",
109
- "follow-redirects@<1.16.0": "1.16.0",
110
- "http-proxy-middleware@>=2.0.0 <2.0.10": "2.0.10",
111
- "immutable@<4.3.9": "4.3.9",
112
- "js-yaml@>=4.0.0 <4.3.0": "4.3.0",
113
- "lodash@<4.18.0": "4.18.1",
114
- "path-to-regexp@<0.1.13": "0.1.13",
115
- "postcss@<8.5.18": "8.5.25",
116
- "qs@>=6.0.0 <6.15.2": "6.15.2",
117
- "serialize-javascript@<7.0.5": "7.0.5",
118
- "shell-quote@<1.9.0": "1.10.0",
119
- "sucrase@<3.35.1": "3.35.1",
120
- "undici@>=7.0.0 <7.28.0": "7.28.0",
121
- "uuid@<11.1.1": "11.1.1",
122
- "webpack-dev-server@<5.2.6": "5.2.6",
123
- "webpack@<5.104.1": "5.109.2",
124
- "websocket-driver@<0.7.5": "0.7.5",
125
- "ws@>=8.0.0 <8.21.0": "8.21.0",
126
- "yaml@>=1.0.0 <1.10.3": "1.10.3",
127
- "yaml@>=2.0.0 <2.8.3": "2.8.3"
128
- }
129
95
  }
130
96
  }