@module-federation/vite 1.21.0 → 1.21.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -167,7 +167,7 @@ export default defineConfig({
167
167
  name: "host",
168
168
  remotes: {
169
169
  remote: {
170
- type: "module", // type "var" (default) for vite remote is supported with remote's `varFilename` option
170
+ type: "module", // omitted object type defaults to "var" with a warning
171
171
  name: "remote",
172
172
  entry: "https://[...]/remoteEntry.js",
173
173
  entryGlobalName: "remote",
@@ -237,6 +237,7 @@ export default defineConfig({
237
237
  ```
238
238
 
239
239
  The host app configuration specifies its name, the filename of its exposed remote entry remoteEntry.js, and importantly, the configuration of the remote application to load.
240
+ Object remotes that omit `type` retain the legacy `"var"` default and emit a warning. Use `type: "module"` for Vite ESM remotes. Use `type: "var"` explicitly only for global-format remotes, such as Webpack/Rspack remotes or a Vite remote's `varFilename` output.
240
241
  You can specify the place the host initialization file is injected with the **hostInitInjectLocation** option, which is described in the example code above.
241
242
  The **moduleParseTimeout** option allows you to configure the maximum time to wait for module parsing during the build process.
242
243
  The **moduleParseIdleTimeout** option is an alternative that resets the timer on every parsed module. It only fires when there has been no module activity for the configured duration, making it suitable for large codebases where the total build time exceeds the fixed timeout.
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { n as normalizePathForImport, r as rebaseImport } from "./buildPaths-BkaQHrd2.js";
2
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-DyJrx8ah.js";
3
- import { a as getCommonSharedSubpaths, c as isNodeModulePath, d as normalizeNodeModulePath, f as resolvePublicPath, i as getCommonSharedSubpathFromNodeModulePath, l as isNuxtClientBase, n as filterId, o as getMatchingNodeModuleSubpath, r as getBasePath$1, s as isAssetLikeImport, t as ensureTrailingSlash, u as isViteOptimizableEntry } from "./pathNormalization-DvgU8LIp.js";
3
+ import { a as getCommonSharedSubpaths, c as isNodeModulePath, d as normalizeNodeModulePath, f as resolvePublicPath, i as getCommonSharedSubpathFromNodeModulePath, l as isNuxtClientBase, n as filterId, o as getMatchingNodeModuleSubpath, r as getBasePath$1, s as isAssetLikeImport, t as ensureTrailingSlash, u as isViteOptimizableEntry } from "./pathNormalization-CHct3UwV.js";
4
4
  import { createRequire } from "node:module";
5
5
  import * as fs$2 from "fs";
6
6
  import { existsSync, readFileSync, realpathSync, statSync, writeFileSync } from "fs";
@@ -522,8 +522,12 @@ function findModuleImportDescriptors(code) {
522
522
  const dynamicPattern = /\bimport\s*\(\s*(?:\/\*[\s\S]*?\*\/\s*)?(["'])([^"']+)\1\s*\)/g;
523
523
  const requirePattern = /\brequire\s*\(\s*(["'])([^"']+)\1\s*\)/g;
524
524
  const sideEffectPattern = /\bimport\s*(["'])([^"']+)\1/g;
525
- for (const match of code.matchAll(staticFromPattern)) {
526
- if (!codePositions[match.index]) continue;
525
+ let match;
526
+ while (match = staticFromPattern.exec(code)) {
527
+ if (!codePositions[match.index]) {
528
+ staticFromPattern.lastIndex = match.index + 1;
529
+ continue;
530
+ }
527
531
  descriptors.push({
528
532
  kind: "static",
529
533
  syntax: "import",
@@ -573,6 +577,7 @@ function sanitizeDevEntryPath(devEntryPath) {
573
577
  */
574
578
  function rewriteEntryScripts(html, createProxySrc) {
575
579
  return html.replace(/<script\b(?=[^>]*\btype=["']module["'])(?=[^>]*\bsrc=["'][^"']+["'])([^>]*)>/gi, (match, attrs) => {
580
+ if (/\svite-ignore(?:\s|=|\/|$)/i.test(attrs)) return match;
576
581
  const srcMatch = attrs.match(/\bsrc=["']([^"']+)["']/i);
577
582
  if (!srcMatch) return match;
578
583
  const originalSrc = srcMatch[1];
@@ -617,6 +622,9 @@ function normalizeRemotes(remotes) {
617
622
  });
618
623
  return result;
619
624
  }
625
+ function warnOmittedObjectRemoteType(remoteKey) {
626
+ mfWarn(`Remote "${remoteKey}" omits type and defaults to 'var'. Set type: 'module' for Vite ESM remotes, or type: 'var' explicitly to silence this warning.`);
627
+ }
620
628
  function normalizeRemoteItem(key, remote) {
621
629
  warnOnReservedInternalNamePrefix(key, "remoteAlias");
622
630
  if (typeof remote === "string") {
@@ -639,6 +647,8 @@ function normalizeRemoteItem(key, remote) {
639
647
  shareScope: "default"
640
648
  };
641
649
  }
650
+ const typeOmitted = remote.type === void 0 || remote.type === null || remote.type === "";
651
+ if (typeOmitted) warnOmittedObjectRemoteType(key);
642
652
  return Object.assign({
643
653
  type: "var",
644
654
  name: key,
@@ -647,6 +657,7 @@ function normalizeRemoteItem(key, remote) {
647
657
  entryGlobalName: key
648
658
  }, {
649
659
  ...remote,
660
+ type: typeOmitted ? "var" : remote.type,
650
661
  internalName: toInternalModuleFederationName(remote.name || key)
651
662
  });
652
663
  }
@@ -664,6 +675,11 @@ function inferVersionFromRequiredVersion(requiredVersion) {
664
675
  if (typeof requiredVersion !== "string") return void 0;
665
676
  return requiredVersion.match(/\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?/)?.[0];
666
677
  }
678
+ /** URI-style package specifiers are not semver ranges for runtime satisfy(). */
679
+ const PACKAGE_SPECIFIER_PROTOCOL_RE = /^[a-z][a-z\d+.-]*:/i;
680
+ function isProtocolRequiredVersion(requiredVersion) {
681
+ return PACKAGE_SPECIFIER_PROTOCOL_RE.test(requiredVersion.trim());
682
+ }
667
683
  function getLitExportSubpathShares(sharedName) {
668
684
  if (sharedName !== "lit") return [];
669
685
  const exportsField = getInstalledPackageJson(sharedName, { packageName: sharedName })?.packageJson.exports;
@@ -691,6 +707,8 @@ function normalizeShareItem(key, shareItem) {
691
707
  requiredVersion: version ? `^${version}` : "*"
692
708
  }
693
709
  };
710
+ const userRequiredVersion = shareItem.requiredVersion;
711
+ const keepUserRequiredVersion = userRequiredVersion === false || typeof userRequiredVersion === "string" && userRequiredVersion.trim() !== "" && !isProtocolRequiredVersion(userRequiredVersion);
694
712
  return {
695
713
  name: key,
696
714
  from: "",
@@ -700,16 +718,33 @@ function normalizeShareItem(key, shareItem) {
700
718
  import: shareItem.import,
701
719
  singleton: shareItem.singleton || false,
702
720
  eager: shareItem.eager || false,
703
- requiredVersion: shareItem.requiredVersion !== void 0 ? shareItem.requiredVersion : isImportFalse || shareItem.version ? "*" : version ? `^${version}` : "*",
721
+ requiredVersion: keepUserRequiredVersion ? userRequiredVersion : isImportFalse || shareItem.version ? "*" : version ? `^${version}` : "*",
704
722
  strictVersion: !!shareItem.strictVersion,
705
723
  ...shareItem.suppressMissingImportWarning ? { suppressMissingImportWarning: true } : {},
706
724
  ...treeShaking ? { treeShaking: { ...treeShaking } } : {}
707
725
  }
708
726
  };
709
727
  }
728
+ /**
729
+ * Trailing-slash keys are package namespace prefixes (`lodash/`, `@scope/ui/`).
730
+ *
731
+ * Packages in COMMON_SHARED_SUBPATHS historically collapsed `pkg/` → `pkg` so
732
+ * Vite would not resolve the invalid `pkg/` specifier, while still auto-mapping
733
+ * known subpaths when a local provider exists.
734
+ *
735
+ * `react/` is different: consumer-only shares need true namespace coverage for
736
+ * any actually-imported subpath, not a hardcoded export list. Keep `react/` as
737
+ * a prefix; concrete subpaths materialize on import via the generic matcher.
738
+ *
739
+ * `react-dom/` must keep collapsing. A browser-wide `react-dom/` prefix would
740
+ * also capture `react-dom/server*`. Browser-safe entries (`react-dom/client`,
741
+ * `react-dom/profiling`) stay via COMMON_SHARED_SUBPATHS (local provider) or
742
+ * an exact shared key; SSR server* entries need an explicit shared key.
743
+ */
710
744
  function normalizeSharedKey(key) {
711
745
  if (!key.endsWith("/")) return key;
712
746
  const baseKey = key.slice(0, -1);
747
+ if (baseKey === "react") return key;
713
748
  return getCommonSharedSubpaths(baseKey).length > 0 ? baseKey : key;
714
749
  }
715
750
  function normalizeShared(shared) {
@@ -1982,6 +2017,10 @@ function getPackageEsmEntryPath(pkg) {
1982
2017
  }) || resolvePackageEntryFromProjectRoot(pkg);
1983
2018
  }
1984
2019
  const packageNamedExportsCache = /* @__PURE__ */ new Map();
2020
+ const sharedExportInspectionCache = /* @__PURE__ */ new Map();
2021
+ function invalidateSharedExportInspectionCache(filePath) {
2022
+ if (!/(?:^|[/\\])node_modules(?:[/\\]|$)/.test(filePath)) sharedExportInspectionCache.clear();
2023
+ }
1985
2024
  const DEFAULT_SHARED_EXPORT_CONDITIONS = [
1986
2025
  "browser",
1987
2026
  "import",
@@ -2009,17 +2048,22 @@ function hasCommonJsExports(source) {
2009
2048
  return false;
2010
2049
  }
2011
2050
  function inspectSharedExportsFromFile(entryPath, exportConditions = DEFAULT_SHARED_EXPORT_CONDITIONS) {
2051
+ if (!entryPath) return void 0;
2052
+ const cacheKey = `${entryPath}\0${exportConditions.join("\0")}`;
2053
+ if (sharedExportInspectionCache.has(cacheKey)) return sharedExportInspectionCache.get(cacheKey);
2012
2054
  try {
2013
- if (!entryPath) return void 0;
2014
2055
  const source = readFileSync(entryPath, "utf-8");
2015
2056
  const scanState = { complete: true };
2016
2057
  const namedExports = getNamedExportsViaRegex(source, entryPath, void 0, scanState, exportConditions);
2017
2058
  const commonJs = hasCommonJsExports(source);
2018
- return {
2059
+ const inspection = {
2019
2060
  namedExports: scanState.complete && !commonJs ? namedExports : void 0,
2020
2061
  commonJs
2021
2062
  };
2063
+ sharedExportInspectionCache.set(cacheKey, inspection);
2064
+ return inspection;
2022
2065
  } catch {
2066
+ sharedExportInspectionCache.set(cacheKey, void 0);
2023
2067
  return;
2024
2068
  }
2025
2069
  }
@@ -3406,12 +3450,24 @@ function generateLocalSharedImportMap(options) {
3406
3450
  }
3407
3451
  `;
3408
3452
  }
3453
+ /** Expand `pkg/` → package root + matching usedShares; never returns the prefix string. */
3454
+ function expandSharedPrefixKey(prefixKey, used) {
3455
+ const base = prefixKey.slice(0, -1);
3456
+ const expanded = /* @__PURE__ */ new Set([base]);
3457
+ for (const pkg of used) {
3458
+ if (pkg.endsWith("/")) continue;
3459
+ if (pkg === base || pkg.startsWith(`${base}/`)) expanded.add(pkg);
3460
+ }
3461
+ return [...expanded];
3462
+ }
3409
3463
  function getOrderedUsedShares(options) {
3410
3464
  const resolvedOptions = options ?? getNormalizeModuleFederationOptions();
3411
- const shares = new Set(getUsedShares(options));
3465
+ const used = getUsedShares(options);
3466
+ const shares = new Set(used);
3412
3467
  Object.keys(resolvedOptions.shared ?? {}).forEach((pkg) => {
3413
3468
  if (!pkg.endsWith("/")) shares.add(pkg);
3414
3469
  });
3470
+ 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);
3415
3471
  return orderSharedDependenciesFirst(Array.from(shares).sort((a, b) => {
3416
3472
  const priority = (pkg) => pkg === "react" ? 0 : pkg === "react-dom" ? 1 : pkg.startsWith("react/") ? 2 : 3;
3417
3473
  return priority(a) - priority(b) || a.localeCompare(b);
@@ -3421,7 +3477,12 @@ function getMaterializedShares(options) {
3421
3477
  const resolvedOptions = options ?? getNormalizeModuleFederationOptions();
3422
3478
  const scopedRegistrations = options ? usedSharesByOptions.get(options) : void 0;
3423
3479
  const shares = new Set(options && scopedRegistrations?.size ? materializedSharesByOptions.get(options) ?? [] : usedShares);
3424
- for (const [pkg, share] of Object.entries(resolvedOptions.shared ?? {})) if (!pkg.endsWith("/") && share.shareConfig?.eager) shares.add(pkg);
3480
+ const usedForEager = options ? usedSharesByOptions.get(options) ?? [] : usedShares;
3481
+ for (const [pkg, share] of Object.entries(resolvedOptions.shared ?? {})) {
3482
+ if (!share.shareConfig?.eager) continue;
3483
+ if (pkg.endsWith("/")) for (const concrete of expandSharedPrefixKey(pkg, usedForEager)) shares.add(concrete);
3484
+ else shares.add(pkg);
3485
+ }
3425
3486
  const configured = /* @__PURE__ */ new Map();
3426
3487
  for (const pkg of getOrderedUsedShares(options)) {
3427
3488
  const packageName = getPackageName(pkg);
@@ -3616,7 +3677,9 @@ const externalSharedProviderSelectionHelperCode = `const __mfSelectExternalShare
3616
3677
  ) => {
3617
3678
  const isLocalProvider = (provider) => __mfMatchesSharedProvider(provider, localShare);
3618
3679
  const candidates = Object.fromEntries(
3619
- Object.entries(versions || {}).filter(([, provider]) => !isLocalProvider(provider))
3680
+ Object.entries(versions || {}).filter(([, provider]) =>
3681
+ !isLocalProvider(provider) && provider?.shareConfig?.import !== false
3682
+ )
3620
3683
  );
3621
3684
  if (localShare?.version && localShare.shareConfig?.import !== false) {
3622
3685
  const sameVersionProvider = candidates[localShare.version];
@@ -4019,6 +4082,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
4019
4082
  const needsSharedProviderSelectionHelper = Object.keys(options.shared ?? {}).length > 0;
4020
4083
  const hasTreeShakingShared = Object.values(options.shared ?? {}).some((share) => !!share?.shareConfig.treeShaking);
4021
4084
  const hasMultipleShareScopes = Array.isArray(options.shareScope);
4085
+ const guardHostAutoInit = command === "build" && Object.keys(options.exposes ?? {}).length > 0 && Object.keys(options.remotes ?? {}).length > 0;
4022
4086
  const materializedShareBatches = toSafeJsLiteral(getShareBatches(options, false));
4023
4087
  const runtimeImports = [
4024
4088
  "init as runtimeInit",
@@ -4925,10 +4989,13 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
4925
4989
  }
4926
4990
  return (exposesMap[moduleName])().then(res => () => res)
4927
4991
  }
4928
- export {
4929
- init,
4930
- getExposes as get
4992
+ ${guardHostAutoInit ? `let __mfInitPromise;
4993
+ function __mfGuardedInit(shared, initScope) {
4994
+ if (shared === undefined && __mfInitPromise) return __mfInitPromise;
4995
+ __mfInitPromise = init(shared, initScope);
4996
+ return __mfInitPromise;
4931
4997
  }
4998
+ export { __mfGuardedInit as init, getExposes as get }` : `export { init, getExposes as get }`}
4932
4999
  `;
4933
5000
  }
4934
5001
  /**
@@ -5090,6 +5157,7 @@ const usedRemotesMap = {};
5090
5157
  const usedRemotesByOptions = /* @__PURE__ */ new WeakMap();
5091
5158
  const dynamicRemotesByOptions = /* @__PURE__ */ new WeakMap();
5092
5159
  const staticRemotesByOptions = /* @__PURE__ */ new WeakMap();
5160
+ const preloadRemotesByOptions = /* @__PURE__ */ new WeakMap();
5093
5161
  const EMPTY_STATIC_REMOTES = /* @__PURE__ */ new Set();
5094
5162
  function getScopedUsedRemotesMap(options) {
5095
5163
  let scoped = usedRemotesByOptions.get(options);
@@ -5127,8 +5195,16 @@ function markStaticRemote(remote, options) {
5127
5195
  }
5128
5196
  remotes.add(remote);
5129
5197
  }
5130
- function getStaticRemotes(options) {
5131
- return staticRemotesByOptions.get(options) ?? EMPTY_STATIC_REMOTES;
5198
+ function markPreloadRemote(remote, options) {
5199
+ let remotes = preloadRemotesByOptions.get(options);
5200
+ if (!remotes) {
5201
+ remotes = /* @__PURE__ */ new Set();
5202
+ preloadRemotesByOptions.set(options, remotes);
5203
+ }
5204
+ remotes.add(remote);
5205
+ }
5206
+ function getPreloadRemotes(options) {
5207
+ return preloadRemotesByOptions.get(options) ?? EMPTY_STATIC_REMOTES;
5132
5208
  }
5133
5209
  function isDynamicOnlyRemote(remote, options) {
5134
5210
  return (dynamicRemotesByOptions.get(options)?.has(remote) ?? false) && !(staticRemotesByOptions.get(options)?.has(remote) ?? false);
@@ -5563,6 +5639,7 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
5563
5639
  let emittedFileName;
5564
5640
  let skipTransformIds = /* @__PURE__ */ new Set();
5565
5641
  let injectedTransformIds = /* @__PURE__ */ new Set();
5642
+ const ignoredHtmlScriptSources = /* @__PURE__ */ new Set();
5566
5643
  let bootstrapDir = "";
5567
5644
  function skipSvelteKitSsrBuild() {
5568
5645
  return (_command === "build" || viteConfig?.command === "build") && viteConfig?.build?.ssr && hasPackageDependency("@sveltejs/kit");
@@ -5627,7 +5704,7 @@ const __mfCurrentScript = document.currentScript;
5627
5704
  const normalizedOptions = federationOptions ?? getNormalizeModuleFederationOptions();
5628
5705
  const isLoadedFirstClientBuild = (_command === "build" || viteConfig?.command === "build") && waitsForInit && !viteConfig?.build?.ssr && normalizedOptions.shareStrategy === "loaded-first";
5629
5706
  if (normalizedOptions.shareStrategy === "loaded-first" && !isLoadedFirstClientBuild) return [];
5630
- const remoteSources = isLoadedFirstClientBuild ? Array.from(getStaticRemotes(normalizedOptions)) : Object.entries(getUsedRemotesMap(federationOptions)).flatMap(([, remotes]) => Array.from(remotes)).filter((remote) => !federationOptions || !isDynamicOnlyRemote(remote, federationOptions));
5707
+ const remoteSources = isLoadedFirstClientBuild ? Array.from(getPreloadRemotes(normalizedOptions)) : Object.entries(getUsedRemotesMap(federationOptions)).flatMap(([, remotes]) => Array.from(remotes)).filter((remote) => !federationOptions || !isDynamicOnlyRemote(remote, federationOptions));
5631
5708
  return Array.from(new Set(remoteSources.flatMap((remote) => {
5632
5709
  const registration = getRemoteRegistration(remote, normalizedOptions.remotes, federationOptions);
5633
5710
  return registration && (registration.type === "module" || registration.type === "esm") && /^(?:https?:)?\/\//.test(registration.entry) ? [registration.entry] : [];
@@ -5647,7 +5724,7 @@ const __mfCurrentScript = document.currentScript;
5647
5724
  const normalizedOptions = federationOptions ?? getNormalizeModuleFederationOptions();
5648
5725
  const isLoadedFirstClientBuild = (_command === "build" || viteConfig?.command === "build") && waitsForInit && !viteConfig?.build?.ssr && normalizedOptions.shareStrategy === "loaded-first";
5649
5726
  const shouldPreloadRemotes = !options?.skipRemotePreload && (normalizedOptions.shareStrategy !== "loaded-first" || isLoadedFirstClientBuild);
5650
- const remoteSources = isLoadedFirstClientBuild ? Array.from(getStaticRemotes(normalizedOptions)) : Object.entries(getUsedRemotesMap(federationOptions)).flatMap(([, remotes]) => Array.from(remotes)).filter((remote) => !federationOptions || !isDynamicOnlyRemote(remote, federationOptions));
5727
+ const remoteSources = isLoadedFirstClientBuild ? Array.from(getPreloadRemotes(normalizedOptions)) : Object.entries(getUsedRemotesMap(federationOptions)).flatMap(([, remotes]) => Array.from(remotes)).filter((remote) => !federationOptions || !isDynamicOnlyRemote(remote, federationOptions));
5651
5728
  const remotePreloads = shouldPreloadRemotes ? remoteSources.sort().map((remote) => {
5652
5729
  const registration = isLoadedFirstClientBuild ? getRemoteRegistration(remote, normalizedOptions.remotes, federationOptions) : void 0;
5653
5730
  return `__mfPreloadRemote(${JSON.stringify(getRuntimeRemoteId(remote, normalizedOptions.remotes, federationOptions))}, ${JSON.stringify(remote)}${registration ? `, ${JSON.stringify(registration)}` : ""})`;
@@ -5764,6 +5841,10 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
5764
5841
  const scriptRegex = /<script\b(?=[^>]*\btype=["']module["'])(?=[^>]*\bsrc=["']([^"']+)["'])[^>]*>/gi;
5765
5842
  let match;
5766
5843
  while ((match = scriptRegex.exec(htmlContent)) !== null) {
5844
+ if (/\svite-ignore(?:\s|=|\/?>)/i.test(match[0])) {
5845
+ ignoredHtmlScriptSources.add(match[1]);
5846
+ continue;
5847
+ }
5767
5848
  const scriptSrc = stripQueryAndHash$1(match[1]);
5768
5849
  if (/^(?:[a-z]+:)?\/\//i.test(scriptSrc)) continue;
5769
5850
  addEntryFile(scriptSrc);
@@ -5945,6 +6026,7 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
5945
6026
  const scriptRegex = /<script\b(?=[^>]*\btype=["']module["'])(?=[^>]*\bsrc=["']([^"']+)["'])[^>]*>\s*<\/script>/gi;
5946
6027
  let rewritten = false;
5947
6028
  htmlContent = htmlContent.replace(scriptRegex, (scriptTag, entrySrc) => {
6029
+ if (ignoredHtmlScriptSources.has(entrySrc)) return scriptTag;
5948
6030
  rewritten = true;
5949
6031
  const strippedInit = stripBase(initPath);
5950
6032
  const strippedEntry = stripBase(entrySrc);
@@ -6990,8 +7072,30 @@ function getRemoteEntrySSRId(options) {
6990
7072
  return `${REMOTE_ENTRY_SSR_ID}:${getVirtualModuleScopeKey(options)}`;
6991
7073
  }
6992
7074
  function getSsrRemoteEntryFileName(browserFilename) {
6993
- const ext = browserFilename.match(/\.[^.]+$/)?.[0] || ".js";
6994
- return `${browserFilename.slice(0, browserFilename.length - ext.length)}.ssr${ext}`;
7075
+ let filename = browserFilename;
7076
+ if (filename.includes("[hash")) {
7077
+ filename = filename.replace(/(?:[._-]?\[hash(?::\d+)?\])/g, "");
7078
+ if (!/\.[^.]+$/.test(filename)) filename = `${filename}.js`;
7079
+ }
7080
+ const ext = filename.match(/\.[^.]+$/)?.[0] || ".js";
7081
+ return `${filename.slice(0, filename.length - ext.length)}.ssr${ext}`;
7082
+ }
7083
+ /** Singleton map for SSR loadShare: expand `pkg/` via usedShares; never serialize the prefix. */
7084
+ function getSsrSharedSingletons(options) {
7085
+ const used = getUsedShares(options);
7086
+ const result = {};
7087
+ for (const [pkg, share] of Object.entries(options.shared)) {
7088
+ if (!share.shareConfig.singleton) continue;
7089
+ if (pkg.endsWith("/")) {
7090
+ for (const concrete of expandSharedPrefixKey(pkg, used)) result[concrete] = {
7091
+ ...share,
7092
+ name: concrete
7093
+ };
7094
+ continue;
7095
+ }
7096
+ result[pkg] = share;
7097
+ }
7098
+ return result;
6995
7099
  }
6996
7100
  /**
6997
7101
  * Generates the SSR remote entry module.
@@ -7005,7 +7109,7 @@ function getSsrRemoteEntryFileName(browserFilename) {
7005
7109
  */
7006
7110
  function generateRemoteEntrySSR(options) {
7007
7111
  const virtualExposesSSRId = getVirtualExposesSSRId(options);
7008
- const sharedSingletons = Object.fromEntries(Object.entries(options.shared).filter(([, share]) => share.shareConfig.singleton));
7112
+ const sharedSingletons = getSsrSharedSingletons(options);
7009
7113
  return `
7010
7114
  import { init as runtimeInit } from "@module-federation/runtime";
7011
7115
 
@@ -7360,7 +7464,7 @@ const Manifest = (providedOptions) => {
7360
7464
  if (this.environment?.name === "ssr") return;
7361
7465
  let filesMap = {};
7362
7466
  const foundRemoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
7363
- const expectedSsrRemoteEntryFile = getSsrRemoteEntryFileName(foundRemoteEntryFile || mfOptions.filename);
7467
+ const expectedSsrRemoteEntryFile = getSsrRemoteEntryFileName(mfOptions.filename);
7364
7468
  const foundSsrRemoteEntryFile = Object.values(bundle).find((file) => file.fileName === expectedSsrRemoteEntryFile)?.fileName;
7365
7469
  if (foundRemoteEntryFile) remoteEntryFile = foundRemoteEntryFile;
7366
7470
  ssrRemoteEntryFile = foundSsrRemoteEntryFile || (_command === "serve" ? getSsrRemoteEntryFileName(resolveDevRemoteEntryFileName(mfOptions.filename)) : expectedSsrRemoteEntryFile);
@@ -9532,6 +9636,7 @@ function registerEntryImports(options, projectRoot, recordShared = true, entryFi
9532
9636
  if (remoteKey) {
9533
9637
  addUsedRemote(remoteKey, request, options);
9534
9638
  markStaticRemote(request, options);
9639
+ markPreloadRemote(request, options);
9535
9640
  } else if (sharedKey && recordShared) addUsedShares(request, options);
9536
9641
  else if (request && !typeOnly) enqueue(request, file, preloadRemotes && isStatic);
9537
9642
  }
@@ -9705,7 +9810,11 @@ export default __mfShared.default ?? __mfShared;`
9705
9810
  else optimizeDeps.include.push(key);
9706
9811
  for (const subpath of getCommonSharedSubpaths(key)) {
9707
9812
  const canResolveSubpath = canResolveSharedSubpath(subpath, root);
9708
- if (["react/compiler-runtime", "react-dom/client"].includes(subpath) && !canResolveSubpath) {
9813
+ if ([
9814
+ "react/compiler-runtime",
9815
+ "react-dom/client",
9816
+ "react-dom/profiling"
9817
+ ].includes(subpath) && !canResolveSubpath) {
9709
9818
  optimizeDeps.exclude.push(subpath);
9710
9819
  continue;
9711
9820
  }
@@ -9774,7 +9883,7 @@ function applyBuildTimeRuntimeDefines(define, options, { target, isAstro, defaul
9774
9883
  }
9775
9884
  function loadPluginDts(options) {
9776
9885
  if (options.dts === false) return [];
9777
- return [import("./pluginDts-BNCg4Gri.js").then(({ default: pluginDts }) => pluginDts(options))];
9886
+ return [import("./pluginDts-sJeW2nss.js").then(({ default: pluginDts }) => pluginDts(options))];
9778
9887
  }
9779
9888
  const INJECT_EXTERNAL_RUNTIME_CORE_PLUGIN = "@module-federation/vite/injectExternalRuntimeCorePlugin";
9780
9889
  function isInjectExternalRuntimeCorePlugin(specifier) {
@@ -9885,6 +9994,11 @@ function federation(mfUserOptions) {
9885
9994
  {
9886
9995
  name: "vite:module-federation-virtual-modules",
9887
9996
  enforce: "pre",
9997
+ configureServer(server) {
9998
+ server.watcher.on("change", invalidateSharedExportInspectionCache);
9999
+ server.watcher.on("add", invalidateSharedExportInspectionCache);
10000
+ server.watcher.on("unlink", invalidateSharedExportInspectionCache);
10001
+ },
9888
10002
  resolveId(id) {
9889
10003
  if (id === "@module-federation/vite/ssrEntryLoader") return resolveImportPath(id);
9890
10004
  let virtualModule = VirtualModule.findById(id);
@@ -10155,6 +10269,10 @@ function federation(mfUserOptions) {
10155
10269
  }
10156
10270
  },
10157
10271
  load(id, loadOptions) {
10272
+ if (id.includes("__loadShare__") && id.endsWith("?commonjs-proxy")) {
10273
+ const target = id.slice(id.startsWith("\0") ? 1 : 0, -15);
10274
+ return `export { __moduleExports as default } from ${JSON.stringify(target)};`;
10275
+ }
10158
10276
  const loadVirtualModule = (importFalseExportUsage) => {
10159
10277
  if (!id.includes("__loadShare__") && !id.includes("__loadRemote__")) return;
10160
10278
  if (id.includes("__loadRemote__") && !refreshLoadRemoteModuleForEnvironment(id, this, loadOptions)) return;
@@ -5,11 +5,7 @@ const COMMON_SHARED_SUBPATHS = {
5
5
  "react/jsx-dev-runtime",
6
6
  "react/compiler-runtime"
7
7
  ],
8
- "react-dom": [
9
- "react-dom/client",
10
- "react-dom/server",
11
- "react-dom/server.browser"
12
- ],
8
+ "react-dom": ["react-dom/client", "react-dom/profiling"],
13
9
  "solid-js": [
14
10
  "solid-js/web",
15
11
  "solid-js/store",
@@ -2,6 +2,7 @@ import { n as normalizePathForImport } from "./buildPaths-BkaQHrd2.js";
2
2
  import { _ as mfError, g as createModuleFederationError, l as hasPackageDependency, p as resolveImportPath } from "./dtsConstants-DyJrx8ah.js";
3
3
  import fs from "fs";
4
4
  import * as path$1 from "node:path";
5
+ import os from "os";
5
6
  import { normalizeOptions } from "@module-federation/sdk";
6
7
  import { consumeTypesAPI, generateTypesAPI, isTSProject, normalizeConsumeTypesOptions, normalizeDtsOptions, normalizeGenerateTypesOptions } from "@module-federation/dts-plugin";
7
8
  import { rpc } from "@module-federation/dts-plugin/core";
@@ -12,7 +13,26 @@ const DEFAULT_DEV_OPTIONS = {
12
13
  disableDynamicRemoteTypeHints: false
13
14
  };
14
15
  const DYNAMIC_HINTS_PLUGIN = "@module-federation/dts-plugin/dynamic-remote-type-hints-plugin";
15
- const getIPv4 = () => process.env["FEDERATION_IPV4"] || "127.0.0.1";
16
+ const localIpv4 = "127.0.0.1";
17
+ const getIpv4Interfaces = () => {
18
+ try {
19
+ const interfaces = os.networkInterfaces();
20
+ const ipv4Interfaces = [];
21
+ Object.values(interfaces).forEach((detail) => {
22
+ detail?.forEach((detail) => {
23
+ const familyV4Value = typeof detail.family === "string" ? "IPv4" : 4;
24
+ if (detail.family === familyV4Value && detail.address !== localIpv4) ipv4Interfaces.push(detail);
25
+ });
26
+ });
27
+ return ipv4Interfaces;
28
+ } catch (_err) {
29
+ return [];
30
+ }
31
+ };
32
+ const getIPv4 = () => {
33
+ if (process.env["FEDERATION_IPV4"]) return process.env["FEDERATION_IPV4"];
34
+ return (getIpv4Interfaces()[0] || { address: localIpv4 }).address;
35
+ };
16
36
  const DEV_TYPES_FOLDER = ".dev-server";
17
37
  const forkDevWorkerPath = (() => {
18
38
  return resolveImportPath("@module-federation/dts-plugin/dist/fork-dev-worker.js");
@@ -606,7 +606,7 @@ async function importTempModule(filePath, versionKey) {
606
606
  }
607
607
  let warnedVmUnavailable = false;
608
608
  async function tryVmStrategy(ssrEntry, options) {
609
- const { loadViaVmStrategy, isVmStrategyAvailable } = await import("./ssrVmStrategy-B0fCaHs5.js");
609
+ const { loadViaVmStrategy, isVmStrategyAvailable } = await import("./ssrVmStrategy-tpI6we9Q.js");
610
610
  if (!await isVmStrategyAvailable()) {
611
611
  if (!warnedVmUnavailable) {
612
612
  warnedVmUnavailable = true;
@@ -1,5 +1,5 @@
1
- import { a as getCommonSharedSubpaths } from "./pathNormalization-DvgU8LIp.js";
2
- import { c as readResponseTextBounded, n as neutralizeBrowserPreloadHelpers, s as fetchWithTimeout, t as SsrEntryHttpError } from "./ssrEntryLoader-0NnTjWR1.js";
1
+ import { a as getCommonSharedSubpaths } from "./pathNormalization-CHct3UwV.js";
2
+ import { c as readResponseTextBounded, n as neutralizeBrowserPreloadHelpers, s as fetchWithTimeout, t as SsrEntryHttpError } from "./ssrEntryLoader-BMtjS_Vl.js";
3
3
  //#region src/utils/ssrVmStrategy.ts
4
4
  /**
5
5
  * vm.SourceTextModule strategy for loading remote SSR entries.
@@ -1,2 +1,2 @@
1
- import { i as ssrEntryLoaderPlugin, n as neutralizeBrowserPreloadHelpers, r as revalidate, t as SsrEntryHttpError } from "../ssrEntryLoader-0NnTjWR1.js";
1
+ import { i as ssrEntryLoaderPlugin, n as neutralizeBrowserPreloadHelpers, r as revalidate, t as SsrEntryHttpError } from "../ssrEntryLoader-BMtjS_Vl.js";
2
2
  export { SsrEntryHttpError, ssrEntryLoaderPlugin as default, neutralizeBrowserPreloadHelpers, revalidate };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/vite",
3
- "version": "1.21.0",
3
+ "version": "1.21.2",
4
4
  "description": "Vite plugin for Module Federation",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -93,4 +93,4 @@
93
93
  "vite": "8.2.0",
94
94
  "vitest": "4.1.10"
95
95
  }
96
- }
96
+ }