@module-federation/vite 1.16.8 → 1.16.10

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
@@ -2,6 +2,10 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/@module-federation/vite.svg)](https://www.npmjs.com/package/@module-federation/vite)
4
4
 
5
+ ## Vite and VoidZero recommend this plugin
6
+
7
+ [Read the announcement](https://www.linkedin.com/posts/voidzero_github-module-federationvite-vite-plugin-activity-7449452398202241024-JyAL).
8
+
5
9
  ## Reason why 🤔
6
10
 
7
11
  [Microservices](https://martinfowler.com/articles/microservices.html) nowadays is a well-known concept and maybe you are using it in your current company.
@@ -47,7 +51,7 @@ pnpm run multi-example
47
51
 
48
52
  ## Getting started 🚀
49
53
 
50
- [https://module-federation.io/guide/build-plugins/plugins-vite.html](https://module-federation.io/guide/build-plugins/plugins-vite.html)
54
+ [https://module-federation.io/integrations/build-tool/vite](https://module-federation.io/integrations/build-tool/vite)
51
55
 
52
56
  With **@module-federation/vite**, the process becomes delightfully simple, you will only find the differences from a normal Vite configuration.
53
57
 
@@ -143,7 +147,9 @@ export default defineConfig({
143
147
  // Optional parameter that controls where the host initialization script is injected.
144
148
  // By default, it is injected into the index.html file.
145
149
  // You can set this to "entry" to inject it into the entry script instead.
146
- // Useful if your application does not load from index.html.
150
+ // Recommended for SSR hosts without index.html (Nitro, TanStack Start) so
151
+ // initHost() completes before hydrateRoot and @module-federation/bridge-react
152
+ // remotes render on first paint.
147
153
  hostInitInjectLocation: "html", // or "entry"
148
154
  // Controls whether all CSS assets from the bundle should be added to every exposed module.
149
155
  // When false (default), the plugin will not process any CSS assets.
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as mfWarn, a as getIsRolldown, c as getPackageNameFromNodeModulePath, d as isNuxtProjectRoot, f as packageNameDecode, g as createModuleFederationError, h as setPackageDetectionCwd, i as getInstalledPackageJson, l as getSharedCacheKey, m as resolveImportPath, o as getPackageDetectionCwd, p as packageNameEncode, r as getInstalledPackageEntry, s as getPackageName, u as hasPackageDependency, v as normalizePathForImport, y as rebaseImport } from "./pluginDts-Cpmdbbr0.js";
1
+ import { _ as mfWarn, a as getIsRolldown, c as getPackageNameFromNodeModulePath, d as isNuxtProjectRoot, f as packageNameDecode, g as createModuleFederationError, h as setPackageDetectionCwd, i as getInstalledPackageJson, l as getSharedCacheKey, m as resolveImportPath, o as getPackageDetectionCwd, p as packageNameEncode, r as getInstalledPackageEntry, s as getPackageName, u as hasPackageDependency, v as normalizePathForImport, y as rebaseImport } from "./pluginDts-CrSsDUnT.js";
2
2
  import { createRequire } from "node:module";
3
3
  import * as fs$1 from "fs";
4
4
  import { existsSync, readFileSync, realpathSync, statSync, writeFileSync } from "fs";
@@ -171,6 +171,71 @@ function injectEntryScript(html, initSrc) {
171
171
  return html.replace("<head>", `<head><script type="module" src=${JSON.stringify(src)}><\/script>`);
172
172
  }
173
173
  //#endregion
174
+ //#region src/utils/pathNormalization.ts
175
+ const COMMON_SHARED_SUBPATHS = {
176
+ react: [
177
+ "react/jsx-runtime",
178
+ "react/jsx-dev-runtime",
179
+ "react/compiler-runtime"
180
+ ],
181
+ "react-dom": [
182
+ "react-dom/client",
183
+ "react-dom/server",
184
+ "react-dom/server.browser"
185
+ ],
186
+ "solid-js": [
187
+ "solid-js/web",
188
+ "solid-js/store",
189
+ "solid-js/html",
190
+ "solid-js/h"
191
+ ],
192
+ zustand: ["zustand/vanilla", "zustand/react"]
193
+ };
194
+ function removeTrailingSlash(value) {
195
+ return value.endsWith("/") ? value.slice(0, -1) : value;
196
+ }
197
+ function ensureTrailingSlash(value) {
198
+ return `${removeTrailingSlash(value)}/`;
199
+ }
200
+ function getBasePath$1(base) {
201
+ return removeTrailingSlash(base || "/");
202
+ }
203
+ function isNuxtClientBase(base) {
204
+ return getBasePath$1(base).endsWith("/_nuxt");
205
+ }
206
+ function normalizeNodeModulePath(source) {
207
+ return source.replace(/\\/g, "/").replace(/\?.*$/, "");
208
+ }
209
+ function isNodeModulePath(source) {
210
+ return source.includes("/node_modules/") || source.includes("\\node_modules\\");
211
+ }
212
+ function filterId(id) {
213
+ return typeof id === "string" && !id.includes("\0");
214
+ }
215
+ function getMatchingNodeModuleSubpath(source, candidates) {
216
+ const normalized = normalizeNodeModulePath(source);
217
+ return [...candidates].sort((a, b) => b.length - a.length).find((candidate) => normalized.includes(`/node_modules/${candidate}/`) || normalized.includes(`/node_modules/${candidate}.`));
218
+ }
219
+ function getCommonSharedSubpaths(sharedKey) {
220
+ return COMMON_SHARED_SUBPATHS[removeTrailingSlash(sharedKey)] || [];
221
+ }
222
+ function getCommonSharedSubpathFromNodeModulePath(source, sharedKey) {
223
+ return getMatchingNodeModuleSubpath(source, getCommonSharedSubpaths(removeTrailingSlash(sharedKey)));
224
+ }
225
+ /**
226
+ * Resolves the public path for remote entries
227
+ * @param options - Module Federation options
228
+ * @param viteBase - Vite's base config value
229
+ * @param originalBase - Original base config before any transformations
230
+ * @returns The resolved public path
231
+ */
232
+ function resolvePublicPath(options, viteBase, originalBase) {
233
+ if (options.publicPath && options.publicPath !== "auto") return options.publicPath;
234
+ if (!originalBase) return "auto";
235
+ if (viteBase) return ensureTrailingSlash(viteBase);
236
+ return "auto";
237
+ }
238
+ //#endregion
174
239
  //#region src/utils/normalizeModuleFederationOptions.ts
175
240
  const INTERNAL_NAME_PREFIX = "__mfe_internal__";
176
241
  function toInternalModuleFederationName(name) {
@@ -257,7 +322,9 @@ function getLitExportSubpathShares(sharedName) {
257
322
  }
258
323
  function normalizeShareItem(key, shareItem) {
259
324
  const isImportFalse = typeof shareItem === "object" && shareItem.import === false;
260
- const version = (typeof shareItem === "object" ? shareItem.version || inferVersionFromRequiredVersion(shareItem.requiredVersion) : void 0) || searchPackageVersion(key);
325
+ const explicitVersion = typeof shareItem === "object" ? shareItem.version : void 0;
326
+ const inferredVersion = typeof shareItem === "object" ? inferVersionFromRequiredVersion(shareItem.requiredVersion) : void 0;
327
+ const version = explicitVersion || searchPackageVersion(key) || inferredVersion;
261
328
  if (typeof shareItem === "string") return {
262
329
  name: shareItem,
263
330
  version,
@@ -282,6 +349,11 @@ function normalizeShareItem(key, shareItem) {
282
349
  }
283
350
  };
284
351
  }
352
+ function normalizeSharedKey(key) {
353
+ if (!key.endsWith("/")) return key;
354
+ const baseKey = key.slice(0, -1);
355
+ return getCommonSharedSubpaths(baseKey).length > 0 ? baseKey : key;
356
+ }
285
357
  function normalizeShared(shared) {
286
358
  explicitSharedKeys = /* @__PURE__ */ new Set();
287
359
  if (!shared) {
@@ -306,16 +378,18 @@ function normalizeShared(shared) {
306
378
  const sourceEntries = [];
307
379
  if (Array.isArray(shared)) shared.forEach((key) => {
308
380
  if (isModuleFederationRuntimePackage(key)) return;
309
- result[key] = normalizeShareItem(key, key);
310
- explicitSharedKeys.add(key);
311
- sourceEntries.push([key, key]);
381
+ const normalizedKey = normalizeSharedKey(key);
382
+ result[normalizedKey] = normalizeShareItem(normalizedKey, normalizedKey);
383
+ explicitSharedKeys.add(normalizedKey);
384
+ sourceEntries.push([normalizedKey, normalizedKey]);
312
385
  });
313
386
  else if (typeof shared === "object") Object.keys(shared).forEach((key) => {
314
387
  if (isModuleFederationRuntimePackage(key)) return;
388
+ const normalizedKey = normalizeSharedKey(key);
315
389
  const value = shared[key];
316
- result[key] = normalizeShareItem(key, value);
317
- explicitSharedKeys.add(key);
318
- sourceEntries.push([key, value]);
390
+ result[normalizedKey] = normalizeShareItem(normalizedKey, value);
391
+ explicitSharedKeys.add(normalizedKey);
392
+ sourceEntries.push([normalizedKey, value]);
319
393
  });
320
394
  sourceEntries.forEach(([key, value]) => {
321
395
  for (const subpathShare of getLitExportSubpathShares(key)) {
@@ -723,6 +797,19 @@ globalThis[__mfCacheGlobalKey] ||= { share: {}, remote: {} };
723
797
  globalThis[__mfCacheGlobalKey].share ||= {};
724
798
  globalThis[__mfCacheGlobalKey].remote ||= {};
725
799
  const __mfModuleCache = globalThis[__mfCacheGlobalKey];
800
+ for (const __mfShareKey of Object.keys(__mfModuleCache.share)) {
801
+ if (__mfShareKey.startsWith("default:")) {
802
+ const __mfLegacyShareKey = __mfShareKey.slice("default:".length);
803
+ if (__mfModuleCache.share[__mfLegacyShareKey] === undefined) {
804
+ __mfModuleCache.share[__mfLegacyShareKey] = __mfModuleCache.share[__mfShareKey];
805
+ }
806
+ } else if (!__mfShareKey.includes(":")) {
807
+ const __mfDefaultShareKey = "default:" + __mfShareKey;
808
+ if (__mfModuleCache.share[__mfDefaultShareKey] === undefined) {
809
+ __mfModuleCache.share[__mfDefaultShareKey] = __mfModuleCache.share[__mfShareKey];
810
+ }
811
+ }
812
+ }
726
813
  `;
727
814
  }
728
815
  function getRuntimeInitPromiseBootstrapCode(enableSsrInit = false) {
@@ -985,6 +1072,49 @@ function isWorkspacePackageEntry(pkg, resolved) {
985
1072
  fromResolvedEntry: resolved
986
1073
  });
987
1074
  }
1075
+ function getWorkspacePackageJson(pkg) {
1076
+ const resolved = getLocalProviderImportPath(pkg) || getProjectResolvedImportPath(pkg);
1077
+ if (!isWorkspacePackageEntry(pkg, resolved)) return;
1078
+ return getInstalledPackageJson(pkg, {
1079
+ packageName: getPackageName(pkg),
1080
+ fromResolvedEntry: resolved
1081
+ })?.packageJson;
1082
+ }
1083
+ function getDependencyNames(packageJson) {
1084
+ if (!packageJson) return [];
1085
+ const names = /* @__PURE__ */ new Set();
1086
+ for (const field of [
1087
+ "dependencies",
1088
+ "peerDependencies",
1089
+ "optionalDependencies"
1090
+ ]) {
1091
+ const deps = packageJson[field];
1092
+ if (!deps || typeof deps !== "object") continue;
1093
+ for (const dep of Object.keys(deps)) names.add(dep);
1094
+ }
1095
+ return Array.from(names);
1096
+ }
1097
+ function isWorkspaceSingletonConsumedByPeer(pkg) {
1098
+ const shared = getNormalizeModuleFederationOptions()?.shared || {};
1099
+ const sharedKeyByPackageName = /* @__PURE__ */ new Map();
1100
+ Object.entries(shared).filter(([, item]) => item.shareConfig.singleton === true).forEach(([key]) => {
1101
+ const packageName = getPackageName(key);
1102
+ if (!sharedKeyByPackageName.get(packageName) || key === packageName) sharedKeyByPackageName.set(packageName, key);
1103
+ });
1104
+ const reachesPkg = (current, seen) => {
1105
+ const packageJson = getWorkspacePackageJson(current);
1106
+ for (const dependency of getDependencyNames(packageJson)) {
1107
+ const sharedDependency = sharedKeyByPackageName.get(dependency);
1108
+ if (!sharedDependency) continue;
1109
+ if (sharedDependency === pkg) return true;
1110
+ if (seen.has(sharedDependency)) continue;
1111
+ seen.add(sharedDependency);
1112
+ if (reachesPkg(sharedDependency, seen)) return true;
1113
+ }
1114
+ return false;
1115
+ };
1116
+ return Array.from(sharedKeyByPackageName.values()).some((sharedPkg) => sharedPkg !== pkg && reachesPkg(sharedPkg, new Set([sharedPkg])));
1117
+ }
988
1118
  function tryResolveImportFromPackageRoot(pkg, root) {
989
1119
  try {
990
1120
  return createRequire$1(pathToFileURL(path$1.join(root, "package.json"))).resolve(pkg);
@@ -1114,26 +1244,46 @@ function materializeCachedLoadShareModule(options) {
1114
1244
  options.addUsedShares(pkg);
1115
1245
  options.writeLocalSharedImportMap();
1116
1246
  }
1247
+ function generateEagerWorkspaceSingletonExports(namedExports, importSource, cacheKey) {
1248
+ const namedExportLine = namedExports.length > 0 ? `\n export { ${namedExports.join(", ")} } from ${escapeGeneratedStringLiteral(importSource)};` : "";
1249
+ return `import * as __mfLocalShare from ${escapeGeneratedStringLiteral(importSource)};
1250
+ let exportModule = __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}];
1251
+ if (exportModule === undefined) {
1252
+ Promise.resolve().then(() => {
1253
+ if (__mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}] === undefined) {
1254
+ __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}] = __mfNormalizeShareModule(__mfLocalShare);
1255
+ }
1256
+ });
1257
+ exportModule = __mfLocalShare;
1258
+ }
1259
+ const __mf_default = exportModule.default ?? exportModule;
1260
+ export { __mf_default as default };${namedExportLine}`;
1261
+ }
1117
1262
  function generateLazyWorkspaceSingletonExports(namedExports, importSource, cacheKey, eagerLocalFallback) {
1118
1263
  const namedExportVars = namedExports.map((_name, i) => `__mf_${i}`);
1119
1264
  const declarations = namedExports.length > 0 ? ["let __mf_default;", ...namedExportVars.map((name) => `let ${name};`)].join("\n ") : "let __mf_default;";
1120
1265
  const assignments = namedExports.length > 0 ? [...namedExports.map((name, i) => `${namedExportVars[i]} = mod[${escapeGeneratedStringLiteral(name)}];`), "__mf_default = mod.default ?? mod;"].join("\n ") : "__mf_default = mod.default ?? mod;";
1121
1266
  const namedExportLine = namedExports.length > 0 ? `\n export { ${namedExports.map((name, i) => `${namedExportVars[i]} as ${name}`).join(", ")} };` : "";
1267
+ const applyLocalFallback = `exportModule = __mfNormalizeShareModule(__mfLocalShare);
1268
+ __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}] = exportModule;
1269
+ __mfApplyLazyShareExports(exportModule);`;
1122
1270
  const body = `${declarations}
1123
1271
  const __mfApplyLazyShareExports = (mod) => {
1124
1272
  ${assignments}
1125
1273
  };
1126
1274
  let exportModule = __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}];
1127
1275
  if (exportModule === undefined) {
1128
- ${eagerLocalFallback ? `exportModule = __mfNormalizeShareModule(__mfLocalShare);
1129
- __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}] = exportModule;
1130
- __mfApplyLazyShareExports(exportModule);` : `initPromise.then(() =>
1131
- import(${escapeGeneratedStringLiteral(importSource)}).then((mod) => {
1132
- exportModule = __mfNormalizeShareModule(mod);
1133
- __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}] = exportModule;
1134
- __mfApplyLazyShareExports(exportModule);
1135
- })
1136
- );`}
1276
+ ${eagerLocalFallback ? applyLocalFallback : `if (import.meta.env.SSR) {
1277
+ ${applyLocalFallback}
1278
+ } else {
1279
+ initPromise.then(() =>
1280
+ import(${escapeGeneratedStringLiteral(importSource)}).then((mod) => {
1281
+ exportModule = __mfNormalizeShareModule(mod);
1282
+ __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}] = exportModule;
1283
+ __mfApplyLazyShareExports(exportModule);
1284
+ })
1285
+ );
1286
+ }`}
1137
1287
  } else {
1138
1288
  __mfApplyLazyShareExports(exportModule);
1139
1289
  }
@@ -1141,6 +1291,16 @@ function generateLazyWorkspaceSingletonExports(namedExports, importSource, cache
1141
1291
  return eagerLocalFallback ? `import * as __mfLocalShare from ${escapeGeneratedStringLiteral(importSource)};
1142
1292
  ${body}` : body;
1143
1293
  }
1294
+ const WORKSPACE_SINGLETON_SSR_LOCAL_SHARE = "__mfNormalizeShareModule(__mfLocalShare)";
1295
+ function prependWorkspaceSingletonSsrImport(code) {
1296
+ if (!code.includes("if (import.meta.env.SSR)")) return code;
1297
+ if (!code.includes(WORKSPACE_SINGLETON_SSR_LOCAL_SHARE)) return code;
1298
+ if (code.includes("import * as __mfLocalShare")) return code;
1299
+ const importMatch = code.match(/initPromise\.then\(\(\)\s*=>\s*\n\s*import\((["'])(.+?)\1\)\.then\(\(mod\)\s*=>\s*\{[\s\S]*?__mfApplyLazyShareExports/);
1300
+ if (!importMatch) return code;
1301
+ const quote = importMatch[1];
1302
+ return `import * as __mfLocalShare from ${quote}${importMatch[2]}${quote};\n${code}`;
1303
+ }
1144
1304
  function generateDeferredHostProvidedExports(namedExports, pkg, cacheKey) {
1145
1305
  const namedExportVars = namedExports.map((_name, i) => `__mf_${i}`);
1146
1306
  const declarations = ["let __mf_default;", ...namedExportVars.map((name) => `let ${name};`)].join("\n ");
@@ -1207,11 +1367,13 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown) {
1207
1367
  const isWorkspacePackage = isWorkspacePackageEntry(pkg, localProviderPath) || isWorkspacePackageEntry(pkg, concreteSharedImportSource);
1208
1368
  const lazyLocalFallbackSource = concreteSharedImportSource || localProviderPath || sharedImportSource;
1209
1369
  const skipServePrebuildWarmup = command !== "build" && (pkg === "lit" || pkg.startsWith("lit/"));
1210
- const usesLazyLocalFallback = isWorkspacePackage && shareItem.shareConfig.singleton === true;
1370
+ const isWorkspaceSingleton = isWorkspacePackage && shareItem.shareConfig.singleton === true;
1371
+ const usesEagerWorkspaceFallback = isWorkspaceSingleton && isWorkspaceSingletonConsumedByPeer(pkg);
1211
1372
  const namedExports = getSharedNamedExports(pkg, shareItem);
1212
1373
  let exportLine;
1213
1374
  let initBlock = "";
1214
- if (usesLazyLocalFallback) {
1375
+ if (usesEagerWorkspaceFallback) exportLine = generateEagerWorkspaceSingletonExports(namedExports, lazyLocalFallbackSource, cacheKey);
1376
+ else if (isWorkspaceSingleton) {
1215
1377
  importLine = `${getRuntimeInitPromiseBootstrapCode()}\n ${importLine}`;
1216
1378
  exportLine = generateLazyWorkspaceSingletonExports(namedExports, lazyLocalFallbackSource, cacheKey, command !== "build");
1217
1379
  } else if (namedExports.length > 0) {
@@ -1234,9 +1396,9 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown) {
1234
1396
  initBlock = `exportModule = __mfNormalizeShareModule(__mfLocalShare);
1235
1397
  __mfModuleCache.share[${escapeGeneratedStringLiteral(cacheKey)}] = exportModule;`;
1236
1398
  }
1237
- const prebuildImportLine = usesLazyLocalFallback || isWorkspacePackage && command !== "build" ? "" : `import * as __mfLocalShare from ${escapeGeneratedStringLiteral(skipServePrebuildWarmup ? devImportSource : sharedImportSource)};`;
1399
+ const prebuildImportLine = isWorkspaceSingleton || isWorkspacePackage && command !== "build" ? "" : `import * as __mfLocalShare from ${escapeGeneratedStringLiteral(skipServePrebuildWarmup ? devImportSource : sharedImportSource)};`;
1238
1400
  const devDynamicImportLine = isWorkspacePackage ? "" : command !== "build" && !skipServePrebuildWarmup ? `;() => import(${escapeGeneratedStringLiteral(devImportSource)}).catch(() => {});` : "";
1239
- const moduleBody = usesLazyLocalFallback ? `
1401
+ const moduleBody = isWorkspaceSingleton ? `
1240
1402
  ${prebuildImportLine}
1241
1403
  ${devDynamicImportLine}
1242
1404
  ${importLine}
@@ -1340,6 +1502,7 @@ function generateLocalSharedImportMap() {
1340
1502
  shareConfig: {
1341
1503
  singleton: ${shareItem.shareConfig.singleton},
1342
1504
  requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)},
1505
+ strictVersion: ${shareItem.shareConfig.strictVersion},
1343
1506
  ${shareItem.shareConfig.import === false ? "import: false," : ""}
1344
1507
  }
1345
1508
  }
@@ -1372,9 +1535,12 @@ function generateUsedSharedPreloadConfig() {
1372
1535
  const shareItem = getShareItemForPreload(pkg);
1373
1536
  if (!shareItem) return null;
1374
1537
  return `${JSON.stringify(pkg)}: {
1538
+ version: ${JSON.stringify(shareItem.version)},
1539
+ scope: ${JSON.stringify(shareItem.scope)},
1375
1540
  shareConfig: {
1376
1541
  singleton: ${shareItem.shareConfig.singleton},
1377
1542
  requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)},
1543
+ strictVersion: ${shareItem.shareConfig.strictVersion},
1378
1544
  ${shareItem.shareConfig.import === false ? "import: false," : ""}
1379
1545
  }
1380
1546
  }`;
@@ -1394,7 +1560,11 @@ function getOrderedUsedShares() {
1394
1560
  }));
1395
1561
  }
1396
1562
  function orderSharedDependenciesFirst(sharedPackages) {
1397
- const sharedKeyByPackageName = new Map(sharedPackages.map((pkg) => [getPackageName(pkg), pkg]));
1563
+ const sharedKeyByPackageName = /* @__PURE__ */ new Map();
1564
+ sharedPackages.forEach((pkg) => {
1565
+ const packageName = getPackageName(pkg);
1566
+ if (!sharedKeyByPackageName.get(packageName) || pkg === packageName) sharedKeyByPackageName.set(packageName, pkg);
1567
+ });
1398
1568
  const visiting = /* @__PURE__ */ new Set();
1399
1569
  const visited = /* @__PURE__ */ new Set();
1400
1570
  const ordered = [];
@@ -1439,6 +1609,11 @@ function generateSharedCacheSeedItem(pkg, shareItem, importPath) {
1439
1609
  __mfModuleCache.share[${JSON.stringify(cacheKey)}] = exportModule;
1440
1610
  }`;
1441
1611
  }
1612
+ const sharedCacheKeyHelperCode = `const __mfGetSharedCacheKey = (pkg, singleton, version, scope) => {
1613
+ const normalizedScope = Array.isArray(scope) ? scope[0] : scope;
1614
+ const prefix = (normalizedScope || "default") + ":";
1615
+ return singleton || !version ? prefix + pkg : prefix + pkg + "@" + version;
1616
+ };`;
1442
1617
  const normalizeRuntimeShareCode = `const __mfNormalizeRuntimeShare = (mod) => {
1443
1618
  let current = mod;
1444
1619
  for (let i = 0; i < 5; i++) {
@@ -1450,6 +1625,40 @@ const normalizeRuntimeShareCode = `const __mfNormalizeRuntimeShare = (mod) => {
1450
1625
  }
1451
1626
  return current;
1452
1627
  };`;
1628
+ const sharedProviderSelectionHelperCode = `const __mfOriginalProviderKey = Symbol("mf.originalSharedProvider");
1629
+ const __mfResolveShareHook = { emit: (params) => params };
1630
+ const __mfCreateProviderSelectionVersions = (versions, strategy) => {
1631
+ if (strategy !== "version-first") return versions;
1632
+ const selectionVersions = {};
1633
+ for (const [version, provider] of Object.entries(versions)) {
1634
+ selectionVersions[version] = Object.assign({}, provider, {
1635
+ loaded: false,
1636
+ loading: undefined,
1637
+ lib: undefined,
1638
+ [__mfOriginalProviderKey]: provider
1639
+ });
1640
+ }
1641
+ return selectionVersions;
1642
+ };
1643
+ const __mfSelectSharedProvider = (versions, pkg, share, strategy) => {
1644
+ if (!versions || !share) return undefined;
1645
+ const scopes = Array.isArray(share.scope) ? share.scope : [share.scope || "default"];
1646
+ const selectionVersions = __mfCreateProviderSelectionVersions(versions, strategy);
1647
+ const shareScopeMap = {};
1648
+ for (const scope of scopes) {
1649
+ shareScopeMap[scope || "default"] = { [pkg]: selectionVersions };
1650
+ }
1651
+ const selected = runtimeShare.getRegisteredShare(
1652
+ shareScopeMap,
1653
+ pkg,
1654
+ { ...share, scope: scopes, strategy },
1655
+ __mfResolveShareHook
1656
+ )?.shared;
1657
+ return selected?.[__mfOriginalProviderKey] || selected;
1658
+ };`;
1659
+ function hasImportFalseShared$1(options) {
1660
+ return Object.values(options.shared ?? {}).some((share) => share?.shareConfig?.import === false);
1661
+ }
1453
1662
  function generateDirectSharedCacheSeedCode(command = "build") {
1454
1663
  return getOrderedUsedShares().map((pkg) => {
1455
1664
  const shareItem = getShareItemForPreload(pkg);
@@ -1487,6 +1696,7 @@ const SSR_ONLY_PLUGIN_SPECIFIERS = new Set(["@module-federation/vite/ssrEntryLoa
1487
1696
  const isSsrOnlyPlugin = (importStatement) => [...SSR_ONLY_PLUGIN_SPECIFIERS].some((s) => importStatement.includes(s));
1488
1697
  const getSsrOnlyPluginSpecifier = (importStatement) => [...SSR_ONLY_PLUGIN_SPECIFIERS].find((s) => importStatement.includes(s));
1489
1698
  function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(options), command = "build") {
1699
+ const needsSharedProviderSelectionHelper = hasImportFalseShared$1(options);
1490
1700
  const pluginImportNames = options.runtimePlugins.map((p, i) => {
1491
1701
  if (typeof p === "string") return [
1492
1702
  `$runtimePlugin_${i}`,
@@ -1509,6 +1719,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1509
1719
  globalThis.__VUE_HMR_RUNTIME__ = { createRecord() {}, rerender() {}, reload() {} };
1510
1720
  }
1511
1721
  import {init as runtimeInit, loadRemote} from "@module-federation/runtime";
1722
+ ${needsSharedProviderSelectionHelper ? "import {share as runtimeShare} from \"@module-federation/runtime/helpers\";" : ""}
1512
1723
  ${pluginImportNames.filter((item) => !isSsrOnlyPlugin(item[1])).map((item) => item[1]).join("\n")}
1513
1724
  ${command === "build" ? getRuntimeInitResolveBootstrapCode() : getRuntimeInitBootstrapCode() + "\n const { initResolve } = globalThis[globalKey];"}
1514
1725
  ${getRuntimeModuleCacheBootstrapCode()}
@@ -1536,6 +1747,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1536
1747
  }
1537
1748
  }
1538
1749
  }
1750
+ ${needsSharedProviderSelectionHelper ? sharedProviderSelectionHelperCode : ""}
1539
1751
 
1540
1752
  async function getLocalSharedImportMap() {
1541
1753
  if (!localSharedImportMapPromise) {
@@ -1555,6 +1767,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1555
1767
  }
1556
1768
 
1557
1769
  async function init(shared = {}, initScope = []) {
1770
+ ${sharedCacheKeyHelperCode}
1558
1771
  const {usedShared, usedRemotes} = await getLocalSharedImportMap()
1559
1772
  try {
1560
1773
  const allInstances = globalThis.__FEDERATION__?.__SHARE__;
@@ -1564,13 +1777,27 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1564
1777
  const scopeShare = scopes?.['${options.shareScope}'];
1565
1778
  if (!scopeShare) continue;
1566
1779
  for (const [pkg, versionMap] of Object.entries(scopeShare)) {
1567
- for (const [version, provider] of Object.entries(versionMap)) {
1780
+ const usedShare = usedShared?.[pkg];
1781
+ const selectedProvider = usedShare?.shareConfig?.import === false
1782
+ ? __mfSelectSharedProvider(versionMap, pkg, usedShare, '${options.shareStrategy}')
1783
+ : undefined;
1784
+ const providerEntries = usedShare?.shareConfig?.import === false
1785
+ ? Object.entries(versionMap).filter(([, provider]) => provider === selectedProvider)
1786
+ : Object.entries(versionMap);
1787
+ for (const [version, provider] of providerEntries) {
1568
1788
  if (!provider.lib) continue;
1569
- const cacheKey = provider.shareConfig?.singleton ? pkg : \`\${pkg}@\${version}\`;
1789
+ const cacheKey = __mfGetSharedCacheKey(pkg, provider.shareConfig?.singleton, version, ${JSON.stringify(options.shareScope)});
1570
1790
  if (__mfModuleCache.share[cacheKey] !== undefined) continue;
1571
1791
  const mod = typeof provider.lib === "function" ? provider.lib() : provider.lib;
1572
1792
  const resolved = await Promise.resolve(mod);
1573
- __mfModuleCache.share[cacheKey] = __mfNormalizeRuntimeShare(resolved);
1793
+ const normalized = __mfNormalizeRuntimeShare(resolved);
1794
+ __mfModuleCache.share[cacheKey] = normalized;
1795
+ if (provider.shareConfig?.singleton && usedShare) {
1796
+ const usedCacheKey = __mfGetSharedCacheKey(pkg, usedShare.shareConfig?.singleton, usedShare.version, usedShare.scope);
1797
+ if (__mfModuleCache.share[usedCacheKey] === undefined) {
1798
+ __mfModuleCache.share[usedCacheKey] = normalized;
1799
+ }
1800
+ }
1574
1801
  }
1575
1802
  }
1576
1803
  }
@@ -1578,6 +1805,14 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1578
1805
  } catch (e) {
1579
1806
  console.error('[Module Federation] Failed to bridge external shared modules', e)
1580
1807
  }
1808
+ for (const [pkg, share] of Object.entries(usedShared)) {
1809
+ const cacheKey = __mfGetSharedCacheKey(pkg, share.shareConfig?.singleton, share.version, share.scope);
1810
+ if (__mfModuleCache.share[cacheKey] !== undefined) continue;
1811
+ const singletonCacheKey = __mfGetSharedCacheKey(pkg, true, share.version, share.scope);
1812
+ if (__mfModuleCache.share[singletonCacheKey] !== undefined) {
1813
+ __mfModuleCache.share[cacheKey] = __mfModuleCache.share[singletonCacheKey];
1814
+ }
1815
+ }
1581
1816
  ${generateDirectSharedCacheSeedCode(command)}
1582
1817
  const __browserPlugins = [${pluginImportNames.filter((item) => !isSsrOnlyPlugin(item[1])).map((item) => `${item[0]}(${item[2]})`).join(", ")}];
1583
1818
  const __ssrPlugins = typeof globalThis.window === 'undefined'
@@ -1614,11 +1849,11 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1614
1849
  console.error('[Module Federation]', e)
1615
1850
  }
1616
1851
  for (const [pkg, share] of Object.entries(usedShared)) {
1617
- const cacheKey = share.shareConfig?.singleton || !share.version ? pkg : \`\${pkg}@\${share.version}\`;
1852
+ const cacheKey = __mfGetSharedCacheKey(pkg, share.shareConfig?.singleton, share.version, share.scope);
1618
1853
  if (share.shareConfig?.import !== false || __mfModuleCache.share[cacheKey] !== undefined) continue;
1619
1854
  ${normalizeRuntimeShareCode}
1620
1855
  const versions = shared?.[pkg];
1621
- const provider = versions && versions[Object.keys(versions)[0]];
1856
+ const provider = __mfSelectSharedProvider(versions, pkg, share, '${options.shareStrategy}');
1622
1857
  if (!provider) continue;
1623
1858
  const factory = provider.lib || (provider.loading ? await provider.loading : await provider.get?.());
1624
1859
  const mod = typeof factory === "function" ? factory() : factory;
@@ -1654,10 +1889,11 @@ function generateHostAutoInitCode(remoteEntryImport, _command = "build") {
1654
1889
  const remoteEntry = await import(${remoteEntryImport});
1655
1890
  const runtime = await remoteEntry.init();
1656
1891
  const usedShared = ${generateUsedSharedPreloadConfig()};
1892
+ ${sharedCacheKeyHelperCode}
1657
1893
  ${normalizeRuntimeShareCode}
1658
1894
  ${shouldPreloadShares ? `
1659
1895
  for (const [pkg, share] of Object.entries(usedShared)) {
1660
- const cacheKey = share.shareConfig?.singleton || !share.version ? pkg : \`\${pkg}@\${share.version}\`;
1896
+ const cacheKey = __mfGetSharedCacheKey(pkg, share.shareConfig?.singleton, share.version, share.scope);
1661
1897
  if (__mfModuleCache.share[cacheKey] !== undefined) {
1662
1898
  continue;
1663
1899
  }
@@ -1866,7 +2102,7 @@ function getRemoteExportBlock(command, deferRemoteLoad, consumer) {
1866
2102
  if (command !== "serve" && command !== "build") return `__mfSyncDefaultExport();
1867
2103
  export { __mfDefaultExport as default };`;
1868
2104
  return `__mfSyncDefaultExport();
1869
- __mfRemotePending?.then(__mfSyncDefaultExport);
2105
+ __mfRemotePending?.then(__mfSyncDefaultExport, () => {});
1870
2106
  export { exportModule as __moduleExports };
1871
2107
  ${deferRemoteLoad ? getLazyRemotePendingExport() : getEagerRemotePendingExport()}
1872
2108
  ${command === "serve" && consumer === "server" ? getServerThenExport() : ""}
@@ -1897,8 +2133,9 @@ function generateRemotes(id, command, enableSsrInit = false, consumer = "unified
1897
2133
  const remoteLoadFailureHandler = command === "build" ? `.catch((error) => {
1898
2134
  delete __mfModuleCache.remote[pendingKey];
1899
2135
  throw error;
1900
- })` : `.catch(() => {
2136
+ })` : `.catch((error) => {
1901
2137
  delete __mfModuleCache.remote[pendingKey];
2138
+ throw error;
1902
2139
  })`;
1903
2140
  const remoteLoadCode = `
1904
2141
  function __mfStartRemoteLoad() {
@@ -2024,9 +2261,11 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
2024
2261
  let _command;
2025
2262
  let emitFileId;
2026
2263
  let viteConfig;
2027
- let clientInjected = forceClientInjected ?? false;
2264
+ let skipHtmlDevFallback = forceClientInjected ?? false;
2265
+ let clientInjected = false;
2028
2266
  let emittedFileName;
2029
2267
  let skipTransformIds = /* @__PURE__ */ new Set();
2268
+ let injectedTransformIds = /* @__PURE__ */ new Set();
2030
2269
  let bootstrapDir = "";
2031
2270
  function skipSvelteKitSsrBuild() {
2032
2271
  return (_command === "build" || viteConfig?.command === "build") && viteConfig?.build?.ssr && hasPackageDependency("@sveltejs/kit");
@@ -2148,6 +2387,10 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
2148
2387
  if (id.startsWith("\0") || id.startsWith("virtual:")) return normalizeModuleId(id);
2149
2388
  return normalizeModuleId(path$1.isAbsolute(id) ? id : path$1.resolve(viteConfig.root, id));
2150
2389
  }
2390
+ function isFederationInternalVirtualId(id) {
2391
+ const normalized = decodeViteId(id).replace(/^\0+/, "");
2392
+ return normalized.includes("virtual:mf:") || /__(?:loadShare|prebuild|loadRemote)__/.test(normalized);
2393
+ }
2151
2394
  function addEntryFile(file) {
2152
2395
  const normalized = normalizeModuleId(file);
2153
2396
  if (!entryFiles.includes(normalized)) entryFiles.push(normalized);
@@ -2255,9 +2498,9 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
2255
2498
  if (envName?.name && envName.name !== "client") return;
2256
2499
  const inputOptions = getBuildInput(config);
2257
2500
  if (!inputOptions) htmlFilePath = path$1.resolve(config.root, "index.html");
2258
- else if (typeof inputOptions === "string") entryFiles = [normalizeModuleId(inputOptions)];
2259
- else if (Array.isArray(inputOptions)) entryFiles = inputOptions.map(normalizeModuleId);
2260
- else if (typeof inputOptions === "object") entryFiles = Object.values(inputOptions).map((input) => normalizeModuleId(String(input)));
2501
+ else if (typeof inputOptions === "string") entryFiles = [resolveProjectId(inputOptions)];
2502
+ else if (Array.isArray(inputOptions)) entryFiles = inputOptions.map(resolveProjectId);
2503
+ else if (typeof inputOptions === "object") entryFiles = Object.values(inputOptions).map((input) => resolveProjectId(String(input)));
2261
2504
  if (entryFiles.length > 0) htmlFilePath = getFirstHtmlEntryFile(entryFiles);
2262
2505
  if (htmlFilePath) addHtmlScriptEntries(htmlFilePath);
2263
2506
  },
@@ -2357,7 +2600,8 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
2357
2600
  if (isSvelteKitServerModule(id)) return;
2358
2601
  if (hasEntryBootstrapParam(id)) return;
2359
2602
  if (normalizeModuleId(id).endsWith(".html")) return;
2360
- if (skipTransformIds.has(resolveProjectId(id))) return;
2603
+ const projectId = resolveProjectId(id);
2604
+ if (skipTransformIds.has(projectId)) return;
2361
2605
  const transformCtx = this;
2362
2606
  const transformEnv = transformCtx != null && typeof transformCtx === "object" ? transformCtx["environment"] : void 0;
2363
2607
  if (transformEnv?.name && transformEnv.name !== "client") return;
@@ -2382,12 +2626,13 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
2382
2626
  const injection = `await import(${JSON.stringify(getEntryPath())}).then(({ initHost }) => initHost());\n `;
2383
2627
  return mapCodeToCodeWithSourcemap(code.replace("vueApp.mount(vueAppRootContainer);", `${injection}vueApp.mount(vueAppRootContainer);`));
2384
2628
  }
2385
- const isHydrationEntryFallback = inject === "entry" && entryFiles.length === 0 && (!htmlFilePath || !fs$1.existsSync(htmlFilePath)) && !clientInjected && !id.includes("node_modules") && (id.startsWith("\0") || /\.(js|ts|mjs|vue|jsx|tsx)(\?|$)/.test(id)) && /hydrateRoot|createRoot|ReactDOM\.render/.test(code);
2629
+ const isHydrationEntryFallback = inject === "entry" && entryFiles.length === 0 && (!htmlFilePath || !fs$1.existsSync(htmlFilePath)) && !clientInjected && !isFederationInternalVirtualId(id) && !id.includes("node_modules") && (id.startsWith("\0") || /\.(js|ts|mjs|vue|jsx|tsx)(\?|$)/.test(id)) && (/hydrateRoot|createRoot|ReactDOM\.render/.test(code) || /\.mount\s*\(\s*['"#]/.test(code) || /\.mount\s*\(/.test(code) && /createSSRApp|createApp/.test(code));
2386
2630
  const isNuxtEntryAsyncModule = /(?:^|\/)nuxt\/dist\/app\/entry\.async\.js(?:\?|$)/.test(id) && code.includes("entry();");
2387
- const isNuxtClientEntryFallback = _command === "serve" && inject === "entry" && (!htmlFilePath || !fs$1.existsSync(htmlFilePath)) && !clientInjected && !hasEntryBootstrapParam(id) && !id.includes("node_modules/.vite") && isNuxtEntryAsyncModule && !entryFiles.some((file) => resolveProjectId(id) === file);
2388
- if (!(_command === "serve" && isNuxtEntryAsyncModule) && (injectEntry() && entryFiles.some((file) => resolveProjectId(id) === file) || _command === "serve" && inject === "html" && !isVinext && !clientInjected && !id.startsWith("\0") && !id.includes("node_modules") && /\.(js|ts|mjs|vue|jsx|tsx)(\?|$)/.test(id) || isHydrationEntryFallback || isNuxtClientEntryFallback)) {
2631
+ const isNuxtClientEntryFallback = _command === "serve" && inject === "entry" && (!htmlFilePath || !fs$1.existsSync(htmlFilePath)) && !clientInjected && !hasEntryBootstrapParam(id) && !id.includes("node_modules/.vite") && isNuxtEntryAsyncModule && !entryFiles.some((file) => projectId === file);
2632
+ if (!(_command === "serve" && isNuxtEntryAsyncModule) && (injectedTransformIds.has(projectId) || injectEntry() && entryFiles.some((file) => projectId === file) || _command === "serve" && inject === "html" && !isVinext && !clientInjected && !skipHtmlDevFallback && !id.startsWith("\0") && !id.includes("node_modules") && /\.(js|ts|mjs|vue|jsx|tsx)(\?|$)/.test(id) || isHydrationEntryFallback || isNuxtClientEntryFallback)) {
2389
2633
  clientInjected = true;
2390
- if (!waitsForInit || _command === "serve" && inject === "entry" && isHydrationEntryFallback) return mapCodeToCodeWithSourcemap(`import ${JSON.stringify(getEntryPath())};\n` + code);
2634
+ injectedTransformIds.add(projectId);
2635
+ if (!waitsForInit) return mapCodeToCodeWithSourcemap(`import ${JSON.stringify(getEntryPath())};\n` + code);
2391
2636
  const entrySrc = id.includes("?") ? `${id}&${ENTRY_BOOTSTRAP_QUERY.slice(1)}` : `${id}${ENTRY_BOOTSTRAP_QUERY}`;
2392
2637
  return mapCodeToCodeWithSourcemap(getBootstrapSource(getEntryPath(), entrySrc, false, { skipRemotePreload: _command === "serve" && isNuxtEntryAsyncModule }));
2393
2638
  }
@@ -2592,7 +2837,7 @@ const REMOTE_HMR_ENDPOINT = "__mf_hmr";
2592
2837
  const REMOTE_HMR_EVENT = "mf:remote-update";
2593
2838
  const REMOTE_HMR_CONNECT_RETRY_DELAY_MS = 1e3;
2594
2839
  const REMOTE_HMR_CONNECT_MAX_RETRIES = 10;
2595
- function getBasePath$1(base) {
2840
+ function getBasePath(base) {
2596
2841
  if (!base) return "/";
2597
2842
  if (base.startsWith("http://") || base.startsWith("https://")) try {
2598
2843
  return new URL(base).pathname || "/";
@@ -2602,11 +2847,11 @@ function getBasePath$1(base) {
2602
2847
  return base;
2603
2848
  }
2604
2849
  function getRemoteHmrPath(base) {
2605
- return `${getBasePath$1(base).replace(/\/?$/, "/")}${REMOTE_HMR_ENDPOINT}`.replace(/\/{2,}/g, "/");
2850
+ return `${getBasePath(base).replace(/\/?$/, "/")}${REMOTE_HMR_ENDPOINT}`.replace(/\/{2,}/g, "/");
2606
2851
  }
2607
2852
  function getHmrWsPath(base, hmrPath) {
2608
- const normalizedBase = getBasePath$1(base);
2609
- const normalizedPath = getBasePath$1(hmrPath || "");
2853
+ const normalizedBase = getBasePath(base);
2854
+ const normalizedPath = getBasePath(hmrPath || "");
2610
2855
  if (!normalizedPath || normalizedPath === "/") return normalizedBase;
2611
2856
  return `${normalizedBase.endsWith("/") ? normalizedBase.slice(0, -1) : normalizedBase}/${normalizedPath.startsWith("/") ? normalizedPath.slice(1) : normalizedPath}`;
2612
2857
  }
@@ -3255,70 +3500,6 @@ const buildFileToShareKeyMap = async (shareKeys, resolveFn) => {
3255
3500
  return fileToShareKey;
3256
3501
  };
3257
3502
  //#endregion
3258
- //#region src/utils/pathNormalization.ts
3259
- const COMMON_SHARED_SUBPATHS = {
3260
- react: [
3261
- "react/jsx-runtime",
3262
- "react/jsx-dev-runtime",
3263
- "react/compiler-runtime"
3264
- ],
3265
- "react-dom": [
3266
- "react-dom/client",
3267
- "react-dom/server",
3268
- "react-dom/server.browser"
3269
- ],
3270
- "solid-js": [
3271
- "solid-js/web",
3272
- "solid-js/store",
3273
- "solid-js/html",
3274
- "solid-js/h"
3275
- ]
3276
- };
3277
- function removeTrailingSlash(value) {
3278
- return value.endsWith("/") ? value.slice(0, -1) : value;
3279
- }
3280
- function ensureTrailingSlash(value) {
3281
- return `${removeTrailingSlash(value)}/`;
3282
- }
3283
- function getBasePath(base) {
3284
- return removeTrailingSlash(base || "/");
3285
- }
3286
- function isNuxtClientBase(base) {
3287
- return getBasePath(base).endsWith("/_nuxt");
3288
- }
3289
- function normalizeNodeModulePath(source) {
3290
- return source.replace(/\\/g, "/").replace(/\?.*$/, "");
3291
- }
3292
- function isNodeModulePath(source) {
3293
- return source.includes("/node_modules/") || source.includes("\\node_modules\\");
3294
- }
3295
- function filterId(id) {
3296
- return typeof id === "string" && !id.includes("\0");
3297
- }
3298
- function getMatchingNodeModuleSubpath(source, candidates) {
3299
- const normalized = normalizeNodeModulePath(source);
3300
- return [...candidates].sort((a, b) => b.length - a.length).find((candidate) => normalized.includes(`/node_modules/${candidate}/`) || normalized.includes(`/node_modules/${candidate}.`));
3301
- }
3302
- function getCommonSharedSubpaths(sharedKey) {
3303
- return COMMON_SHARED_SUBPATHS[removeTrailingSlash(sharedKey)] || [];
3304
- }
3305
- function getCommonSharedSubpathFromNodeModulePath(source, sharedKey) {
3306
- return getMatchingNodeModuleSubpath(source, getCommonSharedSubpaths(removeTrailingSlash(sharedKey)));
3307
- }
3308
- /**
3309
- * Resolves the public path for remote entries
3310
- * @param options - Module Federation options
3311
- * @param viteBase - Vite's base config value
3312
- * @param originalBase - Original base config before any transformations
3313
- * @returns The resolved public path
3314
- */
3315
- function resolvePublicPath(options, viteBase, originalBase) {
3316
- if (options.publicPath && options.publicPath !== "auto") return options.publicPath;
3317
- if (!originalBase) return "auto";
3318
- if (viteBase) return ensureTrailingSlash(viteBase);
3319
- return "auto";
3320
- }
3321
- //#endregion
3322
3503
  //#region src/virtualModules/virtualExposesSSR.ts
3323
3504
  /**
3324
3505
  * Virtual module ID for the SSR exposes map.
@@ -3471,6 +3652,24 @@ function resolveTypesMeta(dts) {
3471
3652
  api: `${typesFolder}.d.ts`
3472
3653
  };
3473
3654
  }
3655
+ function resolveDevRemoteEntryFileName(fileName) {
3656
+ if (!fileName.includes("[hash")) return fileName;
3657
+ const normalized = fileName.replace(/(?:[._-]?\[hash(?::\d+)?\])/g, "");
3658
+ const baseName = path$1.basename(normalized);
3659
+ return path$1.extname(baseName) ? normalized : `${normalized}.js`;
3660
+ }
3661
+ function createRemoteEntryAssetMap(fileName) {
3662
+ return {
3663
+ js: {
3664
+ async: [],
3665
+ sync: [fileName]
3666
+ },
3667
+ css: {
3668
+ async: [],
3669
+ sync: []
3670
+ }
3671
+ };
3672
+ }
3474
3673
  const Manifest = () => {
3475
3674
  const mfOptions = getNormalizeModuleFederationOptions();
3476
3675
  const { name, filename, getPublicPath, manifest: manifestOptions, varFilename } = mfOptions;
@@ -3504,6 +3703,12 @@ const Manifest = () => {
3504
3703
  next();
3505
3704
  return;
3506
3705
  }
3706
+ const devRemoteEntryFile = resolveDevRemoteEntryFileName(filename);
3707
+ if (devRemoteEntryFile !== filename && req.url?.startsWith((viteConfig.base + devRemoteEntryFile).replace(/^\/?/, "/"))) {
3708
+ req.url = req.url.replace(devRemoteEntryFile, filename);
3709
+ next();
3710
+ return;
3711
+ }
3507
3712
  if (req.url?.replace(/\?.*/, "") === (viteConfig.base + mfManifestName).replace(/^\/?/, "/")) {
3508
3713
  res.setHeader("Content-Type", "application/json");
3509
3714
  res.setHeader("Access-Control-Allow-Origin", "*");
@@ -3520,12 +3725,12 @@ const Manifest = () => {
3520
3725
  buildName: name
3521
3726
  },
3522
3727
  remoteEntry: {
3523
- name: filename,
3728
+ name: devRemoteEntryFile,
3524
3729
  path: "",
3525
3730
  type: "module"
3526
3731
  },
3527
3732
  ssrRemoteEntry: {
3528
- name: getSsrRemoteEntryFileName(filename),
3733
+ name: getSsrRemoteEntryFileName(devRemoteEntryFile),
3529
3734
  path: "/__mf_ssr__/",
3530
3735
  type: "module"
3531
3736
  },
@@ -3566,10 +3771,10 @@ const Manifest = () => {
3566
3771
  if (!mfManifestName) return;
3567
3772
  let filesMap = {};
3568
3773
  const foundRemoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
3569
- const expectedSsrRemoteEntryFile = getSsrRemoteEntryFileName(mfOptions.filename);
3774
+ const expectedSsrRemoteEntryFile = getSsrRemoteEntryFileName(foundRemoteEntryFile || mfOptions.filename);
3570
3775
  const foundSsrRemoteEntryFile = Object.values(bundle).find((file) => file.fileName === expectedSsrRemoteEntryFile)?.fileName;
3571
3776
  if (foundRemoteEntryFile) remoteEntryFile = foundRemoteEntryFile;
3572
- ssrRemoteEntryFile = foundSsrRemoteEntryFile || expectedSsrRemoteEntryFile;
3777
+ ssrRemoteEntryFile = foundSsrRemoteEntryFile || (_command === "serve" ? getSsrRemoteEntryFileName(resolveDevRemoteEntryFileName(mfOptions.filename)) : expectedSsrRemoteEntryFile);
3573
3778
  const allCssAssets = mfOptions.bundleAllCSS && !disableAssetsAnalyze ? collectCssAssets(bundle) : /* @__PURE__ */ new Set();
3574
3779
  if (!disableAssetsAnalyze) {
3575
3780
  const exposesModules = Object.keys(mfOptions.exposes).map((item) => mfOptions.exposes[item].import);
@@ -3610,13 +3815,14 @@ const Manifest = () => {
3610
3815
  function generateMFManifest(preloadMap, disableAssetsAnalyze = false) {
3611
3816
  const options = getNormalizeModuleFederationOptions();
3612
3817
  const { name, varFilename } = options;
3818
+ const resolvedRemoteEntryFile = _command === "serve" ? remoteEntryFile || resolveDevRemoteEntryFileName(filename) : remoteEntryFile;
3613
3819
  const remoteEntry = {
3614
- name: remoteEntryFile,
3820
+ name: resolvedRemoteEntryFile,
3615
3821
  path: "",
3616
3822
  type: "module"
3617
3823
  };
3618
3824
  const ssrRemoteEntry = {
3619
- name: ssrRemoteEntryFile || getSsrRemoteEntryFileName(filename),
3825
+ name: ssrRemoteEntryFile || getSsrRemoteEntryFileName(_command === "serve" ? resolveDevRemoteEntryFileName(filename) : filename),
3620
3826
  path: _command === "serve" ? "/__mf_ssr__/" : "",
3621
3827
  type: "module"
3622
3828
  };
@@ -3634,7 +3840,7 @@ const Manifest = () => {
3634
3840
  const shared = Array.from(getUsedShares()).flatMap((shareKey) => {
3635
3841
  const shareItem = getNormalizeShareItem(shareKey);
3636
3842
  if (!shareItem) return [];
3637
- const assets = preloadMap[shareKey] || createEmptyAssetMap();
3843
+ const assets = preloadMap[shareKey] || (_command === "serve" && resolvedRemoteEntryFile ? createRemoteEntryAssetMap(resolvedRemoteEntryFile) : createEmptyAssetMap());
3638
3844
  return [{
3639
3845
  id: `${name}:${shareKey}`,
3640
3846
  name: shareKey,
@@ -3655,7 +3861,7 @@ const Manifest = () => {
3655
3861
  });
3656
3862
  const exposes = Object.entries(options.exposes).map(([key, value]) => {
3657
3863
  const formatKey = key.replace("./", "");
3658
- const assets = preloadMap[value.import] || createEmptyAssetMap();
3864
+ const assets = preloadMap[value.import] || (_command === "serve" && resolvedRemoteEntryFile ? createRemoteEntryAssetMap(resolvedRemoteEntryFile) : createEmptyAssetMap());
3659
3865
  return {
3660
3866
  id: `${name}:${formatKey}`,
3661
3867
  name: formatKey,
@@ -4651,7 +4857,7 @@ function pluginSSRRemoteEntry(options) {
4651
4857
  },
4652
4858
  configureServer(server) {
4653
4859
  const base = "/__mf_ssr__";
4654
- const basePath = getBasePath(viteConfig?.base);
4860
+ const basePath = getBasePath$1(viteConfig?.base);
4655
4861
  const ssrEntryFileName = getSsrRemoteEntryFileName(options.filename);
4656
4862
  if (isNuxtProject || isNuxtClientBase(basePath)) server.middlewares.use((req, _res, next) => {
4657
4863
  if (req.url?.replace(/\?.*/, "") === `${basePath}/${ssrEntryFileName}`) req.url = `${basePath}/__mf_ssr__/${ssrEntryFileName}`;
@@ -4955,6 +5161,13 @@ var normalizeOptimizeDeps_default = {
4955
5161
  if (!optimizeDeps.include) optimizeDeps.include = [];
4956
5162
  if (!optimizeDeps.exclude) optimizeDeps.exclude = [];
4957
5163
  if (!optimizeDeps.needsInterop) optimizeDeps.needsInterop = [];
5164
+ },
5165
+ configResolved: (config) => {
5166
+ const include = config.optimizeDeps?.include;
5167
+ const exclude = config.optimizeDeps?.exclude;
5168
+ if (!include?.length || !exclude?.length) return;
5169
+ const included = new Set(include);
5170
+ config.optimizeDeps.exclude = exclude.filter((dep) => !included.has(dep));
4958
5171
  }
4959
5172
  };
4960
5173
  //#endregion
@@ -5005,6 +5218,17 @@ function appendResolveAlias(config, alias) {
5005
5218
  replacement
5006
5219
  })), alias];
5007
5220
  }
5221
+ function hasImportFalseShared(options) {
5222
+ return Object.values(options.shared ?? {}).some((share) => share?.shareConfig?.import === false);
5223
+ }
5224
+ function getRuntimeHelpersImplementation(runtimeImplementation) {
5225
+ const indexEntryMatch = runtimeImplementation.match(/^(.*[\\/])index(\.[cm]?js)$/);
5226
+ if (indexEntryMatch) return `${indexEntryMatch[1]}helpers${indexEntryMatch[2]}`;
5227
+ const extension = path$1.extname(runtimeImplementation);
5228
+ if (extension) return path$1.join(path$1.dirname(runtimeImplementation), `helpers${extension}`);
5229
+ if (path$1.isAbsolute(runtimeImplementation) || runtimeImplementation.startsWith(".")) return path$1.join(runtimeImplementation, "helpers");
5230
+ return `${runtimeImplementation.replace(/\/$/, "")}/helpers`;
5231
+ }
5008
5232
  const UNSAFE_JS_SOURCE_CHAR_MAP = {
5009
5233
  "<": "\\u003C",
5010
5234
  ">": "\\u003E",
@@ -5108,6 +5332,7 @@ function createEarlyVirtualModulesPlugin(options) {
5108
5332
  external: true
5109
5333
  }));
5110
5334
  build.onResolve({ filter: /.*/ }, (args) => {
5335
+ if (args.kind === "entry-point") return;
5111
5336
  if (!args.importer || args.namespace === "mf-shared") return;
5112
5337
  if (isSharedResolverInternalImporter(args.importer)) return;
5113
5338
  if (!findSharedKey(args.path, shared) || args.path.endsWith(".css")) return;
@@ -5221,7 +5446,7 @@ export default __mfShared.default ?? __mfShared;`
5221
5446
  const SSR_ONLY_PLUGINS = new Set(["@module-federation/vite/ssrEntryLoader"]);
5222
5447
  function loadPluginDts(options) {
5223
5448
  if (options.dts === false) return [];
5224
- return [import("./pluginDts-Cpmdbbr0.js").then((n) => n.n).then(({ default: pluginDts }) => pluginDts(options))];
5449
+ return [import("./pluginDts-CrSsDUnT.js").then((n) => n.n).then(({ default: pluginDts }) => pluginDts(options))];
5225
5450
  }
5226
5451
  function federation(mfUserOptions) {
5227
5452
  if (isTestEnv()) return [];
@@ -5233,6 +5458,7 @@ function federation(mfUserOptions) {
5233
5458
  const virtualExposesId = getVirtualExposesId(options);
5234
5459
  let command;
5235
5460
  let desiredRolldownOutput;
5461
+ let isSsrBuild = false;
5236
5462
  return [
5237
5463
  {
5238
5464
  name: "vite:module-federation-virtual-modules",
@@ -5344,6 +5570,7 @@ function federation(mfUserOptions) {
5344
5570
  enforce: "pre",
5345
5571
  apply: "build",
5346
5572
  config(config) {
5573
+ isSsrBuild = config.build?.ssr === true;
5347
5574
  const runtimeInitId = virtualRuntimeInitStatus.getImportId();
5348
5575
  config.build = config.build || {};
5349
5576
  if (config.build.modulePreload !== false) {
@@ -5465,6 +5692,8 @@ function federation(mfUserOptions) {
5465
5692
  load(id) {
5466
5693
  if (id.includes("__loadShare__") || id.includes("__loadRemote__")) {
5467
5694
  let code = VirtualModule.findById(id)?.code ?? readFileSync(id, "utf-8");
5695
+ const environmentName = this.environment?.name;
5696
+ if (environmentName && environmentName !== "client" || !environmentName && isSsrBuild) code = prependWorkspaceSingletonSsrImport(code);
5468
5697
  code = code.replace(/import\s+["'][^"']*__prebuild__[^"']*["']\s*;?/g, "");
5469
5698
  code = code.replace(/export\s+\*\s+from\s+["'][^"']*__prebuild__[^"']*["']\s*;?/g, "");
5470
5699
  if (!(/\b(?:var|let|const)\s+__moduleExports\b/.test(code) || /\bexport\s+const\s+__moduleExports\b/.test(code) || /\bexport\s*\{[^}]*__moduleExports/.test(code))) {
@@ -5526,8 +5755,14 @@ function federation(mfUserOptions) {
5526
5755
  _options: options,
5527
5756
  config(config, { command: _command }) {
5528
5757
  const isRolldown = getIsRolldown(this);
5758
+ isSsrBuild = _command === "build" && config.build?.ssr === true;
5759
+ const needsSharedProviderSelectionHelper = hasImportFalseShared(options);
5760
+ if (needsSharedProviderSelectionHelper) appendResolveAlias(config, {
5761
+ find: /^@module-federation\/runtime\/helpers$/,
5762
+ replacement: getRuntimeHelpersImplementation(options.implementation)
5763
+ });
5529
5764
  appendResolveAlias(config, {
5530
- find: "@module-federation/runtime",
5765
+ find: /^@module-federation\/runtime$/,
5531
5766
  replacement: options.implementation
5532
5767
  });
5533
5768
  config.build ||= {};
@@ -5536,6 +5771,7 @@ function federation(mfUserOptions) {
5536
5771
  config.optimizeDeps ||= {};
5537
5772
  config.optimizeDeps.include ||= [];
5538
5773
  config.optimizeDeps.include.push("@module-federation/runtime");
5774
+ if (needsSharedProviderSelectionHelper) config.optimizeDeps.include.push("@module-federation/runtime/helpers");
5539
5775
  options.runtimePlugins.forEach((p) => {
5540
5776
  const pluginPath = typeof p === "string" ? p : p[0];
5541
5777
  if (SSR_ONLY_PLUGINS.has(pluginPath)) return;
@@ -5550,7 +5786,17 @@ function federation(mfUserOptions) {
5550
5786
  const envTargetDefineValue = !options.target && isAstro ? "undefined" : JSON.stringify(resolvedTarget);
5551
5787
  if (!config.define) config.define = {};
5552
5788
  if (!("ENV_TARGET" in config.define)) config.define["ENV_TARGET"] = envTargetDefineValue;
5789
+ if (resolvedTarget === "node" && !("FEDERATION_OPTIMIZE_NO_SNAPSHOT_PLUGIN" in config.define)) config.define["FEDERATION_OPTIMIZE_NO_SNAPSHOT_PLUGIN"] = "true";
5553
5790
  if (options.target && "ENV_TARGET" in config.define && config.define["ENV_TARGET"] !== JSON.stringify(options.target)) mfWarn(`ENV_TARGET define (${config.define["ENV_TARGET"]}) differs from target option ("${options.target}"). ENV_TARGET will not be overridden.`);
5791
+ },
5792
+ configEnvironment(name, config) {
5793
+ if (!(config.consumer === "server" || name === "ssr" || name === "server" || config.build?.ssr === true)) return;
5794
+ const isAstro = hasPackageDependency("astro");
5795
+ const envTargetDefineValue = !options.target && isAstro ? "undefined" : JSON.stringify(options.target ?? "node");
5796
+ config.define = { ...config.define ?? {} };
5797
+ if (!("ENV_TARGET" in config.define)) config.define["ENV_TARGET"] = envTargetDefineValue;
5798
+ if (!("FEDERATION_OPTIMIZE_NO_SNAPSHOT_PLUGIN" in config.define)) config.define["FEDERATION_OPTIMIZE_NO_SNAPSHOT_PLUGIN"] = "true";
5799
+ if (options.target && config.define["ENV_TARGET"] !== JSON.stringify(options.target)) mfWarn(`ENV_TARGET define (${config.define["ENV_TARGET"]}) differs from target option ("${options.target}"). ENV_TARGET will not be overridden.`);
5554
5800
  }
5555
5801
  },
5556
5802
  ...Manifest(),
@@ -194,7 +194,8 @@ function getPackageNameFromNodeModulePath(source) {
194
194
  return parts[0];
195
195
  }
196
196
  function getSharedCacheKey(pkg, shareItem) {
197
- return shareItem.shareConfig.singleton || !shareItem.version ? pkg : `${pkg}@${shareItem.version}`;
197
+ const prefix = `${shareItem.scope || "default"}:`;
198
+ return shareItem.shareConfig.singleton || !shareItem.version ? `${prefix}${pkg}` : `${prefix}${pkg}@${shareItem.version}`;
198
199
  }
199
200
  function getInstalledPackageJson(pkg, opts) {
200
201
  const cwd = opts?.cwd || getPackageDetectionCwd();
@@ -87,7 +87,24 @@ const _path = () => nodeImport("path");
87
87
  const _fs = () => nodeImport("fs");
88
88
  const _crypto = () => nodeImport("crypto");
89
89
  const _module = () => nodeImport("module");
90
- const manifestCache = /* @__PURE__ */ new Map();
90
+ const ssrEntryCache = /* @__PURE__ */ new Map();
91
+ const manifestFetchCache = /* @__PURE__ */ new Map();
92
+ var SsrEntryHttpError = class extends Error {
93
+ constructor(url, status, statusText, bodyPreview) {
94
+ super(`Failed to fetch SSR module "${url}": ${status} ${statusText}` + (bodyPreview ? `\npreview: ${bodyPreview}` : ""));
95
+ this.url = url;
96
+ this.status = status;
97
+ this.statusText = statusText;
98
+ this.bodyPreview = bodyPreview;
99
+ this.name = "SsrEntryHttpError";
100
+ }
101
+ };
102
+ function getBodyPreview(body) {
103
+ return body.slice(0, 240).replace(/\s+/g, " ").trim();
104
+ }
105
+ function isSsrEntryHttpError(error) {
106
+ return error instanceof SsrEntryHttpError;
107
+ }
91
108
  async function fetchManifest(manifestUrl) {
92
109
  try {
93
110
  const res = await fetch(manifestUrl);
@@ -97,9 +114,33 @@ async function fetchManifest(manifestUrl) {
97
114
  return null;
98
115
  }
99
116
  }
117
+ async function fetchManifestCached(manifestUrl) {
118
+ if (!manifestFetchCache.has(manifestUrl)) manifestFetchCache.set(manifestUrl, fetchManifest(manifestUrl));
119
+ return manifestFetchCache.get(manifestUrl);
120
+ }
121
+ /** True when the host configured a manifest URL as the remote entry (any .json name). */
122
+ function isManifestEntry(remoteEntryUrl) {
123
+ try {
124
+ const { pathname } = new URL(remoteEntryUrl);
125
+ return /\.json$/i.test(pathname);
126
+ } catch {
127
+ return /\.json(?:[?#]|$)/i.test(remoteEntryUrl);
128
+ }
129
+ }
130
+ function isSsrEntry(remoteEntryUrl) {
131
+ return /\.ssr\.js(?:[?#].*)?$/.test(remoteEntryUrl);
132
+ }
100
133
  function getManifestUrl(remoteEntryUrl) {
134
+ if (isManifestEntry(remoteEntryUrl)) return remoteEntryUrl;
101
135
  return remoteEntryUrl.replace(/\/[^/]+$/, "/mf-manifest.json");
102
136
  }
137
+ function getEntryFilename(entryUrl) {
138
+ return entryUrl.split("/").pop()?.replace(/[?#].*$/, "").replace(/\.[^.]+$/, "") ?? "remoteEntry";
139
+ }
140
+ function resolveEntryAssetUrl(entry, manifestUrl) {
141
+ const base = manifestUrl.replace(/\/[^/]+$/, "/");
142
+ return new URL(`${entry.path || ""}${entry.name}`, base).href;
143
+ }
103
144
  function resolveSSREntryUrl(manifest, manifestUrl) {
104
145
  const meta = manifest?.metaData;
105
146
  if (!meta?.ssrRemoteEntry?.name) return null;
@@ -124,48 +165,72 @@ async function headCheckSsrEntry(candidate) {
124
165
  } catch {}
125
166
  return null;
126
167
  }
127
- async function getSSREntryByConvention(remoteEntryUrl, options = {}) {
128
- const base = remoteEntryUrl.replace(/\.[^.]+$/, "");
129
- const remoteOrigin = remoteEntryUrl.replace(/\/[^/]+$/, "");
130
- const filename = remoteEntryUrl.split("/").pop()?.replace(/\.[^.]+$/, "") ?? "remoteEntry";
131
- const candidates = [
132
- ...options.skipServerBuild ? [] : [{
133
- url: `${remoteOrigin}/__mf_server__/${filename}.ssr.js`,
134
- type: "module"
135
- }],
136
- {
137
- url: `${base}.ssr.js`,
138
- type: "module"
139
- },
140
- {
141
- url: `${remoteOrigin}/__mf_ssr__/${filename}.ssr.js`,
142
- type: "module"
143
- }
144
- ];
168
+ function resolveAssetBaseUrl(entryUrl, manifest, manifestUrl) {
169
+ const remoteEntry = manifest?.metaData?.remoteEntry;
170
+ if (remoteEntry?.name) return resolveEntryAssetUrl(remoteEntry, manifestUrl);
171
+ if (!isManifestEntry(entryUrl)) return entryUrl;
172
+ return new URL("remoteEntry.js", manifestUrl.replace(/\/[^/]+$/, "/")).href;
173
+ }
174
+ async function buildEntryContext(entryUrl) {
175
+ const manifestUrl = getManifestUrl(entryUrl);
176
+ const manifest = await fetchManifestCached(manifestUrl);
177
+ const assetBaseUrl = resolveAssetBaseUrl(entryUrl, manifest, manifestUrl);
178
+ return {
179
+ entryUrl,
180
+ manifestUrl,
181
+ manifest,
182
+ assetBaseUrl,
183
+ filename: getEntryFilename(assetBaseUrl),
184
+ remoteOrigin: assetBaseUrl.replace(/\/[^/]+$/, "")
185
+ };
186
+ }
187
+ function buildSsrEntryCandidates(ctx, options = {}) {
188
+ const { assetBaseUrl, filename, remoteOrigin } = ctx;
189
+ const base = assetBaseUrl.replace(/\.[^.]+$/, "");
190
+ const candidates = [];
191
+ if (!options.skipServerBuild) candidates.push({
192
+ url: `${remoteOrigin}/__mf_server__/${filename}.ssr.js`,
193
+ type: "module"
194
+ });
195
+ candidates.push({
196
+ url: `${base}.ssr.js`,
197
+ type: "module"
198
+ }, {
199
+ url: `${remoteOrigin}/__mf_ssr__/${filename}.ssr.js`,
200
+ type: "module"
201
+ });
202
+ return candidates;
203
+ }
204
+ async function resolveFirstReachableCandidate(candidates) {
145
205
  for (const candidate of candidates) {
146
206
  const hit = await headCheckSsrEntry(candidate);
147
207
  if (hit) return hit;
148
208
  }
149
209
  return null;
150
210
  }
151
- async function getSSREntry(remoteEntryUrl) {
152
- const remoteOrigin = remoteEntryUrl.replace(/\/[^/]+$/, "");
153
- const filename = remoteEntryUrl.split("/").pop()?.replace(/\.[^.]+$/, "") ?? "remoteEntry";
154
- const manifestUrl = getManifestUrl(remoteEntryUrl);
155
- if (!manifestCache.has(manifestUrl)) manifestCache.set(manifestUrl, (async () => {
211
+ async function resolveSSREntryImpl(remoteEntryUrl) {
212
+ if (isSsrEntry(remoteEntryUrl)) return {
213
+ url: remoteEntryUrl,
214
+ type: "module"
215
+ };
216
+ if (!isManifestEntry(remoteEntryUrl)) {
217
+ const filename = getEntryFilename(remoteEntryUrl);
156
218
  const fromServerBuild = await headCheckSsrEntry({
157
- url: `${remoteOrigin}/__mf_server__/${filename}.ssr.js`,
219
+ url: `${remoteEntryUrl.replace(/\/[^/]+$/, "")}/__mf_server__/${filename}.ssr.js`,
158
220
  type: "module"
159
221
  });
160
222
  if (fromServerBuild) return fromServerBuild;
161
- const manifest = await fetchManifest(manifestUrl);
162
- if (manifest) {
163
- const fromManifest = resolveSSREntryUrl(manifest, manifestUrl);
164
- if (fromManifest) return fromManifest;
165
- }
166
- return getSSREntryByConvention(remoteEntryUrl, { skipServerBuild: true });
167
- })());
168
- return manifestCache.get(manifestUrl);
223
+ }
224
+ const ctx = await buildEntryContext(remoteEntryUrl);
225
+ if (ctx.manifest) {
226
+ const fromManifest = resolveSSREntryUrl(ctx.manifest, ctx.manifestUrl);
227
+ if (fromManifest) return fromManifest;
228
+ }
229
+ return resolveFirstReachableCandidate(buildSsrEntryCandidates(ctx, { skipServerBuild: !isManifestEntry(remoteEntryUrl) }));
230
+ }
231
+ async function getSSREntry(remoteEntryUrl) {
232
+ if (!ssrEntryCache.has(remoteEntryUrl)) ssrEntryCache.set(remoteEntryUrl, resolveSSREntryImpl(remoteEntryUrl));
233
+ return ssrEntryCache.get(remoteEntryUrl);
169
234
  }
170
235
  const tempFileCache = /* @__PURE__ */ new Map();
171
236
  let ssrCacheDirPromise;
@@ -204,6 +269,9 @@ function transformSsrCode(code, base, sharedPkgMap) {
204
269
  code = code.replace(/\b([A-Za-z_$][\w$]*)\s*\(\s*\(\s*\)\s*=>\s*import\(([^)]*)\)\s*,\s*\[\]\s*\)/g, "import($2)");
205
270
  return code;
206
271
  }
272
+ function isVitePreloadHelperSpecifier(specifier) {
273
+ return specifier.includes("preload-helper");
274
+ }
207
275
  /**
208
276
  * Fetch an HTTP ESM module, transform it, write it to a temp .js file and
209
277
  * return the file path. Recursively does the same for HTTP transitive imports
@@ -213,12 +281,14 @@ async function fetchEsmToTempFile(url, tmpDir, visited, sharedPkgMap) {
213
281
  if (visited.has(url)) return visited.get(url);
214
282
  if (tempFileCache.has(url)) return tempFileCache.get(url);
215
283
  const promise = (async () => {
216
- let code = await (await fetch(url)).text();
284
+ const res = await fetch(url);
285
+ let code = await res.text();
286
+ if (!res.ok) throw new SsrEntryHttpError(url, res.status, res.statusText, getBodyPreview(code));
217
287
  const base = url.replace(/\/[^/]*$/, "/");
218
288
  const relImports = [];
219
289
  const relRegex = /(?:from|export\s*\*\s*from|import\s*(?:\(|\s))\s*["'`]([^"'`\s]+)["'`]/g;
220
290
  let m;
221
- while ((m = relRegex.exec(code)) !== null) if (m[1].startsWith("./") || m[1].startsWith("../")) relImports.push(new URL(m[1], base).href);
291
+ while ((m = relRegex.exec(code)) !== null) if ((m[1].startsWith("./") || m[1].startsWith("../")) && !isVitePreloadHelperSpecifier(m[1])) relImports.push(new URL(m[1], base).href);
222
292
  const subMap = /* @__PURE__ */ new Map();
223
293
  await Promise.all([...new Set(relImports)].filter((u) => u.startsWith("http://") || u.startsWith("https://")).map(async (u) => {
224
294
  const tmpPath = await fetchEsmToTempFile(u, tmpDir, visited, sharedPkgMap);
@@ -257,11 +327,14 @@ async function loadSSRRemoteEntry(ssrEntry, resolvedShared = {}) {
257
327
  if (urlObj.pathname.includes("/__mf_ssr__/")) {
258
328
  const remoteOrigin = urlObj.origin;
259
329
  const runner = await getOrCreateRunner(remoteOrigin);
260
- if (!runner) return null;
261
- try {
262
- return await runner.import(urlObj.pathname);
330
+ if (!runner) {
331
+ if (process.env.NODE_ENV !== "production") return null;
332
+ } else try {
333
+ const mod = await runner.import(urlObj.pathname);
334
+ if (mod && typeof mod === "object" && "init" in mod) return mod;
335
+ if (process.env.NODE_ENV !== "production") return null;
263
336
  } catch {
264
- return null;
337
+ if (process.env.NODE_ENV !== "production") return null;
265
338
  }
266
339
  }
267
340
  const { mkdirSync } = await _fs();
@@ -270,7 +343,8 @@ async function loadSSRRemoteEntry(ssrEntry, resolvedShared = {}) {
270
343
  const sharedPkgMap = new Map(Object.entries(resolvedShared));
271
344
  try {
272
345
  return await importTempModule(await fetchEsmToTempFile(url, cacheDir, /* @__PURE__ */ new Map(), sharedPkgMap));
273
- } catch {
346
+ } catch (error) {
347
+ if (isSsrEntryHttpError(error)) throw error;
274
348
  return null;
275
349
  }
276
350
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/vite",
3
- "version": "1.16.8",
3
+ "version": "1.16.10",
4
4
  "description": "Vite plugin for Module Federation",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",