@module-federation/vite 1.22.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
+ import { _ as resolvePublicPath, a as matchesSharedSource, c as filterId, d as getNodeModulesSuffix, f as isAssetLikeImport, g as normalizeNodeModulePath, h as isViteOptimizableEntry, i as invalidateSharedKeyMatcher, l as getBasePath$1, m as isNuxtClientBase, n as getSharedRequest, p as isNodeModulePath, r as getSharedRuntimeKey, s as ensureTrailingSlash, t as findSharedKey, u as getCommonSharedSubpaths, v as stripQueryAndHash, y as stripViteFsPrefix } from "./sharedKeyMatcher-Od_nYxJA.js";
1
2
  import { i as resolveHashPlaceholderFileName, n as normalizePathForImport, r as rebaseImport } from "./buildPaths-BoaQTkxt.js";
2
- import { a as getPackageDetectionCwd, c as getSharedCacheDescriptor, d as packageNameDecode, f as packageNameEncode, g as createModuleFederationError, h as sharedCacheHelperCode, i as getIsRolldown, l as hasPackageDependency, m as setPackageDetectionCwd, n as getInstalledPackageEntry, o as getPackageName, p as resolveImportPath, r as getInstalledPackageJson, s as getPackageNameFromNodeModulePath, u as isNuxtProjectRoot, v as mfWarn } from "./dtsConstants-BEGrtvcw.js";
3
- import { a as filterId, c as getCommonSharedSubpaths, d as isNodeModulePath, f as isNuxtClientBase, h as resolvePublicPath, i as ensureTrailingSlash, l as getMatchingNodeModuleSubpath, m as normalizeNodeModulePath, n as invalidateSharedKeyMatcher, o as getBasePath$1, p as isViteOptimizableEntry, r as matchesSharedSource, s as getCommonSharedSubpathFromNodeModulePath, t as findSharedKey, u as isAssetLikeImport } from "./sharedKeyMatcher-DiUzRVH1.js";
3
+ import { C as isReactCoreShare, E as mfWarn, S as REACT_DOM_CLIENT_SHARE, _ as resolveModulePath, a as getIsRolldown, b as supportsCodeSplittingGroupDebugName, c as getPackageNameFromNodeModulePath, d as isNuxtProjectRoot, f as isPackageExportAvailable, g as resolveImportPath, h as packageNameEncode, i as getInstalledPackageJson, l as getSharedCacheDescriptor, m as packageNameDecode, n as getDependencyNames, o as getPackageDetectionCwd, p as isPackageInstalled, r as getInstalledPackageEntry, s as getPackageName, u as hasPackageDependency, v as setPackageDetectionCwd, w as createModuleFederationError, x as REACT_CLIENT_INTERNALS_KEY, y as sharedCacheHelperCode } from "./dtsConstants-DEMpRfBz.js";
4
4
  import { createRequire } from "node:module";
5
5
  import * as fs$2 from "fs";
6
6
  import { existsSync, readFileSync, readdirSync, realpathSync, statSync, writeFileSync } from "fs";
@@ -8,6 +8,7 @@ import { createRequire as createRequire$1, isBuiltin } from "module";
8
8
  import * as path$1 from "node:path";
9
9
  import path, { basename } from "node:path";
10
10
  import { fileURLToPath, pathToFileURL } from "url";
11
+ import * as vite from "vite";
11
12
  import { parseAst, version } from "vite";
12
13
  import { createHash } from "node:crypto";
13
14
  import * as fs$1 from "node:fs";
@@ -400,6 +401,16 @@ function resolveEnvironmentConsumerTarget(ctx) {
400
401
  function isClientEnvironment(ctx) {
401
402
  return resolveEnvironmentConsumerTarget(ctx) !== "server";
402
403
  }
404
+ /**
405
+ * Whether a build hook runs for a server graph. Vite 6+ hooks carry an
406
+ * environment; Vite 5 (and hooks invoked before `configResolved`) fall back to
407
+ * the legacy root `build.ssr` flag.
408
+ */
409
+ function isServerBuildContext(ctx, config) {
410
+ const target = resolveEnvironmentConsumerTarget(ctx);
411
+ if (target) return target === "server";
412
+ return Boolean(config?.build?.ssr);
413
+ }
403
414
  function resolveRemoteConsumer(ctx, hasMultiEnvironment) {
404
415
  if (!hasMultiEnvironment) return "unified";
405
416
  return resolveEnvironmentConsumerTarget(ctx) ?? "client";
@@ -431,7 +442,7 @@ function isJsxClosingTagSlash(code, slashIndex) {
431
442
  return code[cursor] === ">";
432
443
  }
433
444
  /** Mark comments, string/template literals, and regular expressions as non-code. */
434
- function createCodePositionMap(code) {
445
+ function createCodePositionMap(code, onComment) {
435
446
  const positions = Array(code.length).fill(true);
436
447
  const mask = (start, end) => {
437
448
  for (let index = start; index < end; index++) positions[index] = false;
@@ -449,6 +460,7 @@ function createCodePositionMap(code) {
449
460
  index += 2;
450
461
  while (index < code.length && code[index] !== "\n" && code[index] !== "\r") index++;
451
462
  mask(start, index);
463
+ onComment?.(start, index);
452
464
  continue;
453
465
  }
454
466
  if (char === "/" && next === "*") {
@@ -457,6 +469,7 @@ function createCodePositionMap(code) {
457
469
  while (index < code.length && !(code[index] === "*" && code[index + 1] === "/")) index++;
458
470
  index = Math.min(code.length, index + 2);
459
471
  mask(start, index);
472
+ onComment?.(start, index);
460
473
  continue;
461
474
  }
462
475
  if (char === "\"" || char === "'" || char === "`") {
@@ -762,8 +775,8 @@ function normalizeRemoteItem(key, remote) {
762
775
  * @param {string} sharedName
763
776
  * @returns {string | undefined}
764
777
  */
765
- function searchPackageVersion(sharedName) {
766
- const version = getInstalledPackageJson(sharedName)?.packageJson.version;
778
+ function searchPackageVersion(sharedName, cwd) {
779
+ const version = getInstalledPackageJson(sharedName, { cwd })?.packageJson.version;
767
780
  return typeof version === "string" ? version : void 0;
768
781
  }
769
782
  function inferVersionFromRequiredVersion(requiredVersion) {
@@ -798,36 +811,93 @@ const PACKAGE_SPECIFIER_PROTOCOL_RE = /^[a-z][a-z\d+.-]*:/i;
798
811
  function isProtocolRequiredVersion(requiredVersion) {
799
812
  return PACKAGE_SPECIFIER_PROTOCOL_RE.test(requiredVersion.trim());
800
813
  }
814
+ const SEMVER_COMPARATOR_RE = /^(?:[<>=~^]*v?(?:\d+|[xX*])(?:\.(?:\d+|[xX*]))*(?:[-+][\w.-]+)?|[<>=~^]+|[xX*]|-)$/;
815
+ function isSemverRange(range) {
816
+ return range.split("||").every((alternative) => {
817
+ const comparators = alternative.trim().split(/\s+/).filter(Boolean);
818
+ return comparators.length > 0 && comparators.every((c) => SEMVER_COMPARATOR_RE.test(c));
819
+ });
820
+ }
821
+ function isUsableRequiredVersion(requiredVersion) {
822
+ return requiredVersion.trim() !== "" && !isProtocolRequiredVersion(requiredVersion) && isSemverRange(requiredVersion);
823
+ }
824
+ /** Bare specifiers name an installed package; relative/absolute paths do not. */
825
+ function isBareSpecifier(specifier) {
826
+ return !specifier.startsWith(".") && !specifier.startsWith("\0") && !path$1.isAbsolute(specifier) && !PACKAGE_SPECIFIER_PROTOCOL_RE.test(specifier);
827
+ }
828
+ function readProjectPackageJson(cwd, cache) {
829
+ if (cache.has(cwd)) return cache.get(cwd);
830
+ let packageJson;
831
+ try {
832
+ packageJson = JSON.parse(fs$2.readFileSync(path$1.join(cwd, "package.json"), "utf8"));
833
+ } catch {}
834
+ cache.set(cwd, packageJson);
835
+ return packageJson;
836
+ }
801
837
  function getLitExportSubpathShares(sharedName) {
802
838
  if (sharedName !== "lit") return [];
803
839
  const exportsField = getInstalledPackageJson(sharedName, { packageName: sharedName })?.packageJson.exports;
804
840
  if (!exportsField || typeof exportsField === "string") return [];
805
841
  return Object.keys(exportsField).filter((key) => key.startsWith("./") && key !== "." && !key.includes("*")).map((key) => `${sharedName}/${key.slice(2)}`);
806
842
  }
843
+ const sharedVersionConfigs = /* @__PURE__ */ new WeakMap();
844
+ function resolveSharedVersion(key, config, cwd, packageJsonCache = /* @__PURE__ */ new Map(), fallbackVersion) {
845
+ const source = typeof config.import === "string" && isBareSpecifier(config.import) ? config.import : key;
846
+ const version = config.version || searchPackageVersion(source, cwd) || inferVersionFromRequiredVersion(config.requiredVersion) || fallbackVersion;
847
+ let requiredVersion = config.requiredVersion;
848
+ if (requiredVersion === void 0 && !config.version) {
849
+ const packageJson = readProjectPackageJson(cwd, packageJsonCache);
850
+ const packageName = getPackageName(source);
851
+ requiredVersion = packageJson?.dependencies?.[packageName] ?? packageJson?.devDependencies?.[packageName] ?? packageJson?.peerDependencies?.[packageName] ?? packageJson?.optionalDependencies?.[packageName];
852
+ }
853
+ if (requiredVersion === false || typeof requiredVersion === "string" && isUsableRequiredVersion(requiredVersion)) return {
854
+ version,
855
+ requiredVersion
856
+ };
857
+ return {
858
+ version,
859
+ requiredVersion: config.import === false || config.version ? "*" : version ? `^${version}` : "*"
860
+ };
861
+ }
862
+ function resolveSharedVersions(shared, root) {
863
+ const packageJsonCache = /* @__PURE__ */ new Map();
864
+ for (const [key, item] of Object.entries(shared)) {
865
+ const config = sharedVersionConfigs.get(item);
866
+ if (!config) continue;
867
+ const { version, requiredVersion } = resolveSharedVersion(key, config, root, packageJsonCache, item.version);
868
+ item.version = version;
869
+ item.shareConfig.requiredVersion = requiredVersion;
870
+ }
871
+ }
807
872
  function normalizeShareItem(key, shareItem) {
808
- const isImportFalse = typeof shareItem === "object" && shareItem.import === false;
809
- const explicitVersion = typeof shareItem === "object" ? shareItem.version : void 0;
810
- const inferredVersion = typeof shareItem === "object" ? inferVersionFromRequiredVersion(shareItem.requiredVersion) : void 0;
811
873
  const treeShaking = typeof shareItem === "object" ? shareItem.treeShaking : void 0;
812
874
  if (treeShaking && treeShaking.mode !== "server-calc" && treeShaking.mode !== "runtime-infer") throw createModuleFederationError(`Invalid shared config for "${key}": treeShaking.mode must be either "server-calc" or "runtime-infer".`);
813
875
  if (treeShaking && typeof shareItem === "object" && shareItem.eager) throw createModuleFederationError(`Invalid shared config for "${key}": cannot use both "eager: true" and "treeShaking.mode" simultaneously. Choose one strategy.`);
876
+ if (typeof shareItem === "object") {
877
+ const request = typeof shareItem.request === "string" ? shareItem.request : key;
878
+ const shareKey = typeof shareItem.shareKey === "string" ? shareItem.shareKey : key;
879
+ if (request.endsWith("/") !== shareKey.endsWith("/")) throw createModuleFederationError(`Invalid shared config for "${key}": "request" and "shareKey" must both end with "/" for a prefix share, or neither. Got request "${request}" and shareKey "${shareKey}".`);
880
+ }
814
881
  if (treeShaking?.mode === "runtime-infer" && typeof shareItem === "object" && shareItem.singleton) mfWarn(`Shared singleton "${key}" uses runtime-infer tree shaking, which may load both a tree-shaken bundle and a full bundle when consumers require different exports. Prefer server-calc for singleton dependencies. If runtime-infer is required, expand usedExports to reduce this risk.`);
815
- const version = explicitVersion || searchPackageVersion(key) || inferredVersion;
816
- if (typeof shareItem === "string") return {
817
- name: shareItem,
818
- version,
819
- scope: "default",
820
- from: "",
821
- shareConfig: {
822
- import: void 0,
823
- singleton: false,
824
- eager: false,
825
- requiredVersion: version ? `^${version}` : "*"
826
- }
827
- };
828
- const userRequiredVersion = shareItem.requiredVersion;
829
- const keepUserRequiredVersion = userRequiredVersion === false || typeof userRequiredVersion === "string" && userRequiredVersion.trim() !== "" && !isProtocolRequiredVersion(userRequiredVersion);
830
- return {
882
+ const config = typeof shareItem === "object" ? shareItem : {};
883
+ const { version, requiredVersion } = resolveSharedVersion(key, config, getPackageDetectionCwd());
884
+ if (typeof shareItem === "string") {
885
+ const result = {
886
+ name: shareItem,
887
+ version,
888
+ scope: "default",
889
+ from: "",
890
+ shareConfig: {
891
+ import: void 0,
892
+ singleton: false,
893
+ eager: false,
894
+ requiredVersion
895
+ }
896
+ };
897
+ sharedVersionConfigs.set(result, { ...config });
898
+ return result;
899
+ }
900
+ const result = {
831
901
  name: key,
832
902
  from: "",
833
903
  version,
@@ -836,12 +906,17 @@ function normalizeShareItem(key, shareItem) {
836
906
  import: shareItem.import,
837
907
  singleton: shareItem.singleton || false,
838
908
  eager: shareItem.eager || false,
839
- requiredVersion: keepUserRequiredVersion ? userRequiredVersion : isImportFalse || shareItem.version ? "*" : version ? `^${version}` : "*",
909
+ requiredVersion,
840
910
  strictVersion: !!shareItem.strictVersion,
911
+ ...shareItem.request !== void 0 ? { request: shareItem.request } : {},
912
+ ...shareItem.shareKey !== void 0 ? { shareKey: shareItem.shareKey } : {},
913
+ ...shareItem.allowNodeModulesSuffixMatch !== void 0 ? { allowNodeModulesSuffixMatch: shareItem.allowNodeModulesSuffixMatch } : {},
841
914
  ...shareItem.suppressMissingImportWarning ? { suppressMissingImportWarning: true } : {},
842
915
  ...treeShaking ? { treeShaking: { ...treeShaking } } : {}
843
916
  }
844
917
  };
918
+ sharedVersionConfigs.set(result, { ...config });
919
+ return result;
845
920
  }
846
921
  /**
847
922
  * Trailing-slash keys are package namespace prefixes (`lodash/`, `@scope/ui/`).
@@ -885,7 +960,8 @@ function normalizeShared(shared) {
885
960
  const value = shared[key];
886
961
  const hadConfiguredPackageSubpath = (result[normalizedKey]?.shareConfig)?.__mfConfiguredPackageSubpath === true;
887
962
  result[normalizedKey] = normalizeShareItem(normalizedKey, value);
888
- if (key.endsWith("/") || hadConfiguredPackageSubpath) result[normalizedKey].shareConfig.__mfConfiguredPackageSubpath = true;
963
+ const requestIsPrefix = typeof value?.request === "string" && value.request.endsWith("/");
964
+ if (key.endsWith("/") || requestIsPrefix || hadConfiguredPackageSubpath) result[normalizedKey].shareConfig.__mfConfiguredPackageSubpath = true;
889
965
  explicitSharedKeys.add(normalizedKey);
890
966
  sourceEntries.push([normalizedKey, value]);
891
967
  });
@@ -945,6 +1021,9 @@ function getNormalizeModuleFederationOptions() {
945
1021
  function hasRemotes(options = getNormalizeModuleFederationOptions()) {
946
1022
  return Object.keys(options.remotes || {}).length > 0;
947
1023
  }
1024
+ function hasShared(options = getNormalizeModuleFederationOptions()) {
1025
+ return Object.keys(options.shared || {}).length > 0;
1026
+ }
948
1027
  function isRemoteContainer(options = getNormalizeModuleFederationOptions()) {
949
1028
  return Object.keys(options.exposes || {}).length > 0;
950
1029
  }
@@ -958,7 +1037,13 @@ function isExplicitSharedKey(key, options) {
958
1037
  return (options ? explicitSharedKeysByOptions.get(options) : explicitSharedKeys)?.has(key) ?? false;
959
1038
  }
960
1039
  function getNormalizeShareItem(key, options = getNormalizeModuleFederationOptions()) {
961
- return options.shared[key] || options.shared[getPackageName(key)] || options.shared[getPackageName(key) + "/"];
1040
+ const matchedKey = findSharedKey(key, options.shared);
1041
+ const shareItem = options.shared[key] || (matchedKey ? options.shared[matchedKey] : void 0) || options.shared[getPackageName(key)] || options.shared[getPackageName(key) + "/"];
1042
+ if (shareItem) return shareItem;
1043
+ return Object.entries(options.shared).find(([sharedKey, item]) => {
1044
+ const runtimeKey = typeof item.shareConfig.shareKey === "string" ? item.shareConfig.shareKey : sharedKey;
1045
+ return runtimeKey.endsWith("/") ? key === runtimeKey.slice(0, -1) || key.startsWith(runtimeKey) : runtimeKey === key;
1046
+ })?.[1];
962
1047
  }
963
1048
  function normalizeModuleFederationOptions(options) {
964
1049
  warnOnReservedInternalNamePrefix(options.name, "containerName");
@@ -966,6 +1051,7 @@ function normalizeModuleFederationOptions(options) {
966
1051
  const normalized = {
967
1052
  exposes: normalizeExposes(options.exposes),
968
1053
  filename: options.filename || "remoteEntry-[hash]",
1054
+ ssrFilename: options.ssrFilename || void 0,
969
1055
  internalName: toInternalModuleFederationName(options.name),
970
1056
  library: normalizeLibrary(options.library),
971
1057
  name: options.name,
@@ -1071,6 +1157,10 @@ var VirtualModule = class VirtualModule {
1071
1157
  if (!cacheMap[this.tag]) cacheMap[this.tag] = {};
1072
1158
  cacheMap[this.tag][this.name] = this;
1073
1159
  }
1160
+ /** The federation scope this module was created under, if it was scoped. */
1161
+ getScopeName() {
1162
+ return this.scopeName;
1163
+ }
1074
1164
  getImportId() {
1075
1165
  const mfName = this.scopeName ?? getNormalizeModuleFederationOptions().internalName;
1076
1166
  const importIdKey = `${mfName}${this.tag}${this.name}${this.tag}`;
@@ -1102,17 +1192,38 @@ const SERVER_ENV_GUARD = "import.meta.env.SSR";
1102
1192
  const SSR_ENTRY_LOADER_SPECIFIER = "@module-federation/vite/ssrEntryLoader";
1103
1193
  const SSR_ONLY_RUNTIME_PLUGINS = /* @__PURE__ */ new Set([SSR_ENTRY_LOADER_SPECIFIER]);
1104
1194
  /**
1195
+ * Whether a Vite environment builds a server graph.
1196
+ *
1197
+ * Vite 6+ sets `consumer` on the environment config; `build.ssr` covers the
1198
+ * legacy `vite build --ssr` flag. Environment names are user-defined, so `ssr`
1199
+ * and `server` are only a fallback for configs that carry neither field.
1200
+ */
1201
+ function isServerEnvironment(name, config) {
1202
+ return config?.consumer === "server" || Boolean(config?.build?.ssr) || name === "ssr" || name === "server";
1203
+ }
1204
+ /**
1205
+ * Whether a resolved Vite config includes a server graph: the legacy
1206
+ * `build.ssr` flag, or any server environment. Vite always registers an `ssr`
1207
+ * environment for `serve`, so this only gates builds.
1208
+ */
1209
+ function isSsrConfig(config) {
1210
+ if (Boolean(config.build?.ssr)) return true;
1211
+ return Object.entries(config.environments ?? {}).some(([name, environment]) => isServerEnvironment(name, environment));
1212
+ }
1213
+ /**
1105
1214
  * Single source of truth for SSR-related feature gates.
1106
1215
  *
1107
- * - Vite 8+ dev: ModuleRunner + FetchableDevEnvironment for `/__mf_ssr__/` entries.
1108
- * - Any Vite major on build/preview: HTTP fetch + temp-file import via ssrEntryLoader.
1216
+ * - Vite 8+ server environments: ModuleRunner + FetchableDevEnvironment for
1217
+ * `/__mf_ssr__/` entries.
1218
+ * - SSR builds on any Vite major: HTTP fetch + temp-file import via
1219
+ * ssrEntryLoader.
1109
1220
  */
1110
- function getSsrCapabilities(viteMajor, command, hasRemotes) {
1221
+ function getSsrCapabilities(viteMajor, command, hasRemotes, isSsr = false) {
1111
1222
  if (!hasRemotes) return {
1112
1223
  enableSsrInitBootstrap: false,
1113
1224
  injectSsrEntryLoader: false
1114
1225
  };
1115
- const supported = command === "build" || command === "serve" && viteMajor >= 8;
1226
+ const supported = isSsr && (command === "build" || command === "serve" && viteMajor >= 8);
1116
1227
  return {
1117
1228
  enableSsrInitBootstrap: supported,
1118
1229
  injectSsrEntryLoader: supported
@@ -1216,171 +1327,517 @@ function isParsableExpression(source) {
1216
1327
  }
1217
1328
  }
1218
1329
  //#endregion
1219
- //#region src/utils/reactIsland.ts
1220
- const SOURCE_EXTENSIONS$1 = [
1221
- ".tsx",
1222
- ".jsx",
1223
- ".ts",
1224
- ".js",
1225
- ".mts",
1226
- ".mjs",
1227
- ".cts",
1228
- ".cjs"
1229
- ];
1230
- function stripQueryAndHash$2(id) {
1231
- return id.split(/[?#]/, 1)[0];
1232
- }
1233
- function resolveSourceFile(importPath, root) {
1234
- const cleanImport = stripQueryAndHash$2(importPath);
1235
- if (!cleanImport.startsWith(".") && !path$1.isAbsolute(cleanImport)) return;
1236
- const candidate = path$1.isAbsolute(cleanImport) ? cleanImport : path$1.resolve(root, cleanImport);
1237
- return [
1238
- candidate,
1239
- ...SOURCE_EXTENSIONS$1.map((extension) => `${candidate}${extension}`),
1240
- ...SOURCE_EXTENSIONS$1.map((extension) => path$1.join(candidate, `index${extension}`))
1241
- ].find((filePath) => {
1242
- try {
1243
- return fs$1.statSync(filePath).isFile();
1244
- } catch {
1245
- return false;
1246
- }
1247
- });
1248
- }
1249
- function localDefaultReexport(source) {
1250
- const match = source.match(/export\s*{\s*(?:default(?:\s+as\s+default)?|[A-Za-z_$][\w$]*\s+as\s+default)\s*}\s*from\s*["']([^"']+)["']/);
1251
- return match?.[1]?.startsWith(".") ? match[1] : void 0;
1252
- }
1253
- function isReactComponentSource(source, filePath = "component.tsx") {
1254
- if (!(/\bexport\s+default\b/.test(source) || /\bexport\s*{[^}]*\bdefault\b[^}]*}(?:\s*from\s*["'][^"']+["'])?/.test(source))) return false;
1255
- const extension = path$1.extname(stripQueryAndHash$2(filePath)).toLowerCase();
1256
- const canContainJsx = extension === ".tsx" || extension === ".jsx";
1257
- const hasJsx = /<>|<\s*[A-Za-z][\w.:-]*(?:\s[^<>]*?)?\s*\/?>/.test(source);
1258
- const importsReact = /\bfrom\s*["']react["']|\brequire\(\s*["']react["']\s*\)/.test(source);
1259
- const usesReactApi = /\b(?:React\.)?(?:createElement|jsx|jsxs)\s*\(/.test(source);
1260
- const isClientModule = /^\s*["']use client["']\s*;?/m.test(source);
1261
- return canContainJsx && hasJsx || importsReact && (hasJsx || usesReactApi || isClientModule);
1330
+ //#region src/utils/runtimePluginSpecifier.ts
1331
+ function getRuntimePluginSpecifier(plugin) {
1332
+ return typeof plugin === "string" ? plugin : plugin[0];
1262
1333
  }
1263
- function isReactComponentFile(filePath, seen = /* @__PURE__ */ new Set()) {
1264
- const normalizedPath = path$1.resolve(filePath);
1265
- if (seen.has(normalizedPath)) return false;
1266
- seen.add(normalizedPath);
1267
- let source;
1268
- try {
1269
- source = fs$1.readFileSync(normalizedPath, "utf8");
1270
- } catch {
1271
- return false;
1272
- }
1273
- if (isReactComponentSource(source, normalizedPath)) return true;
1274
- const reexport = localDefaultReexport(source);
1275
- if (!reexport) return false;
1276
- const reexportPath = resolveSourceFile(reexport, path$1.dirname(normalizedPath));
1277
- return reexportPath ? isReactComponentFile(reexportPath, seen) : false;
1334
+ /** Drop SSR-only plugins from a client graph; a server graph keeps them all. */
1335
+ function filterRuntimePluginsForTarget(runtimePlugins, ssrOnlySpecifiers, isServer) {
1336
+ if (isServer) return [...runtimePlugins];
1337
+ return runtimePlugins.filter((plugin) => !ssrOnlySpecifiers.has(getRuntimePluginSpecifier(plugin)));
1278
1338
  }
1339
+ //#endregion
1340
+ //#region src/utils/importAnalysis.ts
1341
+ const analysisByBuild = /* @__PURE__ */ new WeakMap();
1279
1342
  /**
1280
- * React is shared by the normal MF runtime when explicitly configured. When it
1281
- * is local, UI exposes can safely advertise an island capability in addition
1282
- * to their unchanged default export.
1343
+ * Share source analysis within one build environment. Callers still resolve
1344
+ * requests and apply their own sharing configuration. Clear at buildStart and
1345
+ * buildEnd so watch rebuilds start fresh and completed builds release source.
1283
1346
  */
1284
- function getReactIslandExposes(options, root) {
1285
- if (options.experiments.ssrMode !== "ISLAND") return /* @__PURE__ */ new Set();
1286
- if (Object.hasOwn(options.shared, "react")) return /* @__PURE__ */ new Set();
1287
- const islandExposes = /* @__PURE__ */ new Set();
1288
- for (const [key, expose] of Object.entries(options.exposes)) {
1289
- const sourceFile = resolveSourceFile(expose.import, root);
1290
- if (sourceFile && isReactComponentFile(sourceFile)) islandExposes.add(key);
1347
+ function getImportAnalysis(build) {
1348
+ let analysis = analysisByBuild.get(build);
1349
+ if (!analysis) {
1350
+ const importsByCode = /* @__PURE__ */ new Map();
1351
+ analysis = {
1352
+ analyze(code) {
1353
+ const cached = importsByCode.get(code);
1354
+ if (cached !== void 0) return cached;
1355
+ const imports = analyzeImports(code);
1356
+ importsByCode.set(code, imports);
1357
+ return imports;
1358
+ },
1359
+ clear() {
1360
+ importsByCode.clear();
1361
+ }
1362
+ };
1363
+ analysisByBuild.set(build, analysis);
1291
1364
  }
1292
- return islandExposes;
1293
- }
1294
- function generateReactIslandBrowserDefinition(enabled) {
1295
- if (!enabled) return "";
1296
- return `
1297
- exportModule.__mf_island = {
1298
- version: 1,
1299
- renderToHtml() {
1300
- return Promise.reject(new Error("[Module Federation] renderToHtml is only available in the SSR remote entry"));
1301
- },
1302
- hydrate(element, props) {
1303
- const root = element && element.hasAttribute && element.hasAttribute("data-mf-island-state")
1304
- ? element
1305
- : element && element.querySelector
1306
- ? element.querySelector("[data-mf-island-state]") || element
1307
- : element;
1308
- if (!root) {
1309
- return Promise.reject(new Error("[Module Federation] Cannot hydrate an island without a root element"));
1310
- }
1311
- let serverProps = {};
1312
- const encodedState = root.getAttribute && root.getAttribute("data-mf-island-state");
1313
- if (encodedState) {
1314
- try {
1315
- serverProps = JSON.parse(decodeURIComponent(encodedState));
1316
- } catch {
1317
- serverProps = {};
1318
- }
1319
- }
1320
- const finalProps = Object.assign({}, serverProps, props || {});
1321
- return Promise.all([import("react"), import("react-dom/client")]).then(([React, ReactDOMClient]) => {
1322
- if (typeof ReactDOMClient.hydrateRoot !== "function") {
1323
- throw new Error("[Module Federation] react-dom/client does not provide hydrateRoot");
1324
- }
1325
- return ReactDOMClient.hydrateRoot(
1326
- root,
1327
- React.createElement(importModule.default, finalProps)
1328
- );
1329
- });
1330
- }
1331
- }`;
1365
+ return analysis;
1332
1366
  }
1333
- function generateReactIslandSSRDefinition(enabled) {
1334
- if (!enabled) return "";
1335
- return `
1336
- exportModule.__mf_island = {
1337
- version: 1,
1338
- async renderToHtml(props) {
1339
- if (typeof importModule.default !== "function" && typeof importModule.default !== "object") {
1340
- throw new Error("[Module Federation] A React island expose must have a default component export");
1341
- }
1342
- const loadedProps = typeof importModule.load === "function" ? await importModule.load() : {};
1343
- const finalProps = Object.assign({}, loadedProps || {}, props || {});
1344
- const [React, ReactDOMServer] = await Promise.all([
1345
- import("react"),
1346
- import("react-dom/server")
1347
- ]);
1348
- const body = ReactDOMServer.renderToString(
1349
- React.createElement(importModule.default, finalProps)
1350
- );
1351
- const state = encodeURIComponent(JSON.stringify(finalProps));
1352
- return '<div data-mf-island-state="' + state + '">' + body + '</div>';
1353
- },
1354
- hydrate() {
1355
- return Promise.reject(new Error("[Module Federation] hydrate is only available in the browser remote entry"));
1356
- }
1357
- }`;
1367
+ function isRecord(value) {
1368
+ return value !== null && typeof value === "object";
1358
1369
  }
1359
- const REACT_ISLAND_CLIENT_ID_PREFIX = "virtual:mf-react-island-client:";
1360
- const REACT_ISLAND_SERVER_ID_PREFIX = "virtual:mf-react-island-server:";
1361
- const RESOLVED_REACT_ISLAND_CLIENT_ID_PREFIX = `\0${REACT_ISLAND_CLIENT_ID_PREFIX}`;
1362
- const RESOLVED_REACT_ISLAND_SERVER_ID_PREFIX = `\0${REACT_ISLAND_SERVER_ID_PREFIX}`;
1363
- function encodeIslandRemoteId(remoteId) {
1364
- return encodeURIComponent(remoteId);
1370
+ function getModuleSource(node) {
1371
+ if (!isRecord(node)) return void 0;
1372
+ const source = node;
1373
+ if (source.type === "Literal" && typeof source.value === "string") return source.value;
1374
+ if (source.type === "StringLiteral" && typeof source.value === "string") return source.value;
1375
+ if (source.type !== "TemplateLiteral") return void 0;
1376
+ const expressions = Array.isArray(source.expressions) ? source.expressions : [];
1377
+ const quasis = Array.isArray(source.quasis) ? source.quasis : [];
1378
+ if (expressions.length > 0 || quasis.length !== 1) return void 0;
1379
+ const quasi = quasis[0];
1380
+ if (!isRecord(quasi) || !isRecord(quasi.value)) return void 0;
1381
+ const value = quasi.value;
1382
+ return typeof value.cooked === "string" ? value.cooked : typeof value.raw === "string" ? value.raw : void 0;
1365
1383
  }
1366
- function decodeIslandRemoteId(encodedRemoteId) {
1367
- return decodeURIComponent(encodedRemoteId);
1384
+ function getExportedName(node) {
1385
+ if (!isRecord(node)) return void 0;
1386
+ const exported = node;
1387
+ if (exported.type === "Identifier" && typeof exported.name === "string") return exported.name;
1388
+ if ((exported.type === "Literal" || exported.type === "StringLiteral") && typeof exported.value === "string") return exported.value;
1368
1389
  }
1369
- function getReactIslandImportRemoteId(source) {
1370
- const queryIndex = source.indexOf("?");
1371
- if (queryIndex === -1) return;
1372
- if (!new URLSearchParams(source.slice(queryIndex + 1)).has("mf-island")) return;
1373
- return source.slice(0, queryIndex);
1390
+ function isTypeOnly(node) {
1391
+ return node.importKind === "type" || node.exportKind === "type";
1374
1392
  }
1375
- function getReactIslandServerImportId(remoteId) {
1376
- return `${REACT_ISLAND_SERVER_ID_PREFIX}${encodeIslandRemoteId(remoteId)}`;
1393
+ function forEachAstNode(root, visit) {
1394
+ const stack = [root];
1395
+ const seen = /* @__PURE__ */ new Set();
1396
+ while (stack.length > 0) {
1397
+ const value = stack.pop();
1398
+ if (!isRecord(value)) continue;
1399
+ if (seen.has(value)) continue;
1400
+ seen.add(value);
1401
+ if (Array.isArray(value)) {
1402
+ for (let index = value.length - 1; index >= 0; index--) stack.push(value[index]);
1403
+ continue;
1404
+ }
1405
+ const node = value;
1406
+ if (typeof node.type === "string") visit(node);
1407
+ Object.entries(node).forEach(([key, child]) => {
1408
+ if (key !== "parent" && key !== "loc") stack.push(child);
1409
+ });
1410
+ }
1377
1411
  }
1378
- function getReactIslandClientImportId(remoteId) {
1379
- return `${REACT_ISLAND_CLIENT_ID_PREFIX}${encodeIslandRemoteId(remoteId)}`;
1412
+ function collectImportDeclaration(node, source, record, requireAllExports) {
1413
+ if (isTypeOnly(node)) return;
1414
+ const specifiers = Array.isArray(node.specifiers) ? node.specifiers : [];
1415
+ if (specifiers.length === 0) {
1416
+ requireAllExports(source);
1417
+ return;
1418
+ }
1419
+ const names = [];
1420
+ for (const specifier of specifiers) {
1421
+ if (!isRecord(specifier)) {
1422
+ requireAllExports(source);
1423
+ return;
1424
+ }
1425
+ if (isTypeOnly(specifier)) continue;
1426
+ if (specifier.type === "ImportNamespaceSpecifier") {
1427
+ requireAllExports(source);
1428
+ return;
1429
+ }
1430
+ if (specifier.type === "ImportDefaultSpecifier") {
1431
+ names.push("default");
1432
+ continue;
1433
+ }
1434
+ if (specifier.type === "ImportSpecifier") {
1435
+ const imported = specifier.imported;
1436
+ if (isRecord(imported) && (imported.type === "Literal" || imported.type === "StringLiteral")) {
1437
+ requireAllExports(source);
1438
+ return;
1439
+ }
1440
+ const name = getExportedName(specifier.imported);
1441
+ if (!name) {
1442
+ requireAllExports(source);
1443
+ return;
1444
+ }
1445
+ names.push(name);
1446
+ continue;
1447
+ }
1448
+ requireAllExports(source);
1449
+ return;
1450
+ }
1451
+ record(names, source);
1380
1452
  }
1381
- function resolveReactIslandConsumerId(id) {
1382
- if (id.startsWith("virtual:mf-react-island-server:")) return `\0${id}`;
1383
- if (id.startsWith("virtual:mf-react-island-client:")) return `\0${id}`;
1453
+ function collectReExport(node, source, record, requireAllExports) {
1454
+ if (isTypeOnly(node)) return;
1455
+ if (node.type === "ExportAllDeclaration") {
1456
+ requireAllExports(source);
1457
+ return;
1458
+ }
1459
+ const specifiers = Array.isArray(node.specifiers) ? node.specifiers : [];
1460
+ if (specifiers.length === 0) {
1461
+ requireAllExports(source);
1462
+ return;
1463
+ }
1464
+ const names = [];
1465
+ for (const specifier of specifiers) {
1466
+ if (!isRecord(specifier)) {
1467
+ requireAllExports(source);
1468
+ return;
1469
+ }
1470
+ if (isTypeOnly(specifier)) continue;
1471
+ if (specifier.type !== "ExportSpecifier") {
1472
+ requireAllExports(source);
1473
+ return;
1474
+ }
1475
+ const local = specifier.local;
1476
+ if (isRecord(local) && (local.type === "Literal" || local.type === "StringLiteral")) {
1477
+ requireAllExports(source);
1478
+ return;
1479
+ }
1480
+ const name = getExportedName(specifier.local);
1481
+ if (!name) {
1482
+ requireAllExports(source);
1483
+ return;
1484
+ }
1485
+ names.push(name);
1486
+ }
1487
+ record(names, source);
1488
+ }
1489
+ function analyzeImports(code) {
1490
+ let ast;
1491
+ try {
1492
+ ast = vite.parseAst(code);
1493
+ } catch {
1494
+ return null;
1495
+ }
1496
+ const imports = [];
1497
+ const recordSource = (names, source) => imports.push({
1498
+ source,
1499
+ usedExports: names
1500
+ });
1501
+ const requireAllExports = (source) => imports.push({
1502
+ source,
1503
+ usedExports: null
1504
+ });
1505
+ const collectImport = (node) => {
1506
+ if (node.type === "ImportDeclaration") {
1507
+ const source = getModuleSource(node.source);
1508
+ if (source) collectImportDeclaration(node, source, recordSource, requireAllExports);
1509
+ return;
1510
+ }
1511
+ if ((node.type === "ExportNamedDeclaration" || node.type === "ExportAllDeclaration") && node.source) {
1512
+ const source = getModuleSource(node.source);
1513
+ if (source) collectReExport(node, source, recordSource, requireAllExports);
1514
+ return;
1515
+ }
1516
+ if (node.type === "ImportExpression") {
1517
+ const source = getModuleSource(node.source);
1518
+ if (source) requireAllExports(source);
1519
+ return;
1520
+ }
1521
+ if (node.type === "CallExpression") {
1522
+ const callee = node.callee;
1523
+ const args = Array.isArray(node.arguments) ? node.arguments : [];
1524
+ if (isRecord(callee) && callee.type === "Identifier" && callee.name === "require" && args.length > 0) {
1525
+ const source = getModuleSource(args[0]);
1526
+ if (source) requireAllExports(source);
1527
+ }
1528
+ }
1529
+ };
1530
+ if ("Visitor" in vite && typeof vite.Visitor === "function") {
1531
+ const visit = (node) => {
1532
+ if (isRecord(node)) collectImport(node);
1533
+ };
1534
+ try {
1535
+ new vite.Visitor({
1536
+ ImportDeclaration: visit,
1537
+ ExportNamedDeclaration: visit,
1538
+ ExportAllDeclaration: visit,
1539
+ ImportExpression: visit,
1540
+ CallExpression: visit
1541
+ }).visit(ast);
1542
+ return imports;
1543
+ } catch {
1544
+ imports.length = 0;
1545
+ }
1546
+ }
1547
+ forEachAstNode(ast, collectImport);
1548
+ return imports;
1549
+ }
1550
+ //#endregion
1551
+ //#region src/utils/treeShaking.ts
1552
+ function shouldAnalyzeSharedExports(shareItem) {
1553
+ return !!(shareItem && (shareItem.shareConfig.treeShaking || shareItem.shareConfig.import === false));
1554
+ }
1555
+ const legacyTreeShakingState = {
1556
+ inferredUsage: /* @__PURE__ */ new Map(),
1557
+ buildMode: false
1558
+ };
1559
+ const treeShakingStates = /* @__PURE__ */ new WeakMap();
1560
+ function getTreeShakingState(options) {
1561
+ if (!options) return legacyTreeShakingState;
1562
+ let state = treeShakingStates.get(options);
1563
+ if (!state) {
1564
+ state = {
1565
+ inferredUsage: /* @__PURE__ */ new Map(),
1566
+ buildMode: false
1567
+ };
1568
+ treeShakingStates.set(options, state);
1569
+ }
1570
+ return state;
1571
+ }
1572
+ function setTreeShakingBuildMode(enabled, options) {
1573
+ getTreeShakingState(options).buildMode = enabled;
1574
+ }
1575
+ function resetTreeShakingExports(options) {
1576
+ getTreeShakingState(options).inferredUsage.clear();
1577
+ }
1578
+ function getOrCreateExportRecord(sharedKey, request, options) {
1579
+ const inferredUsage = getTreeShakingState(options).inferredUsage;
1580
+ let byRequest = inferredUsage.get(sharedKey);
1581
+ if (!byRequest) {
1582
+ byRequest = /* @__PURE__ */ new Map();
1583
+ inferredUsage.set(sharedKey, byRequest);
1584
+ }
1585
+ let record = byRequest.get(request);
1586
+ if (!record) {
1587
+ record = {
1588
+ requiresFullBundle: false,
1589
+ usedExports: /* @__PURE__ */ new Set()
1590
+ };
1591
+ byRequest.set(request, record);
1592
+ }
1593
+ return record;
1594
+ }
1595
+ function recordTreeShakingExports(sharedKey, exports, request = sharedKey, options) {
1596
+ const record = getOrCreateExportRecord(sharedKey, request, options);
1597
+ exports.forEach((name) => record.usedExports.add(name));
1598
+ }
1599
+ function markTreeShakingPackageUnsafe(sharedKey, request = sharedKey, options) {
1600
+ getOrCreateExportRecord(sharedKey, request, options).requiresFullBundle = true;
1601
+ }
1602
+ function getExportRecords(sharedKey, request, options) {
1603
+ const inferredUsage = getTreeShakingState(options).inferredUsage;
1604
+ if (sharedKey) {
1605
+ const records = inferredUsage.get(sharedKey);
1606
+ const wildcard = records?.get("*");
1607
+ const exact = records?.get(request);
1608
+ return [wildcard, exact === wildcard ? void 0 : exact].filter((record) => !!record);
1609
+ }
1610
+ const records = [];
1611
+ inferredUsage.forEach((byRequest, configuredKey) => {
1612
+ const wildcard = byRequest.get("*");
1613
+ const exact = byRequest.get(request);
1614
+ const configuredRequest = getSharedRequest(configuredKey, options?.shared?.[configuredKey]);
1615
+ const keyBase = configuredRequest.endsWith("/") ? configuredRequest.slice(0, -1) : configuredRequest;
1616
+ const requestMatchesConfiguredKey = request === keyBase || request.startsWith(`${keyBase}/`);
1617
+ if (wildcard && requestMatchesConfiguredKey) records.push(wildcard);
1618
+ if (exact && exact !== wildcard) records.push(exact);
1619
+ });
1620
+ return records;
1621
+ }
1622
+ /**
1623
+ * Return the analyzed requirement for one concrete shared request.
1624
+ *
1625
+ * Callers that know the configured share key should pass it explicitly. The
1626
+ * fallback lookup across keys keeps aliases/backwards-compatible callers
1627
+ * working, while still keeping each concrete request's exports isolated.
1628
+ */
1629
+ function getSharedExportUsage(request, shareItem, sharedKey, options) {
1630
+ const treeShaking = shareItem?.shareConfig.treeShaking;
1631
+ if (!shouldAnalyzeSharedExports(shareItem) || !getTreeShakingState(options).buildMode) return;
1632
+ const records = getExportRecords(sharedKey, request, options);
1633
+ if (records.some((record) => record.requiresFullBundle)) return { kind: "full" };
1634
+ const configured = treeShaking?.usedExports ?? [];
1635
+ const result = new Set(configured);
1636
+ records.forEach((record) => record.usedExports.forEach((name) => result.add(name)));
1637
+ if (result.size > 0) return {
1638
+ kind: "exports",
1639
+ usedExports: [...result].sort()
1640
+ };
1641
+ return records.length > 0 ? {
1642
+ kind: "exports",
1643
+ usedExports: []
1644
+ } : { kind: "unknown" };
1645
+ }
1646
+ function getTreeShakingExportUsage(request, shareItem, sharedKey, options) {
1647
+ if (!shareItem?.shareConfig.treeShaking) return void 0;
1648
+ return getSharedExportUsage(request, shareItem, sharedKey, options);
1649
+ }
1650
+ /**
1651
+ * Record consumer imports against this instance's sharing configuration.
1652
+ * Generated wrappers do not contribute consumer usage. If parsing fails,
1653
+ * every share enabled for analysis requires all of its exports.
1654
+ */
1655
+ async function collectTreeShakingImports(code, id, shared, findSharedKey, record, markUnsafe, analysis = getImportAnalysis(shared)) {
1656
+ const normalizedId = normalizePathForImport(id);
1657
+ if (normalizedId.includes("__prebuild__") || normalizedId.includes("__loadShare__") || normalizedId.includes("__mf_tree_shaking_graph__")) return;
1658
+ const imports = analysis.analyze(code);
1659
+ if (imports === null) {
1660
+ Object.entries(shared).forEach(([sharedKey, shareItem]) => {
1661
+ if (shouldAnalyzeSharedExports(shareItem)) markUnsafe(sharedKey, "*");
1662
+ });
1663
+ return;
1664
+ }
1665
+ const pending = [];
1666
+ for (const { source, usedExports } of imports) {
1667
+ const apply = (key) => {
1668
+ if (!key || !shouldAnalyzeSharedExports(shared[key])) return;
1669
+ if (usedExports === null) markUnsafe(key, source);
1670
+ else record(key, usedExports, source);
1671
+ };
1672
+ const key = findSharedKey(source, shared);
1673
+ if (key instanceof Promise) pending.push(key.then(apply));
1674
+ else apply(key);
1675
+ }
1676
+ await Promise.all(pending);
1677
+ }
1678
+ //#endregion
1679
+ //#region src/utils/reactIsland.ts
1680
+ const SOURCE_EXTENSIONS$1 = [
1681
+ ".tsx",
1682
+ ".jsx",
1683
+ ".ts",
1684
+ ".js",
1685
+ ".mts",
1686
+ ".mjs",
1687
+ ".cts",
1688
+ ".cjs"
1689
+ ];
1690
+ function resolveSourceFile(importPath, root) {
1691
+ const cleanImport = stripQueryAndHash(importPath);
1692
+ if (!cleanImport.startsWith(".") && !path$1.isAbsolute(cleanImport)) return;
1693
+ const candidate = path$1.isAbsolute(cleanImport) ? cleanImport : path$1.resolve(root, cleanImport);
1694
+ return [
1695
+ candidate,
1696
+ ...SOURCE_EXTENSIONS$1.map((extension) => `${candidate}${extension}`),
1697
+ ...SOURCE_EXTENSIONS$1.map((extension) => path$1.join(candidate, `index${extension}`))
1698
+ ].find((filePath) => {
1699
+ try {
1700
+ return fs$1.statSync(filePath).isFile();
1701
+ } catch {
1702
+ return false;
1703
+ }
1704
+ });
1705
+ }
1706
+ function localDefaultReexport(source) {
1707
+ const match = source.match(/export\s*{\s*(?:default(?:\s+as\s+default)?|[A-Za-z_$][\w$]*\s+as\s+default)\s*}\s*from\s*["']([^"']+)["']/);
1708
+ return match?.[1]?.startsWith(".") ? match[1] : void 0;
1709
+ }
1710
+ function isReactComponentSource(source, filePath = "component.tsx") {
1711
+ if (!(/\bexport\s+default\b/.test(source) || /\bexport\s*{[^}]*\bdefault\b[^}]*}(?:\s*from\s*["'][^"']+["'])?/.test(source))) return false;
1712
+ const extension = path$1.extname(stripQueryAndHash(filePath)).toLowerCase();
1713
+ const canContainJsx = extension === ".tsx" || extension === ".jsx";
1714
+ const hasJsx = /<>|<\s*[A-Za-z][\w.:-]*(?:\s[^<>]*?)?\s*\/?>/.test(source);
1715
+ const importsReact = /\bfrom\s*["']react["']|\brequire\(\s*["']react["']\s*\)/.test(source);
1716
+ const usesReactApi = /\b(?:React\.)?(?:createElement|jsx|jsxs)\s*\(/.test(source);
1717
+ const isClientModule = /^\s*["']use client["']\s*;?/m.test(source);
1718
+ return canContainJsx && hasJsx || importsReact && (hasJsx || usesReactApi || isClientModule);
1719
+ }
1720
+ function isReactComponentFile(filePath, seen = /* @__PURE__ */ new Set()) {
1721
+ const normalizedPath = path$1.resolve(filePath);
1722
+ if (seen.has(normalizedPath)) return false;
1723
+ seen.add(normalizedPath);
1724
+ let source;
1725
+ try {
1726
+ source = fs$1.readFileSync(normalizedPath, "utf8");
1727
+ } catch {
1728
+ return false;
1729
+ }
1730
+ if (isReactComponentSource(source, normalizedPath)) return true;
1731
+ const reexport = localDefaultReexport(source);
1732
+ if (!reexport) return false;
1733
+ const reexportPath = resolveSourceFile(reexport, path$1.dirname(normalizedPath));
1734
+ return reexportPath ? isReactComponentFile(reexportPath, seen) : false;
1735
+ }
1736
+ /**
1737
+ * React is shared by the normal MF runtime when explicitly configured. When it
1738
+ * is local, UI exposes can safely advertise an island capability in addition
1739
+ * to their unchanged default export.
1740
+ */
1741
+ function getReactIslandExposes(options, root) {
1742
+ if (options.experiments.ssrMode !== "ISLAND") return /* @__PURE__ */ new Set();
1743
+ if (Object.hasOwn(options.shared, "react")) return /* @__PURE__ */ new Set();
1744
+ const islandExposes = /* @__PURE__ */ new Set();
1745
+ for (const [key, expose] of Object.entries(options.exposes)) {
1746
+ const sourceFile = resolveSourceFile(expose.import, root);
1747
+ if (sourceFile && isReactComponentFile(sourceFile)) islandExposes.add(key);
1748
+ }
1749
+ return islandExposes;
1750
+ }
1751
+ function generateReactIslandBrowserDefinition(enabled) {
1752
+ if (!enabled) return "";
1753
+ return `
1754
+ exportModule.__mf_island = {
1755
+ version: 1,
1756
+ renderToHtml() {
1757
+ return Promise.reject(new Error("[Module Federation] renderToHtml is only available in the SSR remote entry"));
1758
+ },
1759
+ hydrate(element, props) {
1760
+ const root = element && element.hasAttribute && element.hasAttribute("data-mf-island-state")
1761
+ ? element
1762
+ : element && element.querySelector
1763
+ ? element.querySelector("[data-mf-island-state]") || element
1764
+ : element;
1765
+ if (!root) {
1766
+ return Promise.reject(new Error("[Module Federation] Cannot hydrate an island without a root element"));
1767
+ }
1768
+ let serverProps = {};
1769
+ const encodedState = root.getAttribute && root.getAttribute("data-mf-island-state");
1770
+ if (encodedState) {
1771
+ try {
1772
+ serverProps = JSON.parse(decodeURIComponent(encodedState));
1773
+ } catch {
1774
+ serverProps = {};
1775
+ }
1776
+ }
1777
+ const finalProps = Object.assign({}, serverProps, props || {});
1778
+ return Promise.all([import("react"), import("react-dom/client")]).then(([React, ReactDOMClient]) => {
1779
+ if (typeof ReactDOMClient.hydrateRoot !== "function") {
1780
+ throw new Error("[Module Federation] react-dom/client does not provide hydrateRoot");
1781
+ }
1782
+ return ReactDOMClient.hydrateRoot(
1783
+ root,
1784
+ React.createElement(importModule.default, finalProps)
1785
+ );
1786
+ });
1787
+ }
1788
+ }`;
1789
+ }
1790
+ function generateReactIslandSSRDefinition(enabled) {
1791
+ if (!enabled) return "";
1792
+ return `
1793
+ exportModule.__mf_island = {
1794
+ version: 1,
1795
+ async renderToHtml(props) {
1796
+ if (typeof importModule.default !== "function" && typeof importModule.default !== "object") {
1797
+ throw new Error("[Module Federation] A React island expose must have a default component export");
1798
+ }
1799
+ const loadedProps = typeof importModule.load === "function" ? await importModule.load() : {};
1800
+ const finalProps = Object.assign({}, loadedProps || {}, props || {});
1801
+ const [React, ReactDOMServer] = await Promise.all([
1802
+ import("react"),
1803
+ import("react-dom/server")
1804
+ ]);
1805
+ const body = ReactDOMServer.renderToString(
1806
+ React.createElement(importModule.default, finalProps)
1807
+ );
1808
+ const state = encodeURIComponent(JSON.stringify(finalProps));
1809
+ return '<div data-mf-island-state="' + state + '">' + body + '</div>';
1810
+ },
1811
+ hydrate() {
1812
+ return Promise.reject(new Error("[Module Federation] hydrate is only available in the browser remote entry"));
1813
+ }
1814
+ }`;
1815
+ }
1816
+ const REACT_ISLAND_CLIENT_ID_PREFIX = "virtual:mf-react-island-client:";
1817
+ const REACT_ISLAND_SERVER_ID_PREFIX = "virtual:mf-react-island-server:";
1818
+ const RESOLVED_REACT_ISLAND_CLIENT_ID_PREFIX = `\0${REACT_ISLAND_CLIENT_ID_PREFIX}`;
1819
+ const RESOLVED_REACT_ISLAND_SERVER_ID_PREFIX = `\0${REACT_ISLAND_SERVER_ID_PREFIX}`;
1820
+ function encodeIslandRemoteId(remoteId) {
1821
+ return encodeURIComponent(remoteId);
1822
+ }
1823
+ function decodeIslandRemoteId(encodedRemoteId) {
1824
+ return decodeURIComponent(encodedRemoteId);
1825
+ }
1826
+ function getReactIslandImportRemoteId(source) {
1827
+ const queryIndex = source.indexOf("?");
1828
+ if (queryIndex === -1) return;
1829
+ if (!new URLSearchParams(source.slice(queryIndex + 1)).has("mf-island")) return;
1830
+ return source.slice(0, queryIndex);
1831
+ }
1832
+ function getReactIslandServerImportId(remoteId) {
1833
+ return `${REACT_ISLAND_SERVER_ID_PREFIX}${encodeIslandRemoteId(remoteId)}`;
1834
+ }
1835
+ function getReactIslandClientImportId(remoteId) {
1836
+ return `${REACT_ISLAND_CLIENT_ID_PREFIX}${encodeIslandRemoteId(remoteId)}`;
1837
+ }
1838
+ function resolveReactIslandConsumerId(id) {
1839
+ if (id.startsWith("virtual:mf-react-island-server:")) return `\0${id}`;
1840
+ if (id.startsWith("virtual:mf-react-island-client:")) return `\0${id}`;
1384
1841
  }
1385
1842
  function remoteIdFromResolvedIslandId(id, prefix) {
1386
1843
  if (!id.startsWith(prefix)) return;
@@ -1832,7 +2289,7 @@ ${exportStatement}
1832
2289
  //#endregion
1833
2290
  //#region src/plugins/pluginReactMixedModeGuard.ts
1834
2291
  function createReactMixedModeRuntimeGuard() {
1835
- return `const __mfReactInternals = mod["__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE"];
2292
+ return `const __mfReactInternals = mod[${JSON.stringify(REACT_CLIENT_INTERNALS_KEY)}];
1836
2293
  if (__mfReactInternals && "A" in __mfReactInternals) {
1837
2294
  let __mfReactDispatcher = __mfReactInternals.A;
1838
2295
  Object.defineProperty(__mfReactInternals, "A", {
@@ -1842,279 +2299,10 @@ if (__mfReactInternals && "A" in __mfReactInternals) {
1842
2299
  set: (next) => {
1843
2300
  if (next && typeof next.getOwner !== "function") next.getOwner = () => null;
1844
2301
  __mfReactDispatcher = next;
1845
- },
1846
- });
1847
- __mfReactInternals.A = __mfReactDispatcher;
1848
- }`;
1849
- }
1850
- //#endregion
1851
- //#region src/utils/treeShaking.ts
1852
- function shouldAnalyzeSharedExports(shareItem) {
1853
- return !!(shareItem && (shareItem.shareConfig.treeShaking || shareItem.shareConfig.import === false));
1854
- }
1855
- const legacyTreeShakingState = {
1856
- inferredUsage: /* @__PURE__ */ new Map(),
1857
- buildMode: false
1858
- };
1859
- const treeShakingStates = /* @__PURE__ */ new WeakMap();
1860
- function getTreeShakingState(options) {
1861
- if (!options) return legacyTreeShakingState;
1862
- let state = treeShakingStates.get(options);
1863
- if (!state) {
1864
- state = {
1865
- inferredUsage: /* @__PURE__ */ new Map(),
1866
- buildMode: false
1867
- };
1868
- treeShakingStates.set(options, state);
1869
- }
1870
- return state;
1871
- }
1872
- function setTreeShakingBuildMode(enabled, options) {
1873
- getTreeShakingState(options).buildMode = enabled;
1874
- }
1875
- function resetTreeShakingExports(options) {
1876
- getTreeShakingState(options).inferredUsage.clear();
1877
- }
1878
- function getOrCreateExportRecord(sharedKey, request, options) {
1879
- const inferredUsage = getTreeShakingState(options).inferredUsage;
1880
- let byRequest = inferredUsage.get(sharedKey);
1881
- if (!byRequest) {
1882
- byRequest = /* @__PURE__ */ new Map();
1883
- inferredUsage.set(sharedKey, byRequest);
1884
- }
1885
- let record = byRequest.get(request);
1886
- if (!record) {
1887
- record = {
1888
- requiresFullBundle: false,
1889
- usedExports: /* @__PURE__ */ new Set()
1890
- };
1891
- byRequest.set(request, record);
1892
- }
1893
- return record;
1894
- }
1895
- function recordTreeShakingExports(sharedKey, exports, request = sharedKey, options) {
1896
- const record = getOrCreateExportRecord(sharedKey, request, options);
1897
- exports.forEach((name) => record.usedExports.add(name));
1898
- }
1899
- function markTreeShakingPackageUnsafe(sharedKey, request = sharedKey, options) {
1900
- getOrCreateExportRecord(sharedKey, request, options).requiresFullBundle = true;
1901
- }
1902
- function getExportRecords(sharedKey, request, options) {
1903
- const inferredUsage = getTreeShakingState(options).inferredUsage;
1904
- if (sharedKey) {
1905
- const records = inferredUsage.get(sharedKey);
1906
- const wildcard = records?.get("*");
1907
- const exact = records?.get(request);
1908
- return [wildcard, exact === wildcard ? void 0 : exact].filter((record) => !!record);
1909
- }
1910
- const records = [];
1911
- inferredUsage.forEach((byRequest, configuredKey) => {
1912
- const wildcard = byRequest.get("*");
1913
- const exact = byRequest.get(request);
1914
- const keyBase = configuredKey.endsWith("/") ? configuredKey.slice(0, -1) : configuredKey;
1915
- const requestMatchesConfiguredKey = request === keyBase || request.startsWith(`${keyBase}/`);
1916
- if (wildcard && requestMatchesConfiguredKey) records.push(wildcard);
1917
- if (exact && exact !== wildcard) records.push(exact);
1918
- });
1919
- return records;
1920
- }
1921
- /**
1922
- * Return the analyzed requirement for one concrete shared request.
1923
- *
1924
- * Callers that know the configured share key should pass it explicitly. The
1925
- * fallback lookup across keys keeps aliases/backwards-compatible callers
1926
- * working, while still keeping each concrete request's exports isolated.
1927
- */
1928
- function getSharedExportUsage(request, shareItem, sharedKey, options) {
1929
- const treeShaking = shareItem?.shareConfig.treeShaking;
1930
- if (!shouldAnalyzeSharedExports(shareItem) || !getTreeShakingState(options).buildMode) return;
1931
- const records = getExportRecords(sharedKey, request, options);
1932
- if (records.some((record) => record.requiresFullBundle)) return { kind: "full" };
1933
- const configured = treeShaking?.usedExports ?? [];
1934
- const result = new Set(configured);
1935
- records.forEach((record) => record.usedExports.forEach((name) => result.add(name)));
1936
- if (result.size > 0) return {
1937
- kind: "exports",
1938
- usedExports: [...result].sort()
1939
- };
1940
- return records.length > 0 ? {
1941
- kind: "exports",
1942
- usedExports: []
1943
- } : { kind: "unknown" };
1944
- }
1945
- function getTreeShakingExportUsage(request, shareItem, sharedKey, options) {
1946
- if (!shareItem?.shareConfig.treeShaking) return void 0;
1947
- return getSharedExportUsage(request, shareItem, sharedKey, options);
1948
- }
1949
- function getModuleSource(node) {
1950
- if (!node || typeof node !== "object") return void 0;
1951
- const source = node;
1952
- if (source.type === "Literal" && typeof source.value === "string") return source.value;
1953
- if (source.type === "StringLiteral" && typeof source.value === "string") return source.value;
1954
- if (source.type !== "TemplateLiteral") return void 0;
1955
- const expressions = Array.isArray(source.expressions) ? source.expressions : [];
1956
- const quasis = Array.isArray(source.quasis) ? source.quasis : [];
1957
- if (expressions.length > 0 || quasis.length !== 1) return void 0;
1958
- const value = quasis[0]?.value;
1959
- return typeof value?.cooked === "string" ? value.cooked : typeof value?.raw === "string" ? value.raw : void 0;
1960
- }
1961
- function getExportedName(node) {
1962
- if (!node || typeof node !== "object") return void 0;
1963
- const exported = node;
1964
- if (exported.type === "Identifier" && typeof exported.name === "string") return exported.name;
1965
- if ((exported.type === "Literal" || exported.type === "StringLiteral") && typeof exported.value === "string") return exported.value;
1966
- }
1967
- function isTypeOnly(node) {
1968
- return node.importKind === "type" || node.exportKind === "type";
1969
- }
1970
- function forEachAstNode(root, visit) {
1971
- const stack = [root];
1972
- const seen = /* @__PURE__ */ new Set();
1973
- while (stack.length > 0) {
1974
- const value = stack.pop();
1975
- if (!value || typeof value !== "object") continue;
1976
- if (seen.has(value)) continue;
1977
- seen.add(value);
1978
- if (Array.isArray(value)) {
1979
- for (let index = value.length - 1; index >= 0; index--) stack.push(value[index]);
1980
- continue;
1981
- }
1982
- const node = value;
1983
- if (typeof node.type === "string") visit(node);
1984
- Object.entries(node).forEach(([key, child]) => {
1985
- if (key !== "parent" && key !== "loc") stack.push(child);
1986
- });
1987
- }
1988
- }
1989
- function collectImportDeclaration(node, source, record, markUnsafe) {
1990
- if (isTypeOnly(node)) return;
1991
- const specifiers = Array.isArray(node.specifiers) ? node.specifiers : [];
1992
- if (specifiers.length === 0) {
1993
- markUnsafe(source);
1994
- return;
1995
- }
1996
- const names = [];
1997
- for (const specifier of specifiers) {
1998
- if (isTypeOnly(specifier)) continue;
1999
- if (specifier.type === "ImportNamespaceSpecifier") {
2000
- markUnsafe(source);
2001
- return;
2002
- }
2003
- if (specifier.type === "ImportDefaultSpecifier") {
2004
- names.push("default");
2005
- continue;
2006
- }
2007
- if (specifier.type === "ImportSpecifier") {
2008
- const imported = specifier.imported;
2009
- if (imported?.type === "Literal" || imported?.type === "StringLiteral") {
2010
- markUnsafe(source);
2011
- return;
2012
- }
2013
- const name = getExportedName(specifier.imported);
2014
- if (!name) {
2015
- markUnsafe(source);
2016
- return;
2017
- }
2018
- names.push(name);
2019
- continue;
2020
- }
2021
- markUnsafe(source);
2022
- return;
2023
- }
2024
- record(names, source);
2025
- }
2026
- function collectReExport(node, source, record, markUnsafe) {
2027
- if (isTypeOnly(node)) return;
2028
- if (node.type === "ExportAllDeclaration") {
2029
- markUnsafe(source);
2030
- return;
2031
- }
2032
- const specifiers = Array.isArray(node.specifiers) ? node.specifiers : [];
2033
- if (specifiers.length === 0) {
2034
- markUnsafe(source);
2035
- return;
2036
- }
2037
- const names = [];
2038
- for (const specifier of specifiers) {
2039
- if (isTypeOnly(specifier)) continue;
2040
- if (specifier.type !== "ExportSpecifier") {
2041
- markUnsafe(source);
2042
- return;
2043
- }
2044
- const local = specifier.local;
2045
- if (local?.type === "Literal" || local?.type === "StringLiteral") {
2046
- markUnsafe(source);
2047
- return;
2048
- }
2049
- const name = getExportedName(specifier.local);
2050
- if (!name) {
2051
- markUnsafe(source);
2052
- return;
2053
- }
2054
- names.push(name);
2055
- }
2056
- record(names, source);
2057
- }
2058
- /**
2059
- * Collect the exports required by a consumer's ESM graph.
2060
- *
2061
- * Parsing the module avoids treating import-looking text in comments, strings,
2062
- * templates, or regular expressions as real dependencies. If parsing fails,
2063
- * every configured share whose exports are analyzed is conservatively marked
2064
- * as requiring its full export surface instead of guessing from source text.
2065
- *
2066
- * Generated federation wrappers are excluded because their imports describe
2067
- * the wrapper implementation, not the consumer's requirements.
2068
- */
2069
- function collectTreeShakingImports(code, id, shared, findSharedKey, record, markUnsafe) {
2070
- const normalizedId = normalizePathForImport(id);
2071
- if (normalizedId.includes("__prebuild__") || normalizedId.includes("__loadShare__") || normalizedId.includes("__mf_tree_shaking_graph__")) return;
2072
- let ast;
2073
- try {
2074
- ast = parseAst(code);
2075
- } catch {
2076
- Object.entries(shared).forEach(([sharedKey, shareItem]) => {
2077
- if (shouldAnalyzeSharedExports(shareItem)) markUnsafe(sharedKey, "*");
2078
- });
2079
- return;
2080
- }
2081
- const matchShared = (source) => {
2082
- const sharedKey = findSharedKey(source, shared);
2083
- return sharedKey && shouldAnalyzeSharedExports(shared[sharedKey]) ? sharedKey : void 0;
2084
- };
2085
- const recordSource = (names, source) => {
2086
- const sharedKey = matchShared(source);
2087
- if (sharedKey) record(sharedKey, names, source);
2088
- };
2089
- const markSourceUnsafe = (source) => {
2090
- const sharedKey = matchShared(source);
2091
- if (sharedKey) markUnsafe(sharedKey, source);
2092
- };
2093
- forEachAstNode(ast, (node) => {
2094
- if (node.type === "ImportDeclaration") {
2095
- const source = getModuleSource(node.source);
2096
- if (source) collectImportDeclaration(node, source, recordSource, markSourceUnsafe);
2097
- return;
2098
- }
2099
- if ((node.type === "ExportNamedDeclaration" || node.type === "ExportAllDeclaration") && node.source) {
2100
- const source = getModuleSource(node.source);
2101
- if (source) collectReExport(node, source, recordSource, markSourceUnsafe);
2102
- return;
2103
- }
2104
- if (node.type === "ImportExpression") {
2105
- const source = getModuleSource(node.source);
2106
- if (source) markSourceUnsafe(source);
2107
- return;
2108
- }
2109
- if (node.type === "CallExpression") {
2110
- const callee = node.callee;
2111
- const args = Array.isArray(node.arguments) ? node.arguments : [];
2112
- if (callee?.type === "Identifier" && callee.name === "require" && args.length > 0) {
2113
- const source = getModuleSource(args[0]);
2114
- if (source) markSourceUnsafe(source);
2115
- }
2116
- }
2117
- });
2302
+ },
2303
+ });
2304
+ __mfReactInternals.A = __mfReactDispatcher;
2305
+ }`;
2118
2306
  }
2119
2307
  //#endregion
2120
2308
  //#region src/utils/typeArgumentScanner.ts
@@ -2191,6 +2379,77 @@ function findLikelyTypeArgumentEnd(source, start, codePositions) {
2191
2379
  }
2192
2380
  }
2193
2381
  //#endregion
2382
+ //#region src/virtualModules/shareTags.ts
2383
+ const LOAD_SHARE_TAG = "__loadShare__";
2384
+ /** A share's local copy. Reachable only through `import()`, so it stays lazy. */
2385
+ const PREBUILD_TAG = "__prebuild__";
2386
+ //#endregion
2387
+ //#region src/virtualModules/loadShareSharedChunk.ts
2388
+ const HELPERS_MODULE_NAME = "loadShareHelpers";
2389
+ const HELPERS_MODULE_TAG = "__mf_v__";
2390
+ const HELPERS_MODULE_MARKER = `${HELPERS_MODULE_TAG}${HELPERS_MODULE_NAME}${HELPERS_MODULE_TAG}`;
2391
+ const SHARED_CHUNK_SUFFIX = `${LOAD_SHARE_TAG}shared`;
2392
+ const HELPER_EXPORT_LIST = [
2393
+ "__mfGetSharedCacheDescriptor",
2394
+ "__mfReadSharedCache",
2395
+ "__mfSharedCacheListenersKey",
2396
+ "__mfGetSharedCacheListeners",
2397
+ "__mfSubscribeSharedCache",
2398
+ "__mfSharedCacheOwnersKey",
2399
+ "__mfGetSharedCacheOwners",
2400
+ "__mfReadSharedCacheOwner",
2401
+ "__mfGetSharedModuleIdentity",
2402
+ "__mfIsSameSharedModule",
2403
+ "__mfWriteSharedCache",
2404
+ "__mfTreeShakingSharedCacheKey",
2405
+ "__mfGetTreeShakingSharedCache",
2406
+ "__mfReadTreeShakingSharedCache",
2407
+ "__mfWriteTreeShakingSharedCache",
2408
+ "__mfTreeShakingSelectionCacheKey",
2409
+ "__mfGetTreeShakingSelectionCache",
2410
+ "__mfReadTreeShakingSharedSelection",
2411
+ "__mfWriteTreeShakingSharedSelection"
2412
+ ].join(", ");
2413
+ const helperModules = /* @__PURE__ */ new WeakMap();
2414
+ function getSharedCacheHelpersModule(options) {
2415
+ let module = helperModules.get(options);
2416
+ if (!module) {
2417
+ module = new VirtualModule(HELPERS_MODULE_NAME, HELPERS_MODULE_TAG, "", getFederationScopeKey(options));
2418
+ module.writeSync(`${sharedCacheHelperCode}\nexport { ${HELPER_EXPORT_LIST} };`);
2419
+ helperModules.set(options, module);
2420
+ }
2421
+ return module;
2422
+ }
2423
+ function getSharedCacheHelpersImportCode(options) {
2424
+ const importId = getSharedCacheHelpersModule(options).getImportId();
2425
+ return `import { ${HELPER_EXPORT_LIST} } from ${JSON.stringify(importId)};`;
2426
+ }
2427
+ function isSharedCacheHelpersId(id) {
2428
+ return id.includes(HELPERS_MODULE_MARKER);
2429
+ }
2430
+ function getSharedChunkName(id) {
2431
+ const ownerTag = isSharedCacheHelpersId(id) ? HELPERS_MODULE_MARKER : LOAD_SHARE_TAG;
2432
+ return `${id.slice(0, id.indexOf(ownerTag))}${SHARED_CHUNK_SUFFIX}`;
2433
+ }
2434
+ function isSharedChunk(chunk) {
2435
+ return chunk.name?.endsWith(SHARED_CHUNK_SUFFIX) ?? false;
2436
+ }
2437
+ /**
2438
+ * Fallbacks inlined into a shared chunk, which means they are no longer lazy.
2439
+ * Only inlined modules count: a shared chunk also imports fallback chunks with
2440
+ * the experiment off, because Rolldown hoists its runtime helpers into whichever
2441
+ * chunk first uses them.
2442
+ */
2443
+ function findEagerFallbacksInSharedChunk(bundle) {
2444
+ const offenders = /* @__PURE__ */ new Map();
2445
+ for (const [fileName, chunk] of Object.entries(bundle)) {
2446
+ if (chunk.type !== "chunk" || !isSharedChunk(chunk)) continue;
2447
+ const inlined = Object.keys(chunk.modules ?? {}).filter((id) => id.includes(PREBUILD_TAG));
2448
+ if (inlined.length > 0) offenders.set(fileName, inlined);
2449
+ }
2450
+ return offenders;
2451
+ }
2452
+ //#endregion
2194
2453
  //#region src/virtualModules/virtualShared_preBuild.ts
2195
2454
  /**
2196
2455
  * Even the resolveId hook cannot interfere with vite pre-build,
@@ -2226,7 +2485,7 @@ function isValidEsmExportName(name) {
2226
2485
  const JS_IDENTIFIER_PATTERN = `[\$_\\p{ID_Start}][\$_\\u200C\\u200D\\p{ID_Continue}]*`;
2227
2486
  function resolvePackageEntryFromProjectRoot(pkg) {
2228
2487
  try {
2229
- return createRequire$1(pathToFileURL(path$1.join(getPackageDetectionCwd(), "package.json"))).resolve(pkg);
2488
+ return resolveModulePath(pkg, path$1.join(getPackageDetectionCwd(), "package.json"));
2230
2489
  } catch {
2231
2490
  return;
2232
2491
  }
@@ -2257,6 +2516,18 @@ const DEFAULT_SHARED_EXPORT_CONDITIONS = [
2257
2516
  "module",
2258
2517
  "default"
2259
2518
  ];
2519
+ function getSharedExportSource(source) {
2520
+ const parts = [];
2521
+ let offset = 0;
2522
+ const codePositions = createCodePositionMap(source, (start, end) => {
2523
+ parts.push(source.slice(offset, start), source.slice(start, end).replace(/[^\r\n\u2028\u2029]/g, " "));
2524
+ offset = end;
2525
+ });
2526
+ return {
2527
+ source: parts.length ? parts.join("") + source.slice(offset) : source,
2528
+ codePositions
2529
+ };
2530
+ }
2260
2531
  function hasCodeMatch(source, regex, codePositions) {
2261
2532
  regex.lastIndex = 0;
2262
2533
  let match;
@@ -2301,8 +2572,7 @@ function getMutableExportsFromFile(entryPath, exportConditions = DEFAULT_SHARED_
2301
2572
  if (!entryPath || visited.has(entryPath)) return [];
2302
2573
  visited.add(entryPath);
2303
2574
  try {
2304
- const source = readFileSync(entryPath, "utf-8");
2305
- const codePositions = createCodePositionMap(source);
2575
+ const { source, codePositions } = getSharedExportSource(readFileSync(entryPath, "utf-8"));
2306
2576
  const mutableBindings = /* @__PURE__ */ new Set();
2307
2577
  const mutableExports = /* @__PURE__ */ new Set();
2308
2578
  let match;
@@ -2373,7 +2643,7 @@ function resolveConfiguredImportPath(importSource, exportConditions = DEFAULT_SH
2373
2643
  });
2374
2644
  if (esmEntry) return esmEntry;
2375
2645
  try {
2376
- return createRequire$1(pathToFileURL(path$1.join(projectRoot, "package.json"))).resolve(importSource);
2646
+ return resolveModulePath(importSource, path$1.join(projectRoot, "package.json"));
2377
2647
  } catch {
2378
2648
  return;
2379
2649
  }
@@ -2428,7 +2698,7 @@ function resolveReExportModule(filePath, specifier, exportConditions) {
2428
2698
  });
2429
2699
  if (esmEntry) return esmEntry;
2430
2700
  try {
2431
- return resolveFileLikeModule(createRequire$1(pathToFileURL(filePath)).resolve(specifier));
2701
+ return resolveFileLikeModule(resolveModulePath(specifier, filePath));
2432
2702
  } catch {
2433
2703
  return;
2434
2704
  }
@@ -2616,7 +2886,9 @@ function hasUnsupportedBindingPattern(source, start) {
2616
2886
  }
2617
2887
  function getNamedExportsViaRegex(source, filePath, visited, scanState = { complete: true }, exportConditions = DEFAULT_SHARED_EXPORT_CONDITIONS) {
2618
2888
  const names = /* @__PURE__ */ new Set();
2619
- const codePositions = createCodePositionMap(source);
2889
+ const inspected = getSharedExportSource(source);
2890
+ source = inspected.source;
2891
+ const codePositions = inspected.codePositions;
2620
2892
  const recognizedExportStarts = /* @__PURE__ */ new Set();
2621
2893
  visited = visited || /* @__PURE__ */ new Set();
2622
2894
  if (filePath) visited.add(filePath);
@@ -2754,7 +3026,8 @@ function getRequiredNamedExports(specifier) {
2754
3026
  const getActiveHandles = process._getActiveHandles;
2755
3027
  const handlesBeforeRequire = typeof getActiveHandles === "function" ? new Set(getActiveHandles.call(process)) : void 0;
2756
3028
  try {
2757
- const mod = createRequire$1(pathToFileURL(path$1.join(getPackageDetectionCwd(), "package.json")))(specifier);
3029
+ const projectPackageJson = path$1.join(getPackageDetectionCwd(), "package.json");
3030
+ const mod = createRequire$1(pathToFileURL(projectPackageJson))(resolveModulePath(specifier, projectPackageJson));
2758
3031
  const runtimeNamedKeys = Object.keys(mod).filter((key) => key !== "default" && key !== "__esModule");
2759
3032
  if (runtimeNamedKeys.some((key) => !isValidEsmExportName(key))) return void 0;
2760
3033
  return runtimeNamedKeys;
@@ -2797,7 +3070,7 @@ function getSharedNamedExports(pkg, shareItem, exportConditions = DEFAULT_SHARED
2797
3070
  }
2798
3071
  function getLocalProviderImportPath(pkg) {
2799
3072
  try {
2800
- const resolved = resolveWorkspaceEsmEntry(pkg, createRequire$1(pathToFileURL(path$1.join(getPackageDetectionCwd(), "package.json"))).resolve(pkg));
3073
+ const resolved = resolveWorkspaceEsmEntry(pkg, resolveModulePath(pkg, path$1.join(getPackageDetectionCwd(), "package.json")));
2801
3074
  return isWorkspaceFilePath(resolved) ? resolved : void 0;
2802
3075
  } catch {
2803
3076
  const resolved = getInstalledPackageEntry(pkg, {
@@ -2818,7 +3091,7 @@ function getProjectResolvedImportPath(pkg) {
2818
3091
  if (esmEntry) return esmEntry;
2819
3092
  }
2820
3093
  try {
2821
- return resolveWorkspaceEsmEntry(pkg, createRequire$1(pathToFileURL(path$1.join(getPackageDetectionCwd(), "package.json"))).resolve(pkg));
3094
+ return resolveWorkspaceEsmEntry(pkg, resolveModulePath(pkg, path$1.join(getPackageDetectionCwd(), "package.json")));
2822
3095
  } catch {
2823
3096
  return;
2824
3097
  }
@@ -2874,25 +3147,11 @@ function getSharedDependencyGraphPackageJson(pkg) {
2874
3147
  const installedPackageJson = getInstalledPackageJson(pkg, { packageName: getPackageName(pkg) })?.packageJson;
2875
3148
  if (installedPackageJson) return installedPackageJson;
2876
3149
  try {
2877
- const packageJsonPath = createRequire$1(pathToFileURL(path$1.join(getPackageDetectionCwd(), "package.json"))).resolve(`${getPackageName(pkg)}/package.json`);
3150
+ const packageJsonPath = resolveModulePath(`${getPackageName(pkg)}/package.json`, path$1.join(getPackageDetectionCwd(), "package.json"));
2878
3151
  return JSON.parse(readFileSync(packageJsonPath, "utf-8"));
2879
3152
  } catch {}
2880
3153
  return getWorkspacePackageJson(pkg);
2881
3154
  }
2882
- function getDependencyNames(packageJson) {
2883
- if (!packageJson) return [];
2884
- const names = /* @__PURE__ */ new Set();
2885
- for (const field of [
2886
- "dependencies",
2887
- "peerDependencies",
2888
- "optionalDependencies"
2889
- ]) {
2890
- const deps = packageJson[field];
2891
- if (!deps || typeof deps !== "object") continue;
2892
- for (const dep of Object.keys(deps)) names.add(dep);
2893
- }
2894
- return Array.from(names);
2895
- }
2896
3155
  function isSharedSingletonConsumedByPeer(pkg, options = getNormalizeModuleFederationOptions(), requireFederationRuntimeDependency = false) {
2897
3156
  const shared = options?.shared || {};
2898
3157
  if (!requireFederationRuntimeDependency && Object.entries(shared).some(([key, item]) => key !== pkg && key.startsWith(`${pkg}/`) && item.shareConfig.singleton === true)) return true;
@@ -2901,25 +3160,39 @@ function isSharedSingletonConsumedByPeer(pkg, options = getNormalizeModuleFedera
2901
3160
  const packageName = getPackageName(key);
2902
3161
  if (!sharedKeyByPackageName.get(packageName) || key === packageName) sharedKeyByPackageName.set(packageName, key);
2903
3162
  });
2904
- const reachesPkg = (current, seen, hasFederationRuntimeDependency = false) => {
3163
+ const runtimeDependencyCache = /* @__PURE__ */ new Map();
3164
+ const reachesFederationRuntime = (current, seen) => {
3165
+ if (runtimeDependencyCache.has(current)) return runtimeDependencyCache.get(current);
3166
+ const result = getDependencyNames(getSharedDependencyGraphPackageJson(current)).some((dependency) => {
3167
+ if (dependency === "@module-federation/enhanced" || dependency === "@module-federation/runtime" || dependency === "@module-federation/runtime-core") return true;
3168
+ if (seen.has(dependency)) return false;
3169
+ seen.add(dependency);
3170
+ const reachable = reachesFederationRuntime(dependency, seen);
3171
+ seen.delete(dependency);
3172
+ return reachable;
3173
+ });
3174
+ runtimeDependencyCache.set(current, result);
3175
+ return result;
3176
+ };
3177
+ const reachesPkg = (current, seen) => {
2905
3178
  const dependencies = getDependencyNames(getSharedDependencyGraphPackageJson(current));
2906
- const usesFederationRuntime = dependencies.some((dependency) => dependency === "@module-federation/enhanced" || dependency === "@module-federation/runtime" || dependency === "@module-federation/runtime-core");
2907
- const runtimeIsReachable = hasFederationRuntimeDependency || usesFederationRuntime;
2908
3179
  for (const dependency of dependencies) {
2909
3180
  const sharedDependency = sharedKeyByPackageName.get(dependency);
2910
- if (!sharedDependency) continue;
2911
- if (sharedDependency === pkg) return !requireFederationRuntimeDependency || runtimeIsReachable;
2912
- if (seen.has(sharedDependency)) continue;
2913
- seen.add(sharedDependency);
2914
- if (reachesPkg(sharedDependency, seen, runtimeIsReachable)) return true;
3181
+ if (sharedDependency === pkg) return true;
3182
+ if (!sharedDependency && !requireFederationRuntimeDependency) continue;
3183
+ const next = sharedDependency || dependency;
3184
+ if (seen.has(next)) continue;
3185
+ seen.add(next);
3186
+ if (reachesPkg(next, seen)) return true;
3187
+ seen.delete(next);
2915
3188
  }
2916
3189
  return false;
2917
3190
  };
2918
- return Array.from(sharedKeyByPackageName.values()).some((sharedPkg) => sharedPkg !== pkg && reachesPkg(sharedPkg, /* @__PURE__ */ new Set([sharedPkg])));
3191
+ return Array.from(sharedKeyByPackageName.values()).some((sharedPkg) => sharedPkg !== pkg && (!requireFederationRuntimeDependency || reachesFederationRuntime(sharedPkg, /* @__PURE__ */ new Set([sharedPkg]))) && reachesPkg(sharedPkg, /* @__PURE__ */ new Set([sharedPkg])));
2919
3192
  }
2920
3193
  function tryResolveImportFromPackageRoot(pkg, root) {
2921
3194
  try {
2922
- return resolveWorkspaceEsmEntry(pkg, createRequire$1(pathToFileURL(path$1.join(root, "package.json"))).resolve(pkg), root);
3195
+ return resolveWorkspaceEsmEntry(pkg, resolveModulePath(pkg, path$1.join(root, "package.json")), root);
2923
3196
  } catch {
2924
3197
  return;
2925
3198
  }
@@ -2952,9 +3225,11 @@ function resolveConcreteSharedImportSource(pkg, projectRoot) {
2952
3225
  if (resolved) return resolved;
2953
3226
  currentDir = path$1.dirname(currentDir);
2954
3227
  }
2955
- return tryResolveImportFromPackageRoot(pkg, currentDir);
3228
+ return tryResolveImportFromPackageRoot(pkg, currentDir) ?? getInstalledPackageEntry(pkg, {
3229
+ conditions: DEFAULT_SHARED_EXPORT_CONDITIONS,
3230
+ resolveSubpathWithRequire: false
3231
+ });
2956
3232
  }
2957
- const PREBUILD_TAG = "__prebuild__";
2958
3233
  const TREE_SHAKING_PROVIDER_TAG = "__treeShakingProvider__";
2959
3234
  const TREE_SHAKING_GRAPH_QUERY = "__mf_tree_shaking_graph__";
2960
3235
  const legacySharedVirtualModuleState = {
@@ -2963,9 +3238,11 @@ const legacySharedVirtualModuleState = {
2963
3238
  treeShakingProviderCacheMap: {},
2964
3239
  materializedTreeShakingProviders: /* @__PURE__ */ new Set(),
2965
3240
  loadShareCacheMap: {},
2966
- warnedMissingImportFalse: /* @__PURE__ */ new Set()
3241
+ warnedMissingImportFalse: /* @__PURE__ */ new Set(),
3242
+ coalescableLoadShares: /* @__PURE__ */ new Set()
2967
3243
  };
2968
3244
  const sharedVirtualModuleStates = /* @__PURE__ */ new WeakMap();
3245
+ const sharedVirtualModuleStatesByOwner = /* @__PURE__ */ new Map();
2969
3246
  function getSharedVirtualModuleState(options) {
2970
3247
  if (!options) try {
2971
3248
  const currentOptions = getNormalizeModuleFederationOptions();
@@ -2982,12 +3259,19 @@ function getSharedVirtualModuleState(options) {
2982
3259
  materializedTreeShakingProviders: /* @__PURE__ */ new Set(),
2983
3260
  loadShareCacheMap: {},
2984
3261
  warnedMissingImportFalse: /* @__PURE__ */ new Set(),
3262
+ coalescableLoadShares: /* @__PURE__ */ new Set(),
2985
3263
  ownerKey: getFederationScopeKey(options)
2986
3264
  };
2987
3265
  sharedVirtualModuleStates.set(options, state);
3266
+ if (state.ownerKey !== void 0) sharedVirtualModuleStatesByOwner.set(state.ownerKey, state);
2988
3267
  }
2989
3268
  return state;
2990
3269
  }
3270
+ /** State of the instance that owns a scoped virtual id; `options` covers unscoped ids. */
3271
+ function getSharedVirtualModuleStateForId(id, options) {
3272
+ const ownerKey = id === void 0 ? void 0 : VirtualModule.findById(id)?.getScopeName();
3273
+ return (ownerKey !== void 0 ? sharedVirtualModuleStatesByOwner.get(ownerKey) : void 0) ?? getSharedVirtualModuleState(options);
3274
+ }
2991
3275
  function createScopedSharedVirtualModule(pkg, tag, options) {
2992
3276
  return new VirtualModule(pkg, tag, ".js", getSharedVirtualModuleState(options).ownerKey);
2993
3277
  }
@@ -3104,7 +3388,7 @@ function writePreBuildLibPath(pkg, shareItem, options, exportConditions) {
3104
3388
  const cache = globalThis[__mfCacheGlobalKey]?.share;
3105
3389
  const sharedReact = cache && __mfReadSharedCache(cache, ${reactCacheDescriptor});
3106
3390
  const reactExports = sharedReact?.default ?? sharedReact;
3107
- const internals = reactExports?.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
3391
+ const internals = reactExports?.[${JSON.stringify(REACT_CLIENT_INTERNALS_KEY)}];
3108
3392
  return internals?.H?.useMemoCache(size);
3109
3393
  };
3110
3394
  export default { c };
@@ -3182,7 +3466,6 @@ function getPreBuildShareItem(pkg, options) {
3182
3466
  function getSharedImportSource(pkg, shareItem, options) {
3183
3467
  return getConcreteSharedImportSource(pkg, shareItem) || getPreBuildLibImportId(pkg, options);
3184
3468
  }
3185
- const LOAD_SHARE_TAG = "__loadShare__";
3186
3469
  function getLoadShareImportId(pkg, _isRolldown, options) {
3187
3470
  const { loadShareCacheMap } = getSharedVirtualModuleState(options);
3188
3471
  if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = createScopedSharedVirtualModule(pkg, LOAD_SHARE_TAG, options);
@@ -3242,14 +3525,14 @@ function getSharedCacheReadExpression(cacheDescriptor, treeShakingConsumer) {
3242
3525
  * a merged chunk, TDZ bindings otherwise), so the exports stay unassigned until the deferred cache write
3243
3526
  * re-applies them; a host-provided copy re-applies them through the cache subscription as before.
3244
3527
  */
3245
- function generateEagerWorkspaceSingletonExports(namedExports, importSource, cacheDescriptor, cacheOwner, treeShakingConsumer, mutableExports = []) {
3528
+ function generateEagerWorkspaceSingletonExports(edges, namedExports, importSource, cacheDescriptor, cacheOwner, treeShakingConsumer, mutableExports = []) {
3246
3529
  const copiedExports = namedExports.filter((name) => !mutableExports.includes(name));
3247
3530
  const namedExportVars = copiedExports.map((_name, i) => `__mf_${i}`);
3248
3531
  const declarations = namedExports.length > 0 ? ["let __mf_default;", ...namedExportVars.map((name) => `let ${name};`)].join("\n ") : "let __mf_default;";
3249
3532
  const assignments = [...copiedExports.map((name, i) => `${namedExportVars[i]} = mod[${escapeGeneratedStringLiteral(name)}];`), "__mf_default = mod.default ?? mod;"].join("\n ");
3250
3533
  const namedExportLine = copiedExports.length > 0 ? `\n export { ${copiedExports.map((name, i) => `${namedExportVars[i]} as ${name}`).join(", ")} };` : "";
3251
- const mutableExportLine = mutableExports.length ? `\n export { ${mutableExports.join(", ")} } from ${escapeGeneratedStringLiteral(importSource)};` : "";
3252
- return `import * as __mfLocalShare from ${escapeGeneratedStringLiteral(importSource)};
3534
+ const mutableExportLine = mutableExports.length ? `\n ${edges.reExportNames(mutableExports, importSource)}` : "";
3535
+ return `${edges.importNamespace(importSource)}
3253
3536
  let exportModule = ${getSharedCacheReadExpression(cacheDescriptor, treeShakingConsumer)};
3254
3537
  if (exportModule === undefined) {
3255
3538
  Promise.resolve().then(() => {
@@ -3277,28 +3560,26 @@ function generateEagerWorkspaceSingletonExports(namedExports, importSource, cach
3277
3560
  __mfApplyEagerShareExportsWhenReady(exportModule);
3278
3561
  export { __mf_default as default };${namedExportLine}${mutableExportLine}`;
3279
3562
  }
3280
- function generateLazyWorkspaceSingletonExports(namedExports, importSource, cacheDescriptor, cacheOwner, treeShakingConsumer, serveLocalFallback = false, mutableExports = []) {
3563
+ function generateLazyWorkspaceSingletonExports(edges, namedExports, importSource, cacheDescriptor, cacheOwner, treeShakingConsumer, serveLocalFallback = false, mutableExports = [], deferredEntryFallback = false) {
3281
3564
  const copiedExports = namedExports.filter((name) => !mutableExports.includes(name));
3282
3565
  const namedExportVars = copiedExports.map((_name, i) => `__mf_${i}`);
3283
3566
  const declarations = namedExports.length > 0 ? ["let __mf_default;", ...namedExportVars.map((name) => `let ${name};`)].join("\n ") : "let __mf_default;";
3284
3567
  const assignments = copiedExports.length > 0 ? [...copiedExports.map((name, i) => `${namedExportVars[i]} = mod[${escapeGeneratedStringLiteral(name)}];`), "__mf_default = mod.default ?? mod;"].join("\n ") : "__mf_default = mod.default ?? mod;";
3285
3568
  const namedExportLine = copiedExports.length > 0 ? `\n export { ${copiedExports.map((name, i) => `${namedExportVars[i]} as ${name}`).join(", ")} };` : "";
3286
- const mutableExportLine = mutableExports.length ? `\n export { ${mutableExports.join(", ")} } from ${escapeGeneratedStringLiteral(importSource)};` : "";
3569
+ const mutableExportLine = mutableExports.length ? `\n ${edges.reExportNames(mutableExports, importSource)}` : "";
3287
3570
  const applyLocalFallback = `exportModule = __mfNormalizeShareModule(__mfLocalShare);
3288
3571
  __mfWriteSharedCache(__mfModuleCache.share, ${cacheDescriptor}, exportModule, ${cacheOwner});
3289
3572
  __mfApplyLazyShareExports(exportModule);`;
3290
- return `${declarations}
3291
- const __mfApplyLazyShareExports = (mod) => {
3292
- ${assignments}
3293
- };
3294
- __mfSubscribeSharedCache(__mfModuleCache.share, ${cacheDescriptor}, __mfApplyLazyShareExports);
3295
- let exportModule = ${getSharedCacheReadExpression(cacheDescriptor, treeShakingConsumer)};
3296
- if (exportModule === undefined) {
3297
- if (import.meta.env.SSR${serveLocalFallback ? " || (import.meta.env.DEV && typeof __mfLocalShare !== 'undefined')" : ""}) {
3298
- ${applyLocalFallback}
3299
- } else {
3300
- __mfTrackPendingShareLoad(initPromise.then(() => {
3301
- exportModule = ${getSharedCacheReadExpression(cacheDescriptor, treeShakingConsumer)};
3573
+ const readDeferredShare = getSharedCacheReadExpression(cacheDescriptor, treeShakingConsumer);
3574
+ const deferredEntryLoad = `Promise.race([
3575
+ initPromise.then(() => ${readDeferredShare}),
3576
+ new Promise((resolve) => {
3577
+ const current = ${readDeferredShare};
3578
+ if (current !== undefined) resolve(current);
3579
+ else __mfSubscribeSharedCache(__mfModuleCache.share, ${cacheDescriptor}, resolve);
3580
+ })
3581
+ ]).then((cached) => {
3582
+ exportModule = cached;
3302
3583
  if (exportModule !== undefined) {
3303
3584
  __mfApplyLazyShareExports(exportModule);
3304
3585
  return;
@@ -3307,8 +3588,32 @@ function generateLazyWorkspaceSingletonExports(namedExports, importSource, cache
3307
3588
  exportModule = __mfNormalizeShareModule(mod);
3308
3589
  __mfWriteSharedCache(__mfModuleCache.share, ${cacheDescriptor}, exportModule, ${cacheOwner});
3309
3590
  });
3310
- }));
3311
- }
3591
+ })`;
3592
+ const deferredInitLoad = `initPromise.then(() => {
3593
+ exportModule = ${readDeferredShare};
3594
+ if (exportModule !== undefined) {
3595
+ __mfApplyLazyShareExports(exportModule);
3596
+ return;
3597
+ }
3598
+ return import(${escapeGeneratedStringLiteral(importSource)}).then((mod) => {
3599
+ exportModule = __mfNormalizeShareModule(mod);
3600
+ __mfWriteSharedCache(__mfModuleCache.share, ${cacheDescriptor}, exportModule, ${cacheOwner});
3601
+ });
3602
+ })`;
3603
+ const synchronousFallbackConditions = [...deferredEntryFallback ? [] : ["import.meta.env.SSR"], ...serveLocalFallback ? ["(import.meta.env.DEV && typeof __mfLocalShare !== 'undefined')"] : []];
3604
+ const trackPendingLoad = `__mfTrackPendingShareLoad(${deferredEntryFallback ? deferredEntryLoad : deferredInitLoad});`;
3605
+ return `${declarations}
3606
+ const __mfApplyLazyShareExports = (mod) => {
3607
+ ${assignments}
3608
+ };
3609
+ __mfSubscribeSharedCache(__mfModuleCache.share, ${cacheDescriptor}, __mfApplyLazyShareExports);
3610
+ let exportModule = ${readDeferredShare};
3611
+ if (exportModule === undefined) {
3612
+ ${synchronousFallbackConditions.length > 0 ? `if (${synchronousFallbackConditions.join(" || ")}) {
3613
+ ${applyLocalFallback}
3614
+ } else {
3615
+ ${trackPendingLoad}
3616
+ }` : trackPendingLoad}
3312
3617
  } else {
3313
3618
  __mfApplyLazyShareExports(exportModule);
3314
3619
  }
@@ -3344,6 +3649,14 @@ function generateDeferredHostProvidedExports(namedExports, pkg, cacheDescriptor,
3344
3649
  if (exportModule === undefined) {
3345
3650
  __mfTrackPendingShareLoad(initPromise.then(() => {
3346
3651
  exportModule = ${getSharedCacheReadExpression(cacheDescriptor, treeShakingConsumer)};
3652
+ // A share init() left to its dynamic import is normally bridged before that import runs;
3653
+ // bridge it here when this wrapper is reached another way.
3654
+ if (exportModule === undefined && typeof __mfPromiseState.loadLazyShares === "function") {
3655
+ return __mfPromiseState.loadLazyShares([${escapeGeneratedStringLiteral(pkg)}]).then(() => {
3656
+ exportModule = ${getSharedCacheReadExpression(cacheDescriptor, treeShakingConsumer)};
3657
+ });
3658
+ }
3659
+ }).then(() => {
3347
3660
  if (exportModule === undefined) {
3348
3661
  throw new Error("[Module Federation] Shared module ${pkg} was imported before federation bootstrap finished.");
3349
3662
  }
@@ -3352,7 +3665,7 @@ function generateDeferredHostProvidedExports(namedExports, pkg, cacheDescriptor,
3352
3665
  } else {
3353
3666
  __mfApplyHostProvidedExports(exportModule);
3354
3667
  }
3355
- export { __mf_default as default };${namedExportLine}`;
3668
+ export { __mf_default as default, exportModule as __moduleExports };${namedExportLine}`;
3356
3669
  }
3357
3670
  function selectImportFalseNamedExports(detectedNamedExports, usage) {
3358
3671
  if (!detectedNamedExports || usage?.kind !== "exports") return detectedNamedExports ?? [];
@@ -3391,9 +3704,49 @@ const initializedLocalShareModuleCode = `const __mfInitializedLocalShare = (mod)
3391
3704
  throw error;
3392
3705
  }
3393
3706
  };`;
3707
+ function createLocalPayloadEdges() {
3708
+ let edges = 0;
3709
+ return {
3710
+ importNamespace(source) {
3711
+ edges++;
3712
+ return `import * as __mfLocalShare from ${escapeGeneratedStringLiteral(source)};`;
3713
+ },
3714
+ reExportAll(source) {
3715
+ edges++;
3716
+ return `export * from ${escapeGeneratedStringLiteral(source)}`;
3717
+ },
3718
+ reExportNames(names, source) {
3719
+ if (names.length === 0) return "";
3720
+ edges++;
3721
+ return `export { ${names.join(", ")} } from ${escapeGeneratedStringLiteral(source)};`;
3722
+ },
3723
+ get none() {
3724
+ return edges === 0;
3725
+ }
3726
+ };
3727
+ }
3728
+ function recordCoalescability(pkg, hasNoLocalPayloadEdge, command, shareConfig, coalescableLoadShares) {
3729
+ const coalescable = command === "build" && shareConfig.eager !== true && shareConfig.import !== false && hasNoLocalPayloadEdge;
3730
+ if (coalescable) coalescableLoadShares.add(pkg);
3731
+ else coalescableLoadShares.delete(pkg);
3732
+ return coalescable;
3733
+ }
3734
+ /**
3735
+ * `prependWorkspaceSingletonSsrImport` adds a local-payload edge in the server
3736
+ * build's load hook, after this module has generated the wrapper. `id` names
3737
+ * the owning instance when the hook belongs to a different one.
3738
+ */
3739
+ function markLoadShareWrapperNotCoalescable(pkg, options, id) {
3740
+ getSharedVirtualModuleStateForId(id, options).coalescableLoadShares.delete(pkg);
3741
+ }
3742
+ /** With `id`, answers from the owning instance's state, whichever instance asks. */
3743
+ function isCoalescableLoadShareWrapper(pkg, options, id) {
3744
+ return getSharedVirtualModuleStateForId(id, options).coalescableLoadShares.has(pkg);
3745
+ }
3394
3746
  function writeLoadShareModule(pkg, shareItem, command, _isRolldown, options, exportConditions, importFalseExportUsage) {
3395
3747
  const resolvedOptions = options ?? getNormalizeModuleFederationOptions();
3396
- const { loadShareCacheMap } = getSharedVirtualModuleState(options);
3748
+ const { loadShareCacheMap, coalescableLoadShares } = getSharedVirtualModuleState(options);
3749
+ const edges = createLocalPayloadEdges();
3397
3750
  if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = createScopedSharedVirtualModule(pkg, LOAD_SHARE_TAG, options);
3398
3751
  let importLine = getRuntimeModuleCacheBootstrapCode(exportConditions);
3399
3752
  const cacheDescriptor = getSharedCacheDescriptorLiteral(pkg, shareItem);
@@ -3413,6 +3766,7 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown, options, exp
3413
3766
  }
3414
3767
  exportLine = generateDeferredHostProvidedExports([], pkg, cacheDescriptor, treeShakingConsumer);
3415
3768
  }
3769
+ recordCoalescability(pkg, edges.none, command, shareItem.shareConfig, coalescableLoadShares);
3416
3770
  loadShareCacheMap[pkg].writeSync(`
3417
3771
  ${getRuntimeInitPromiseBootstrapCode(false, runtimeInitOwnerImportId)}
3418
3772
  ${importLine}
@@ -3434,13 +3788,14 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown, options, exp
3434
3788
  const mutableExports = new Set(isLocalOnlyContainer(resolvedOptions) ? getSharedMutableExports(pkg, shareItem, exportConditions) : []);
3435
3789
  const copiedNamedExports = namedExports.filter((name) => !mutableExports.has(name));
3436
3790
  const liveNamedExports = namedExports.filter((name) => mutableExports.has(name));
3437
- const liveNamedExportLine = liveNamedExports.length ? `export { ${liveNamedExports.join(", ")} } from ${escapeGeneratedStringLiteral(sharedImportSource)};` : "";
3791
+ const liveNamedExportLine = edges.reExportNames(liveNamedExports, sharedImportSource);
3438
3792
  const hasCompleteExportCoverage = detectedNamedExports !== void 0;
3439
3793
  const isWorkspaceSingleton = isWorkspacePackage && shareItem.shareConfig.singleton === true;
3440
3794
  const usesDeferredSingletonFallback = hasCompleteExportCoverage && shareItem.shareConfig.eager !== true && (isWorkspacePackage || command !== "build" && isRemoteOnlyContainer(resolvedOptions) && shareItem.shareConfig.singleton === true || command === "build" && isRemoteContainer(resolvedOptions) && !isSharedSingletonConsumedByPeer(pkg, resolvedOptions, true));
3441
3795
  const servesRemoteSingletonFallback = command !== "build" && isRemoteOnlyContainer(resolvedOptions) && shareItem.shareConfig.singleton === true;
3442
3796
  const isConsumedByPeerSingleton = isSharedSingletonConsumedByPeer(pkg, resolvedOptions);
3443
3797
  const usesEntryInjectedRemoteFallback = hasCompleteExportCoverage && !isWorkspaceSingleton && isRemoteContainer(resolvedOptions) && shareItem.shareConfig.singleton === true && resolvedOptions.hostInitInjectLocation === "entry" && (command === "build" || isConsumedByPeerSingleton);
3798
+ const usesDeferredEntryInjectedSingletonFallback = usesEntryInjectedRemoteFallback && !isReactCoreShare(pkg) && (pkg === "react-dom/client" || shareItem.shareConfig.eager !== true && !isSharedSingletonConsumedByPeer(pkg, resolvedOptions, true));
3444
3799
  const usesEagerWorkspaceFallback = hasCompleteExportCoverage && isWorkspaceSingleton && !servesRemoteSingletonFallback && (isConsumedByPeerSingleton || shareItem.shareConfig.eager === true);
3445
3800
  const usesDeferredTreeShakingFallback = hasCompleteExportCoverage && Boolean(treeShakingConsumer);
3446
3801
  const reactMixedModeGuard = pkg === "react" ? createReactMixedModeRuntimeGuard() : "";
@@ -3448,11 +3803,14 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown, options, exp
3448
3803
  let initBlock = "";
3449
3804
  if (usesDeferredTreeShakingFallback) {
3450
3805
  importLine = `${getRuntimeInitPromiseBootstrapCode(false, runtimeInitOwnerImportId)}\n ${importLine}`;
3451
- exportLine = generateLazyWorkspaceSingletonExports(namedExports, lazyLocalFallbackSource, cacheDescriptor, cacheOwner, treeShakingConsumer, command !== "build" && !servesRemoteSingletonFallback && (isWorkspaceSingleton || isWorkspacePackage), liveNamedExports);
3452
- } else if (usesEagerWorkspaceFallback || usesEntryInjectedRemoteFallback) exportLine = generateEagerWorkspaceSingletonExports(namedExports, lazyLocalFallbackSource, cacheDescriptor, cacheOwner, treeShakingConsumer, liveNamedExports);
3806
+ exportLine = generateLazyWorkspaceSingletonExports(edges, namedExports, lazyLocalFallbackSource, cacheDescriptor, cacheOwner, treeShakingConsumer, command !== "build" && !servesRemoteSingletonFallback && (isWorkspaceSingleton || isWorkspacePackage), liveNamedExports);
3807
+ } else if (usesDeferredEntryInjectedSingletonFallback) {
3808
+ importLine = `${getRuntimeInitPromiseBootstrapCode(false, runtimeInitOwnerImportId)}\n ${importLine}`;
3809
+ exportLine = generateLazyWorkspaceSingletonExports(edges, namedExports, lazyLocalFallbackSource, cacheDescriptor, cacheOwner, treeShakingConsumer, false, liveNamedExports, true);
3810
+ } else if (usesEagerWorkspaceFallback || usesEntryInjectedRemoteFallback) exportLine = generateEagerWorkspaceSingletonExports(edges, namedExports, lazyLocalFallbackSource, cacheDescriptor, cacheOwner, treeShakingConsumer, liveNamedExports);
3453
3811
  else if (usesDeferredSingletonFallback) {
3454
3812
  importLine = `${getRuntimeInitPromiseBootstrapCode(false, runtimeInitOwnerImportId)}\n ${importLine}`;
3455
- exportLine = generateLazyWorkspaceSingletonExports(namedExports, lazyLocalFallbackSource, cacheDescriptor, cacheOwner, treeShakingConsumer, command !== "build" && !servesRemoteSingletonFallback && (isWorkspaceSingleton || isWorkspacePackage), liveNamedExports);
3813
+ exportLine = generateLazyWorkspaceSingletonExports(edges, namedExports, lazyLocalFallbackSource, cacheDescriptor, cacheOwner, treeShakingConsumer, command !== "build" && !servesRemoteSingletonFallback && (isWorkspaceSingleton || isWorkspacePackage), liveNamedExports);
3456
3814
  } else if (detectedNamedExports === void 0) {
3457
3815
  exportLine = `const __mfDefaultExport = (() => {
3458
3816
  ${generateShareModuleUnwrapCode({
@@ -3462,7 +3820,7 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown, options, exp
3462
3820
  })}
3463
3821
  })();
3464
3822
  export default __mfDefaultExport;
3465
- export * from ${escapeGeneratedStringLiteral(coherentLocalSource)}`;
3823
+ ${edges.reExportAll(coherentLocalSource)}`;
3466
3824
  initBlock = `exportModule = __mfNormalizeShareModule(__mfLocalShare);
3467
3825
  __mfWriteSharedCache(__mfModuleCache.share, ${cacheDescriptor}, exportModule, ${cacheOwner});`;
3468
3826
  } else if (namedExports.length > 0 && shareItem.shareConfig.singleton === true) {
@@ -3513,21 +3871,23 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown, options, exp
3513
3871
  __mfSubscribeSharedCache(__mfModuleCache.share, ${cacheDescriptor}, __mfApplySharedDefaultExport);
3514
3872
  __mfApplySharedDefaultExport(exportModule);
3515
3873
  export { __mfDefaultExport as default };
3516
- export * from ${escapeGeneratedStringLiteral(sharedImportSource)}`;
3874
+ ${edges.reExportAll(sharedImportSource)}`;
3517
3875
  initBlock = `exportModule = __mfNormalizeShareModule(__mfLocalShare);
3518
3876
  __mfWriteSharedCache(__mfModuleCache.share, ${cacheDescriptor}, exportModule, ${cacheOwner});`;
3519
3877
  } else {
3520
- exportLine = `export default exportModule.default ?? exportModule\n export * from ${escapeGeneratedStringLiteral(sharedImportSource)}`;
3878
+ exportLine = `export default exportModule.default ?? exportModule\n ${edges.reExportAll(sharedImportSource)}`;
3521
3879
  initBlock = `exportModule = __mfNormalizeShareModule(__mfLocalShare);
3522
3880
  __mfWriteSharedCache(__mfModuleCache.share, ${cacheDescriptor}, exportModule, ${cacheOwner});`;
3523
3881
  }
3524
- const prebuildImportLine = usesEagerWorkspaceFallback || usesEntryInjectedRemoteFallback ? "" : usesDeferredSingletonFallback || usesDeferredTreeShakingFallback ? !servesRemoteSingletonFallback && usesDeferredSingletonFallback && command !== "build" && (isWorkspaceSingleton || isWorkspacePackage) ? `import * as __mfLocalShare from ${escapeGeneratedStringLiteral(lazyLocalFallbackSource)};` : "" : `import * as __mfLocalShare from ${escapeGeneratedStringLiteral(detectedNamedExports === void 0 ? coherentLocalSource : skipServePrebuildWarmup ? devImportSource : sharedImportSource)};`;
3525
- const devDynamicImportLine = isWorkspacePackage ? "" : usesDeferredSingletonFallback || usesDeferredTreeShakingFallback ? "" : command !== "build" && !skipServePrebuildWarmup ? `;() => import(${escapeGeneratedStringLiteral(devImportSource)}).catch(() => {});` : "";
3526
- const moduleBody = usesDeferredSingletonFallback || usesDeferredTreeShakingFallback || usesEagerWorkspaceFallback || usesEntryInjectedRemoteFallback ? `
3527
- ${prebuildImportLine}
3882
+ const staticLocalShareSource = detectedNamedExports === void 0 ? coherentLocalSource : skipServePrebuildWarmup ? devImportSource : sharedImportSource;
3883
+ const prebuildImportLine = usesEagerWorkspaceFallback || usesEntryInjectedRemoteFallback ? "" : usesDeferredSingletonFallback || usesDeferredTreeShakingFallback ? !servesRemoteSingletonFallback && usesDeferredSingletonFallback && command !== "build" && (isWorkspaceSingleton || isWorkspacePackage) ? edges.importNamespace(lazyLocalFallbackSource) : "" : edges.importNamespace(staticLocalShareSource);
3884
+ const devDynamicImportLine = isWorkspacePackage ? "" : usesDeferredSingletonFallback || usesDeferredTreeShakingFallback || usesDeferredEntryInjectedSingletonFallback ? "" : command !== "build" && !skipServePrebuildWarmup ? `;() => import(${escapeGeneratedStringLiteral(devImportSource)}).catch(() => {});` : "";
3885
+ const cacheHelpers = recordCoalescability(pkg, edges.none, command, shareItem.shareConfig, coalescableLoadShares) ? getSharedCacheHelpersImportCode(resolvedOptions) : sharedCacheHelperCode;
3886
+ const moduleBody = usesDeferredSingletonFallback || usesDeferredTreeShakingFallback || usesDeferredEntryInjectedSingletonFallback || usesEagerWorkspaceFallback || usesEntryInjectedRemoteFallback ? `
3887
+ ${usesDeferredEntryInjectedSingletonFallback ? "" : prebuildImportLine}
3528
3888
  ${devDynamicImportLine}
3529
3889
  ${importLine}
3530
- ${sharedCacheHelperCode}
3890
+ ${cacheHelpers}
3531
3891
  ${normalizeLocalShareModuleCode}
3532
3892
  ${initializedLocalShareModuleCode}
3533
3893
  ${exportLine}
@@ -3535,7 +3895,7 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown, options, exp
3535
3895
  ${prebuildImportLine}
3536
3896
  ${devDynamicImportLine}
3537
3897
  ${importLine}
3538
- ${sharedCacheHelperCode}
3898
+ ${cacheHelpers}
3539
3899
  ${normalizeLocalShareModuleCode}
3540
3900
  let exportModule = ${getSharedCacheReadExpression(cacheDescriptor, treeShakingConsumer)}
3541
3901
  if (exportModule === undefined) {
@@ -3579,6 +3939,7 @@ function addConfiguredShare(pkg, options) {
3579
3939
  if (options) getScopedUsedShares(options).add(pkg);
3580
3940
  }
3581
3941
  const LOCAL_SHARED_IMPORT_MAP_ID = "virtual:mf-localSharedImportMap";
3942
+ const LAZY_CONSUME_ONLY_SHARES_PLACEHOLDER = "__MF_LAZY_CONSUME_ONLY_SHARES__";
3582
3943
  const localOwnerIds = /* @__PURE__ */ new WeakMap();
3583
3944
  let nextLocalOwnerId = 1;
3584
3945
  function getLocalOwnerKey(options) {
@@ -3616,6 +3977,10 @@ function getLocalSharedPackagePath(pkg, shareItem, options) {
3616
3977
  if (shouldUseDirectReactImport() && pkg === "react") return "react";
3617
3978
  return getConcreteSharedImportSource(pkg, shareItem) || getLocalProviderImportPath(pkg) || getSharedImportSource(pkg, shareItem, options);
3618
3979
  }
3980
+ function getCanonicalSharedKey(pkg, shareItem) {
3981
+ const { request, shareKey } = shareItem.shareConfig;
3982
+ return request !== void 0 || shareKey !== void 0 ? getSharedRuntimeKey(pkg, shareItem) : pkg;
3983
+ }
3619
3984
  function getDirectSharedCacheSeedImportPath(pkg, shareItem) {
3620
3985
  return getConcreteSharedImportSource(pkg, shareItem) || getProjectResolvedImportPath(pkg) || getLocalProviderImportPath(pkg) || pkg;
3621
3986
  }
@@ -3629,7 +3994,7 @@ function generateLocalSharedImportMap(options) {
3629
3994
  import {loadShare} from "@module-federation/runtime";
3630
3995
  ${orderedShares.map((pkg, index) => {
3631
3996
  const shareItem = getNormalizeShareItem(pkg, resolvedOptions);
3632
- if (!shareItem?.shareConfig.eager || shareItem.shareConfig.import === false) return "";
3997
+ if (!shareItem || !shareItem.shareConfig.eager || shareItem.shareConfig.import === false) return "";
3633
3998
  return `import * as __mfEagerShare_${index} from ${toSafeJsLiteral(getLocalSharedPackagePath(pkg, shareItem, options))};`;
3634
3999
  }).filter(Boolean).join("\n")}
3635
4000
  ${normalizeRuntimeShareCode}
@@ -3654,12 +4019,17 @@ function generateLocalSharedImportMap(options) {
3654
4019
  const __mfHostOnly = (name) => async () => {
3655
4020
  throw new Error(\`[Module Federation] Shared module '\${name}' must be provided by host\`);
3656
4021
  };
4022
+ // Replaced by the lazy consume-only share plugin with the keys that only a dynamic
4023
+ // import() reaches, so init() leaves them to that import; an unreplaced string matches no key.
4024
+ const __mfLazyShares = ${JSON.stringify(LAZY_CONSUME_ONLY_SHARES_PLACEHOLDER)};
4025
+ const __mfIsLazyShare = (name) => Array.isArray(__mfLazyShares) && __mfLazyShares.includes(name);
3657
4026
  const __mfConsumeOnly = (name, version, scope, materialize, shareConfig) => ({
3658
4027
  name,
3659
4028
  version,
3660
4029
  scope: [scope],
3661
4030
  loaded: false,
3662
- materialize,
4031
+ materialize: materialize && !__mfIsLazyShare(name),
4032
+ lazy: __mfIsLazyShare(name),
3663
4033
  eager: shareConfig.eager,
3664
4034
  from: ${toSafeJsLiteral(resolvedOptions.name)},
3665
4035
  canLiveRebind: true,
@@ -3669,7 +4039,8 @@ function generateLocalSharedImportMap(options) {
3669
4039
  const importMap = {
3670
4040
  ${orderedShares.map((pkg, index) => {
3671
4041
  const shareItem = getNormalizeShareItem(pkg, resolvedOptions);
3672
- if (shareItem?.shareConfig.import === false) return `
4042
+ if (!shareItem) return "";
4043
+ if (shareItem.shareConfig.import === false) return `
3673
4044
  ${toSafeJsLiteral(pkg)}: __mfHostOnly(${toSafeJsLiteral(pkg)})`;
3674
4045
  return `
3675
4046
  ${toSafeJsLiteral(pkg)}: async () => {
@@ -3685,7 +4056,7 @@ function generateLocalSharedImportMap(options) {
3685
4056
  const shareItem = getNormalizeShareItem(key, resolvedOptions);
3686
4057
  if (!shareItem) return null;
3687
4058
  const isReactFamily = key.startsWith("react/") || key === "react-dom/client";
3688
- const cacheKeys = [key, ...key === "react-dom/client" ? ["react-dom"] : []].flatMap((pkg) => {
4059
+ const cacheKeys = [key, ...key === "react-dom/client" ? [getPackageName(REACT_DOM_CLIENT_SHARE)] : []].flatMap((pkg) => {
3689
4060
  const descriptor = getSharedCacheDescriptor(pkg, shareItem);
3690
4061
  return [descriptor.canonical, ...descriptor.aliases ?? []];
3691
4062
  });
@@ -3697,7 +4068,7 @@ function generateLocalSharedImportMap(options) {
3697
4068
  const canLiveRebind = shareItem.shareConfig.import === false || detectedNamedExports !== void 0;
3698
4069
  const treeShakingConfig = canLiveRebind ? shareItem.shareConfig.treeShaking : void 0;
3699
4070
  if (shareItem.shareConfig.import === false && !treeShakingConfig) return `
3700
- ${toSafeJsLiteral(key)}: __mfConsumeOnly(${toSafeJsLiteral(key)}, ${toSafeJsLiteral(shareItem.version)}, ${toSafeJsLiteral(shareItem.scope)}, ${sharesToMaterialize.has(key)}, {singleton: ${shareItem.shareConfig.singleton}, requiredVersion: ${toSafeJsLiteral(shareItem.shareConfig.requiredVersion)}, strictVersion: ${shareItem.shareConfig.strictVersion}, eager: ${Boolean(shareItem.shareConfig.eager)}})`;
4071
+ ${toSafeJsLiteral(key)}: __mfConsumeOnly(${toSafeJsLiteral(key)}, ${toSafeJsLiteral(shareItem.version)}, ${toSafeJsLiteral(shareItem.scope)}, ${sharesToMaterialize.has(key)}, {singleton: ${shareItem.shareConfig.singleton}, requiredVersion: ${toSafeJsLiteral(shareItem.shareConfig.requiredVersion)}, strictVersion: ${shareItem.shareConfig.strictVersion}, eager: ${Boolean(shareItem.shareConfig.eager)}, ${shareItem.shareConfig.request !== void 0 ? `request: ${toSafeJsLiteral(shareItem.shareConfig.request)},` : ""} ${shareItem.shareConfig.shareKey !== void 0 ? `shareKey: ${toSafeJsLiteral(shareItem.shareConfig.shareKey)},` : ""}})`;
3701
4072
  const treeShakingUsage = treeShakingConfig ? getTreeShakingExportUsage(key, shareItem, shareItem.name, options) : void 0;
3702
4073
  const treeShakingProviderExports = treeShakingUsage?.kind === "exports" ? treeShakingUsage.usedExports : [];
3703
4074
  const treeShakingUsedExports = resolvedOptions.injectTreeShakingUsedExports === false ? treeShakingConfig?.usedExports || [] : treeShakingProviderExports;
@@ -3768,6 +4139,8 @@ function generateLocalSharedImportMap(options) {
3768
4139
  requiredVersion: ${toSafeJsLiteral(shareItem.shareConfig.requiredVersion)},
3769
4140
  strictVersion: ${shareItem.shareConfig.strictVersion},
3770
4141
  eager: ${Boolean(shareItem.shareConfig.eager)},
4142
+ ${shareItem.shareConfig.request !== void 0 ? `request: ${toSafeJsLiteral(shareItem.shareConfig.request)},` : ""}
4143
+ ${shareItem.shareConfig.shareKey !== void 0 ? `shareKey: ${toSafeJsLiteral(shareItem.shareConfig.shareKey)},` : ""}
3771
4144
  ${shareItem.shareConfig.import === false ? "import: false," : ""}
3772
4145
  },
3773
4146
  ${treeShakingConfig ? `treeShaking: {
@@ -3806,10 +4179,11 @@ function generateLocalSharedImportMap(options) {
3806
4179
  }
3807
4180
  `;
3808
4181
  }
3809
- /** Expand `pkg/` → package root + matching usedShares; never returns the prefix string. */
4182
+ /** Expand `pkg/` → package root (if importable) + matching usedShares; never returns the prefix string. */
3810
4183
  function expandSharedPrefixKey(prefixKey, used) {
3811
4184
  const base = prefixKey.slice(0, -1);
3812
- const expanded = /* @__PURE__ */ new Set([base]);
4185
+ const baseImportable = isPackageInstalled(base) && isPackageExportAvailable(base);
4186
+ const expanded = new Set(baseImportable ? [base] : []);
3813
4187
  for (const pkg of used) {
3814
4188
  if (pkg.endsWith("/")) continue;
3815
4189
  if (pkg === base || pkg.startsWith(`${base}/`)) expanded.add(pkg);
@@ -3819,11 +4193,17 @@ function expandSharedPrefixKey(prefixKey, used) {
3819
4193
  function getOrderedUsedShares(options) {
3820
4194
  const resolvedOptions = options ?? getNormalizeModuleFederationOptions();
3821
4195
  const used = getUsedShares(options);
3822
- const shares = new Set(used);
4196
+ const shares = /* @__PURE__ */ new Set();
4197
+ const addShare = (pkg) => {
4198
+ const shareItem = getNormalizeShareItem(pkg, resolvedOptions);
4199
+ shares.add(shareItem ? getCanonicalSharedKey(pkg, shareItem) : pkg);
4200
+ };
4201
+ used.forEach(addShare);
3823
4202
  Object.keys(resolvedOptions.shared ?? {}).forEach((pkg) => {
3824
- if (!pkg.endsWith("/")) shares.add(pkg);
4203
+ const share = resolvedOptions.shared?.[pkg];
4204
+ if (share && !getSharedRequest(pkg, share).endsWith("/")) addShare(pkg);
3825
4205
  });
3826
- for (const [pkg, share] of Object.entries(resolvedOptions.shared ?? {})) if (pkg.endsWith("/") && share.shareConfig?.eager) for (const concrete of expandSharedPrefixKey(pkg, used)) shares.add(concrete);
4206
+ for (const [pkg, share] of Object.entries(resolvedOptions.shared ?? {})) if (share.shareConfig?.eager && getSharedRequest(pkg, share).endsWith("/")) for (const concrete of expandSharedPrefixKey(getSharedRequest(pkg, share), used)) addShare(concrete);
3827
4207
  return orderSharedDependenciesFirst(Array.from(shares).sort((a, b) => {
3828
4208
  const priority = (pkg) => pkg === "react" ? 0 : pkg === "react-dom" ? 1 : pkg.startsWith("react/") ? 2 : 3;
3829
4209
  return priority(a) - priority(b) || a.localeCompare(b);
@@ -3836,7 +4216,8 @@ function getMaterializedShares(options) {
3836
4216
  const usedForEager = options ? usedSharesByOptions.get(options) ?? [] : usedShares;
3837
4217
  for (const [pkg, share] of Object.entries(resolvedOptions.shared ?? {})) {
3838
4218
  if (!share.shareConfig?.eager) continue;
3839
- if (pkg.endsWith("/")) for (const concrete of expandSharedPrefixKey(pkg, usedForEager)) shares.add(concrete);
4219
+ const request = getSharedRequest(pkg, share);
4220
+ if (request.endsWith("/")) for (const concrete of expandSharedPrefixKey(request, usedForEager)) shares.add(concrete);
3840
4221
  else shares.add(pkg);
3841
4222
  }
3842
4223
  const configured = /* @__PURE__ */ new Map();
@@ -3864,10 +4245,14 @@ function getMaterializedShares(options) {
3864
4245
  }
3865
4246
  }
3866
4247
  }
3867
- return orderSharedDependenciesFirst([...shares].sort((a, b) => {
4248
+ const sorted = [...shares].sort((a, b) => {
3868
4249
  const priority = (pkg) => pkg === "react" ? 0 : pkg === "react-dom" ? 1 : pkg.startsWith("react/") ? 2 : 3;
3869
4250
  return priority(a) - priority(b) || a.localeCompare(b);
3870
- }));
4251
+ });
4252
+ return orderSharedDependenciesFirst([...new Set(sorted.map((pkg) => {
4253
+ const shareItem = getNormalizeShareItem(pkg, resolvedOptions);
4254
+ return shareItem ? getCanonicalSharedKey(pkg, shareItem) : pkg;
4255
+ }))]);
3871
4256
  }
3872
4257
  /** Shared keys a share's package.json depends on (roots stand in for their subpaths, subpaths for their root), keyed by share. */
3873
4258
  function getSharePrerequisites(ordered) {
@@ -3955,9 +4340,30 @@ function orderSharedDependenciesFirst(sharedPackages) {
3955
4340
  }
3956
4341
  function getShareItemForPreload(pkg, options = getNormalizeModuleFederationOptions()) {
3957
4342
  const shared = options.shared;
3958
- const wildcardKey = `${getPackageName(pkg)}/`;
4343
+ const packageName = getPackageName(pkg);
4344
+ const wildcardKey = `${packageName}/`;
3959
4345
  if (isExplicitSharedKey(pkg, options)) return shared[pkg];
3960
4346
  if (isExplicitSharedKey(wildcardKey, options)) return shared[wildcardKey];
4347
+ if (pkg !== packageName && isExplicitSharedKey(packageName, options) && shared[packageName]?.shareConfig.import !== false && getCommonSharedSubpaths(packageName).includes(pkg)) return shared[packageName];
4348
+ const shareItem = getNormalizeShareItem(pkg, options);
4349
+ if (!shareItem) return void 0;
4350
+ if (shareItem.shareConfig.request === void 0 && shareItem.shareConfig.shareKey === void 0) return;
4351
+ const runtimeKey = getSharedRuntimeKey(pkg, shareItem);
4352
+ if (runtimeKey === pkg || runtimeKey.endsWith("/") && (pkg === runtimeKey.slice(0, -1) || pkg.startsWith(runtimeKey))) return shareItem;
4353
+ }
4354
+ /**
4355
+ * Entry-injected renderer wrappers (see `REACT_DOM_CLIENT_SHARE`) assign
4356
+ * `createRoot` only after `initPromise` and a dynamic import, so a standalone
4357
+ * remote must evaluate that wrapper before the app entry. The subpath is often
4358
+ * absent from `getMaterializedShares()` when pending shares is emitted:
4359
+ * `react-dom/` collapses to `react-dom`, and the entry import may not be
4360
+ * recorded yet.
4361
+ */
4362
+ function shouldPreloadEntryDeferredReactDomClient(options) {
4363
+ if (options.hostInitInjectLocation !== "entry" || !isRemoteContainer(options)) return false;
4364
+ const shareItem = getShareItemForPreload(REACT_DOM_CLIENT_SHARE, options);
4365
+ if (!shareItem || shareItem.shareConfig.singleton !== true) return false;
4366
+ return shareItem.shareConfig.import !== false && !shareItem.shareConfig.treeShaking;
3961
4367
  }
3962
4368
  function generateSharedCacheSeedItem(pkg, shareItem, importPath, options = getNormalizeModuleFederationOptions()) {
3963
4369
  const cacheDescriptor = getSharedCacheDescriptor(pkg, shareItem);
@@ -3987,6 +4393,8 @@ const normalizeRuntimeShareCode = `const __mfNormalizeRuntimeShare = (mod) => {
3987
4393
  };`;
3988
4394
  const sharedProviderSelectionHelperCode = `const __mfOriginalProviderKey = Symbol("mf.originalSharedProvider");
3989
4395
  const __mfResolveShareHook = { emit: (params) => params };
4396
+ const __mfGetShareScopeNames = (share) =>
4397
+ Array.isArray(share.scope) ? share.scope : [share.scope || "default"];
3990
4398
  const __mfCreateProviderSelectionVersions = (versions, strategy) => {
3991
4399
  if (strategy !== "version-first") return versions;
3992
4400
  const selectionVersions = {};
@@ -4028,7 +4436,7 @@ const sharedProviderSelectionHelperCode = `const __mfOriginalProviderKey = Symbo
4028
4436
  Object.entries(versions).filter(([, provider]) => provider?.shareConfig?.import !== false)
4029
4437
  );
4030
4438
  if (Object.keys(candidates).length === 0) return undefined;
4031
- const scopes = Array.isArray(share.scope) ? share.scope : [share.scope || "default"];
4439
+ const scopes = __mfGetShareScopeNames(share);
4032
4440
  const selectionVersions = __mfCreateProviderSelectionVersions(candidates, strategy);
4033
4441
  const shareScopeMap = {};
4034
4442
  for (const scope of scopes) {
@@ -4140,7 +4548,28 @@ const externalSharedProviderSelectionHelperCode = `const __mfSelectExternalShare
4140
4548
  ) return undefined;
4141
4549
  return { provider, scopeRootProvider };
4142
4550
  };`;
4143
- function generateRuntimeSharedCacheSeedCode(shareStrategy, options) {
4551
+ /**
4552
+ * A consume-only stub never outranks a provider: when registering this container's
4553
+ * `import: false` share replaces an unloaded provider of the same version (#1311),
4554
+ * the `afterRegisterShare` hook restores the provider. Registered once per instance.
4555
+ */
4556
+ function generateKeepProvidersOverStubsCode(runtimeVar) {
4557
+ return `if (!${runtimeVar}.__mfKeepAdoptedProviders) {
4558
+ ${runtimeVar}.__mfKeepAdoptedProviders = true;
4559
+ ${runtimeVar}.sharedHandler?.hooks?.lifecycle?.afterRegisterShare?.on?.((args) => {
4560
+ const { shared, previousShared, registeredShared } = args || {};
4561
+ if (
4562
+ shared?.shareConfig?.import !== false ||
4563
+ registeredShared !== shared ||
4564
+ !previousShared ||
4565
+ previousShared.shareConfig?.import === false
4566
+ ) return;
4567
+ const versions = ${runtimeVar}.shareScopeMap?.[args.scope]?.[args.pkgName];
4568
+ if (versions && versions[shared.version] === shared) versions[shared.version] = previousShared;
4569
+ });
4570
+ }`;
4571
+ }
4572
+ function generateRuntimeSharedCacheSeedCode(shareStrategy, options, command = "build") {
4144
4573
  const seedBatches = getShareBatches(options, false);
4145
4574
  const seedOrder = seedBatches.flat();
4146
4575
  const seedIndex = new Map(seedOrder.map((pkg, index) => [pkg, index]));
@@ -4154,7 +4583,7 @@ function generateRuntimeSharedCacheSeedCode(shareStrategy, options) {
4154
4583
  // import and set materialize. An import:false share has no local fallback
4155
4584
  // though, so on a cold request (materialize not set yet) it must still be
4156
4585
  // attempted here, or it is never seeded and its consumer reads it undefined.
4157
- const __mfSeedKeys = __mfSeedOrder.filter((pkg) => usedShared[pkg] && (usedShared[pkg].materialize !== false || usedShared[pkg].shareConfig?.import === false));
4586
+ const __mfSeedKeys = __mfSeedOrder.filter((pkg) => usedShared[pkg] && (usedShared[pkg].materialize !== false || (usedShared[pkg].shareConfig?.import === false && !usedShared[pkg].lazy)));
4158
4587
  __mfModuleCache.providerInit ||= new Map();
4159
4588
  const __mfInitializeProviderOnce = (key, initialize) => {
4160
4589
  const existing = __mfModuleCache.providerInit.get(key);
@@ -4187,6 +4616,16 @@ function generateRuntimeSharedCacheSeedCode(shareStrategy, options) {
4187
4616
  );
4188
4617
  return;
4189
4618
  }
4619
+ ${command === "serve" ? `// A pending webpack provider for this share, or for its package when this
4620
+ // is a subpath, is only bridged after init(). Seeding the local fallback now
4621
+ // would evaluate the package's dev proxy, which snapshots its exports, before
4622
+ // the bridge runs and pin a second copy. The proxy seeds itself on first import.
4623
+ if (
4624
+ typeof __mfGetPendingExternalSharedProvider === 'function' &&
4625
+ __mfGetPendingExternalSharedProvider(pkg, share)
4626
+ ) {
4627
+ return;
4628
+ }` : ""}
4190
4629
  const externalProvider = typeof __mfGetExternalSharedProvider === 'function'
4191
4630
  ? __mfGetExternalSharedProvider(pkg, share)
4192
4631
  : undefined;
@@ -4215,6 +4654,12 @@ function generateRuntimeSharedCacheSeedCode(shareStrategy, options) {
4215
4654
  const mod = typeof factory === "function" ? factory() : factory;
4216
4655
  return Promise.resolve(mod);
4217
4656
  });
4657
+ // The seeded local copy is what this container's consumers are bound to.
4658
+ // Flag the Runtime's provider as eager so a same-version sibling cannot
4659
+ // take over the share scope slot via the Runtime's name tie-break.
4660
+ for (const provider of initRes.options.shared?.[pkg] || []) {
4661
+ if (provider.get === share.get) provider.eager = true;
4662
+ }
4218
4663
  ${normalizeRuntimeShareCode}
4219
4664
  const normalizedModule = __mfNormalizeRuntimeShare(resolved);
4220
4665
  const exportModule = normalizedModule === resolved ? {...resolved} : normalizedModule;
@@ -4487,8 +4932,8 @@ function generateTreeShakingSnapshotPluginCode(enabled) {
4487
4932
  },
4488
4933
  });`;
4489
4934
  }
4490
- function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(options), command = "build", exportConditions) {
4491
- const needsSharedProviderSelectionHelper = Object.keys(options.shared ?? {}).length > 0;
4935
+ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(options), command = "build", exportConditions, isSsrBuild = false) {
4936
+ const needsSharedProviderSelectionHelper = hasShared(options);
4492
4937
  const hasTreeShakingShared = Object.values(options.shared ?? {}).some((share) => !!share?.shareConfig.treeShaking);
4493
4938
  const hasMultipleShareScopes = Array.isArray(options.shareScope);
4494
4939
  const guardHostAutoInit = command === "build" && isRemoteContainer(options) && hasRemotes(options);
@@ -4499,7 +4944,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
4499
4944
  ...hasTreeShakingShared ? ["getRemoteEntry"] : []
4500
4945
  ].join(", ");
4501
4946
  const runtimeHelperImports = [...hasTreeShakingShared ? ["global as runtimeGlobal"] : [], ...needsSharedProviderSelectionHelper ? ["share as runtimeShare"] : []];
4502
- const pluginImportNames = options.runtimePlugins.map((p, i) => {
4947
+ const pluginImportNames = filterRuntimePluginsForTarget(options.runtimePlugins, SSR_ONLY_RUNTIME_PLUGINS, isSsrBuild).map((p, i) => {
4503
4948
  if (typeof p === "string") return [
4504
4949
  `$runtimePlugin_${i}`,
4505
4950
  `import $runtimePlugin_${i} from "${p}";`,
@@ -4822,13 +5267,36 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
4822
5267
  };
4823
5268
  }
4824
5269
  const runtimeResolveShareHook = initRes.sharedHandler.hooks.lifecycle.resolveShare;
5270
+ // Registering this container's shares lets its consume-only stub displace the parent's
5271
+ // unloaded same-version provider whenever this container's name sorts after the parent's
5272
+ // (the Runtime keeps the higher name). Nothing can be loaded from a stub, so put the
5273
+ // provider back; a share bridged later, e.g. from a lazy import(), still finds it.
5274
+ ${generateKeepProvidersOverStubsCode("initRes")}
4825
5275
  const __mfRuntimeProviderOrigins = new WeakMap();
4826
5276
  runtimeResolveShareHook.on((args) => {
4827
5277
  const loadId = args.shareInfo?.[__mfRuntimeShareLoadIdKey];
4828
5278
  const resolver = args.resolver;
4829
5279
  if (typeof resolver !== "function") return args;
4830
5280
  const instrumentedResolver = (...resolverArgs) => {
4831
- const resolved = resolver(...resolverArgs);
5281
+ let resolved = resolver(...resolverArgs);
5282
+ // A consume-only stub can never be loaded. The Runtime still settles on one when
5283
+ // it carries the highest version, e.g. a parent that registers its provider under
5284
+ // "0.0.0"; hand back the provider this container selects for itself instead.
5285
+ if (
5286
+ resolved?.shared?.shareConfig?.import === false &&
5287
+ typeof __mfSelectSharedProvider === "function" &&
5288
+ usedShared[args.pkgName]
5289
+ ) {
5290
+ const provider = __mfSelectSharedProvider(
5291
+ args.shareScopeMap?.[args.scope]?.[args.pkgName],
5292
+ args.pkgName,
5293
+ usedShared[args.pkgName],
5294
+ '${options.shareStrategy}'
5295
+ );
5296
+ if (provider && provider.shareConfig?.import !== false) {
5297
+ resolved = { shared: provider, useTreesShaking: resolved.useTreesShaking };
5298
+ }
5299
+ }
4832
5300
  const selectedProvider = resolved?.shared;
4833
5301
  if (
4834
5302
  selectedProvider &&
@@ -5241,7 +5709,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
5241
5709
  );
5242
5710
  }
5243
5711
  }
5244
- ${generateRuntimeSharedCacheSeedCode(options.shareStrategy, options)}
5712
+ ${generateRuntimeSharedCacheSeedCode(options.shareStrategy, options, command)}
5245
5713
  ${initializeSharingCode}
5246
5714
  __mfRestoreForeignSharedProviders();
5247
5715
  // Calling provider.get() marks a provider as loaded. Wait until the Runtime has
@@ -5259,9 +5727,13 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
5259
5727
  );
5260
5728
  }));
5261
5729
  };
5262
- await __mfBridgeSharedProviders();
5263
5730
  if (__mfUsesWebpackShareScope) {
5731
+ // A webpack host's loadShare() awaits initializeSharing(), which awaits this
5732
+ // init(). Bridging here would call the host's provider.get() and re-enter
5733
+ // loadShare(), so both promises wait on each other forever (#1326).
5264
5734
  __mfLateBridgeShared = __mfBridgeSharedProviders;
5735
+ } else {
5736
+ await __mfBridgeSharedProviders();
5265
5737
  }
5266
5738
  try {
5267
5739
  const allInstances = globalThis.__FEDERATION__?.__SHARE__;
@@ -5415,6 +5887,29 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
5415
5887
  (pkg) => !__mfBlockedSeedKeys.has(__mfSeedIndex.get(pkg))
5416
5888
  ));
5417
5889
  await __mfSeedLocalShared(__mfReadyDeferredSeedKeys);
5890
+ ${command === "build" ? `// A consume-only share reached only through import() is bridged when that import runs
5891
+ // (see pluginLazyConsumeOnlyShares), through the same provider selection init() uses.
5892
+ const __mfLazyShareLoads = new Map();
5893
+ __mfResolveState.loadLazyShares = async (names) => {
5894
+ const requested = new Set(names);
5895
+ for (const batch of __mfMaterializedShareBatches) await Promise.all(batch.filter((pkg) => requested.has(pkg)).map((pkg) => {
5896
+ const share = usedShared[pkg];
5897
+ if (!share || !share.lazy || !__mfIsRuntimeOnlySharePending(pkg)) return;
5898
+ let load = __mfLazyShareLoads.get(pkg);
5899
+ if (!load) {
5900
+ load = __mfBridgeExternalSharedProvider(
5901
+ pkg,
5902
+ share,
5903
+ ${hasMultipleShareScopes ? "getShareVersions(pkg, share)" : "shared[pkg]"},
5904
+ initialShared[pkg],
5905
+ undefined
5906
+ ).then(() => __mfIsRuntimeOnlySharePending(pkg) ? __mfResolveImportFalseShared(pkg, share) : undefined);
5907
+ load.catch(() => __mfLazyShareLoads.delete(pkg));
5908
+ __mfLazyShareLoads.set(pkg, load);
5909
+ }
5910
+ return load;
5911
+ }));
5912
+ };` : ""}
5418
5913
  initResolve(initRes)
5419
5914
  return initRes
5420
5915
  }
@@ -5431,8 +5926,13 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
5431
5926
  ${guardHostAutoInit ? `let __mfInitPromise;
5432
5927
  function __mfGuardedInit(shared, initScope, remoteEntryInitOptions) {
5433
5928
  if (shared === undefined && __mfInitPromise) return __mfInitPromise;
5434
- __mfInitPromise = init(shared, initScope, remoteEntryInitOptions);
5435
- return __mfInitPromise;
5929
+ // A call skipped by the circular-init guard resolves to undefined and must not
5930
+ // replace the cached result of the call that actually initialized the container.
5931
+ const prev = __mfInitPromise;
5932
+ const next = init(shared, initScope, remoteEntryInitOptions);
5933
+ __mfInitPromise = prev ? next.then((res) => (res === undefined ? prev : res)) : next;
5934
+ if (prev) __mfInitPromise.catch(() => {});
5935
+ return next;
5436
5936
  }
5437
5937
  export { __mfGuardedInit as init, getExposes as get }` : `export { init, getExposes as get }`}
5438
5938
  `;
@@ -5468,7 +5968,28 @@ function generateHostAutoInitCode(remoteEntryImport, _command = "build", options
5468
5968
  const hostInitShareBatches = toSafeJsLiteral(getShareBatches(options, false));
5469
5969
  const cacheOwner = toSafeJsLiteral(resolvedOptions.name);
5470
5970
  const preferLocalVinextReact = hasPackageDependency("vinext") && (!exportConditions?.includes("browser") || exportConditions.includes("worker"));
5971
+ const hasConfiguredShared = hasShared(resolvedOptions);
5972
+ const hostInitSharedProviderHelperImport = shouldPreloadShares && hasConfiguredShared ? "import {share as runtimeShare} from \"@module-federation/runtime/helpers\";" : "";
5973
+ const hostInitSharedProviderHelperCode = shouldPreloadShares && hasConfiguredShared ? `
5974
+ ${sharedProviderSelectionHelperCode}
5975
+ const __mfHasUsableProvider = (versions, pkg, share, scopeName) => {
5976
+ // Keep runtime singleton negotiation unchanged. A singleton already
5977
+ // registered in this scope is authoritative, even when runtime-core
5978
+ // reports a version mismatch.
5979
+ if (share.shareConfig?.singleton) {
5980
+ return Object.values(versions || {}).some(
5981
+ (provider) => provider?.shareConfig?.import !== false
5982
+ );
5983
+ }
5984
+ return Boolean(__mfSelectSharedProvider(
5985
+ versions,
5986
+ pkg,
5987
+ { ...share, scope: [scopeName] },
5988
+ ${toSafeJsLiteral(resolvedOptions.shareStrategy)}
5989
+ ));
5990
+ };` : "";
5471
5991
  return `
5992
+ ${hostInitSharedProviderHelperImport}
5472
5993
  ${getRuntimeModuleCacheBootstrapCode(exportConditions)}
5473
5994
  let hostInitPromise;
5474
5995
  async function initHost() {
@@ -5482,16 +6003,18 @@ function generateHostAutoInitCode(remoteEntryImport, _command = "build", options
5482
6003
  ${normalizeRuntimeShareCode}
5483
6004
  ${shouldPreloadShares ? `
5484
6005
  const __mfHasAlternativeSharedVersion = (pkg, share) =>
5485
- (Array.isArray(share.scope) ? share.scope : [share.scope || 'default']).some(
6006
+ __mfGetShareScopeNames(share).some(
5486
6007
  (scopeName) => Object.keys(runtime.shareScopeMap?.[scopeName]?.[pkg] || {}).some(
5487
6008
  (version) => version !== share.version
5488
6009
  )
5489
6010
  );
5490
6011
  const __mfHostInitShareBatches = ${hostInitShareBatches};
6012
+ ${hostInitSharedProviderHelperCode}
5491
6013
  for (const __mfHostInitShareBatch of __mfHostInitShareBatches) {
5492
6014
  await Promise.all(__mfHostInitShareBatch.map(async (pkg) => {
5493
6015
  const share = usedShared[pkg];
5494
- if (!share || share.materialize === false) return;
6016
+ // A standalone container has no dynamic-import boundary to load a lazy share behind.
6017
+ if (!share || (share.materialize === false && !share.lazy)) return;
5495
6018
  // remoteEntry.init resolves tree-enabled shares into the
5496
6019
  // coverage-aware cache. Never republish that selected partial under
5497
6020
  // a generic full-module key here.
@@ -5505,18 +6028,44 @@ function generateHostAutoInitCode(remoteEntryImport, _command = "build", options
5505
6028
  )`}
5506
6029
  ) return;
5507
6030
  // An import:false share has nothing to load until a foreign provider
5508
- // registers: its own stub getter throws by construction.
5509
- if (
5510
- share.shareConfig?.import === false &&
5511
- !(Array.isArray(share.scope) ? share.scope : [share.scope || 'default']).some((scopeName) =>
5512
- Object.values(runtime.shareScopeMap?.[scopeName]?.[pkg] || {}).some(
5513
- (provider) => provider?.shareConfig?.import !== false
5514
- )
5515
- )
5516
- ) return;
6031
+ // registers: its own stub getter throws by construction. A standalone
6032
+ // container initialized on the same page keeps its providers in its
6033
+ // own runtime scope (#1307), so adopt those before giving up.
6034
+ if (share.shareConfig?.import === false) {
6035
+ const __mfScopeNames = __mfGetShareScopeNames(share);
6036
+ const __mfNeedsSiblingProvider = (scopeName) =>
6037
+ !__mfHasUsableProvider(
6038
+ runtime.shareScopeMap?.[scopeName]?.[pkg],
6039
+ pkg,
6040
+ share,
6041
+ scopeName
6042
+ );
6043
+ if (__mfScopeNames.some(__mfNeedsSiblingProvider)) {
6044
+ // loadShare() re-runs initializeSharing(), which re-registers this
6045
+ // container's own stub and lets it displace an unloaded adopted
6046
+ // provider whenever this container's name sorts after the provider's
6047
+ // (#1311). Put the provider back: a stub never outranks a provider.
6048
+ ${generateKeepProvidersOverStubsCode("runtime")}
6049
+ for (const instance of globalThis.__FEDERATION__?.__INSTANCES__ || []) {
6050
+ for (const scopeName of __mfScopeNames) {
6051
+ const versions = instance?.shareScopeMap?.[scopeName]?.[pkg];
6052
+ if (!__mfHasUsableProvider(versions, pkg, share, scopeName)) continue;
6053
+ if (!__mfNeedsSiblingProvider(scopeName)) continue;
6054
+ const target = (runtime.shareScopeMap[scopeName] ||= {})[pkg] ||= {};
6055
+ for (const [version, provider] of Object.entries(versions)) {
6056
+ if (provider?.shareConfig?.import === false) continue;
6057
+ if (target[version] && target[version].shareConfig?.import !== false) continue;
6058
+ target[version] = provider;
6059
+ }
6060
+ }
6061
+ }
6062
+ }
6063
+ if (__mfScopeNames.every(__mfNeedsSiblingProvider)) return;
6064
+ }
5517
6065
  await runtime.loadShare(pkg, {
5518
6066
  customShareInfo: { shareConfig: share.shareConfig }
5519
6067
  }).then(async (factory) => {
6068
+ if (factory === false) return;
5520
6069
  const mod = typeof factory === "function" ? factory() : factory;
5521
6070
  let resolved = __mfNormalizeRuntimeShare(await Promise.resolve(mod));
5522
6071
  ${preferLocalVinextReact ? `if (
@@ -5596,22 +6145,32 @@ function getPendingSharesState(options) {
5596
6145
  }
5597
6146
  function generatePendingSharesCode(command = "build", options) {
5598
6147
  const resolvedOptions = options ?? getNormalizeModuleFederationOptions();
5599
- const pendingShareImports = command === "build" ? getMaterializedShares(options).filter((pkg) => {
6148
+ const pendingSharePkgs = command === "build" ? getMaterializedShares(options).filter((pkg) => {
5600
6149
  const shareItem = getShareItemForPreload(pkg, resolvedOptions);
5601
6150
  if (!shareItem || pkg.endsWith("/")) return false;
5602
6151
  if (shareItem.shareConfig.eager) return false;
5603
6152
  return shareItem.shareConfig.import !== false && !shareItem.shareConfig.treeShaking;
5604
- }).map((pkg) => `[${toSafeJsLiteral(pkg)}, () => import(${toSafeJsLiteral(getLoadShareModulePath(pkg, false, options))})]`) : [];
6153
+ }) : [];
6154
+ if (command === "build" && shouldPreloadEntryDeferredReactDomClient(resolvedOptions) && !pendingSharePkgs.includes("react-dom/client")) pendingSharePkgs.push(REACT_DOM_CLIENT_SHARE);
6155
+ const pendingShareImports = pendingSharePkgs.map((pkg) => `[${toSafeJsLiteral(pkg)}, () => import(${toSafeJsLiteral(getLoadShareModulePath(pkg, false, options))})]`);
5605
6156
  return `
5606
6157
  ${getRuntimeModuleCacheBootstrapCode()}
5607
6158
  ${sharedCacheHelperCode}
5608
6159
  const __mfPendingShareImports = [${pendingShareImports.join(", ")}];
5609
6160
  export async function preloadPendingShares() {
5610
6161
  if (__mfPendingShareImports.length === 0) return;
6162
+ const __mfRendererShare = ${toSafeJsLiteral(REACT_DOM_CLIENT_SHARE)};
6163
+ const __mfRendererParent = ${toSafeJsLiteral(getPackageName(REACT_DOM_CLIENT_SHARE))};
5611
6164
  const {usedShared} = await import("${getLocalSharedImportMapPath(options)}");
5612
6165
  await Promise.all(__mfPendingShareImports.map(async ([pkg, load]) => {
5613
- const share = usedShared[pkg];
5614
- if (!share || share.materialize === false || share.treeShaking || share.shareConfig?.import === false) return;
6166
+ const exactShare = usedShared[pkg];
6167
+ const share = exactShare ?? (pkg === __mfRendererShare ? usedShared[__mfRendererParent] : undefined);
6168
+ if (!share || share.treeShaking || share.shareConfig?.import === false) return;
6169
+ // The collapsed parent does not mark the renderer subpath materialized until the entry
6170
+ // imports it, and that import map can be emitted first. The deferred renderer wrapper
6171
+ // still has to run before a standalone entry reads createRoot. A cache hit (the host
6172
+ // renderer) skips load(), so a nested leaf does not import its own client.
6173
+ if (exactShare && exactShare.materialize === false && pkg !== __mfRendererShare) return;
5615
6174
  const cacheDescriptor = __mfGetSharedCacheDescriptor(pkg, share.shareConfig?.singleton, share.version, share.scope);
5616
6175
  if (__mfReadSharedCache(__mfModuleCache.share, cacheDescriptor) !== undefined) return;
5617
6176
  await load().catch((err) => console.warn("[module-federation] shared preload failed:", pkg, err));
@@ -6100,9 +6659,6 @@ if (typeof document !== 'undefined' && document.head) {
6100
6659
  function getFirstHtmlEntryFile(entryFiles) {
6101
6660
  return entryFiles.find((file) => file.endsWith(".html"));
6102
6661
  }
6103
- function stripQueryAndHash$1(file) {
6104
- return file.split(/[?#]/)[0];
6105
- }
6106
6662
  function isReactRouterClientRouteInput(file) {
6107
6663
  return /[?&]__react-router-build-client-route(?:[=&]|$)/.test(file);
6108
6664
  }
@@ -6153,6 +6709,7 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
6153
6709
  let emitFileId;
6154
6710
  let pendingSharesEmitId;
6155
6711
  let viteConfig;
6712
+ let devServer;
6156
6713
  let skipHtmlDevFallback = forceClientInjected ?? false;
6157
6714
  let clientInjected = false;
6158
6715
  let emittedFileName;
@@ -6229,6 +6786,28 @@ const __mfCurrentScript = document.currentScript;
6229
6786
  return registration && (registration.type === "module" || registration.type === "esm") && /^(?:https?:)?\/\//.test(registration.entry) && !/\.json(?:[?#]|$)/i.test(registration.entry) ? [registration.entry] : [];
6230
6787
  })));
6231
6788
  }
6789
+ async function warmupDevEntryGraph(entryUrl) {
6790
+ const server = devServer;
6791
+ if (!server) return;
6792
+ const seen = /* @__PURE__ */ new Set();
6793
+ const cacheDir = normalizePathForImport(server.config?.cacheDir ?? "").replace(/\/$/, "") + "/";
6794
+ const visit = async (url) => {
6795
+ if (seen.has(url)) return;
6796
+ seen.add(url);
6797
+ try {
6798
+ await server.transformRequest(url);
6799
+ } catch {
6800
+ return;
6801
+ }
6802
+ const deps = [...(await server.moduleGraph.getModuleByUrl(url))?.importedModules ?? []].filter((dep) => {
6803
+ if (!dep.file || dep.type !== "js" || !path$1.isAbsolute(dep.file)) return false;
6804
+ const file = normalizePathForImport(dep.file);
6805
+ return !file.includes("/node_modules/") && !file.startsWith(cacheDir);
6806
+ });
6807
+ await Promise.all(deps.map((dep) => visit(dep.url)));
6808
+ };
6809
+ await visit(entryUrl).catch(() => {});
6810
+ }
6232
6811
  function getBootstrapSource(initSrc, entrySrc, useSystemImportFallback = false, options) {
6233
6812
  const importHelper = useSystemImportFallback ? `const __mfImport = (src) =>
6234
6813
  globalThis.System && typeof globalThis.System.import === 'function'
@@ -6255,7 +6834,7 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6255
6834
  }
6256
6835
  ` : "";
6257
6836
  const sharedPreloadSources = _command === "serve" && waitsForInit && isRemoteOnlyContainer(normalizedOptions) && federationOptions ? Array.from(getUsedShares(federationOptions)).filter((pkg) => !pkg.endsWith("/")).filter((pkg) => {
6258
- const shareItem = federationOptions.shared[pkg] || Object.entries(federationOptions.shared).find(([key]) => key.endsWith("/") && pkg.startsWith(key))?.[1];
6837
+ const shareItem = getNormalizeShareItem(pkg, federationOptions);
6259
6838
  const isExplicitShare = Object.hasOwn(federationOptions.shared, pkg);
6260
6839
  return shareItem?.shareConfig?.singleton === true && shareItem?.shareConfig?.import !== false && !shareItem?.shareConfig?.treeShaking && (isExplicitShare || typeof shareItem?.shareConfig?.import === "string" || Boolean(getProjectResolvedImportPath(pkg)));
6261
6840
  }).map((pkg) => toViteEncodedId(getLoadShareModulePath(pkg, false, federationOptions))) : [];
@@ -6345,7 +6924,7 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6345
6924
  function isWorkspaceSourceId(id) {
6346
6925
  const normalized = normalizeModuleId(decodeViteId(id));
6347
6926
  if (normalized.startsWith("\0") || normalized.startsWith("virtual:")) return false;
6348
- const filePath = stripQueryAndHash$1(normalized);
6927
+ const filePath = stripQueryAndHash(normalized);
6349
6928
  if (filePath.startsWith("/@fs/")) return true;
6350
6929
  if (!path$1.isAbsolute(filePath)) return false;
6351
6930
  const root = normalizePathForImport(path$1.resolve(viteConfig.root));
@@ -6367,7 +6946,7 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6367
6946
  ignoredHtmlScriptSources.add(match[1]);
6368
6947
  continue;
6369
6948
  }
6370
- const scriptSrc = stripQueryAndHash$1(match[1]);
6949
+ const scriptSrc = stripQueryAndHash(match[1]);
6371
6950
  if (/^(?:[a-z]+:)?\/\//i.test(scriptSrc)) continue;
6372
6951
  addEntryFile(scriptSrc);
6373
6952
  addEntryFile(scriptSrc.startsWith("/") ? path$1.resolve(viteConfig.root, scriptSrc.slice(1)) : path$1.resolve(path$1.dirname(htmlPath), scriptSrc));
@@ -6375,7 +6954,7 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6375
6954
  }
6376
6955
  function addEntryRemoteImports(entrySrc) {
6377
6956
  if (!federationOptions || /^(?:[a-z]+:)?\/\//i.test(entrySrc)) return;
6378
- const file = path$1.resolve(viteConfig.root, stripQueryAndHash$1(entrySrc).replace(/^\//, ""));
6957
+ const file = path$1.resolve(viteConfig.root, stripQueryAndHash(entrySrc).replace(/^\//, ""));
6379
6958
  if (!fs$2.existsSync(file)) return;
6380
6959
  const code = fs$2.readFileSync(file, "utf-8");
6381
6960
  for (const source of findModuleImportSources(code)) {
@@ -6402,6 +6981,7 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6402
6981
  skipTransformIds = new Set(skipTransformFor.map(resolveProjectId));
6403
6982
  },
6404
6983
  configureServer(server) {
6984
+ devServer = server;
6405
6985
  server.middlewares.use((req, res, next) => {
6406
6986
  const rawUrl = req.url?.split("#")[0] ?? "";
6407
6987
  if (normalizeDevHtmlProxyId(rawUrl.split("?")[0]) === DEV_HTML_PROXY_PREFIX.slice(0, -1)) {
@@ -6411,9 +6991,12 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6411
6991
  const entrySrc = params.get("entry");
6412
6992
  if (initSrc && entrySrc) {
6413
6993
  const withBase = (src) => viteConfig.base + src.replace(/^\//, "");
6414
- res.statusCode = 200;
6415
- res.setHeader("Content-Type", "application/javascript");
6416
- res.end(getBootstrapSource(withBase(initSrc), withBase(entrySrc)));
6994
+ const source = getBootstrapSource(withBase(initSrc), withBase(entrySrc));
6995
+ warmupDevEntryGraph(entrySrc).finally(() => {
6996
+ res.statusCode = 200;
6997
+ res.setHeader("Content-Type", "application/javascript");
6998
+ res.end(source);
6999
+ });
6417
7000
  return;
6418
7001
  }
6419
7002
  }
@@ -6461,7 +7044,8 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6461
7044
  const initSrc = params.get("init");
6462
7045
  const entrySrc = params.get("entry");
6463
7046
  if (!initSrc || !entrySrc) return;
6464
- return getBootstrapSource(initSrc, entrySrc);
7047
+ const source = getBootstrapSource(initSrc, entrySrc);
7048
+ return warmupDevEntryGraph(entrySrc).then(() => source);
6465
7049
  },
6466
7050
  transform(code, id) {
6467
7051
  if (id.includes("node_modules") || inject !== "html" || htmlFilePath) return;
@@ -6679,17 +7263,20 @@ function checkAliasConflicts(options) {
6679
7263
  }
6680
7264
  return false;
6681
7265
  };
6682
- for (const sharedKey of sharedKeys) for (const aliasEntry of userAliases) {
6683
- const replacement = aliasEntry.replacement;
6684
- if (!matchesSharedKey(aliasEntry, sharedKey)) continue;
6685
- if (replacement === "$1") break;
6686
- if (typeof replacement === "string") {
6687
- if (getPackageNameFromNodeModulePath(replacement) === (sharedKey.endsWith("/") ? sharedKey.slice(0, -1) : sharedKey)) continue;
6688
- conflicts.push({
6689
- sharedModule: sharedKey,
6690
- alias: String(aliasEntry.find),
6691
- target: replacement
6692
- });
7266
+ for (const sharedKey of sharedKeys) {
7267
+ const request = getSharedRequest(sharedKey, shared[sharedKey]);
7268
+ for (const aliasEntry of userAliases) {
7269
+ const replacement = aliasEntry.replacement;
7270
+ if (!matchesSharedKey(aliasEntry, request)) continue;
7271
+ if (replacement === "$1") break;
7272
+ if (typeof replacement === "string") {
7273
+ if (getPackageNameFromNodeModulePath(replacement) === (request.endsWith("/") ? request.slice(0, -1) : request)) continue;
7274
+ conflicts.push({
7275
+ sharedModule: sharedKey,
7276
+ alias: String(aliasEntry.find),
7277
+ target: replacement
7278
+ });
7279
+ }
6693
7280
  }
6694
7281
  }
6695
7282
  if (conflicts.length > 0) {
@@ -7404,9 +7991,6 @@ function pluginExternalRuntimeCore() {
7404
7991
  };
7405
7992
  }
7406
7993
  //#endregion
7407
- //#region package.json
7408
- var version$1 = "1.22.0";
7409
- //#endregion
7410
7994
  //#region src/virtualModules/index.ts
7411
7995
  function initVirtualModules(command, remoteEntryId, enableSsrInit = false, options) {
7412
7996
  writeLocalSharedImportMap(options);
@@ -7424,6 +8008,11 @@ const JS_EXTENSIONS = [
7424
8008
  ".mjs",
7425
8009
  ".cjs"
7426
8010
  ];
8011
+ /** A module path without its JS extension, so `./src/App` matches `/root/src/App.tsx`. */
8012
+ const stripKnownJsExtension = (file) => {
8013
+ const ext = path$1.extname(file);
8014
+ return JS_EXTENSIONS.includes(ext) ? path$1.join(path$1.dirname(file), path$1.basename(file, ext)) : file;
8015
+ };
7427
8016
  /**
7428
8017
  * Creates an empty asset map structure for tracking JS and CSS assets
7429
8018
  * @returns Initialized asset map with sync/async arrays for JS and CSS
@@ -7494,16 +8083,31 @@ const collectStaticChunks = (bundle, roots) => {
7494
8083
  };
7495
8084
  /**
7496
8085
  * Analyzes assets associated with a chunk without mutating the output map.
7497
- * The static-import traversal is cycle-safe and ignores missing bundle entries.
8086
+ * Dynamic imports are collected transitively (a lazy route nested behind another
8087
+ * lazy route is still reachable), following both static and dynamic edges.
8088
+ * The traversal is cycle-safe and ignores missing bundle entries.
7498
8089
  */
7499
8090
  const analyzeChunkAssets = (bundle, fileName, chunk) => {
7500
8091
  const dynamicAssets = [];
7501
- for (const currentChunk of collectStaticChunks(bundle, [fileName])) for (const dynamicImport of currentChunk.dynamicImports ?? []) {
7502
- if (!bundle[dynamicImport]) continue;
7503
- dynamicAssets.push({
7504
- fileName: dynamicImport,
7505
- type: isCSSFile(dynamicImport) ? "css" : "js"
7506
- });
8092
+ const visited = /* @__PURE__ */ new Set([fileName]);
8093
+ const queue = [fileName];
8094
+ const enqueue = (imported) => {
8095
+ if (visited.has(imported)) return;
8096
+ visited.add(imported);
8097
+ queue.push(imported);
8098
+ };
8099
+ for (let queueIndex = 0; queueIndex < queue.length; queueIndex++) {
8100
+ const currentChunk = bundle[queue[queueIndex]];
8101
+ if (!currentChunk || currentChunk.type !== "chunk") continue;
8102
+ for (const imported of currentChunk.imports ?? []) enqueue(imported);
8103
+ for (const dynamicImport of currentChunk.dynamicImports ?? []) {
8104
+ if (!bundle[dynamicImport]) continue;
8105
+ dynamicAssets.push({
8106
+ fileName: dynamicImport,
8107
+ type: isCSSFile(dynamicImport) ? "css" : "js"
8108
+ });
8109
+ enqueue(dynamicImport);
8110
+ }
7507
8111
  }
7508
8112
  return {
7509
8113
  importedCss: Array.from(chunk.viteMetadata?.importedCss ?? []),
@@ -7527,8 +8131,8 @@ const processModuleAssets = (bundle, filesMap, moduleMatcher, options = {}) => {
7527
8131
  const comparableModulePath = options.root ? path$1.resolve(options.root, modulePath) : modulePath;
7528
8132
  const comparableModulePaths = [comparableModulePath];
7529
8133
  if (options.stripKnownJsExtensions) {
7530
- const ext = path$1.extname(comparableModulePath);
7531
- if (JS_EXTENSIONS.includes(ext)) comparableModulePaths.push(path$1.join(path$1.dirname(comparableModulePath), path$1.basename(comparableModulePath, ext)));
8134
+ const stripped = stripKnownJsExtension(comparableModulePath);
8135
+ if (stripped !== comparableModulePath) comparableModulePaths.push(stripped);
7532
8136
  }
7533
8137
  const matchKey = comparableModulePaths.map(moduleMatcher).find(Boolean);
7534
8138
  if (!matchKey) continue;
@@ -7589,6 +8193,118 @@ const buildFileToShareKeyMap = async (shareKeys, resolveFn, options) => {
7589
8193
  return fileToShareKey;
7590
8194
  };
7591
8195
  //#endregion
8196
+ //#region src/plugins/pluginLazyConsumeOnlyShares.ts
8197
+ const chunkModuleIds = (chunk) => [...chunk.facadeModuleId ? [chunk.facadeModuleId] : [], ...chunk.moduleIds ?? Object.keys(chunk.modules ?? {})];
8198
+ function buildLazyShareGraph(chunks, wrapperShares, exposeModules) {
8199
+ const sharesInChunk = /* @__PURE__ */ new Map();
8200
+ const startupRoots = [];
8201
+ for (const [fileName, chunk] of Object.entries(chunks)) {
8202
+ if (chunk.type !== "chunk") continue;
8203
+ const moduleIds = chunkModuleIds(chunk);
8204
+ sharesInChunk.set(fileName, new Set(moduleIds.map((id) => wrapperShares.get(normalizeVirtualModuleId(id))).filter((share) => share !== void 0)));
8205
+ if (chunk.isEntry || moduleIds.some((id) => exposeModules.has(stripKnownJsExtension(id)))) startupRoots.push(fileName);
8206
+ }
8207
+ const sharesInClosure = (roots) => new Set(collectStaticChunks(chunks, roots).flatMap((chunk) => [...sharesInChunk.get(chunk.fileName) ?? []]));
8208
+ const lazyShares = new Set([...sharesInChunk.values()].flatMap((shares) => [...shares]));
8209
+ for (const share of sharesInClosure(startupRoots)) lazyShares.delete(share);
8210
+ const sharesByChunk = /* @__PURE__ */ new Map();
8211
+ if (lazyShares.size > 0) for (const fileName of sharesInChunk.keys()) {
8212
+ const shares = [...sharesInClosure([fileName])].filter((share) => lazyShares.has(share));
8213
+ if (shares.length > 0) sharesByChunk.set(fileName, shares.sort());
8214
+ }
8215
+ return {
8216
+ lazyShares,
8217
+ sharesByChunk
8218
+ };
8219
+ }
8220
+ const COMMENTS = String.raw`(?:\s|\/\*[\s\S]*?\*\/|\/\/[^\n]*\n)*`;
8221
+ const DYNAMIC_IMPORT_REGEX = new RegExp(String.raw`\bimport\(${COMMENTS}(["'` + "`" + String.raw`])([^"'` + "`" + String.raw`\n]+)\1${COMMENTS}\)`, "g");
8222
+ const QUOTES = [
8223
+ "\"",
8224
+ "'",
8225
+ "`"
8226
+ ];
8227
+ /**
8228
+ * A consume-only (`import: false`) share that only a dynamic `import()` reaches is
8229
+ * left out of `init()` and bridged when that import runs: the import expression is
8230
+ * wrapped so the share is in the cache before the chunk evaluates. There is no
8231
+ * other async boundary in an ESM graph without top-level await, so a wrapper
8232
+ * reached statically from an entry or an expose keeps loading during `init()`.
8233
+ */
8234
+ function pluginLazyConsumeOnlyShares(options) {
8235
+ let viteConfig;
8236
+ const graphs = /* @__PURE__ */ new WeakMap();
8237
+ const helperName = `__mfLoadLazyShares_${options.internalName.replace(/[^A-Za-z0-9_$]/g, "_")}`;
8238
+ return {
8239
+ name: "module-federation:lazy-consume-only-shares",
8240
+ apply: "build",
8241
+ configResolved(config) {
8242
+ viteConfig = config;
8243
+ },
8244
+ renderChunk(code, chunk, _outputOptions, meta) {
8245
+ const renderedChunk = chunk;
8246
+ const chunks = meta?.chunks;
8247
+ if (!chunks || Object.keys(options.exposes).length === 0) return null;
8248
+ if (isServerBuildContext(this, viteConfig)) return null;
8249
+ let graph = graphs.get(chunks);
8250
+ if (!graph) {
8251
+ const isRolldown = getIsRolldown(this);
8252
+ const wrapperShares = /* @__PURE__ */ new Map();
8253
+ for (const shareKey of getUsedShares(options)) {
8254
+ const shareConfig = getNormalizeShareItem(shareKey, options)?.shareConfig;
8255
+ if (shareConfig?.import !== false || shareConfig.eager || shareConfig.treeShaking) continue;
8256
+ wrapperShares.set(normalizeVirtualModuleId(getLoadShareModulePath(shareKey, isRolldown, options)), shareKey);
8257
+ }
8258
+ const root = viteConfig?.root ?? process.cwd();
8259
+ graph = buildLazyShareGraph(chunks, wrapperShares, new Set(Object.values(options.exposes).map((expose) => stripKnownJsExtension(path$1.resolve(root, expose.import)))));
8260
+ graphs.set(chunks, graph);
8261
+ }
8262
+ if (graph.lazyShares.size === 0) return null;
8263
+ const rewriter = new CodeRewriter(code);
8264
+ let edited = false;
8265
+ const importMapId = normalizeVirtualModuleId(getLocalSharedImportMapPath(options));
8266
+ if (chunkModuleIds(renderedChunk).some((id) => normalizeVirtualModuleId(id) === importMapId)) for (const quote of QUOTES) {
8267
+ const literal = `${quote}${LAZY_CONSUME_ONLY_SHARES_PLACEHOLDER}${quote}`;
8268
+ const start = code.indexOf(literal);
8269
+ if (start === -1) continue;
8270
+ rewriter.overwrite(start, start + literal.length, JSON.stringify([...graph.lazyShares].sort()));
8271
+ edited = true;
8272
+ break;
8273
+ }
8274
+ const chunkDir = path$1.posix.dirname(renderedChunk.fileName);
8275
+ const codePositions = createCodePositionMap(code);
8276
+ let usesHelper = false;
8277
+ for (const match of code.matchAll(DYNAMIC_IMPORT_REGEX)) {
8278
+ const [expression, , specifier] = match;
8279
+ const start = match.index;
8280
+ if (!codePositions[start]) continue;
8281
+ const target = path$1.posix.normalize(path$1.posix.join(chunkDir, specifier));
8282
+ const shares = graph.sharesByChunk.get(target);
8283
+ if (!shares || !renderedChunk.dynamicImports.includes(target)) continue;
8284
+ rewriter.overwrite(start, start + expression.length, `${helperName}(${JSON.stringify(shares)}).then(() => ${expression})`);
8285
+ usesHelper = edited = true;
8286
+ }
8287
+ if (!edited) return null;
8288
+ if (usesHelper) {
8289
+ const stateKey = JSON.stringify(getRuntimeInitGlobalKey(getRuntimeInitStatusImportId(options)));
8290
+ rewriter.overwrite(code.length, code.length, `
8291
+ function ${helperName}(names) {
8292
+ const state = globalThis[${stateKey}];
8293
+ return state ? state.initPromise.then(() => (typeof state.loadLazyShares === "function" ? state.loadLazyShares(names) : undefined)) : Promise.resolve();
8294
+ }
8295
+ `);
8296
+ }
8297
+ return {
8298
+ code: rewriter.toString(),
8299
+ map: rewriter.generateMap(renderedChunk.fileName)
8300
+ };
8301
+ }
8302
+ };
8303
+ }
8304
+ //#endregion
8305
+ //#region package.json
8306
+ var version$1 = "1.23.0";
8307
+ //#endregion
7592
8308
  //#region src/virtualModules/virtualExposesSSR.ts
7593
8309
  /**
7594
8310
  * Virtual module ID for the SSR exposes map.
@@ -7643,7 +8359,8 @@ function getSsrFileNameParts(browserFilename) {
7643
8359
  ext
7644
8360
  };
7645
8361
  }
7646
- function getSsrRemoteEntryFileName(browserFilename) {
8362
+ function getSsrRemoteEntryFileName(options, browserFilename = options.filename) {
8363
+ if (options.ssrFilename) return options.ssrFilename;
7647
8364
  const { base, ext } = getSsrFileNameParts(browserFilename);
7648
8365
  return `${base}.ssr${ext ?? ".js"}`;
7649
8366
  }
@@ -7657,14 +8374,15 @@ function getSsrSharedSingletons(options) {
7657
8374
  const result = {};
7658
8375
  for (const [pkg, share] of Object.entries(options.shared)) {
7659
8376
  if (!share.shareConfig.singleton) continue;
7660
- if (pkg.endsWith("/")) {
7661
- for (const concrete of expandSharedPrefixKey(pkg, used)) result[concrete] = {
8377
+ const request = getSharedRequest(pkg, share);
8378
+ if (request.endsWith("/")) {
8379
+ for (const concrete of expandSharedPrefixKey(request, used)) result[getSharedRuntimeKey(concrete, share)] = {
7662
8380
  ...share,
7663
8381
  name: concrete
7664
8382
  };
7665
8383
  continue;
7666
8384
  }
7667
- result[pkg] = share;
8385
+ result[getSharedRuntimeKey(pkg, share)] = share;
7668
8386
  }
7669
8387
  return result;
7670
8388
  }
@@ -8009,7 +8727,7 @@ const Manifest = (providedOptions) => {
8009
8727
  type: "module"
8010
8728
  },
8011
8729
  ssrRemoteEntry: {
8012
- name: getSsrRemoteEntryFileName(devRemoteEntryFile),
8730
+ name: getSsrRemoteEntryFileName(mfOptions, devRemoteEntryFile),
8013
8731
  path: "/__mf_ssr__/",
8014
8732
  type: "module"
8015
8733
  },
@@ -8052,6 +8770,33 @@ const Manifest = (providedOptions) => {
8052
8770
  publicPath = mfOptions.publicPath === "auto" ? "auto" : resolvePublicPath(mfOptions, base, _originalConfigBase);
8053
8771
  },
8054
8772
  /**
8773
+ * A standalone `vite build --ssr` may run with its own `filename`, e.g.
8774
+ * `defineConfig(({ isSsrBuild }) => ...)`. The manifest written by the
8775
+ * earlier client build then advertises an SSR entry derived from the
8776
+ * browser filename, which is not the file this build emitted. Point the
8777
+ * manifest and stats on disk at the emitted SSR entry.
8778
+ */
8779
+ writeBundle(outputOptions) {
8780
+ if (!mfManifestName || _command !== "build" || isConsumerProject) return;
8781
+ const environment = this.environment;
8782
+ if (!(environment ? environment.name === "ssr" : Boolean(viteConfig?.build?.ssr))) return;
8783
+ const ssrEntryName = getSsrRemoteEntryFileName(mfOptions);
8784
+ const outDirs = [...new Set([outputOptions.dir, viteConfig?.environments?.client?.build?.outDir].filter((dir) => typeof dir === "string").map((dir) => path$1.resolve(root, dir)))];
8785
+ if (!outDirs.some((dir) => fs$1.existsSync(path$1.resolve(dir, ssrEntryName)))) return;
8786
+ for (const dir of outDirs) for (const fileName of [mfManifestName, mfManifestStatsName]) {
8787
+ if (!fileName) continue;
8788
+ const file = path$1.resolve(dir, fileName);
8789
+ if (!fs$1.existsSync(file)) continue;
8790
+ try {
8791
+ const data = JSON.parse(fs$1.readFileSync(file, "utf8"));
8792
+ const entry = data?.metaData?.ssrRemoteEntry;
8793
+ if (!entry || typeof entry !== "object" || entry.name === ssrEntryName) continue;
8794
+ entry.name = ssrEntryName;
8795
+ fs$1.writeFileSync(file, JSON.stringify(data));
8796
+ } catch {}
8797
+ }
8798
+ },
8799
+ /**
8055
8800
  * Generates the module federation manifest file
8056
8801
  * @param options - Rollup output options
8057
8802
  * @param bundle - Generated bundle assets
@@ -8061,10 +8806,10 @@ const Manifest = (providedOptions) => {
8061
8806
  if (this.environment?.name === "ssr") return;
8062
8807
  let filesMap = {};
8063
8808
  const foundRemoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
8064
- const expectedSsrRemoteEntryFile = getSsrRemoteEntryFileName(mfOptions.filename);
8809
+ const expectedSsrRemoteEntryFile = getSsrRemoteEntryFileName(mfOptions);
8065
8810
  const foundSsrRemoteEntryFile = Object.values(bundle).find((file) => file.fileName === expectedSsrRemoteEntryFile)?.fileName;
8066
8811
  if (foundRemoteEntryFile) remoteEntryFile = foundRemoteEntryFile;
8067
- ssrRemoteEntryFile = foundSsrRemoteEntryFile || (_command === "serve" ? getSsrRemoteEntryFileName(resolveHashPlaceholderFileName(mfOptions.filename)) : expectedSsrRemoteEntryFile);
8812
+ ssrRemoteEntryFile = foundSsrRemoteEntryFile || (_command === "serve" ? getSsrRemoteEntryFileName(mfOptions, resolveHashPlaceholderFileName(mfOptions.filename)) : expectedSsrRemoteEntryFile);
8068
8813
  const allCssAssets = mfOptions.bundleAllCSS && !disableAssetsAnalyze ? collectCssAssets(bundle) : /* @__PURE__ */ new Set();
8069
8814
  if (allCssAssets.size > 0) {
8070
8815
  const secondaryCss = /* @__PURE__ */ new Set();
@@ -8089,14 +8834,25 @@ const Manifest = (providedOptions) => {
8089
8834
  expandExposeAssets(filesMap, exposesModules, bundle, foundRemoteEntryFile, mfOptions, getIsRolldown(this));
8090
8835
  const fileToShareKey = await buildFileToShareKeyMap(getUsedShares(mfOptions), this.resolve.bind(this), mfOptions);
8091
8836
  processModuleAssets(Object.fromEntries(Object.entries(bundle).filter(([, file]) => !isTreeShakingProviderChunk(file))), filesMap, (modulePath) => fileToShareKey.get(modulePath));
8837
+ const deferredSharedAssets = {
8838
+ js: /* @__PURE__ */ new Set(),
8839
+ css: /* @__PURE__ */ new Set()
8840
+ };
8092
8841
  for (const shareKey of getUsedShares(mfOptions)) {
8093
8842
  const shareItem = getNormalizeShareItem(shareKey, mfOptions);
8094
8843
  const assets = filesMap[shareKey];
8095
8844
  if (!assets || shareItem?.shareConfig.eager === true) continue;
8096
- assets.js.async.push(...assets.js.sync.splice(0));
8097
- assets.css.async.push(...assets.css.sync.splice(0));
8845
+ for (const type of ASSET_TYPES) {
8846
+ assets[type].async.push(...assets[type].sync.splice(0));
8847
+ for (const asset of assets[type].async) deferredSharedAssets[type].add(asset);
8848
+ }
8098
8849
  }
8099
8850
  if (mfOptions.bundleAllCSS) addCssAssetsToAllExports(filesMap, allCssAssets);
8851
+ for (const exposeModule of exposesModules) {
8852
+ const assets = filesMap[exposeModule];
8853
+ if (!assets) continue;
8854
+ for (const type of ASSET_TYPES) for (const timing of LOAD_TIMINGS) assets[type][timing] = assets[type][timing].filter((asset) => !deferredSharedAssets[type].has(asset));
8855
+ }
8100
8856
  filesMap = deduplicateAssets(filesMap);
8101
8857
  }
8102
8858
  const manifest = await applyManifestAdditionalData(generateMFManifest(filesMap, disableAssetsAnalyze), void 0);
@@ -8130,7 +8886,7 @@ const Manifest = (providedOptions) => {
8130
8886
  type: "module"
8131
8887
  };
8132
8888
  const ssrRemoteEntry = {
8133
- name: ssrRemoteEntryFile || getSsrRemoteEntryFileName(_command === "serve" ? resolveHashPlaceholderFileName(filename) : filename),
8889
+ name: ssrRemoteEntryFile || getSsrRemoteEntryFileName(mfOptions, _command === "serve" ? resolveHashPlaceholderFileName(filename) : filename),
8134
8890
  path: _command === "serve" ? "/__mf_ssr__/" : "",
8135
8891
  type: "module"
8136
8892
  };
@@ -8447,6 +9203,7 @@ function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposes
8447
9203
  return cleanId.includes(getHostAutoInitPath(options)) || cleanId.includes(getHostAutoInitPath());
8448
9204
  };
8449
9205
  const getEnvironmentConditions = (context) => context.environment?.config?.resolve?.conditions;
9206
+ const isSsrBuild = (context) => isServerBuildContext(context, viteConfig);
8450
9207
  function isRemoteImport(source) {
8451
9208
  return Object.keys(options.remotes).some((name) => source === name || source.startsWith(name + "/"));
8452
9209
  }
@@ -8550,7 +9307,7 @@ function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposes
8550
9307
  }
8551
9308
  },
8552
9309
  async load(id) {
8553
- if (id === remoteEntryId) return getParsePromise().then((_) => generateRemoteEntry(options, virtualExposesId, _command, getEnvironmentConditions(this)));
9310
+ if (id === remoteEntryId) return getParsePromise().then((_) => generateRemoteEntry(options, virtualExposesId, _command, getEnvironmentConditions(this), isSsrBuild(this)));
8554
9311
  if (id === virtualExposesId) {
8555
9312
  await refreshExposeRemoteDependencies(this);
8556
9313
  return generateExposes(options, exposeRemoteDependencies, _command, reactIslandExposes);
@@ -8560,7 +9317,7 @@ function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposes
8560
9317
  async transform(code, id) {
8561
9318
  return mapCodeToCodeWithSourcemap(await (async () => {
8562
9319
  if (!filterId(id)) return;
8563
- if (id.includes(remoteEntryId)) return getParsePromise().then((_) => generateRemoteEntry(options, virtualExposesId, _command, getEnvironmentConditions(this)));
9320
+ if (id.includes(remoteEntryId)) return getParsePromise().then((_) => generateRemoteEntry(options, virtualExposesId, _command, getEnvironmentConditions(this), isSsrBuild(this)));
8564
9321
  if (id === virtualExposesId) {
8565
9322
  await refreshExposeRemoteDependencies(this);
8566
9323
  return generateExposes(options, exposeRemoteDependencies, _command, reactIslandExposes);
@@ -8658,7 +9415,7 @@ function pluginProxyRemotes_default(options) {
8658
9415
  const remoteModule = getRemoteVirtualModule(source, command, enableSsrInit, consumer, options);
8659
9416
  addUsedRemote(remoteName, source, options);
8660
9417
  refreshHostAutoInit(options);
8661
- return remoteModule.getImportId();
9418
+ return remoteModule.getResolvedId();
8662
9419
  }
8663
9420
  return {
8664
9421
  name: "proxyRemotes",
@@ -8678,7 +9435,7 @@ function pluginProxyRemotes_default(options) {
8678
9435
  },
8679
9436
  configResolved(config) {
8680
9437
  hasMultiEnvironment = Boolean(config.environments?.ssr);
8681
- enableSsrInit = getSsrCapabilities(parseInt(version, 10), command, Object.keys(remotes).length > 0).enableSsrInitBootstrap;
9438
+ enableSsrInit = getSsrCapabilities(parseInt(version, 10), command, Object.keys(remotes).length > 0, isSsrConfig(config)).enableSsrInitBootstrap;
8682
9439
  },
8683
9440
  resolveId(source, importer) {
8684
9441
  const resolvedIslandConsumerId = resolveReactIslandConsumerId(source);
@@ -8702,6 +9459,96 @@ function pluginProxyRemotes_default(options) {
8702
9459
  };
8703
9460
  }
8704
9461
  //#endregion
9462
+ //#region src/utils/sharedSource.ts
9463
+ const pendingEntryLookups = /* @__PURE__ */ new Map();
9464
+ const getEntryLookupKey = (source, importer) => `${source}\0${importer}`;
9465
+ /** Whether a resolveId call is one of the shared source resolver's own entry lookups. */
9466
+ function isSharedEntryLookup(source, importer, options) {
9467
+ return options.custom?.__mfSharedEntryLookup === true || pendingEntryLookups.has(getEntryLookupKey(source, importer));
9468
+ }
9469
+ /** Identify shared entries through Vite, with a cache scoped to this federation instance. */
9470
+ function createSharedSourceResolver(shared, getResolutionConfig) {
9471
+ const caches = /* @__PURE__ */ new Map();
9472
+ async function matchEntry(source, suffix, resolveEntry) {
9473
+ const packageName = getPackageNameFromNodeModulePath(source);
9474
+ if (!packageName) return;
9475
+ const candidates = /* @__PURE__ */ new Set();
9476
+ if (findSharedKey(packageName, shared)) candidates.add(packageName);
9477
+ if (findSharedKey(suffix, shared)) candidates.add(suffix);
9478
+ for (const key of Object.keys(shared)) {
9479
+ const request = getSharedRequest(key, shared[key]);
9480
+ if (getPackageName(request) !== packageName) continue;
9481
+ if (!request.endsWith("/")) candidates.add(request);
9482
+ for (const subpath of getCommonSharedSubpaths(request)) if (findSharedKey(subpath, shared)) candidates.add(subpath);
9483
+ }
9484
+ if (candidates.size === 0) return;
9485
+ const resolvedSource = await resolveEntry(source);
9486
+ if (!resolvedSource) return;
9487
+ for (const candidate of candidates) {
9488
+ const entry = await resolveEntry(candidate);
9489
+ if (!entry) continue;
9490
+ const allowNodeModulesSuffixMatch = shared[findSharedKey(candidate, shared) ?? candidate]?.shareConfig?.allowNodeModulesSuffixMatch === true;
9491
+ if (normalizeNodeModulePath(entry) === normalizeNodeModulePath(resolvedSource) || allowNodeModulesSuffixMatch && getNodeModulesSuffix(entry) === suffix) return candidate;
9492
+ }
9493
+ }
9494
+ return {
9495
+ clear() {
9496
+ caches.clear();
9497
+ },
9498
+ async resolve(context, source, options = {}) {
9499
+ if (source.startsWith("\0") || source.includes("#")) return;
9500
+ const queryIndex = source.indexOf("?");
9501
+ const query = queryIndex === -1 ? "" : source.slice(queryIndex + 1);
9502
+ if (query && [...new URLSearchParams(query).keys()].some((key) => ![
9503
+ "v",
9504
+ "t",
9505
+ "import"
9506
+ ].includes(key))) return;
9507
+ if (findSharedKey(source, shared)) return source;
9508
+ const suffix = getNodeModulesSuffix(source);
9509
+ if (!suffix) return;
9510
+ const normalizedSource = stripViteFsPrefix(normalizeNodeModulePath(source));
9511
+ const environment = context.environment ?? !!options.ssr;
9512
+ const cacheable = !options.isEntry && !options.scan && (!options.kind || options.kind === "import-statement") && Object.keys(options.attributes ?? {}).length === 0 && Object.keys(options.custom ?? {}).length === 0;
9513
+ let cache = cacheable ? caches.get(environment) : void 0;
9514
+ if (cacheable && !cache) {
9515
+ cache = /* @__PURE__ */ new Map();
9516
+ caches.set(environment, cache);
9517
+ }
9518
+ if (cache?.has(normalizedSource)) return cache.get(normalizedSource);
9519
+ const { root, conditions } = getResolutionConfig(context, options);
9520
+ const result = await matchEntry(normalizedSource, suffix, async (request) => {
9521
+ if (!path$1.isAbsolute(request) && !isPackageExportAvailable(request, {
9522
+ cwd: root,
9523
+ conditions
9524
+ })) return void 0;
9525
+ const importer = path$1.join(root, "package.json");
9526
+ const lookupKey = getEntryLookupKey(request, importer);
9527
+ pendingEntryLookups.set(lookupKey, (pendingEntryLookups.get(lookupKey) ?? 0) + 1);
9528
+ try {
9529
+ const resolved = await context.resolve(request, importer, {
9530
+ ...options,
9531
+ skipSelf: true,
9532
+ custom: {
9533
+ ...options.custom,
9534
+ __mfSharedEntryLookup: true
9535
+ }
9536
+ });
9537
+ return resolved && !resolved.external ? resolved.id : void 0;
9538
+ } catch {
9539
+ return;
9540
+ } finally {
9541
+ const remaining = pendingEntryLookups.get(lookupKey) - 1;
9542
+ if (remaining) pendingEntryLookups.set(lookupKey, remaining);
9543
+ else pendingEntryLookups.delete(lookupKey);
9544
+ }
9545
+ });
9546
+ cache?.set(normalizedSource, result);
9547
+ return result;
9548
+ }
9549
+ };
9550
+ }
9551
+ //#endregion
8705
9552
  //#region src/utils/PromiseStore.ts
8706
9553
  /**
8707
9554
  * example:
@@ -8742,7 +9589,7 @@ function tryResolveFromProjectRoot(source) {
8742
9589
  const browserEntry = getInstalledPackageEntry(source, { cwd: getPackageDetectionCwd() });
8743
9590
  if (browserEntry) return browserEntry;
8744
9591
  try {
8745
- return createRequire$1(pathToFileURL(path$1.join(getPackageDetectionCwd(), "package.json"))).resolve(source);
9592
+ return resolveModulePath(source, path$1.join(getPackageDetectionCwd(), "package.json"));
8746
9593
  } catch {
8747
9594
  return;
8748
9595
  }
@@ -8751,23 +9598,6 @@ function isBuildConfigImporter(importer) {
8751
9598
  if (!importer) return false;
8752
9599
  return /(^|\/)(?:nuxt|vite|vitest|webpack|rollup|rspack)\.config\.[cm]?[jt]sx?$/.test(importer.replace(/\\/g, "/"));
8753
9600
  }
8754
- function findSharedKeyForSource(source, shared) {
8755
- const key = findSharedKey(source, shared);
8756
- if (key) return key;
8757
- const explicitSharedSubpathKeys = Object.keys(shared || {}).filter((sharedKey) => getPackageName(sharedKey) !== sharedKey && !sharedKey.endsWith("/"));
8758
- if (isNodeModulePath(source)) {
8759
- const explicitSubpathKey = getMatchingNodeModuleSubpath(source, explicitSharedSubpathKeys);
8760
- if (explicitSubpathKey) return explicitSubpathKey;
8761
- const normalizedSource = normalizeNodeModulePath(source);
8762
- const explicitSubpathEntryKey = explicitSharedSubpathKeys.find((sharedKey) => {
8763
- const entry = getInstalledPackageEntry(sharedKey, { cwd: getPackageDetectionCwd() });
8764
- return entry ? normalizeNodeModulePath(entry) === normalizedSource : false;
8765
- });
8766
- if (explicitSubpathEntryKey) return explicitSubpathEntryKey;
8767
- }
8768
- const packageName = getPackageNameFromNodeModulePath(source);
8769
- return packageName ? findSharedKey(packageName, shared) : void 0;
8770
- }
8771
9601
  /**
8772
9602
  * Reads the dependencies of an installed package from its package.json.
8773
9603
  */
@@ -8785,9 +9615,13 @@ function getPackageDependencies(pkg) {
8785
9615
  */
8786
9616
  function excludeSharedSubDependencies(shared) {
8787
9617
  const sharedKeys = new Set(Object.keys(shared));
8788
- const sharedKeyByBase = new Map(Object.keys(shared).map((key) => [key.endsWith("/") ? key.slice(0, -1) : key, key]));
9618
+ const requestBase = (key) => {
9619
+ const request = getSharedRequest(key, shared[key]);
9620
+ return request.endsWith("/") ? request.slice(0, -1) : request;
9621
+ };
9622
+ const sharedKeyByBase = new Map(Object.keys(shared).map((key) => [requestBase(key), key]));
8789
9623
  for (const parentKey of sharedKeys) {
8790
- const deps = getPackageDependencies(parentKey);
9624
+ const deps = getPackageDependencies(requestBase(parentKey));
8791
9625
  for (const dep of deps) {
8792
9626
  const depKey = sharedKeyByBase.get(dep);
8793
9627
  if (depKey && depKey !== parentKey) {
@@ -9114,6 +9948,7 @@ function isSharedPackageRuntimeDependency(sharedKey, dependency, conditions) {
9114
9948
  function proxySharedModule(options) {
9115
9949
  const { shared = {}, federationOptions, getParsePromise = () => Promise.resolve() } = options;
9116
9950
  let _config;
9951
+ const getBuildImportAnalysis = (environment) => getImportAnalysis(environment ?? _config ?? options);
9117
9952
  let _command = "serve";
9118
9953
  let useDirectReactImport = false;
9119
9954
  let useRolldown = false;
@@ -9131,7 +9966,7 @@ function proxySharedModule(options) {
9131
9966
  const getRuntimeDependencyConditions = (context, resolveOptions) => {
9132
9967
  const environment = context.environment;
9133
9968
  const environmentConfig = environment?.config;
9134
- const isSsr = resolveOptions.ssr === true || Boolean(_config?.build?.ssr) || environmentConfig?.consumer === "server" || Boolean(environmentConfig?.build?.ssr) || environment?.name === "ssr" || environment?.name === "server";
9969
+ const isSsr = resolveOptions.ssr === true || Boolean(_config?.build?.ssr) || isServerEnvironment(environment?.name, environmentConfig);
9135
9970
  return getSharedExportConditions({
9136
9971
  environmentConditions: environmentConfig?.resolve?.conditions,
9137
9972
  isProduction: environmentConfig?.isProduction ?? isProduction,
@@ -9141,6 +9976,10 @@ function proxySharedModule(options) {
9141
9976
  ssrTarget
9142
9977
  });
9143
9978
  };
9979
+ const sharedSourceResolver = createSharedSourceResolver(shared, (context, resolveOptions) => ({
9980
+ root: _config?.root || getPackageDetectionCwd(),
9981
+ conditions: getRuntimeDependencyConditions(context, resolveOptions)
9982
+ }));
9144
9983
  const refreshTreeShakingForEnvironment = (context) => refreshTreeShakingModules(federationOptions, _command, getIsRolldown(context), getEnvironmentConditions(context));
9145
9984
  const normalizeTreeShakingOutputPath = (value) => {
9146
9985
  const normalized = normalizePathForImport(value);
@@ -9183,14 +10022,15 @@ function proxySharedModule(options) {
9183
10022
  }, federationOptions);
9184
10023
  },
9185
10024
  resolveId(source) {
9186
- if (source === getLocalSharedImportMapPath(federationOptions)) return getResolvedLocalSharedImportMapId(federationOptions);
10025
+ const resolvedId = getResolvedLocalSharedImportMapId(federationOptions);
10026
+ if (source === getLocalSharedImportMapPath(federationOptions) || source === resolvedId) return resolvedId;
9187
10027
  },
9188
10028
  load(id) {
9189
10029
  if (id === getResolvedLocalSharedImportMapId(federationOptions)) return getParsePromise().then((_) => {
9190
10030
  refreshTreeShakingForEnvironment(this);
9191
- const providerPackages = /* @__PURE__ */ new Set([...Object.keys(shared).filter((pkg) => !pkg.endsWith("/")), ...getUsedShares(federationOptions)]);
10031
+ const providerPackages = /* @__PURE__ */ new Set([...Object.keys(shared).filter((pkg) => !getSharedRequest(pkg, shared[pkg]).endsWith("/")), ...getUsedShares(federationOptions)]);
9192
10032
  for (const pkg of providerPackages) {
9193
- const sharedKey = findSharedKeyForSource(pkg, shared);
10033
+ const sharedKey = findSharedKey(pkg, shared);
9194
10034
  const shareItem = shared[pkg] || (sharedKey ? shared[sharedKey] : void 0);
9195
10035
  if (shareItem) emitTreeShakingProvider(this, pkg, shareItem);
9196
10036
  }
@@ -9210,6 +10050,7 @@ function proxySharedModule(options) {
9210
10050
  setTreeShakingBuildMode(command === "build", federationOptions);
9211
10051
  resetTreeShakingExports(federationOptions);
9212
10052
  emittedTreeShakingProviders.clear();
10053
+ sharedSourceResolver.clear();
9213
10054
  sharedDependencyCache.clear();
9214
10055
  dependencyManifestCache.clear();
9215
10056
  sharedRuntimeDependencyCache.clear();
@@ -9232,30 +10073,42 @@ function proxySharedModule(options) {
9232
10073
  const resolvedOptions = federationOptions ?? getNormalizeModuleFederationOptions();
9233
10074
  const registerConfiguredShare = _command === "build" && Object.keys(resolvedOptions.exposes).length > 0 ? addUsedShares : addConfiguredShare;
9234
10075
  Object.keys(shared).forEach((key) => {
9235
- if (key.endsWith("/")) return;
9236
- if (useDirectReactImport && key === "react") {
9237
- registerConfiguredShare(key, federationOptions);
10076
+ if (key.endsWith("/") || getSharedRequest(key, shared[key]).endsWith("/")) return;
10077
+ const runtimeKey = getSharedRuntimeKey(key, shared[key]);
10078
+ if (useDirectReactImport && runtimeKey === "react") {
10079
+ registerConfiguredShare(runtimeKey, federationOptions);
9238
10080
  return;
9239
10081
  }
9240
- writeLoadShareModule(key, shared[key], _command, isRolldown, federationOptions);
9241
- if (shared[key].shareConfig.import !== false) writePreBuildLibPath(key, shared[key], federationOptions);
9242
- registerConfiguredShare(key, federationOptions);
10082
+ writeLoadShareModule(runtimeKey, shared[key], _command, isRolldown, federationOptions);
10083
+ if (shared[key].shareConfig.import !== false) writePreBuildLibPath(runtimeKey, shared[key], federationOptions);
10084
+ registerConfiguredShare(runtimeKey, federationOptions);
9243
10085
  });
9244
10086
  writeLocalSharedImportMap(federationOptions);
9245
10087
  refreshHostAutoInit(federationOptions);
9246
10088
  },
10089
+ watchChange() {
10090
+ sharedSourceResolver.clear();
10091
+ },
9247
10092
  buildStart() {
10093
+ sharedSourceResolver.clear();
9248
10094
  if (_command !== "build") return;
10095
+ if (hasAnalyzableShares) getBuildImportAnalysis(this.environment).clear();
9249
10096
  resetTreeShakingExports(federationOptions);
9250
10097
  emittedTreeShakingProviders.clear();
9251
10098
  refreshTreeShakingForEnvironment(this);
9252
10099
  },
10100
+ buildEnd() {
10101
+ if (_command === "build" && hasAnalyzableShares) getBuildImportAnalysis(this.environment).clear();
10102
+ },
9253
10103
  shouldTransformCachedModule() {
9254
10104
  return _command === "build" && hasAnalyzableShares;
9255
10105
  },
9256
- transform(code, id) {
10106
+ async transform(code, id, transformOptions) {
9257
10107
  if (_command !== "build" || !hasAnalyzableShares) return;
9258
- collectTreeShakingImports(code, id, shared, findSharedKeyForSource, (sharedKey, exports, request) => recordTreeShakingExports(sharedKey, exports, request, federationOptions), (sharedKey, request) => markTreeShakingPackageUnsafe(sharedKey, request, federationOptions));
10108
+ await collectTreeShakingImports(code, id, shared, async (source, shares) => {
10109
+ const request = await sharedSourceResolver.resolve(this, source, transformOptions);
10110
+ return request ? findSharedKey(request, shares) : void 0;
10111
+ }, (sharedKey, exports, request) => recordTreeShakingExports(sharedKey, exports, request, federationOptions), (sharedKey, request) => markTreeShakingPackageUnsafe(sharedKey, request, federationOptions), getBuildImportAnalysis(this.environment));
9259
10112
  refreshTreeShakingForEnvironment(this);
9260
10113
  }
9261
10114
  },
@@ -9264,6 +10117,7 @@ function proxySharedModule(options) {
9264
10117
  enforce: "pre",
9265
10118
  apply: "build",
9266
10119
  async resolveId(source, importer, resolveOptions) {
10120
+ if (isSharedEntryLookup(source, importer, resolveOptions)) return;
9267
10121
  const sourceToken = getTreeShakingGraphToken(source);
9268
10122
  const importerToken = getTreeShakingGraphToken(importer);
9269
10123
  const token = sourceToken || importerToken;
@@ -9271,7 +10125,8 @@ function proxySharedModule(options) {
9271
10125
  const cleanSource = normalizePathForImport(stripTreeShakingGraphQuery(source));
9272
10126
  const cleanImporter = importer ? normalizePathForImport(stripTreeShakingGraphQuery(importer)) : void 0;
9273
10127
  if (!sourceToken && importerToken) {
9274
- const nestedSharedKey = findSharedKeyForSource(cleanSource, shared);
10128
+ const request = await sharedSourceResolver.resolve(this, cleanSource, resolveOptions);
10129
+ const nestedSharedKey = request ? findSharedKey(request, shared) : void 0;
9275
10130
  if (nestedSharedKey && getPackageName(nestedSharedKey) !== getPackageName(importerToken)) return this.resolve(cleanSource, cleanImporter, {
9276
10131
  ...resolveOptions,
9277
10132
  skipSelf: true
@@ -9298,21 +10153,24 @@ function proxySharedModule(options) {
9298
10153
  name: "proxyPreBuildShared:resolve-shared-loadShare",
9299
10154
  enforce: "pre",
9300
10155
  async resolveId(source, importer, resolveOptions) {
9301
- if (resolveOptions.custom?.__mfTreeShakingGraph) return;
9302
- function shouldSkipTaggedImporterProxy(sharedKey, tag) {
10156
+ if (isSharedEntryLookup(source, importer, resolveOptions) || resolveOptions.custom?.__mfTreeShakingGraph) return;
10157
+ const sharedSource = await sharedSourceResolver.resolve(this, source, resolveOptions);
10158
+ if (!sharedSource) return;
10159
+ const key = findSharedKey(sharedSource, shared);
10160
+ if (!key) return;
10161
+ const shouldSkipTaggedImporterProxy = (sharedKey, tag) => {
9303
10162
  if (!importer?.includes(tag)) return false;
9304
10163
  const taggedModule = VirtualModule.findModule(tag, importer);
9305
10164
  if (!taggedModule) return true;
9306
- return taggedModule.name === sharedKey || matchesSharedSource(source, taggedModule.name);
9307
- }
9308
- const key = findSharedKeyForSource(source, shared);
9309
- if (!key) return;
10165
+ return taggedModule.name === sharedKey || matchesSharedSource(sharedSource, taggedModule.name);
10166
+ };
9310
10167
  const importerPackage = getSharedPackageFromFile(importer, shared);
9311
10168
  if (importerPackage === getPackageName(key)) return;
9312
10169
  if (importerPackage && shared[key].shareConfig.import !== false) {
9313
10170
  const importerIsUnsharedWorkspacePackage = !isNodeModulePath(importer) && !Object.keys(shared).some((sharedKey) => getPackageName(sharedKey) === importerPackage);
9314
- const runtimeDependencyRequest = key.endsWith("/") && matchesSharedSource(source, key) ? source : key;
9315
- if (importerIsUnsharedWorkspacePackage ? isSharedPackageRuntimeDependency(runtimeDependencyRequest, importerPackage, getRuntimeDependencyConditions(this, resolveOptions)) : isSharedPackageDependency(key, importerPackage)) return;
10171
+ const request = getSharedRequest(key, shared[key]);
10172
+ const runtimeDependencyRequest = request.endsWith("/") && matchesSharedSource(sharedSource, key, shared[key]) ? sharedSource : request;
10173
+ if (importerIsUnsharedWorkspacePackage ? isSharedPackageRuntimeDependency(runtimeDependencyRequest, importerPackage, getRuntimeDependencyConditions(this, resolveOptions)) : isSharedPackageDependency(request, importerPackage)) return;
9316
10174
  }
9317
10175
  if (useDirectReactImport && key === "react") return;
9318
10176
  if (isAssetLikeImport(source)) return;
@@ -9322,8 +10180,8 @@ function proxySharedModule(options) {
9322
10180
  if (importer && (importer.includes("hostAutoInit") || importer.includes("__H_A_I__"))) return;
9323
10181
  if (shouldSkipTaggedImporterProxy(key, "__loadShare__")) return;
9324
10182
  if (shouldSkipTaggedImporterProxy(key, "__prebuild__")) return;
9325
- const shareSource = key === "vue" && source.startsWith("vue/dist/") ? key : isNodeModulePath(source) ? getCommonSharedSubpathFromNodeModulePath(source, key) || key : source;
9326
- if (shouldKeepSharedImportLocal(source, importer, key, shared, importerPackage)) {
10183
+ const shareSource = key === "vue" && sharedSource.startsWith("vue/dist/") ? key : sharedSource;
10184
+ if (shouldKeepSharedImportLocal(sharedSource, importer, key, shared, importerPackage)) {
9327
10185
  const localSource = getPrebuildResolutionSource(shareSource, shared[key]);
9328
10186
  return tryResolveFromProjectRoot(localSource) || localSource;
9329
10187
  }
@@ -9613,17 +10471,21 @@ function collectFromRegex(code, isRemoteImport) {
9613
10471
  }
9614
10472
  function pluginRemoteNamedExports(options) {
9615
10473
  const remoteNames = Object.keys(options.remotes);
10474
+ let root = process.cwd();
9616
10475
  const isNodeModulesId = (id) => id.includes("/node_modules/") || id.includes("\\node_modules\\");
9617
10476
  function isRemoteImport(source, importerId) {
9618
10477
  return remoteNames.some((name) => {
9619
10478
  if (source.startsWith(name + "/")) return true;
9620
10479
  if (source !== name) return false;
9621
- return !isNodeModulesId(importerId);
10480
+ return !isNodeModulesId(importerId) || !getInstalledPackageEntry(source, { cwd: root });
9622
10481
  }) || source.includes("__loadRemote__");
9623
10482
  }
9624
10483
  return {
9625
10484
  name: "module-federation-remote-named-exports",
9626
10485
  enforce: "post",
10486
+ configResolved(config) {
10487
+ root = config.root || process.cwd();
10488
+ },
9627
10489
  async transform(code, id) {
9628
10490
  if (remoteNames.length === 0) return;
9629
10491
  if (id.includes("__loadRemote__") || id.includes("__loadShare__")) return;
@@ -9649,7 +10511,6 @@ function pluginRemoteNamedExports(options) {
9649
10511
  const MAX_RUNNER_BODY_BYTES = 1024 * 1024;
9650
10512
  const MAX_RUNNER_START_OFFSET = 1024 * 1024;
9651
10513
  const ALLOWED_RUNNER_INVOKE_NAMES = /* @__PURE__ */ new Set(["fetchModule", "getBuiltins"]);
9652
- const VITE_FS_PREFIX = "/@fs/";
9653
10514
  function isPlainObject(value) {
9654
10515
  return !!value && typeof value === "object" && !Array.isArray(value);
9655
10516
  }
@@ -9668,12 +10529,6 @@ function isSafeRunnerFetchModuleOptions(value) {
9668
10529
  }
9669
10530
  return true;
9670
10531
  }
9671
- function stripQueryAndHash(id) {
9672
- const queryIndex = id.indexOf("?");
9673
- const hashIndex = id.indexOf("#");
9674
- const endIndex = queryIndex === -1 ? hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex);
9675
- return endIndex === -1 ? id : id.slice(0, endIndex);
9676
- }
9677
10532
  function decodeRunnerFilePath(filePath) {
9678
10533
  try {
9679
10534
  return decodeURIComponent(filePath);
@@ -9717,8 +10572,8 @@ function isSafeRunnerFetchModuleId(id, config) {
9717
10572
  const cleanId = decodeRunnerFilePath(stripQueryAndHash(decoded));
9718
10573
  if (!cleanId || hasRelativeTraversal(cleanId)) return false;
9719
10574
  const allowedDirectories = getRunnerAllowedDirectories(config);
9720
- if (cleanId.startsWith(VITE_FS_PREFIX)) {
9721
- const fsPath = `/${cleanId.slice(5)}`;
10575
+ if (cleanId.startsWith("/@fs/")) {
10576
+ const fsPath = stripViteFsPrefix(cleanId);
9722
10577
  return path$1.isAbsolute(fsPath) && isPathWithinAllowedDirectories(fsPath, allowedDirectories);
9723
10578
  }
9724
10579
  if (path$1.isAbsolute(cleanId)) {
@@ -9782,18 +10637,25 @@ function pluginSSRRemoteEntry(options) {
9782
10637
  const remoteEntrySSRId = getRemoteEntrySSRId(options);
9783
10638
  const virtualExposesSSRId = getVirtualExposesSSRId(options);
9784
10639
  let cachedSsrRemoteEntrySource;
9785
- const ssrOutputFilename = getSsrRemoteEntryFileName(options.filename);
10640
+ const ssrOutputFilename = getSsrRemoteEntryFileName(options);
9786
10641
  const ssrExposesFileName = getSsrExposesFileName(options.filename);
9787
10642
  let ssrOutputFiles = /* @__PURE__ */ new Set();
9788
10643
  let ssrOutputDir = "";
9789
10644
  let clientOutputDir = "";
9790
- const ssrOnlyExternals = [
10645
+ const mfRuntimePackages = [
9791
10646
  "@module-federation/runtime",
9792
10647
  "@module-federation/runtime-core",
9793
- "@module-federation/sdk",
9794
- ...options.ssrExternals ?? []
10648
+ "@module-federation/sdk"
9795
10649
  ];
10650
+ const ssrOnlyExternals = [...mfRuntimePackages, ...options.ssrExternals ?? []];
9796
10651
  const ssrOnlyExternalPattern = new RegExp(`^(${ssrOnlyExternals.map((e) => e.replace(/[/\\^$*+?.()|[\]{}]/g, "\\$&")).join("|")})(\\/.*)?$`);
10652
+ let noExternal;
10653
+ const isNoExternal = (id) => {
10654
+ const pkg = ssrOnlyExternalPattern.exec(id)?.[1] ?? id;
10655
+ if (!noExternal || !mfRuntimePackages.includes(pkg)) return false;
10656
+ if (noExternal === true) return true;
10657
+ return (Array.isArray(noExternal) ? noExternal : [noExternal]).some((rule) => typeof rule === "string" ? rule === pkg : rule.test(pkg));
10658
+ };
9797
10659
  const ssrModuleIds = /* @__PURE__ */ new Set([remoteEntrySSRId, virtualExposesSSRId]);
9798
10660
  const resolvedAbsToPackage = /* @__PURE__ */ new Map();
9799
10661
  let isServe = false;
@@ -9824,7 +10686,9 @@ function pluginSSRRemoteEntry(options) {
9824
10686
  enforce: "pre",
9825
10687
  configResolved(config) {
9826
10688
  isServe = config.command === "serve";
10689
+ noExternal = config.environments?.ssr?.resolve?.noExternal ?? config.ssr?.noExternal;
9827
10690
  for (const pkg of ssrOnlyExternals) {
10691
+ if (isNoExternal(pkg)) continue;
9828
10692
  const aliasEntry = (config.resolve?.alias)?.find((a) => a.find === pkg || a.find instanceof RegExp && a.find.test(pkg));
9829
10693
  if (aliasEntry?.replacement) resolvedAbsToPackage.set(aliasEntry.replacement, pkg);
9830
10694
  }
@@ -9833,7 +10697,7 @@ function pluginSSRRemoteEntry(options) {
9833
10697
  if (id === remoteEntrySSRId || id.startsWith(remoteEntrySSRId)) return id;
9834
10698
  if (id === virtualExposesSSRId || id.startsWith(virtualExposesSSRId)) return id;
9835
10699
  if (!importer || !ssrModuleIds.has(importer)) return;
9836
- if (ssrOnlyExternalPattern.test(id)) return {
10700
+ if (ssrOnlyExternalPattern.test(id) && !isNoExternal(id)) return {
9837
10701
  id,
9838
10702
  external: true
9839
10703
  };
@@ -9858,7 +10722,7 @@ function pluginSSRRemoteEntry(options) {
9858
10722
  configureServer(server) {
9859
10723
  const base = "/__mf_ssr__";
9860
10724
  const basePath = getBasePath$1(viteConfig?.base);
9861
- const ssrEntryFileName = getSsrRemoteEntryFileName(options.filename);
10725
+ const ssrEntryFileName = getSsrRemoteEntryFileName(options);
9862
10726
  if (isNuxtProject || isNuxtClientBase(basePath)) server.middlewares.use((req, _res, next) => {
9863
10727
  if (req.url?.replace(/\?.*/, "") === `${basePath}/${ssrEntryFileName}`) req.url = `${basePath}/__mf_ssr__/${ssrEntryFileName}`;
9864
10728
  next();
@@ -9927,7 +10791,7 @@ function pluginSSRRemoteEntry(options) {
9927
10791
  resolveId(id) {
9928
10792
  if (id === remoteEntrySSRId || id.startsWith(remoteEntrySSRId)) return id;
9929
10793
  if (id === virtualExposesSSRId || id.startsWith(virtualExposesSSRId)) return id;
9930
- if (id === `/__mf_ssr__/${getSsrRemoteEntryFileName(options.filename)}`) return remoteEntrySSRId;
10794
+ if (id === `/__mf_ssr__/${getSsrRemoteEntryFileName(options)}`) return remoteEntrySSRId;
9931
10795
  if (id === `/__mf_ssr__/${ssrExposesFileName}`) return virtualExposesSSRId;
9932
10796
  },
9933
10797
  load(id) {
@@ -10132,6 +10996,85 @@ var aliasToArrayPlugin_default = {
10132
10996
  }
10133
10997
  };
10134
10998
  //#endregion
10999
+ //#region src/utils/deferredPrebuildHelper.ts
11000
+ function isExportAllHelper(code, exportName) {
11001
+ try {
11002
+ const ast = parseAst(code);
11003
+ let localName;
11004
+ for (const node of ast.body) {
11005
+ if (node.type !== "ExportNamedDeclaration") continue;
11006
+ for (const specifier of node.specifiers) if (specifier.type === "ExportSpecifier" && specifier.exported.type === "Identifier" && specifier.exported.name === exportName && specifier.local.type === "Identifier") localName = specifier.local.name;
11007
+ }
11008
+ if (!localName) return false;
11009
+ for (const node of ast.body) {
11010
+ if (node.type !== "VariableDeclaration") continue;
11011
+ for (const declaration of node.declarations) {
11012
+ if (declaration.id.type !== "Identifier" || declaration.id.name !== localName) continue;
11013
+ const initializer = declaration.init;
11014
+ if (!initializer) return false;
11015
+ const source = code.slice(initializer.start, initializer.end);
11016
+ return source.includes("Symbol.toStringTag") && source.includes("Module");
11017
+ }
11018
+ }
11019
+ } catch {}
11020
+ return false;
11021
+ }
11022
+ /**
11023
+ * Rolldown sometimes places its shared namespace helper in a local prebuild
11024
+ * chunk. A loadShare wrapper then imports that helper statically, evaluating the
11025
+ * fallback even when a host provider is already in the cache. Inline only the
11026
+ * recognized Rolldown helper; leave every other prebuild import untouched.
11027
+ */
11028
+ function inlineDeferredPrebuildNamespaceHelper(bundle) {
11029
+ for (const chunk of Object.values(bundle)) {
11030
+ if (chunk.type !== "chunk" || !chunk.fileName.includes("__loadShare__")) continue;
11031
+ let ast;
11032
+ try {
11033
+ ast = parseAst(chunk.code);
11034
+ } catch {
11035
+ continue;
11036
+ }
11037
+ const edits = [];
11038
+ const deferredSources = /* @__PURE__ */ new Set();
11039
+ forEachAstNode(ast, (node) => {
11040
+ if (node.type !== "ImportExpression") return;
11041
+ const source = getModuleSource(node.source);
11042
+ if (source) deferredSources.add(source);
11043
+ });
11044
+ const retainedImports = /* @__PURE__ */ new Set();
11045
+ const removedImports = /* @__PURE__ */ new Set();
11046
+ for (const node of ast.body) {
11047
+ if (node.type !== "ImportDeclaration") continue;
11048
+ const source = getModuleSource(node.source);
11049
+ if (!source) continue;
11050
+ const targetName = path.posix.normalize(path.posix.join(path.posix.dirname(chunk.fileName), source));
11051
+ const [specifier] = node.specifiers;
11052
+ const exported = specifier?.type === "ImportSpecifier" && specifier.imported;
11053
+ const target = bundle[targetName];
11054
+ if (!source.includes("__prebuild__") || node.specifiers.length !== 1 || !exported || exported.type !== "Identifier" || target?.type !== "chunk" || !deferredSources.has(source) || !Object.keys(target.modules ?? {}).some((id) => id.includes("rolldown/runtime.js")) || !isExportAllHelper(target.code, exported.name)) {
11055
+ retainedImports.add(targetName);
11056
+ continue;
11057
+ }
11058
+ removedImports.add(targetName);
11059
+ edits.push({
11060
+ start: node.start,
11061
+ end: node.end,
11062
+ replacement: `const ${specifier.local.name} = (all, noSymbols) => {
11063
+ const namespace = {};
11064
+ for (const name in all) Object.defineProperty(namespace, name, {
11065
+ get: all[name], enumerable: true,
11066
+ });
11067
+ if (!noSymbols) Object.defineProperty(namespace, Symbol.toStringTag, { value: 'Module' });
11068
+ return namespace;
11069
+ };`
11070
+ });
11071
+ }
11072
+ if (edits.length === 0) continue;
11073
+ for (const edit of edits.reverse()) chunk.code = chunk.code.slice(0, edit.start) + edit.replacement + chunk.code.slice(edit.end);
11074
+ if (chunk.imports) chunk.imports = chunk.imports.filter((imported) => !removedImports.has(imported) || retainedImports.has(imported));
11075
+ }
11076
+ }
11077
+ //#endregion
10135
11078
  //#region src/utils/controlChunkSanitizer.ts
10136
11079
  const FEDERATION_CONTROL_CHUNK_HINTS = ["hostInit", "localSharedImportMap"];
10137
11080
  function stripEmptyPreloadCalls(code) {
@@ -10253,7 +11196,7 @@ function applyRuntimeCapabilityDefines(define, options, { defaultDisableSnapshot
10253
11196
  function getRuntimeCapabilityConfigurationWarnings(options) {
10254
11197
  const warnings = [];
10255
11198
  if (options.disableRemote && Object.keys(options.remotes).length > 0) warnings.push("disableRemote is true, but remotes are configured. Remote loading will be unavailable at runtime.");
10256
- if (options.disableShared && Object.keys(options.shared).length > 0) warnings.push("disableShared is true, but shared dependencies are configured. Shared dependency loading will be unavailable at runtime.");
11199
+ if (options.disableShared && hasShared(options)) warnings.push("disableShared is true, but shared dependencies are configured. Shared dependency loading will be unavailable at runtime.");
10257
11200
  return warnings;
10258
11201
  }
10259
11202
  //#endregion
@@ -10349,7 +11292,7 @@ function isFederationHtmlPreloadDependency(dep, includeSharedRuntime = false) {
10349
11292
  }
10350
11293
  function canResolveSharedSubpath(subpath, projectRoot) {
10351
11294
  try {
10352
- return isViteOptimizableEntry(createRequire$1(pathToFileURL(path$1.join(projectRoot, "package.json"))).resolve(subpath));
11295
+ return isViteOptimizableEntry(resolveModulePath(subpath, path$1.join(projectRoot, "package.json")));
10353
11296
  } catch (error) {
10354
11297
  if (error?.code === "ERR_PACKAGE_PATH_NOT_EXPORTED" && !isBarePackageSubpath(subpath)) {
10355
11298
  const entry = resolveViteImportPackageEntry(subpath, projectRoot);
@@ -10564,6 +11507,7 @@ function createEarlyVirtualModulesPlugin(options) {
10564
11507
  const resolvedConfiguredEntryFiles = (typeof buildInput === "string" ? [buildInput] : Array.isArray(buildInput) ? buildInput : buildInput && typeof buildInput === "object" ? Object.values(buildInput) : []).map((entry) => String(entry)).filter((entry) => !isReactRouterBuildClientRouteInput(entry)).map((entry) => entry.split(/[?#]/)[0]).map((entry) => path$1.isAbsolute(entry) ? entry : path$1.resolve(root, entry));
10565
11508
  resetConcreteSharedImportSourceCache();
10566
11509
  setPackageDetectionCwd(root);
11510
+ resolveSharedVersions(shared, root);
10567
11511
  const isVinext = hasPackageDependency("vinext");
10568
11512
  initVirtualModules(_command, getRemoteEntryId(options), false, options);
10569
11513
  const isRolldown = getIsRolldown(this);
@@ -10576,21 +11520,31 @@ function createEarlyVirtualModulesPlugin(options) {
10576
11520
  config.optimizeDeps.exclude.push(...Object.keys(remotes || {}));
10577
11521
  }
10578
11522
  }
10579
- if (!config.build?.ssr && (Object.keys(shared ?? {}).length > 0 || Object.keys(remotes ?? {}).length > 0)) {
11523
+ if (!config.build?.ssr && (hasShared(options) || hasRemotes(options))) {
10580
11524
  const hasJsxSource = registerEntryImports(options, root, _command === "serve", resolvedConfiguredEntryFiles);
10581
11525
  if (_command === "serve") hasClientJsxSource = hasJsxSource;
10582
11526
  }
10583
- if (shared && Object.keys(shared).length > 0) {
11527
+ if (hasShared(options)) {
10584
11528
  if (_command === "serve") {
10585
11529
  excludeSharedSubDependencies(shared);
10586
11530
  config.optimizeDeps = config.optimizeDeps || {};
10587
11531
  config.optimizeDeps.include = config.optimizeDeps.include || [];
10588
11532
  const optimizeDeps = config.optimizeDeps;
11533
+ const preparedShares = /* @__PURE__ */ new Map();
11534
+ const writeSharedModules = (source, shareItem) => {
11535
+ if (preparedShares.get(source) === shareItem) return;
11536
+ writeLoadShareModule(source, shareItem, _command, isRolldown, options);
11537
+ if (shareItem.shareConfig?.import !== false) writePreBuildLibPath(source, shareItem, options);
11538
+ preparedShares.set(source, shareItem);
11539
+ };
10589
11540
  if (isRolldown) {
10590
11541
  optimizeDeps.rolldownOptions ??= {};
10591
11542
  optimizeDeps.rolldownOptions.plugins ??= [];
10592
11543
  optimizeDeps.rolldownOptions.plugins.push({
10593
11544
  name: "module-federation:optimize-shared-resolver",
11545
+ buildStart() {
11546
+ preparedShares.clear();
11547
+ },
10594
11548
  load(id) {
10595
11549
  if (!id.startsWith("module-federation:optimized-require-")) return;
10596
11550
  const sourcePackage = id.slice(36);
@@ -10618,13 +11572,11 @@ function createEarlyVirtualModulesPlugin(options) {
10618
11572
  if (isCommonJsImporter(importer) && !isReactSingleton && !isReactDomRequire) return;
10619
11573
  if (resolveOptions?.kind !== "entry-point") addUsedShares(source, options);
10620
11574
  if (isReactRequire || isReactDomRequire) {
10621
- writeLoadShareModule(source, shareItem, _command, isRolldown, options);
10622
- if (shareItem.shareConfig?.import !== false) writePreBuildLibPath(source, shareItem, options);
11575
+ writeSharedModules(source, shareItem);
10623
11576
  return { id: `module-federation:optimized-require-${source}` };
10624
11577
  }
10625
11578
  const loadSharePath = getLoadShareModulePath(source, isRolldown, options);
10626
- writeLoadShareModule(source, shareItem, _command, isRolldown, options);
10627
- if (shareItem.shareConfig?.import !== false) writePreBuildLibPath(source, shareItem, options);
11579
+ writeSharedModules(source, shareItem);
10628
11580
  return {
10629
11581
  id: loadSharePath,
10630
11582
  external: true
@@ -10637,6 +11589,9 @@ function createEarlyVirtualModulesPlugin(options) {
10637
11589
  optimizeDeps.esbuildOptions.plugins.push({
10638
11590
  name: "module-federation:optimize-shared-proxy",
10639
11591
  setup(build) {
11592
+ build.onStart(() => {
11593
+ preparedShares.clear();
11594
+ });
10640
11595
  build.onResolve({ filter: createViteEncodedIdPrefixRegExp("virtual:mf:") }, (args) => ({
10641
11596
  path: args.path,
10642
11597
  external: true
@@ -10654,8 +11609,7 @@ function createEarlyVirtualModulesPlugin(options) {
10654
11609
  if (args.kind === "import-statement" || args.kind === "dynamic-import") {
10655
11610
  const shareItem = shared[key];
10656
11611
  const loadSharePath = getLoadShareModulePath(args.path, isRolldown, options);
10657
- writeLoadShareModule(args.path, shareItem, _command, isRolldown, options);
10658
- if (shareItem.shareConfig?.import !== false) writePreBuildLibPath(args.path, shareItem, options);
11612
+ writeSharedModules(args.path, shareItem);
10659
11613
  return {
10660
11614
  path: loadSharePath,
10661
11615
  external: true
@@ -10674,8 +11628,7 @@ function createEarlyVirtualModulesPlugin(options) {
10674
11628
  if (!key) return;
10675
11629
  const shareItem = shared[key];
10676
11630
  const loadSharePath = getLoadShareModulePath(args.path, isRolldown, options);
10677
- writeLoadShareModule(args.path, shareItem, _command, isRolldown, options);
10678
- if (shareItem.shareConfig?.import !== false) writePreBuildLibPath(args.path, shareItem, options);
11631
+ writeSharedModules(args.path, shareItem);
10679
11632
  return {
10680
11633
  loader: "js",
10681
11634
  resolveDir: root,
@@ -10690,12 +11643,14 @@ export default __mfShared.default ?? __mfShared;`
10690
11643
  }
10691
11644
  for (const key of Object.keys(shared)) {
10692
11645
  const shareItem = shared[key];
10693
- if (key.endsWith("/")) {
11646
+ const request = getSharedRequest(key, shareItem);
11647
+ const runtimeKey = getSharedRuntimeKey(key, shareItem);
11648
+ if (key.endsWith("/") || request.endsWith("/") || runtimeKey.endsWith("/")) {
10694
11649
  if (_command === "serve" && shareItem.shareConfig?.import !== false) {
10695
11650
  const optimizeDeps = config.optimizeDeps ??= {};
10696
11651
  optimizeDeps.include ??= [];
10697
11652
  optimizeDeps.exclude ??= [];
10698
- for (const subpath of getCommonSharedSubpaths(key)) {
11653
+ for (const subpath of getCommonSharedSubpaths(request)) {
10699
11654
  writePreBuildLibPath(subpath, shareItem, options);
10700
11655
  if (canResolveSharedSubpath(subpath, root)) optimizeDeps.include.push(subpath);
10701
11656
  else optimizeDeps.exclude.push(subpath);
@@ -10703,23 +11658,24 @@ export default __mfShared.default ?? __mfShared;`
10703
11658
  }
10704
11659
  continue;
10705
11660
  }
10706
- if (isVinext && key === "react") {
10707
- addConfiguredShare(key, options);
11661
+ if (isVinext && runtimeKey === "react") {
11662
+ addConfiguredShare(runtimeKey, options);
10708
11663
  continue;
10709
11664
  }
10710
- getLoadShareModulePath(key, isRolldown, options);
10711
- writeLoadShareModule(key, shareItem, _command, isRolldown, options);
10712
- if (shareItem.shareConfig?.import !== false) writePreBuildLibPath(key, shareItem, options);
10713
- addConfiguredShare(key, options);
11665
+ getLoadShareModulePath(runtimeKey, isRolldown, options);
11666
+ writeLoadShareModule(runtimeKey, shareItem, _command, isRolldown, options);
11667
+ if (shareItem.shareConfig?.import !== false) writePreBuildLibPath(runtimeKey, shareItem, options);
11668
+ addConfiguredShare(runtimeKey, options);
10714
11669
  if (_command === "serve" && shareItem.shareConfig?.import !== false) {
10715
11670
  const optimizeDeps = config.optimizeDeps ??= {};
10716
11671
  optimizeDeps.include ??= [];
10717
11672
  optimizeDeps.exclude ??= [];
10718
- const shouldBypassOptimizeDep = isLitShare(key) || !canResolveSharedSubpath(key, root);
10719
- if (optimizeDeps.include.includes(key)) optimizeDeps.exclude = optimizeDeps.exclude.filter((dep) => dep !== key);
10720
- else if (shouldBypassOptimizeDep || optimizeDeps.exclude.includes(key)) optimizeDeps.exclude.push(key);
10721
- else optimizeDeps.include.push(key);
10722
- for (const subpath of getCommonSharedSubpaths(key)) {
11673
+ const shouldBypassOptimizeDep = isLitShare(runtimeKey) || !canResolveSharedSubpath(runtimeKey, root);
11674
+ if (optimizeDeps.include.includes(runtimeKey)) optimizeDeps.exclude = optimizeDeps.exclude.filter((dep) => dep !== runtimeKey);
11675
+ else if (shouldBypassOptimizeDep || optimizeDeps.exclude.includes(runtimeKey)) optimizeDeps.exclude.push(runtimeKey);
11676
+ else optimizeDeps.include.push(runtimeKey);
11677
+ const commonSubpaths = shareItem.shareConfig.request === void 0 && shareItem.shareConfig.shareKey === void 0 ? getCommonSharedSubpaths(runtimeKey) : [];
11678
+ for (const subpath of commonSubpaths) {
10723
11679
  const canResolveSubpath = canResolveSharedSubpath(subpath, root);
10724
11680
  if ([
10725
11681
  "react/compiler-runtime",
@@ -10735,7 +11691,7 @@ export default __mfShared.default ?? __mfShared;`
10735
11691
  addConfiguredShare(subpath, options);
10736
11692
  if (canResolveSubpath) {
10737
11693
  optimizeDeps.include.push(subpath);
10738
- if (key === "react-dom") optimizeDeps.include.push(`${key} > ${subpath}`);
11694
+ if (runtimeKey === "react-dom") optimizeDeps.include.push(`${runtimeKey} > ${subpath}`);
10739
11695
  } else optimizeDeps.exclude.push(subpath);
10740
11696
  }
10741
11697
  }
@@ -10753,10 +11709,8 @@ export default __mfShared.default ?? __mfShared;`
10753
11709
  const automaticJsxRuntime = getAutomaticJsxRuntime(config);
10754
11710
  if (automaticJsxRuntime && materializeAutomaticJsxRuntime(options, automaticJsxRuntime)) writeLocalSharedImportMap(options);
10755
11711
  }
10756
- if (!getSsrCapabilities(parseInt(version, 10), config.command, hasRemotes(options)).injectSsrEntryLoader) return;
10757
- if (options.runtimePlugins.some((p) => {
10758
- return (typeof p === "string" ? p : p[0]) === "@module-federation/vite/ssrEntryLoader";
10759
- })) return;
11712
+ if (!getSsrCapabilities(parseInt(version, 10), config.command, hasRemotes(options), isSsrConfig(config)).injectSsrEntryLoader) return;
11713
+ if (options.runtimePlugins.some((p) => getRuntimePluginSpecifier(p) === "@module-federation/vite/ssrEntryLoader")) return;
10760
11714
  const projectRequire = createRequire$1(pathToFileURL(path$1.join(config.root, "package.json")));
10761
11715
  const sharedKeys = Object.keys(options.shared ?? {});
10762
11716
  const commonSharedPkgs = [
@@ -10799,16 +11753,14 @@ function applyBuildTimeRuntimeDefines(define, options, { target, isAstro, defaul
10799
11753
  }
10800
11754
  function loadPluginDts(options) {
10801
11755
  if (options.dts === false) return [];
10802
- return [import("./pluginDts-D7Faa4NJ.js").then(({ default: pluginDts }) => pluginDts(options))];
11756
+ return [import("./pluginDts-VSLhAx6d.js").then(({ default: pluginDts }) => pluginDts(options))];
10803
11757
  }
10804
11758
  const INJECT_EXTERNAL_RUNTIME_CORE_PLUGIN = "@module-federation/vite/injectExternalRuntimeCorePlugin";
10805
11759
  function isInjectExternalRuntimeCorePlugin(specifier) {
10806
11760
  return specifier === INJECT_EXTERNAL_RUNTIME_CORE_PLUGIN || specifier.includes("injectExternalRuntimeCorePlugin") || specifier.includes("inject-external-runtime-core-plugin");
10807
11761
  }
10808
11762
  function hasInjectExternalRuntimeCorePlugin(runtimePlugins) {
10809
- return runtimePlugins.some((plugin) => {
10810
- return isInjectExternalRuntimeCorePlugin(typeof plugin === "string" ? plugin : plugin[0]);
10811
- });
11763
+ return runtimePlugins.some((plugin) => isInjectExternalRuntimeCorePlugin(getRuntimePluginSpecifier(plugin)));
10812
11764
  }
10813
11765
  function resolveInjectExternalRuntimeCorePlugin() {
10814
11766
  try {
@@ -10855,7 +11807,7 @@ function federation(mfUserOptions) {
10855
11807
  const emittedRuntimeCapabilityWarnings = /* @__PURE__ */ new Set();
10856
11808
  const getLoadHookExportConditions = (context, loadOptions) => {
10857
11809
  const environment = context.environment;
10858
- const isSsr = loadOptions?.ssr === true || isSsrBuild || environment?.config?.consumer === "server" || Boolean(environment?.config?.build?.ssr) || environment?.name === "ssr" || environment?.name === "server";
11810
+ const isSsr = loadOptions?.ssr === true || isSsrBuild || isServerEnvironment(environment?.name, environment?.config);
10859
11811
  return getSharedExportConditions({
10860
11812
  environmentConditions: environment?.config?.resolve?.conditions,
10861
11813
  isProduction: environment?.config?.isProduction ?? isProduction,
@@ -10979,7 +11931,8 @@ function federation(mfUserOptions) {
10979
11931
  ssrResolveConditions = config.ssr?.resolve?.conditions ? [...config.ssr.resolve.conditions] : void 0;
10980
11932
  ssrTarget = config.ssr?.target ?? "node";
10981
11933
  isProduction = config.isProduction;
10982
- const ssrCapabilities = getSsrCapabilities(parseInt(version, 10), command, Object.keys(options.remotes).length > 0);
11934
+ const ssrCapabilities = getSsrCapabilities(parseInt(version, 10), command, Object.keys(options.remotes).length > 0, isSsrConfig(config));
11935
+ resolveSharedVersions(shared, config.root);
10983
11936
  initVirtualModules(command, remoteEntryId, ssrCapabilities.enableSsrInitBootstrap, options);
10984
11937
  }
10985
11938
  },
@@ -11028,6 +11981,7 @@ function federation(mfUserOptions) {
11028
11981
  federationOptions: options,
11029
11982
  getParsePromise: () => moduleParseController.parsePromise
11030
11983
  }),
11984
+ pluginLazyConsumeOnlyShares(options),
11031
11985
  {
11032
11986
  name: "module-federation-esm-shims",
11033
11987
  enforce: "pre",
@@ -11079,6 +12033,7 @@ function federation(mfUserOptions) {
11079
12033
  priority: USER_GROUP_MAX_PRIORITY
11080
12034
  };
11081
12035
  };
12036
+ const federationGroupDebugName = supportsCodeSplittingGroupDebugName(this) ? { debugName: "module-federation" } : {};
11082
12037
  let warnedAboutManualChunks = false;
11083
12038
  let warnedAboutObjectManualChunks = false;
11084
12039
  const applyManualChunks = (output, useCodeSplitting) => {
@@ -11086,11 +12041,13 @@ function federation(mfUserOptions) {
11086
12041
  const isPatchedByPlugin = typeof output.manualChunks === "function" && patchedManualChunks.has(output.manualChunks);
11087
12042
  const mfChunkName = function(id) {
11088
12043
  if (id.includes(runtimeInitId) || id.includes("__mf_v__runtimeInit__mf_v__")) return "runtimeInit";
12044
+ if (isSharedCacheHelpersId(id)) return getSharedChunkName(id);
11089
12045
  if (id.includes("__loadShare__")) {
11090
12046
  const pkg = getCachedLoadSharePkg(id);
11091
12047
  const key = pkg && findSharedKey(pkg, shared);
11092
- if (useCodeSplitting && key && shared[key].shareConfig.eager === true) return "loadShare-eager";
12048
+ if (key && shared[key].shareConfig.eager === true) return "loadShare-eager";
11093
12049
  if (key && shared[key].shareConfig.import === false) return null;
12050
+ if (pkg && !id.includes("commonjs-proxy") && isCoalescableLoadShareWrapper(pkg, options, id)) return getSharedChunkName(id);
11094
12051
  const match = id.match(/([^/\\]+__loadShare__[^/\\]+)/);
11095
12052
  return match ? match[1] : "loadShare";
11096
12053
  }
@@ -11127,7 +12084,8 @@ function federation(mfUserOptions) {
11127
12084
  };
11128
12085
  const mfNameGroup = {
11129
12086
  name: mfChunkName,
11130
- priority: MF_GROUP_PRIORITY
12087
+ priority: MF_GROUP_PRIORITY,
12088
+ ...federationGroupDebugName
11131
12089
  };
11132
12090
  federationGroups.add(mfPreloadGroup);
11133
12091
  federationGroups.add(mfNameGroup);
@@ -11200,7 +12158,14 @@ function federation(mfUserOptions) {
11200
12158
  if (!virtualModule?.code) return null;
11201
12159
  let code = virtualModule.code;
11202
12160
  const consumerTarget = resolveEnvironmentConsumerTarget(this);
11203
- if (consumerTarget === "server" || !consumerTarget && isSsrBuild) code = prependWorkspaceSingletonSsrImport(code);
12161
+ if (consumerTarget === "server" || !consumerTarget && isSsrBuild) {
12162
+ const withSsrImport = prependWorkspaceSingletonSsrImport(code);
12163
+ if (withSsrImport !== code) {
12164
+ const pkg = getCachedLoadSharePkg(id);
12165
+ if (pkg) markLoadShareWrapperNotCoalescable(pkg, options, id);
12166
+ code = withSsrImport;
12167
+ }
12168
+ }
11204
12169
  code = code.replace(/import\s+["'][^"']*__prebuild__[^"']*["']\s*;?/g, "");
11205
12170
  code = code.replace(/export\s+\*\s+from\s+["'][^"']*__prebuild__[^"']*["']\s*;?/g, "");
11206
12171
  if (!(/\b(?:var|let|const)\s+__moduleExports\b/.test(code) || /\bexport\s+const\s+__moduleExports\b/.test(code) || /\bexport\s*\{[^}]*__moduleExports/.test(code))) {
@@ -11218,6 +12183,9 @@ function federation(mfUserOptions) {
11218
12183
  return loadVirtualModule();
11219
12184
  },
11220
12185
  generateBundle(_outputOptions, bundle, _isWrite) {
12186
+ inlineDeferredPrebuildNamespaceHelper(bundle);
12187
+ for (const [fileName, fallbacks] of findEagerFallbacksInSharedChunk(bundle)) mfWarn(`A shared-dependency fallback was merged into the loadShare chunk ${fileName}: ${fallbacks.join(", ")}.\n That fallback is no longer lazy, so consumers download their local copy even when a peer provides the share, and the container can deadlock.
12188
+ Stop the shared module from statically importing another share.`);
11221
12189
  for (const [fileName, chunk] of Object.entries(bundle)) {
11222
12190
  if (!isOutputChunk(chunk)) continue;
11223
12191
  if (!isFederationControlChunk(fileName, filename)) continue;
@@ -11266,7 +12234,7 @@ function federation(mfUserOptions) {
11266
12234
  config(config, { command: _command }) {
11267
12235
  const isRolldown = getIsRolldown(this);
11268
12236
  isSsrBuild = _command === "build" && Boolean(config.build?.ssr);
11269
- const needsRuntimeHelpers = Object.keys(options.shared ?? {}).length > 0;
12237
+ const needsRuntimeHelpers = hasShared(options);
11270
12238
  if (needsRuntimeHelpers) appendResolveAlias(config, {
11271
12239
  find: /^@module-federation\/runtime\/helpers$/,
11272
12240
  replacement: getRuntimeHelpersImplementation(options.implementation)
@@ -11283,7 +12251,7 @@ function federation(mfUserOptions) {
11283
12251
  config.optimizeDeps.include.push("@module-federation/runtime");
11284
12252
  if (needsRuntimeHelpers) config.optimizeDeps.include.push("@module-federation/runtime/helpers");
11285
12253
  options.runtimePlugins.forEach((p) => {
11286
- const pluginPath = typeof p === "string" ? p : p[0];
12254
+ const pluginPath = getRuntimePluginSpecifier(p);
11287
12255
  if (SSR_ONLY_RUNTIME_PLUGINS.has(pluginPath)) return;
11288
12256
  if (pluginPath && !pluginPath.startsWith(".") && !pluginPath.startsWith("/") && !pluginPath.startsWith("\0") && !pluginPath.startsWith("virtual:")) {
11289
12257
  let optimizeDep = pluginPath;
@@ -11319,7 +12287,7 @@ function federation(mfUserOptions) {
11319
12287
  if (prematureExit) prematureExit.closeBundle = void 0;
11320
12288
  },
11321
12289
  configEnvironment(name, config) {
11322
- if (!(config.consumer === "server" || name === "ssr" || name === "server" || config.build?.ssr === true)) return;
12290
+ if (!isServerEnvironment(name, config)) return;
11323
12291
  const isAstro = hasPackageDependency("astro");
11324
12292
  config.define = { ...config.define ?? {} };
11325
12293
  applyBuildTimeRuntimeDefines(config.define, options, {