@module-federation/vite 1.21.5 → 1.21.6

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.
@@ -43,5 +43,24 @@ function isAbsoluteUrl(src) {
43
43
  if (/^[a-z]:[\\/]/i.test(src)) return false;
44
44
  return EXTERNAL_URL_RE.test(src);
45
45
  }
46
+ const HASH_PLACEHOLDER_RE = /(?:[._-]?\[hash(?::\d+)?\])/g;
47
+ function hasFileExtension(fileName) {
48
+ return fileName.slice(Math.max(fileName.lastIndexOf("/"), fileName.lastIndexOf("\\")) + 1).lastIndexOf(".") > 0;
49
+ }
50
+ /**
51
+ * Resolve a bundler `filename` template that still contains `[hash]` placeholders
52
+ * into the concrete, stable file name Module Federation serves.
53
+ *
54
+ * The federation entries are emitted by us rather than hashed by the bundler, so
55
+ * the placeholder is dropped instead of being substituted. When stripping it also
56
+ * removes the extension (`mf-[hash:8]` → `mf`), `.js` is appended so the result
57
+ * stays a loadable module. The extension check deliberately looks at the basename
58
+ * only — a dotted directory (`assets/v1.2/entry`) must not be mistaken for one.
59
+ */
60
+ function resolveHashPlaceholderFileName(fileName) {
61
+ if (!fileName.includes("[hash")) return fileName;
62
+ const normalized = fileName.replace(HASH_PLACEHOLDER_RE, "");
63
+ return hasFileExtension(normalized) ? normalized : `${normalized}.js`;
64
+ }
46
65
  //#endregion
47
- export { normalizePathForImport as n, rebaseImport as r, EXTERNAL_URL_RE as t };
66
+ export { resolveHashPlaceholderFileName as i, normalizePathForImport as n, rebaseImport as r, EXTERNAL_URL_RE as t };
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as normalizePathForImport, r as rebaseImport } from "./buildPaths-BkaQHrd2.js";
1
+ import { i as resolveHashPlaceholderFileName, n as normalizePathForImport, r as rebaseImport } from "./buildPaths-BoaQTkxt.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-BsaLBaaK.js";
3
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";
4
4
  import { createRequire } from "node:module";
@@ -14,13 +14,23 @@ import * as fs$1 from "node:fs";
14
14
  import { existsSync as existsSync$1, readFileSync as readFileSync$1 } from "node:fs";
15
15
  import { pathToFileURL as pathToFileURL$1 } from "node:url";
16
16
  import { isIPv6 } from "node:net";
17
+ //#region src/utils/regexEscape.ts
18
+ const REGEXP_SPECIAL_CHARS_RE = /[.*+?^${}()|[\]\\]/g;
19
+ /**
20
+ * Escape `value` so it matches literally when interpolated into a regex source.
21
+ *
22
+ * Federation interpolates user-controlled strings — package names, chunk file
23
+ * names, virtual module ids — into generated matchers. Those routinely contain
24
+ * `.`, `+`, `[` and `\`, which would otherwise change what the pattern matches.
25
+ */
26
+ function escapeRegExp(value) {
27
+ return value.replace(REGEXP_SPECIAL_CHARS_RE, "\\$&");
28
+ }
29
+ //#endregion
17
30
  //#region src/utils/bundleHelpers.ts
18
31
  function isOutputChunk$1(chunk) {
19
32
  return chunk.type === "chunk";
20
33
  }
21
- function escapeRegExp$2(value) {
22
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
23
- }
24
34
  /**
25
35
  * Whether `code` references `name` as a whole identifier.
26
36
  *
@@ -30,7 +40,7 @@ function escapeRegExp$2(value) {
30
40
  * as "unused", which orphans a still-referenced import.
31
41
  */
32
42
  function isIdentifierReferenced(name, code) {
33
- return new RegExp(`(?<![$\\w])${escapeRegExp$2(name)}(?![$\\w])`).test(code);
43
+ return new RegExp(`(?<![$\\w])${escapeRegExp(name)}(?![$\\w])`).test(code);
34
44
  }
35
45
  function getProxyBaseName(fileName) {
36
46
  return fileName.replace(/^.*\//, "").replace(/\.js$/, "").replace(/-[A-Za-z0-9_-]+$/, "");
@@ -40,10 +50,10 @@ function getProxyBaseName(fileName) {
40
50
  * regex end-anchor, so the pattern would silently match nothing.
41
51
  */
42
52
  function functionDeclarationRegExp(name) {
43
- return new RegExp(`function\\s+${escapeRegExp$2(name)}\\s*\\(`);
53
+ return new RegExp(`function\\s+${escapeRegExp(name)}\\s*\\(`);
44
54
  }
45
55
  function extractFunctionDeclaration(code, functionName) {
46
- const funcRe = new RegExp(`function\\s+${escapeRegExp$2(functionName)}\\s*\\([^)]*\\)\\s*\\{`);
56
+ const funcRe = new RegExp(`function\\s+${escapeRegExp(functionName)}\\s*\\([^)]*\\)\\s*\\{`);
47
57
  const funcStart = code.search(funcRe);
48
58
  if (funcStart < 0) return;
49
59
  let depth = 0;
@@ -127,7 +137,7 @@ function rewriteEsmProxyConsumers(code, proxyChunks) {
127
137
  const claimedLocals = /* @__PURE__ */ new Set();
128
138
  for (const [proxyFileName, proxyInfo] of Array.from(proxyChunks.entries())) {
129
139
  const proxyBaseName = getProxyBaseName(proxyFileName);
130
- const importMatch = new RegExp(`import\\s*\\{([^}]+)\\}\\s*from\\s*["']([^"']*${escapeRegExp$2(proxyBaseName)}[^"']*)["']\\s*;?`).exec(nextCode);
140
+ const importMatch = new RegExp(`import\\s*\\{([^}]+)\\}\\s*from\\s*["']([^"']*${escapeRegExp(proxyBaseName)}[^"']*)["']\\s*;?`).exec(nextCode);
131
141
  if (!importMatch) continue;
132
142
  const fullImport = importMatch[0];
133
143
  const bindings = importMatch[1].split(",").map((s) => {
@@ -184,7 +194,7 @@ function rewriteSystemProxyConsumers(code, systemProxyInfo) {
184
194
  let nextCode = code;
185
195
  for (const [proxyFileName, proxyInfo] of Array.from(systemProxyInfo.entries())) {
186
196
  const proxyBaseName = getProxyBaseName(proxyFileName);
187
- const depMatch = new RegExp(`["']([^"']*${escapeRegExp$2(proxyBaseName)}[^"']*)["']`).exec(nextCode);
197
+ const depMatch = new RegExp(`["']([^"']*${escapeRegExp(proxyBaseName)}[^"']*)["']`).exec(nextCode);
188
198
  if (!depMatch) continue;
189
199
  let setterIndex = 0;
190
200
  const depListMatch = nextCode.match(/System\.register\(\[([\s\S]*?)\]/);
@@ -940,7 +950,7 @@ function normalizeModuleFederationOptions(options) {
940
950
  disableSnapshot: options.disableSnapshot,
941
951
  experiments: normalizeExperiments(options.experiments)
942
952
  };
943
- if (normalized.experiments.ssrMode === "ISLAND" && Object.prototype.hasOwnProperty.call(normalized.shared, "react")) mfWarn("Island expose generation is disabled because experiments.ssrMode is \"ISLAND\" and React is configured as shared. Remove \"react\" from shared to generate island exposes, or remove ssrMode to use standard shared rendering.");
953
+ if (normalized.experiments.ssrMode === "ISLAND" && Object.hasOwn(normalized.shared, "react")) mfWarn("Island expose generation is disabled because experiments.ssrMode is \"ISLAND\" and React is configured as shared. Remove \"react\" from shared to generate island exposes, or remove ssrMode to use standard shared rendering.");
944
954
  explicitSharedKeysByOptions.set(normalized, new Set(explicitSharedKeys));
945
955
  return config = normalized;
946
956
  }
@@ -958,11 +968,8 @@ const idCacheMap = {};
958
968
  const VITE_ID_PREFIX = "/@id/";
959
969
  const VITE_ENCODED_NULL_BYTE_PREFIX = `${VITE_ID_PREFIX}__x00__`;
960
970
  const MF_OWNER_INFIX = "__mf_owner__";
961
- function escapeRegExp$1(value) {
962
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
963
- }
964
971
  function createViteEncodedIdPrefixRegExp(sourcePrefix = "") {
965
- return new RegExp(`^(?:${escapeRegExp$1(VITE_ENCODED_NULL_BYTE_PREFIX)})?${sourcePrefix}`);
972
+ return new RegExp(`^(?:${escapeRegExp(VITE_ENCODED_NULL_BYTE_PREFIX)})?${sourcePrefix}`);
966
973
  }
967
974
  function toViteEncodedId(id) {
968
975
  return `${VITE_ENCODED_NULL_BYTE_PREFIX}${id}`;
@@ -1103,7 +1110,7 @@ function serializeRuntimeOptions(options) {
1103
1110
  if (val instanceof Map) return `new Map([${Array.from(val.entries()).map(([k, v]) => `[${valueToCode(k)}, ${valueToCode(v)}]`).join(", ")}])`;
1104
1111
  if (val instanceof Set) return `new Set([${Array.from(val.values()).map(valueToCode).join(", ")}])`;
1105
1112
  const properties = [];
1106
- for (const key in val) if (Object.prototype.hasOwnProperty.call(val, key)) properties.push(`${toSafeJsLiteral(key)}: ${valueToCode(val[key])}`);
1113
+ for (const key in val) if (Object.hasOwn(val, key)) properties.push(`${toSafeJsLiteral(key)}: ${valueToCode(val[key])}`);
1107
1114
  return `{${properties.join(", ")}}`;
1108
1115
  } finally {
1109
1116
  ancestors.delete(val);
@@ -1112,7 +1119,7 @@ function serializeRuntimeOptions(options) {
1112
1119
  return toSafeJsLiteral(String(val));
1113
1120
  }
1114
1121
  const topLevelProps = [];
1115
- for (const key in options) if (Object.prototype.hasOwnProperty.call(options, key)) topLevelProps.push(`${toSafeJsLiteral(key)}: ${valueToCode(options[key])}`);
1122
+ for (const key in options) if (Object.hasOwn(options, key)) topLevelProps.push(`${toSafeJsLiteral(key)}: ${valueToCode(options[key])}`);
1116
1123
  return `{${topLevelProps.join(", ")}}`;
1117
1124
  }
1118
1125
  const NATIVE_FUNCTION_SOURCE = /\{\s*\[native code\]\s*\}\s*$/;
@@ -1223,7 +1230,7 @@ function isReactComponentFile(filePath, seen = /* @__PURE__ */ new Set()) {
1223
1230
  */
1224
1231
  function getReactIslandExposes(options, root) {
1225
1232
  if (options.experiments.ssrMode !== "ISLAND") return /* @__PURE__ */ new Set();
1226
- if (Object.prototype.hasOwnProperty.call(options.shared, "react")) return /* @__PURE__ */ new Set();
1233
+ if (Object.hasOwn(options.shared, "react")) return /* @__PURE__ */ new Set();
1227
1234
  const islandExposes = /* @__PURE__ */ new Set();
1228
1235
  for (const [key, expose] of Object.entries(options.exposes)) {
1229
1236
  const sourceFile = resolveSourceFile(expose.import, root);
@@ -3707,6 +3714,7 @@ function getMaterializedShares(options) {
3707
3714
  const pending = [...shares];
3708
3715
  while (pending.length) {
3709
3716
  const pkg = pending.pop();
3717
+ const share = getNormalizeShareItem(pkg, resolvedOptions);
3710
3718
  const packageName = getPackageName(pkg);
3711
3719
  const packageJson = getInstalledPackageJson(pkg)?.packageJson ?? (pkg !== packageName ? getInstalledPackageJson(packageName)?.packageJson : void 0);
3712
3720
  const dependencies = {
@@ -3716,7 +3724,8 @@ function getMaterializedShares(options) {
3716
3724
  };
3717
3725
  for (const dependency of Object.keys(dependencies)) {
3718
3726
  const sharedDependency = configured.get(dependency);
3719
- if (sharedDependency && !shares.has(sharedDependency)) {
3727
+ const dependencyShare = sharedDependency ? getNormalizeShareItem(sharedDependency, resolvedOptions) : void 0;
3728
+ if (sharedDependency && !shares.has(sharedDependency) && dependencyShare?.scope === share?.scope) {
3720
3729
  shares.add(sharedDependency);
3721
3730
  pending.push(sharedDependency);
3722
3731
  }
@@ -4438,9 +4447,9 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
4438
4447
  return exposesMapPromise
4439
4448
  }
4440
4449
 
4441
- async function init(shared = {}, initScope = []) {
4450
+ async function init(shared = {}, initScope = [], remoteEntryInitOptions = {}) {
4442
4451
  ${sharedCacheHelperCode}
4443
- const getShareScope = (scopeName) => ${hasMultipleShareScopes} ? (shared?.[scopeName] || {}) : shared;
4452
+ const getShareScope = (scopeName) => remoteEntryInitOptions.shareScopeMap?.[scopeName] ?? (${hasMultipleShareScopes} ? (shared?.[scopeName] || {}) : shared);
4444
4453
  const getShareScopeNames = (share) => {
4445
4454
  const configuredScopes = Array.isArray(share?.scope) ? share.scope : [share?.scope || shareScopeName];
4446
4455
  if (!${hasMultipleShareScopes}) return configuredScopes;
@@ -5272,9 +5281,9 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
5272
5281
  return (exposesMap[moduleName])().then(res => () => res)
5273
5282
  }
5274
5283
  ${guardHostAutoInit ? `let __mfInitPromise;
5275
- function __mfGuardedInit(shared, initScope) {
5284
+ function __mfGuardedInit(shared, initScope, remoteEntryInitOptions) {
5276
5285
  if (shared === undefined && __mfInitPromise) return __mfInitPromise;
5277
- __mfInitPromise = init(shared, initScope);
5286
+ __mfInitPromise = init(shared, initScope, remoteEntryInitOptions);
5278
5287
  return __mfInitPromise;
5279
5288
  }
5280
5289
  export { __mfGuardedInit as init, getExposes as get }` : `export { init, getExposes as get }`}
@@ -5324,6 +5333,12 @@ function generateHostAutoInitCode(remoteEntryImport, _command = "build", options
5324
5333
  const {usedShared} = await import("${getLocalSharedImportMapPath(options)}");
5325
5334
  ${normalizeRuntimeShareCode}
5326
5335
  ${shouldPreloadShares ? `
5336
+ const __mfHasAlternativeSharedVersion = (pkg, share) =>
5337
+ (Array.isArray(share.scope) ? share.scope : [share.scope || 'default']).some(
5338
+ (scopeName) => Object.keys(runtime.shareScopeMap?.[scopeName]?.[pkg] || {}).some(
5339
+ (version) => version !== share.version
5340
+ )
5341
+ );
5327
5342
  const __mfHostInitShareBatches = ${hostInitShareBatches};
5328
5343
  for (const __mfHostInitShareBatch of __mfHostInitShareBatches) {
5329
5344
  await Promise.all(__mfHostInitShareBatch.map(async (pkg) => {
@@ -5336,7 +5351,10 @@ function generateHostAutoInitCode(remoteEntryImport, _command = "build", options
5336
5351
  const cacheDescriptor = __mfGetSharedCacheDescriptor(pkg, share.shareConfig?.singleton, share.version, share.scope);
5337
5352
  if (
5338
5353
  __mfReadSharedCache(__mfModuleCache.share, cacheDescriptor) !== undefined &&
5339
- __mfReadSharedCacheOwner(__mfModuleCache.share, cacheDescriptor) ${_command === "serve" ? "!== undefined" : `=== ${cacheOwner}`}
5354
+ ${_command === "serve" ? `__mfReadSharedCacheOwner(__mfModuleCache.share, cacheDescriptor) !== undefined` : `(
5355
+ (!share.shareConfig?.singleton && __mfReadSharedCacheOwner(__mfModuleCache.share, cacheDescriptor) === ${cacheOwner}) ||
5356
+ (share.shareConfig?.singleton && !__mfHasAlternativeSharedVersion(pkg, share))
5357
+ )`}
5340
5358
  ) return;
5341
5359
  // An import:false share has nothing to load until a foreign provider
5342
5360
  // registers: its own stub getter throws by construction.
@@ -5431,8 +5449,9 @@ function getPendingSharesState(options) {
5431
5449
  function generatePendingSharesCode(command = "build", options) {
5432
5450
  const resolvedOptions = options ?? getNormalizeModuleFederationOptions();
5433
5451
  const pendingShareImports = command === "build" ? getMaterializedShares(options).filter((pkg) => {
5434
- const shareItem = resolvedOptions.shared?.[pkg];
5435
- return Boolean(shareItem) && !pkg.endsWith("/") && shareItem.shareConfig.import !== false && !shareItem.shareConfig.treeShaking;
5452
+ const shareItem = getShareItemForPreload(pkg, resolvedOptions);
5453
+ if (!shareItem || pkg.endsWith("/")) return false;
5454
+ return shareItem.shareConfig.import !== false && !shareItem.shareConfig.treeShaking;
5436
5455
  }).map((pkg) => `[${toSafeJsLiteral(pkg)}, () => import(${toSafeJsLiteral(getLoadShareModulePath(pkg, false, options))})]`) : [];
5437
5456
  return `
5438
5457
  ${getRuntimeModuleCacheBootstrapCode()}
@@ -5525,8 +5544,15 @@ function getScopedUsedRemotesMap(options) {
5525
5544
  return scoped;
5526
5545
  }
5527
5546
  function recordUsedRemote(map, remoteKey, remoteModule) {
5547
+ ensureUsedRemoteKey(map, remoteKey).add(remoteModule);
5548
+ }
5549
+ function ensureUsedRemoteKey(map, remoteKey) {
5528
5550
  if (!map[remoteKey]) map[remoteKey] = /* @__PURE__ */ new Set();
5529
- map[remoteKey].add(remoteModule);
5551
+ return map[remoteKey];
5552
+ }
5553
+ function ensureUsedRemote(remoteKey, options) {
5554
+ ensureUsedRemoteKey(usedRemotesMap, remoteKey);
5555
+ if (options) ensureUsedRemoteKey(getScopedUsedRemotesMap(options), remoteKey);
5530
5556
  }
5531
5557
  function addUsedRemote(remoteKey, remoteModule, options) {
5532
5558
  recordUsedRemote(usedRemotesMap, remoteKey, remoteModule);
@@ -5833,7 +5859,7 @@ function generateRemotes(id, command, enableSsrInit = false, consumer = "unified
5833
5859
  }
5834
5860
  //#endregion
5835
5861
  //#region src/plugins/pluginAddEntry.ts
5836
- const isPreloadableVirtualMfChunk = (name) => name.includes("virtual_mf") && !name.includes("__prebuild__");
5862
+ const isPreloadableVirtualMfChunk = (name) => name.includes("virtual_mf") && !name.includes("__prebuild__") && !name.includes("__loadShare__");
5837
5863
  const HOST_INIT_PRELOAD_CHUNKS = [
5838
5864
  (name) => name === "hostInit",
5839
5865
  (name) => name === "remoteEntry",
@@ -5935,12 +5961,6 @@ function stripQueryAndHash$1(file) {
5935
5961
  function isReactRouterClientRouteInput(file) {
5936
5962
  return /[?&]__react-router-build-client-route(?:[=&]|$)/.test(file);
5937
5963
  }
5938
- function resolveDevHashEntryFileName$1(fileName) {
5939
- if (!fileName.includes("[hash")) return fileName;
5940
- const normalized = fileName.replace(/(?:[._-]?\[hash(?::\d+)?\])/g, "");
5941
- const baseName = path$1.basename(normalized);
5942
- return path$1.extname(baseName) ? normalized : `${normalized}.js`;
5943
- }
5944
5964
  function getBuildInput(config) {
5945
5965
  return config.build?.rollupOptions?.input ?? config.build?.rolldownOptions?.input;
5946
5966
  }
@@ -6058,7 +6078,7 @@ const __mfCurrentScript = document.currentScript;
6058
6078
  const normalizedOptions = federationOptions ?? getNormalizeModuleFederationOptions();
6059
6079
  const isLoadedFirstClientBuild = (_command === "build" || viteConfig?.command === "build") && waitsForInit && !viteConfig?.build?.ssr && normalizedOptions.shareStrategy === "loaded-first";
6060
6080
  if (normalizedOptions.shareStrategy === "loaded-first" && !isLoadedFirstClientBuild) return [];
6061
- const remoteSources = isLoadedFirstClientBuild ? Array.from(getPreloadRemotes(normalizedOptions)) : Object.entries(getUsedRemotesMap(federationOptions)).flatMap(([, remotes]) => Array.from(remotes)).filter((remote) => !federationOptions || !isDynamicOnlyRemote(remote, federationOptions));
6081
+ const remoteSources = isLoadedFirstClientBuild ? Array.from(getPreloadRemotes(normalizedOptions)) : Object.keys(getUsedRemotesMap(federationOptions));
6062
6082
  return Array.from(new Set(remoteSources.flatMap((remote) => {
6063
6083
  const registration = getRemoteRegistration(remote, normalizedOptions.remotes, federationOptions);
6064
6084
  return registration && (registration.type === "module" || registration.type === "esm") && /^(?:https?:)?\/\//.test(registration.entry) ? [registration.entry] : [];
@@ -6091,7 +6111,7 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6091
6111
  ` : "";
6092
6112
  const sharedPreloadSources = _command === "serve" && waitsForInit && Object.keys(normalizedOptions.exposes || {}).length > 0 && Object.keys(normalizedOptions.remotes || {}).length === 0 && federationOptions ? Array.from(getUsedShares(federationOptions)).filter((pkg) => !pkg.endsWith("/")).filter((pkg) => {
6093
6113
  const shareItem = federationOptions.shared[pkg] || Object.entries(federationOptions.shared).find(([key]) => key.endsWith("/") && pkg.startsWith(key))?.[1];
6094
- const isExplicitShare = Object.prototype.hasOwnProperty.call(federationOptions.shared, pkg);
6114
+ const isExplicitShare = Object.hasOwn(federationOptions.shared, pkg);
6095
6115
  return shareItem?.shareConfig?.singleton === true && shareItem?.shareConfig?.import !== false && !shareItem?.shareConfig?.treeShaking && (isExplicitShare || typeof shareItem?.shareConfig?.import === "string" || Boolean(getProjectResolvedImportPath(pkg)));
6096
6116
  }).map((pkg) => toViteEncodedId(getLoadShareModulePath(pkg, false, federationOptions))) : [];
6097
6117
  const sharedPreloadBlock = sharedPreloadSources.length > 0 ? `
@@ -6256,7 +6276,7 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6256
6276
  next();
6257
6277
  return;
6258
6278
  }
6259
- const devFileName = resolveDevHashEntryFileName$1(fileName);
6279
+ const devFileName = resolveHashPlaceholderFileName(fileName);
6260
6280
  if (devFileName !== fileName && req.url?.startsWith((viteConfig.base + devFileName).replace(/^\/?/, "/"))) req.url = req.url.replace(devFileName, fileName);
6261
6281
  if (req.url && req.url.startsWith((viteConfig.base + fileName).replace(/^\/?/, "/"))) {
6262
6282
  req.url = devEntryPath;
@@ -7231,6 +7251,9 @@ function pluginExternalRuntimeCore() {
7231
7251
  };
7232
7252
  }
7233
7253
  //#endregion
7254
+ //#region package.json
7255
+ var version$1 = "1.21.6";
7256
+ //#endregion
7234
7257
  //#region src/virtualModules/index.ts
7235
7258
  function initVirtualModules(command, remoteEntryId, enableSsrInit = false, options) {
7236
7259
  writeLocalSharedImportMap(options);
@@ -7458,21 +7481,22 @@ const REMOTE_ENTRY_SSR_ID = "virtual:mf-REMOTE_ENTRY_SSR_ID";
7458
7481
  function getRemoteEntrySSRId(options) {
7459
7482
  return `${REMOTE_ENTRY_SSR_ID}:${getVirtualModuleScopeKey(options)}`;
7460
7483
  }
7461
- function stripSsrFilenameHashPlaceholder(filename) {
7462
- if (!filename.includes("[hash")) return filename;
7463
- filename = filename.replace(/(?:[._-]?\[hash(?::\d+)?\])/g, "");
7464
- if (!/\.[^.]+$/.test(filename)) filename = `${filename}.js`;
7465
- return filename;
7484
+ const FILE_EXTENSION_RE = /\.[^.]+$/;
7485
+ function getSsrFileNameParts(browserFilename) {
7486
+ const filename = resolveHashPlaceholderFileName(browserFilename);
7487
+ const ext = FILE_EXTENSION_RE.exec(filename)?.[0];
7488
+ return {
7489
+ base: ext ? filename.slice(0, filename.length - ext.length) : filename,
7490
+ ext
7491
+ };
7466
7492
  }
7467
7493
  function getSsrRemoteEntryFileName(browserFilename) {
7468
- const filename = stripSsrFilenameHashPlaceholder(browserFilename);
7469
- const ext = filename.match(/\.[^.]+$/)?.[0] || ".js";
7470
- return `${filename.slice(0, filename.length - ext.length)}.ssr${ext}`;
7494
+ const { base, ext } = getSsrFileNameParts(browserFilename);
7495
+ return `${base}.ssr${ext ?? ".js"}`;
7471
7496
  }
7472
7497
  function getSsrExposesFileName(browserFilename) {
7473
- const filename = stripSsrFilenameHashPlaceholder(browserFilename);
7474
- const ext = filename.match(/\.[^.]+$/)?.[0];
7475
- return `${ext ? filename.slice(0, filename.length - ext.length) : filename}.exposes.js`;
7498
+ const { base } = getSsrFileNameParts(browserFilename);
7499
+ return `${base}.exposes.js`;
7476
7500
  }
7477
7501
  /** Singleton map for SSR loadShare: expand `pkg/` via usedShares; never serialize the prefix. */
7478
7502
  function getSsrSharedSingletons(options) {
@@ -7650,12 +7674,6 @@ function resolveTypesMeta(dts) {
7650
7674
  api: `${typesFolder}.d.ts`
7651
7675
  };
7652
7676
  }
7653
- function resolveDevRemoteEntryFileName(fileName) {
7654
- if (!fileName.includes("[hash")) return fileName;
7655
- const normalized = fileName.replace(/(?:[._-]?\[hash(?::\d+)?\])/g, "");
7656
- const baseName = path$1.basename(normalized);
7657
- return path$1.extname(baseName) ? normalized : `${normalized}.js`;
7658
- }
7659
7677
  function createRemoteEntryAssetMap(fileName) {
7660
7678
  return {
7661
7679
  js: {
@@ -7741,10 +7759,10 @@ const Manifest = (providedOptions) => {
7741
7759
  let mfManifestStatsName = mfManifestName ? getStatsFileName(mfManifestName) : void 0;
7742
7760
  const isConsumerProject = Object.keys(mfOptions.exposes).length === 0;
7743
7761
  let disableAssetsAnalyze = false;
7744
- const getDefaultDisableAssetsAnalyze = (command) => command === "serve" && isConsumerProject && (typeof manifestOptions !== "object" || !Object.prototype.hasOwnProperty.call(manifestOptions, "disableAssetsAnalyze"));
7762
+ const getDefaultDisableAssetsAnalyze = (command) => command === "serve" && isConsumerProject && (typeof manifestOptions !== "object" || !Object.hasOwn(manifestOptions, "disableAssetsAnalyze"));
7745
7763
  const getConfiguredDisableAssetsAnalyze = (command) => {
7746
7764
  if (typeof manifestOptions === "object" && manifestOptions !== null) {
7747
- if (Object.prototype.hasOwnProperty.call(manifestOptions, "disableAssetsAnalyze")) return manifestOptions.disableAssetsAnalyze === true;
7765
+ if (Object.hasOwn(manifestOptions, "disableAssetsAnalyze")) return manifestOptions.disableAssetsAnalyze === true;
7748
7766
  }
7749
7767
  return getDefaultDisableAssetsAnalyze(command);
7750
7768
  };
@@ -7774,7 +7792,7 @@ const Manifest = (providedOptions) => {
7774
7792
  */
7775
7793
  configureServer(server) {
7776
7794
  server.middlewares.use((req, res, next) => {
7777
- const devRemoteEntryFile = resolveDevRemoteEntryFileName(filename);
7795
+ const devRemoteEntryFile = resolveHashPlaceholderFileName(filename);
7778
7796
  if (devRemoteEntryFile !== filename && Object.keys(mfOptions.exposes).length > 0 && req.url?.startsWith((viteConfig.base + devRemoteEntryFile).replace(/^\/?/, "/"))) {
7779
7797
  req.url = req.url.replace(devRemoteEntryFile, filename);
7780
7798
  next();
@@ -7817,7 +7835,7 @@ const Manifest = (providedOptions) => {
7817
7835
  } : void 0,
7818
7836
  types: resolveTypesMeta(mfOptions.dts),
7819
7837
  globalName: name,
7820
- pluginVersion: "0.2.5",
7838
+ pluginVersion: version$1,
7821
7839
  publicPath
7822
7840
  }
7823
7841
  });
@@ -7861,7 +7879,7 @@ const Manifest = (providedOptions) => {
7861
7879
  const expectedSsrRemoteEntryFile = getSsrRemoteEntryFileName(mfOptions.filename);
7862
7880
  const foundSsrRemoteEntryFile = Object.values(bundle).find((file) => file.fileName === expectedSsrRemoteEntryFile)?.fileName;
7863
7881
  if (foundRemoteEntryFile) remoteEntryFile = foundRemoteEntryFile;
7864
- ssrRemoteEntryFile = foundSsrRemoteEntryFile || (_command === "serve" ? getSsrRemoteEntryFileName(resolveDevRemoteEntryFileName(mfOptions.filename)) : expectedSsrRemoteEntryFile);
7882
+ ssrRemoteEntryFile = foundSsrRemoteEntryFile || (_command === "serve" ? getSsrRemoteEntryFileName(resolveHashPlaceholderFileName(mfOptions.filename)) : expectedSsrRemoteEntryFile);
7865
7883
  const allCssAssets = mfOptions.bundleAllCSS && !disableAssetsAnalyze ? collectCssAssets(bundle) : /* @__PURE__ */ new Set();
7866
7884
  if (allCssAssets.size > 0) {
7867
7885
  const secondaryCss = /* @__PURE__ */ new Set();
@@ -7886,6 +7904,13 @@ const Manifest = (providedOptions) => {
7886
7904
  expandExposeAssets(filesMap, exposesModules, bundle, foundRemoteEntryFile, mfOptions);
7887
7905
  const fileToShareKey = await buildFileToShareKeyMap(getUsedShares(mfOptions), this.resolve.bind(this), mfOptions);
7888
7906
  processModuleAssets(Object.fromEntries(Object.entries(bundle).filter(([, file]) => !isTreeShakingProviderChunk(file))), filesMap, (modulePath) => fileToShareKey.get(modulePath));
7907
+ for (const shareKey of getUsedShares(mfOptions)) {
7908
+ const shareItem = getNormalizeShareItem(shareKey, mfOptions);
7909
+ const assets = filesMap[shareKey];
7910
+ if (!assets || shareItem?.shareConfig.eager === true) continue;
7911
+ assets.js.async.push(...assets.js.sync.splice(0));
7912
+ assets.css.async.push(...assets.css.sync.splice(0));
7913
+ }
7889
7914
  if (mfOptions.bundleAllCSS) addCssAssetsToAllExports(filesMap, allCssAssets);
7890
7915
  filesMap = deduplicateAssets(filesMap);
7891
7916
  }
@@ -7913,14 +7938,14 @@ const Manifest = (providedOptions) => {
7913
7938
  function generateMFManifest(preloadMap, disableAssetsAnalyze = false) {
7914
7939
  const options = mfOptions;
7915
7940
  const { name, varFilename } = options;
7916
- const resolvedRemoteEntryFile = _command === "serve" ? remoteEntryFile || resolveDevRemoteEntryFileName(filename) : remoteEntryFile;
7941
+ const resolvedRemoteEntryFile = _command === "serve" ? remoteEntryFile || resolveHashPlaceholderFileName(filename) : remoteEntryFile;
7917
7942
  const remoteEntry = {
7918
7943
  name: resolvedRemoteEntryFile,
7919
7944
  path: "",
7920
7945
  type: "module"
7921
7946
  };
7922
7947
  const ssrRemoteEntry = {
7923
- name: ssrRemoteEntryFile || getSsrRemoteEntryFileName(_command === "serve" ? resolveDevRemoteEntryFileName(filename) : filename),
7948
+ name: ssrRemoteEntryFile || getSsrRemoteEntryFileName(_command === "serve" ? resolveHashPlaceholderFileName(filename) : filename),
7924
7949
  path: _command === "serve" ? "/__mf_ssr__/" : "",
7925
7950
  type: "module"
7926
7951
  };
@@ -8007,7 +8032,7 @@ const Manifest = (providedOptions) => {
8007
8032
  varRemoteEntry,
8008
8033
  types: resolveTypesMeta(options.dts),
8009
8034
  globalName: name,
8010
- pluginVersion: "0.2.5",
8035
+ pluginVersion: version$1,
8011
8036
  ...!!getPublicPath ? { getPublicPath } : { publicPath }
8012
8037
  },
8013
8038
  ...disableAssetsAnalyze ? {} : { shared },
@@ -8220,12 +8245,6 @@ function pluginModuleParseEnd_default(excludeFn, options, controller = createMod
8220
8245
  }
8221
8246
  //#endregion
8222
8247
  //#region src/plugins/pluginProxyRemoteEntry.ts
8223
- function resolveDevHashEntryFileName(fileName) {
8224
- if (!fileName.includes("[hash")) return fileName;
8225
- const normalized = fileName.replace(/(?:[._-]?\[hash(?::\d+)?\])/g, "");
8226
- const baseName = path$1.basename(normalized);
8227
- return path$1.extname(baseName) ? normalized : `${normalized}.js`;
8228
- }
8229
8248
  function resolveAbsoluteDevRemoteEntryUrl(publicPath, fileName) {
8230
8249
  const base = new URL(publicPath);
8231
8250
  base.pathname = ensureTrailingSlash(base.pathname);
@@ -8366,7 +8385,7 @@ function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposes
8366
8385
  const host = formatDevServerHostForOrigin(viteConfig.server?.host);
8367
8386
  const resolvedPublicPath = resolvePublicPath(options, viteConfig.base, originalConfigBase);
8368
8387
  const devPublicPath = resolvedPublicPath === "auto" ? "/" : resolvedPublicPath;
8369
- const remoteEntryFileName = resolveDevHashEntryFileName(options.filename);
8388
+ const remoteEntryFileName = resolveHashPlaceholderFileName(options.filename);
8370
8389
  const isAbsolutePublicPath = /^https?:\/\//i.test(devPublicPath);
8371
8390
  const remoteEntryUrl = JSON.stringify(isAbsolutePublicPath ? resolveAbsoluteDevRemoteEntryUrl(devPublicPath, remoteEntryFileName) : `${ensureTrailingSlash(devPublicPath)}${remoteEntryFileName}`);
8372
8391
  const fallbackOrigin = `//${host}:${viteConfig.server?.port}`;
@@ -8438,9 +8457,6 @@ function resolveRemoteConsumer(ctx, hasMultiEnvironment) {
8438
8457
  function isNodeModulesImporter(importer) {
8439
8458
  return importer?.includes("/node_modules/") || importer?.includes("\\node_modules\\");
8440
8459
  }
8441
- function escapeRegExp(value) {
8442
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8443
- }
8444
8460
  function appendAlias(config, alias) {
8445
8461
  config.resolve ??= {};
8446
8462
  const existingAlias = config.resolve.alias;
@@ -8748,7 +8764,7 @@ const NON_RUNTIME_DIRS = /* @__PURE__ */ new Set([
8748
8764
  "dist",
8749
8765
  "build"
8750
8766
  ]);
8751
- /** Bundled artifacts of a published package never import workspace packages; skip them instead of scanning megabytes. */
8767
+ /** Keep local runtime walks bounded without skipping the package entry itself. */
8752
8768
  const MAX_SCANNED_SOURCE_BYTES = 256 * 1024;
8753
8769
  const BARE_PACKAGE_SPECIFIER_RE = /^(?:@[^\s'"`()\/]+\/)?[^\s'"`()\/.@][^\s'"`()\/]*(?:\/[^\s'"`()]*)?$/;
8754
8770
  /** Module specifiers evaluated by a source file. */
@@ -8764,24 +8780,30 @@ function collectAllRuntimeImports(dir, into) {
8764
8780
  try {
8765
8781
  entries = readdirSync(dir, { withFileTypes: true });
8766
8782
  } catch {
8767
- return;
8783
+ return false;
8768
8784
  }
8785
+ let complete = true;
8769
8786
  for (const entry of entries) {
8770
8787
  if (entry.isDirectory()) {
8771
- if (!NON_RUNTIME_DIRS.has(entry.name)) collectAllRuntimeImports(path$1.join(dir, entry.name), into);
8788
+ if (!NON_RUNTIME_DIRS.has(entry.name) && !collectAllRuntimeImports(path$1.join(dir, entry.name), into)) complete = false;
8772
8789
  continue;
8773
8790
  }
8774
8791
  if (!SOURCE_FILE_RE.test(entry.name) || NON_RUNTIME_SOURCE_RE.test(entry.name)) continue;
8775
8792
  const file = path$1.join(dir, entry.name);
8776
8793
  let code;
8777
8794
  try {
8778
- if (statSync(file).size > MAX_SCANNED_SOURCE_BYTES) continue;
8795
+ if (statSync(file).size > MAX_SCANNED_SOURCE_BYTES) {
8796
+ complete = false;
8797
+ continue;
8798
+ }
8779
8799
  code = readFileSync(file, "utf-8");
8780
8800
  } catch {
8801
+ complete = false;
8781
8802
  continue;
8782
8803
  }
8783
8804
  for (const specifier of getRuntimeImportSpecifiers(code)) into.add(specifier);
8784
8805
  }
8806
+ return complete;
8785
8807
  }
8786
8808
  const SOURCE_EXTENSIONS = [
8787
8809
  "",
@@ -8807,19 +8829,27 @@ function resolveLocalRuntimeImport(importer, specifier) {
8807
8829
  }
8808
8830
  function collectReachableRuntimeImports(entry, dir, into) {
8809
8831
  const visited = /* @__PURE__ */ new Set();
8810
- const queue = [entry];
8832
+ const queue = [{
8833
+ file: entry,
8834
+ isEntry: true
8835
+ }];
8811
8836
  let scanned = false;
8837
+ let complete = true;
8812
8838
  while (queue.length) {
8813
- const file = queue.shift();
8839
+ const { file, isEntry } = queue.shift();
8814
8840
  const relative = path$1.relative(dir, file);
8815
8841
  if (relative.startsWith("..") || path$1.isAbsolute(relative) || visited.has(file)) continue;
8816
8842
  visited.add(file);
8817
8843
  let code;
8818
8844
  try {
8819
- if (statSync(file).size > MAX_SCANNED_SOURCE_BYTES) continue;
8845
+ if (!isEntry && statSync(file).size > MAX_SCANNED_SOURCE_BYTES) {
8846
+ complete = false;
8847
+ continue;
8848
+ }
8820
8849
  code = readFileSync(file, "utf-8");
8821
8850
  scanned = true;
8822
8851
  } catch {
8852
+ complete = false;
8823
8853
  continue;
8824
8854
  }
8825
8855
  for (const specifier of getRuntimeModuleSpecifiers(code)) {
@@ -8828,10 +8858,13 @@ function collectReachableRuntimeImports(entry, dir, into) {
8828
8858
  continue;
8829
8859
  }
8830
8860
  const local = resolveLocalRuntimeImport(file, specifier);
8831
- if (local) queue.push(local);
8861
+ if (local) queue.push({
8862
+ file: local,
8863
+ isEntry: false
8864
+ });
8832
8865
  }
8833
8866
  }
8834
- return scanned;
8867
+ return scanned && complete;
8835
8868
  }
8836
8869
  /**
8837
8870
  * Whether `dependency` is reachable from the shared package through the imports its source files
@@ -8840,11 +8873,13 @@ function collectReachableRuntimeImports(entry, dir, into) {
8840
8873
  * the fallback's evaluation graph rather than the package's declared closure — in a monorepo the
8841
8874
  * latter covers far more than the module graph ever does.
8842
8875
  */
8843
- function isSharedPackageRuntimeDependency(sharedKey, dependency) {
8876
+ function isSharedPackageRuntimeDependency(sharedKey, dependency, conditions) {
8844
8877
  const sharedPackage = getPackageName(sharedKey);
8845
- let reachable = sharedRuntimeDependencyCache.get(sharedKey);
8846
- if (!reachable) {
8847
- reachable = /* @__PURE__ */ new Set();
8878
+ const cacheKey = `${sharedKey}\0${JSON.stringify(conditions ?? null)}`;
8879
+ let result = sharedRuntimeDependencyCache.get(cacheKey);
8880
+ if (!result) {
8881
+ const reachable = /* @__PURE__ */ new Set();
8882
+ let complete = true;
8848
8883
  const visited = /* @__PURE__ */ new Set();
8849
8884
  const queue = [{
8850
8885
  request: sharedKey,
@@ -8852,16 +8887,26 @@ function isSharedPackageRuntimeDependency(sharedKey, dependency) {
8852
8887
  }];
8853
8888
  while (queue.length) {
8854
8889
  const { request, installed } = queue.shift();
8855
- if (!installed) continue;
8890
+ if (!installed) {
8891
+ complete = false;
8892
+ continue;
8893
+ }
8856
8894
  const visitKey = `${installed.dir}\0${request}`;
8857
8895
  if (visited.has(visitKey)) continue;
8858
8896
  visited.add(visitKey);
8859
8897
  const specifiers = /* @__PURE__ */ new Set();
8860
8898
  const entry = getInstalledPackageEntry(request, {
8861
8899
  cwd: installed.dir,
8862
- packageName: getPackageName(request)
8900
+ packageName: getPackageName(request),
8901
+ resolveSubpathWithRequire: false,
8902
+ ...conditions !== void 0 ? { conditions: [...conditions] } : {}
8863
8903
  });
8864
- if (!entry || !collectReachableRuntimeImports(entry, installed.dir, specifiers)) collectAllRuntimeImports(installed.dir, specifiers);
8904
+ if (!entry) {
8905
+ if (!collectAllRuntimeImports(installed.dir, specifiers)) complete = false;
8906
+ } else if (!collectReachableRuntimeImports(entry, installed.dir, specifiers)) {
8907
+ complete = false;
8908
+ collectAllRuntimeImports(installed.dir, specifiers);
8909
+ }
8865
8910
  for (const specifier of specifiers) {
8866
8911
  const dep = getPackageName(specifier);
8867
8912
  if (dep === sharedPackage) continue;
@@ -8873,9 +8918,13 @@ function isSharedPackageRuntimeDependency(sharedKey, dependency) {
8873
8918
  });
8874
8919
  }
8875
8920
  }
8876
- sharedRuntimeDependencyCache.set(sharedKey, reachable);
8921
+ result = {
8922
+ dependencies: reachable,
8923
+ complete
8924
+ };
8925
+ sharedRuntimeDependencyCache.set(cacheKey, result);
8877
8926
  }
8878
- return reachable.has(dependency);
8927
+ return result.dependencies.has(dependency) || !result.complete && isSharedPackageDependency(sharedKey, dependency);
8879
8928
  }
8880
8929
  function proxySharedModule(options) {
8881
8930
  const { shared = {}, federationOptions, getParsePromise = () => Promise.resolve() } = options;
@@ -8883,12 +8932,30 @@ function proxySharedModule(options) {
8883
8932
  let _command = "serve";
8884
8933
  let useDirectReactImport = false;
8885
8934
  let useRolldown = false;
8935
+ let isProduction = false;
8936
+ let rootResolveConditions;
8937
+ let ssrResolveConditions;
8938
+ let ssrTarget = "node";
8886
8939
  const savePrebuild = new PromiseStore();
8887
8940
  let devServer;
8888
8941
  const materializedLoadShareSources = /* @__PURE__ */ new Set();
8889
8942
  const emittedTreeShakingProviders = /* @__PURE__ */ new Set();
8890
8943
  const hasAnalyzableShares = Object.values(shared).some((share) => shouldAnalyzeSharedExports(share));
8891
- const getEnvironmentConditions = (context) => context.environment?.config?.resolve?.conditions;
8944
+ const getEnvironmentConfig = (context) => context.environment?.config;
8945
+ const getEnvironmentConditions = (context) => getEnvironmentConfig(context)?.resolve?.conditions;
8946
+ const getRuntimeDependencyConditions = (context, resolveOptions) => {
8947
+ const environment = context.environment;
8948
+ const environmentConfig = environment?.config;
8949
+ const isSsr = resolveOptions.ssr === true || Boolean(_config?.build?.ssr) || environmentConfig?.consumer === "server" || Boolean(environmentConfig?.build?.ssr) || environment?.name === "ssr" || environment?.name === "server";
8950
+ return getSharedExportConditions({
8951
+ environmentConditions: environmentConfig?.resolve?.conditions,
8952
+ isProduction: environmentConfig?.isProduction ?? isProduction,
8953
+ isSsr,
8954
+ rootConditions: rootResolveConditions,
8955
+ ssrConditions: ssrResolveConditions,
8956
+ ssrTarget
8957
+ });
8958
+ };
8892
8959
  const refreshTreeShakingForEnvironment = (context) => refreshTreeShakingModules(federationOptions, _command, getIsRolldown(context), getEnvironmentConditions(context));
8893
8960
  const normalizeTreeShakingOutputPath = (value) => {
8894
8961
  const normalized = normalizePathForImport(value);
@@ -8972,8 +9039,13 @@ function proxySharedModule(options) {
8972
9039
  },
8973
9040
  configResolved(config) {
8974
9041
  _config = config;
9042
+ isProduction = config.isProduction;
9043
+ rootResolveConditions = config.resolve?.conditions ? [...config.resolve.conditions] : void 0;
9044
+ ssrResolveConditions = config.ssr?.resolve?.conditions ? [...config.ssr.resolve.conditions] : void 0;
9045
+ ssrTarget = config.ssr?.target ?? "node";
8975
9046
  const isRolldown = getIsRolldown(this);
8976
- const registerConfiguredShare = _command === "serve" ? addConfiguredShare : addUsedShares;
9047
+ const resolvedOptions = federationOptions ?? getNormalizeModuleFederationOptions();
9048
+ const registerConfiguredShare = _command === "build" && Object.keys(resolvedOptions.exposes).length > 0 ? addUsedShares : addConfiguredShare;
8977
9049
  Object.keys(shared).forEach((key) => {
8978
9050
  if (key.endsWith("/")) return;
8979
9051
  if (useDirectReactImport && key === "react") {
@@ -9053,7 +9125,9 @@ function proxySharedModule(options) {
9053
9125
  const importerPackage = getSharedPackageFromFile(importer, shared);
9054
9126
  if (importerPackage === getPackageName(key)) return;
9055
9127
  if (importerPackage) {
9056
- if (!isNodeModulePath(importer) && !Object.keys(shared).some((sharedKey) => getPackageName(sharedKey) === importerPackage) ? isSharedPackageRuntimeDependency(key, importerPackage) : isSharedPackageDependency(key, importerPackage)) return;
9128
+ const importerIsUnsharedWorkspacePackage = !isNodeModulePath(importer) && !Object.keys(shared).some((sharedKey) => getPackageName(sharedKey) === importerPackage);
9129
+ const runtimeDependencyRequest = key.endsWith("/") && matchesSharedSource(source, key) ? source : key;
9130
+ if (importerIsUnsharedWorkspacePackage ? isSharedPackageRuntimeDependency(runtimeDependencyRequest, importerPackage, getRuntimeDependencyConditions(this, resolveOptions)) : isSharedPackageDependency(key, importerPackage)) return;
9057
9131
  }
9058
9132
  if (useDirectReactImport && key === "react") return;
9059
9133
  if (isAssetLikeImport(source)) return;
@@ -9922,7 +9996,7 @@ function isFederationControlChunk(fileName, filename) {
9922
9996
  function sanitizeFederationControlChunk(code, fileName, filename) {
9923
9997
  let nextCode = stripEmptyPreloadCalls(code);
9924
9998
  if (fileName.includes("localSharedImportMap")) {
9925
- const remoteEntryImportRegex = new RegExp(`import\\s*["'][^"']*${filename.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']\\s*;?`, "g");
9999
+ const remoteEntryImportRegex = new RegExp(`import\\s*["'][^"']*${escapeRegExp(filename)}["']\\s*;?`, "g");
9926
10000
  nextCode = nextCode.replace(remoteEntryImportRegex, "");
9927
10001
  }
9928
10002
  return nextCode;
@@ -10054,13 +10128,15 @@ function appendResolveAlias(config, alias) {
10054
10128
  replacement
10055
10129
  })), alias];
10056
10130
  }
10131
+ const RUNTIME_INDEX_ENTRY_RE = /^(.*[\\/])index(\.[cm]?js)$/;
10132
+ const TRAILING_SLASH_RE = /\/$/;
10057
10133
  function getRuntimeHelpersImplementation(runtimeImplementation) {
10058
- const indexEntryMatch = runtimeImplementation.match(/^(.*[\\/])index(\.[cm]?js)$/);
10134
+ const indexEntryMatch = RUNTIME_INDEX_ENTRY_RE.exec(runtimeImplementation);
10059
10135
  if (indexEntryMatch) return normalizePathForImport(`${indexEntryMatch[1]}helpers${indexEntryMatch[2]}`);
10060
10136
  const extension = path$1.extname(runtimeImplementation);
10061
10137
  if (extension) return normalizePathForImport(path$1.join(path$1.dirname(runtimeImplementation), `helpers${extension}`));
10062
10138
  if (path$1.isAbsolute(runtimeImplementation) || runtimeImplementation.startsWith(".")) return normalizePathForImport(path$1.join(runtimeImplementation, "helpers"));
10063
- return `${runtimeImplementation.replace(/\/$/, "")}/helpers`;
10139
+ return `${runtimeImplementation.replace(TRAILING_SLASH_RE, "")}/helpers`;
10064
10140
  }
10065
10141
  const UNSAFE_JS_SOURCE_CHAR_MAP = {
10066
10142
  "<": "\\u003C",
@@ -10307,7 +10383,7 @@ function createEarlyVirtualModulesPlugin(options) {
10307
10383
  initVirtualModules(_command, getRemoteEntryId(options), false, options);
10308
10384
  const isRolldown = getIsRolldown(this);
10309
10385
  if (remotes && Object.keys(remotes).length > 0) {
10310
- for (const key of Object.keys(remotes)) addUsedRemote(key, key, options);
10386
+ for (const key of Object.keys(remotes)) ensureUsedRemote(key, options);
10311
10387
  if (_command === "serve") {
10312
10388
  config.optimizeDeps = config.optimizeDeps || {};
10313
10389
  config.optimizeDeps.exclude = config.optimizeDeps.exclude || [];
@@ -10537,7 +10613,7 @@ function applyBuildTimeRuntimeDefines(define, options, { target, isAstro, defaul
10537
10613
  }
10538
10614
  function loadPluginDts(options) {
10539
10615
  if (options.dts === false) return [];
10540
- return [import("./pluginDts-BhONN9dR.js").then(({ default: pluginDts }) => pluginDts(options))];
10616
+ return [import("./pluginDts-4sHIZPIi.js").then(({ default: pluginDts }) => pluginDts(options))];
10541
10617
  }
10542
10618
  const INJECT_EXTERNAL_RUNTIME_CORE_PLUGIN = "@module-federation/vite/injectExternalRuntimeCorePlugin";
10543
10619
  function isInjectExternalRuntimeCorePlugin(specifier) {
@@ -11109,10 +11185,10 @@ function federation(mfUserOptions) {
11109
11185
  apply: "build",
11110
11186
  config(_config, { command }) {
11111
11187
  const manifest = options.manifest;
11112
- const getDefaultDisableAssetsAnalyze = (cfgCommand) => cfgCommand === "serve" && (typeof manifest !== "object" || !Object.prototype.hasOwnProperty.call(manifest, "disableAssetsAnalyze"));
11188
+ const getDefaultDisableAssetsAnalyze = (cfgCommand) => cfgCommand === "serve" && (typeof manifest !== "object" || !Object.hasOwn(manifest, "disableAssetsAnalyze"));
11113
11189
  const getConfiguredDisableAssetsAnalyze = (cfgCommand) => {
11114
11190
  if (typeof manifest === "object" && manifest !== null) {
11115
- if (Object.prototype.hasOwnProperty.call(manifest, "disableAssetsAnalyze")) return manifest.disableAssetsAnalyze === true;
11191
+ if (Object.hasOwn(manifest, "disableAssetsAnalyze")) return manifest.disableAssetsAnalyze === true;
11116
11192
  }
11117
11193
  return getDefaultDisableAssetsAnalyze(cfgCommand);
11118
11194
  };
@@ -1,4 +1,4 @@
1
- import { n as normalizePathForImport } from "./buildPaths-BkaQHrd2.js";
1
+ import { n as normalizePathForImport } from "./buildPaths-BoaQTkxt.js";
2
2
  import { _ as mfError, g as createModuleFederationError, l as hasPackageDependency, p as resolveImportPath } from "./dtsConstants-BsaLBaaK.js";
3
3
  import fs from "fs";
4
4
  import * as path$1 from "node:path";
@@ -34,6 +34,7 @@ const getIPv4 = () => {
34
34
  return (getIpv4Interfaces()[0] || { address: localIpv4 }).address;
35
35
  };
36
36
  const DEV_TYPES_FOLDER = ".dev-server";
37
+ const UPDATE_DEBOUNCE_MS = 300;
37
38
  const forkDevWorkerPath = (() => {
38
39
  return resolveImportPath("@module-federation/dts-plugin/dist/fork-dev-worker.js");
39
40
  })();
@@ -256,11 +257,16 @@ function pluginDts(options) {
256
257
  disableLiveReload: devOptions.disableLiveReload,
257
258
  disableHotTypesReload: devOptions.disableHotTypesReload
258
259
  });
259
- const update = () => devWorker?.update();
260
+ let updateTimer;
261
+ const update = () => {
262
+ clearTimeout(updateTimer);
263
+ updateTimer = setTimeout(() => devWorker?.update(), UPDATE_DEBOUNCE_MS);
264
+ };
260
265
  server.watcher.on("change", update);
261
266
  server.watcher.on("add", update);
262
267
  server.watcher.on("unlink", update);
263
268
  server.httpServer?.once("close", () => {
269
+ clearTimeout(updateTimer);
264
270
  devWorker?.exit();
265
271
  server.watcher.off("change", update);
266
272
  server.watcher.off("add", update);
@@ -1,4 +1,4 @@
1
- import { t as EXTERNAL_URL_RE } from "./buildPaths-BkaQHrd2.js";
1
+ import { t as EXTERNAL_URL_RE } from "./buildPaths-BoaQTkxt.js";
2
2
  //#region src/utils/fetchWithTimeout.ts
3
3
  const DEFAULT_SSR_FETCH_TIMEOUT_MS = 1e4;
4
4
  const DEFAULT_SSR_FETCH_MAX_BYTES = 10 * 1024 * 1024;
@@ -188,7 +188,8 @@ async function resolveSharedExternal(id, resolvedShared) {
188
188
  }
189
189
  async function getOrCreateRunner(remoteOrigin, resolvedShared, fetchTimeoutMs, fetchMaxBytes) {
190
190
  const cacheKey = getRunnerCacheKey(remoteOrigin, resolvedShared, fetchTimeoutMs, fetchMaxBytes);
191
- if (runnerCache.has(cacheKey)) return runnerCache.get(cacheKey);
191
+ const cached = runnerCache.get(cacheKey);
192
+ if (cached) return cached.promise;
192
193
  const promise = (async () => {
193
194
  const viteRunner = await getModuleRunnerModule();
194
195
  if (!viteRunner) return null;
@@ -215,7 +216,10 @@ async function getOrCreateRunner(remoteOrigin, resolvedShared, fetchTimeoutMs, f
215
216
  return null;
216
217
  }
217
218
  })();
218
- runnerCache.set(cacheKey, promise);
219
+ runnerCache.set(cacheKey, {
220
+ remoteOrigin,
221
+ promise
222
+ });
219
223
  return promise;
220
224
  }
221
225
  const _path = () => nodeImport("path");
@@ -252,10 +256,19 @@ function parseRunnerInvokeResult(data) {
252
256
  * Version key for a resolved SSR entry. Derived from the remote's manifest
253
257
  * content so a redeploy at the same URL produces a different key, which in
254
258
  * turn produces different temp-file names — busting both our caches and
255
- * Node's ESM module cache. Convention-resolved entries (no manifest) get a
256
- * stable placeholder key and cannot be revalidated automatically.
259
+ * Node's ESM module cache. Convention-resolved entries (no manifest) use a
260
+ * stable placeholder key for ordinary loads; explicit `revalidate()` calls
261
+ * advance a process-local generation so the next import is fresh.
257
262
  */
258
263
  const UNVERSIONED = "unversioned";
264
+ const unversionedGenerations = /* @__PURE__ */ new Map();
265
+ let unversionedGlobalGeneration = 0;
266
+ function getUnversionedVersionKey(remoteEntryUrl) {
267
+ return `${UNVERSIONED}-${unversionedGlobalGeneration}-${unversionedGenerations.get(remoteEntryUrl) ?? 0}`;
268
+ }
269
+ function bumpUnversionedGeneration(remoteEntryUrl) {
270
+ unversionedGenerations.set(remoteEntryUrl, (unversionedGenerations.get(remoteEntryUrl) ?? 0) + 1);
271
+ }
259
272
  function hashString(value) {
260
273
  let hash = 2166136261;
261
274
  for (let i = 0; i < value.length; i++) {
@@ -392,16 +405,16 @@ function buildSsrEntryCandidates(ctx, options = {}) {
392
405
  if (!options.skipServerBuild) candidates.push({
393
406
  url: `${remoteOrigin}/__mf_server__/${filename}.ssr.js`,
394
407
  type: "module",
395
- versionKey: UNVERSIONED
408
+ versionKey: getUnversionedVersionKey(ctx.entryUrl)
396
409
  });
397
410
  candidates.push({
398
411
  url: `${base}.ssr.js`,
399
412
  type: "module",
400
- versionKey: UNVERSIONED
413
+ versionKey: getUnversionedVersionKey(ctx.entryUrl)
401
414
  }, {
402
415
  url: `${remoteOrigin}/__mf_ssr__/${filename}.ssr.js`,
403
416
  type: "module",
404
- versionKey: UNVERSIONED
417
+ versionKey: getUnversionedVersionKey(ctx.entryUrl)
405
418
  });
406
419
  return candidates;
407
420
  }
@@ -416,14 +429,14 @@ async function resolveSSREntryImpl(remoteEntryUrl, fetchTimeoutMs, fetchMaxBytes
416
429
  if (isSsrEntry(remoteEntryUrl)) return {
417
430
  url: remoteEntryUrl,
418
431
  type: "module",
419
- versionKey: UNVERSIONED
432
+ versionKey: getUnversionedVersionKey(remoteEntryUrl)
420
433
  };
421
434
  if (!isManifestEntry(remoteEntryUrl)) {
422
435
  const filename = getEntryFilename(remoteEntryUrl);
423
436
  const fromServerBuild = await headCheckSsrEntry({
424
437
  url: `${remoteEntryUrl.replace(/\/[^/]+$/, "")}/__mf_server__/${filename}.ssr.js`,
425
438
  type: "module",
426
- versionKey: UNVERSIONED
439
+ versionKey: getUnversionedVersionKey(remoteEntryUrl)
427
440
  }, fetchTimeoutMs);
428
441
  if (fromServerBuild) return fromServerBuild;
429
442
  }
@@ -477,6 +490,18 @@ function dropRemoteCaches(remoteEntryUrl) {
477
490
  tempFilePathCache.delete(key);
478
491
  }
479
492
  }
493
+ function clearRunnerCaches(remoteEntryUrl) {
494
+ let remoteOrigin;
495
+ if (remoteEntryUrl) try {
496
+ remoteOrigin = new URL(remoteEntryUrl).origin;
497
+ } catch {
498
+ return;
499
+ }
500
+ for (const cached of runnerCache.values()) {
501
+ if (remoteOrigin && cached.remoteOrigin !== remoteOrigin) continue;
502
+ cached.promise.then((runner) => runner?.clearCache?.()).catch(() => {});
503
+ }
504
+ }
480
505
  /**
481
506
  * Drop the loader's caches so the next `loadEntry` re-resolves and re-fetches
482
507
  * remote SSR entries. Pass a remote entry URL to scope the invalidation to one
@@ -489,16 +514,19 @@ function dropRemoteCaches(remoteEntryUrl) {
489
514
  */
490
515
  function revalidate(remoteEntryUrl) {
491
516
  if (remoteEntryUrl) {
517
+ bumpUnversionedGeneration(remoteEntryUrl);
492
518
  for (const key of ssrEntryCache.keys()) if (key.endsWith(`::${remoteEntryUrl}`)) ssrEntryCache.delete(key);
493
519
  const manifestUrl = getManifestUrl(remoteEntryUrl);
494
520
  for (const key of manifestFetchCache.keys()) if (key.endsWith(`::${manifestUrl}`)) manifestFetchCache.delete(key);
495
521
  dropRemoteCaches(remoteEntryUrl);
496
522
  } else {
523
+ unversionedGlobalGeneration += 1;
497
524
  ssrEntryCache.clear();
498
525
  manifestFetchCache.clear();
499
526
  tempFileCache.clear();
500
527
  tempFilePathCache.clear();
501
528
  }
529
+ clearRunnerCaches(remoteEntryUrl);
502
530
  const federation = globalThis.__FEDERATION__;
503
531
  for (const instance of federation?.__INSTANCES__ ?? []) try {
504
532
  instance?.moduleCache?.clear?.();
@@ -555,6 +583,9 @@ function transformSsrCode(code, base, sharedPkgMap) {
555
583
  function isVitePreloadHelperSpecifier(specifier) {
556
584
  return specifier.includes("preload-helper");
557
585
  }
586
+ function getTempFileImportUrl(filePath, versionKey) {
587
+ return `file://${filePath}?v=${encodeURIComponent(versionKey)}`;
588
+ }
558
589
  /**
559
590
  * Fetch an HTTP ESM module, transform it, write it to a temp .js file and
560
591
  * return the file path. Recursively does the same for HTTP transitive imports
@@ -601,7 +632,7 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
601
632
  const subMap = /* @__PURE__ */ new Map();
602
633
  await Promise.all([...new Set(relImports)].filter((u) => u.startsWith("http://") || u.startsWith("https://")).map(async (u) => {
603
634
  const tmpPath = await fetchEsmToTempFile(u, tmpDir, visited, pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey, fetchMaxBytes);
604
- subMap.set(u, `file://${tmpPath}`);
635
+ subMap.set(u, getTempFileImportUrl(tmpPath, versionKey));
605
636
  }));
606
637
  code = transformSsrCode(code, base, sharedPkgMap);
607
638
  for (const [httpUrl, fileUrl] of subMap) code = code.split(httpUrl).join(fileUrl);
@@ -631,7 +662,7 @@ async function importTempModule(filePath, versionKey) {
631
662
  }
632
663
  let warnedVmUnavailable = false;
633
664
  async function tryVmStrategy(ssrEntry, options) {
634
- const { loadViaVmStrategy, isVmStrategyAvailable } = await import("./ssrVmStrategy-D4KB-y3H.js");
665
+ const { loadViaVmStrategy, isVmStrategyAvailable } = await import("./ssrVmStrategy-CkmYR5_u.js");
635
666
  if (!await isVmStrategyAvailable()) {
636
667
  if (!warnedVmUnavailable) {
637
668
  warnedVmUnavailable = true;
@@ -1,5 +1,5 @@
1
1
  import { t as findSharedKey } from "./sharedKeyMatcher-DiUzRVH1.js";
2
- import { c as readResponseTextBounded, n as neutralizeBrowserPreloadHelpers, s as fetchWithTimeout, t as SsrEntryHttpError } from "./ssrEntryLoader-CqtaiDUp.js";
2
+ import { c as readResponseTextBounded, n as neutralizeBrowserPreloadHelpers, s as fetchWithTimeout, t as SsrEntryHttpError } from "./ssrEntryLoader-BqzV2t-n.js";
3
3
  //#region src/utils/ssrVmStrategy.ts
4
4
  /**
5
5
  * vm.SourceTextModule strategy for loading remote SSR entries.
@@ -90,6 +90,7 @@ function createSyntheticModule(vm, specifier, namespace) {
90
90
  }
91
91
  const httpModuleCache = /* @__PURE__ */ new Map();
92
92
  const namespaceCache = /* @__PURE__ */ new Map();
93
+ const linkQueues = /* @__PURE__ */ new WeakMap();
93
94
  const contextIds = /* @__PURE__ */ new WeakMap();
94
95
  let nextContextId = 1;
95
96
  function getContextId(context) {
@@ -153,10 +154,21 @@ async function linkModule(vm, specifier, referencingModule, options) {
153
154
  if (url) return getHttpModule(vm, url, options);
154
155
  return createSyntheticModule(vm, specifier, await loadBareModule(specifier, options));
155
156
  }
157
+ async function linkModuleGraph(module, linker, cacheContext) {
158
+ const current = (linkQueues.get(cacheContext) ?? Promise.resolve()).catch(() => {}).then(async () => {
159
+ if (module.status === "unlinked") await module.link(linker);
160
+ });
161
+ linkQueues.set(cacheContext, current);
162
+ try {
163
+ await current;
164
+ } finally {
165
+ if (linkQueues.get(cacheContext) === current) linkQueues.delete(cacheContext);
166
+ }
167
+ }
156
168
  async function importDynamically(vm, specifier, referencingModule, options) {
157
169
  const linker = (spec, referencer) => linkModule(vm, spec, referencer, options);
158
170
  const module = await linker(specifier, referencingModule);
159
- if (module.status === "unlinked") await module.link(linker);
171
+ await linkModuleGraph(module, linker, options.cacheContext);
160
172
  if (module.status === "linked") await module.evaluate();
161
173
  return module;
162
174
  }
@@ -172,7 +184,7 @@ async function loadViaVmStrategy(entryUrl, options) {
172
184
  if (!namespaceCache.has(cacheKey)) namespaceCache.set(cacheKey, (async () => {
173
185
  const entryModule = await getHttpModule(vm, entryUrl, options);
174
186
  const linker = (specifier, referencingModule) => linkModule(vm, specifier, referencingModule, options);
175
- if (entryModule.status === "unlinked") await entryModule.link(linker);
187
+ await linkModuleGraph(entryModule, linker, options.cacheContext);
176
188
  if (entryModule.status === "linked") await entryModule.evaluate();
177
189
  return entryModule.namespace;
178
190
  })().catch((error) => {
@@ -1,2 +1,2 @@
1
- import { i as ssrEntryLoaderPlugin, n as neutralizeBrowserPreloadHelpers, r as revalidate, t as SsrEntryHttpError } from "../ssrEntryLoader-CqtaiDUp.js";
1
+ import { i as ssrEntryLoaderPlugin, n as neutralizeBrowserPreloadHelpers, r as revalidate, t as SsrEntryHttpError } from "../ssrEntryLoader-BqzV2t-n.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.5",
3
+ "version": "1.21.6",
4
4
  "description": "Vite plugin for Module Federation",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -91,6 +91,6 @@
91
91
  "tsdown": "0.22.14",
92
92
  "typescript": "7.0.2",
93
93
  "vite": "8.2.0",
94
- "vitest": "4.1.10"
94
+ "vitest": "4.1.11"
95
95
  }
96
96
  }