@module-federation/vite 1.23.5 → 1.23.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.
@@ -39,6 +39,9 @@ function normalizePathForImport(path) {
39
39
  return path.replace(/\\/g, "/");
40
40
  }
41
41
  const EXTERNAL_URL_RE = /^(?:[a-z]+:|\/\/)/i;
42
+ function isHttpUrl(value) {
43
+ return value.startsWith("http://") || value.startsWith("https://");
44
+ }
42
45
  function isAbsoluteUrl(src) {
43
46
  if (/^[a-z]:[\\/]/i.test(src)) return false;
44
47
  return EXTERNAL_URL_RE.test(src);
@@ -205,28 +208,91 @@ const REGEX_PREFIX_KEYWORDS = /* @__PURE__ */ new Set([
205
208
  "void",
206
209
  "yield"
207
210
  ]);
211
+ const CONTROL_PAREN_KEYWORDS = /* @__PURE__ */ new Set([
212
+ "if",
213
+ "while",
214
+ "for",
215
+ "with",
216
+ "switch",
217
+ "catch"
218
+ ]);
219
+ function isWhitespace(char) {
220
+ if (char === void 0) return false;
221
+ const code = char.charCodeAt(0);
222
+ if (code < 128) return code === 32 || code >= 9 && code <= 13;
223
+ return /\s/.test(char);
224
+ }
225
+ function isAsciiLetter(code) {
226
+ return code >= 97 && code <= 122 || code >= 65 && code <= 90;
227
+ }
228
+ function isAsciiDigit(code) {
229
+ return code >= 48 && code <= 57;
230
+ }
231
+ function isIdentifierStart(char) {
232
+ const code = char.charCodeAt(0);
233
+ if (code < 128) return isAsciiLetter(code) || code === 36 || code === 95;
234
+ return /[$_\p{ID_Start}]/u.test(char);
235
+ }
236
+ function isIdentifierPart(char) {
237
+ if (char === void 0) return false;
238
+ const code = char.charCodeAt(0);
239
+ if (code < 128) return isAsciiLetter(code) || isAsciiDigit(code) || code === 36 || code === 95;
240
+ return /[$_\u200C\u200D\p{ID_Continue}]/u.test(char);
241
+ }
242
+ function isRegexFlag(char) {
243
+ if (char === void 0) return false;
244
+ const code = char.charCodeAt(0);
245
+ if (code < 128) return isAsciiLetter(code) || isAsciiDigit(code) || code === 36 || code === 95;
246
+ return /[$_\p{ID_Continue}]/u.test(char);
247
+ }
248
+ function isNumberPart(char) {
249
+ if (char === void 0) return false;
250
+ const code = char.charCodeAt(0);
251
+ return isAsciiLetter(code) || isAsciiDigit(code) || code === 95 || code === 46;
252
+ }
208
253
  function isJsxClosingTagSlash(code, slashIndex) {
209
254
  if (code[slashIndex - 1] !== "<") return false;
210
255
  let cursor = slashIndex + 1;
211
- while (/\s/.test(code[cursor] || "")) cursor++;
256
+ while (isWhitespace(code[cursor])) cursor++;
212
257
  if (code[cursor] === ">") return true;
213
258
  const tagStart = cursor;
214
259
  while (/[-:.$_\u200C\u200D\p{ID_Continue}]/u.test(code[cursor] || "")) cursor++;
215
260
  if (cursor === tagStart) return false;
216
- while (/\s/.test(code[cursor] || "")) cursor++;
261
+ while (isWhitespace(code[cursor])) cursor++;
217
262
  return code[cursor] === ">";
218
263
  }
219
264
  /** Mark comments, string/template literals, and regular expressions as non-code. */
220
265
  function createCodePositionMap(code, onComment) {
221
- const positions = Array(code.length).fill(true);
266
+ const positions = new Uint8Array(code.length).fill(1);
222
267
  const mask = (start, end) => {
223
- for (let index = start; index < end; index++) positions[index] = false;
268
+ positions.fill(0, start, end);
224
269
  };
225
270
  let canStartRegex = true;
271
+ let pendingControlParen;
272
+ const controlParens = [];
273
+ let templateStart;
274
+ const templateExpressions = [];
226
275
  for (let index = 0; index < code.length;) {
227
276
  const char = code[index];
228
277
  const next = code[index + 1];
229
- if (/\s/.test(char)) {
278
+ if (templateStart !== void 0) {
279
+ if (char === "\\") index += 2;
280
+ else if (char === "`") {
281
+ mask(templateStart, ++index);
282
+ templateStart = void 0;
283
+ canStartRegex = false;
284
+ } else if (char === "$" && next === "{") {
285
+ templateExpressions.push({
286
+ start: templateStart,
287
+ braceDepth: 0
288
+ });
289
+ templateStart = void 0;
290
+ canStartRegex = true;
291
+ index += 2;
292
+ } else index++;
293
+ continue;
294
+ }
295
+ if (isWhitespace(char)) {
230
296
  index++;
231
297
  continue;
232
298
  }
@@ -247,7 +313,13 @@ function createCodePositionMap(code, onComment) {
247
313
  onComment?.(start, index);
248
314
  continue;
249
315
  }
250
- if (char === "\"" || char === "'" || char === "`") {
316
+ const controlKeyword = pendingControlParen;
317
+ pendingControlParen = void 0;
318
+ if (char === "`") {
319
+ templateStart = index++;
320
+ continue;
321
+ }
322
+ if (char === "\"" || char === "'") {
251
323
  const quote = char;
252
324
  const start = index++;
253
325
  while (index < code.length) {
@@ -265,8 +337,7 @@ function createCodePositionMap(code, onComment) {
265
337
  canStartRegex = false;
266
338
  continue;
267
339
  }
268
- const closesJsxTag = isJsxClosingTagSlash(code, index);
269
- if (char === "/" && canStartRegex && !closesJsxTag) {
340
+ if (char === "/" && canStartRegex && !isJsxClosingTagSlash(code, index)) {
270
341
  const start = index;
271
342
  let cursor = index + 1;
272
343
  let escaped = false;
@@ -293,7 +364,7 @@ function createCodePositionMap(code, onComment) {
293
364
  }
294
365
  if (regexChar === "/" && !inCharacterClass) {
295
366
  cursor++;
296
- while (/[$_\p{ID_Continue}]/u.test(code[cursor] || "")) cursor++;
367
+ while (isRegexFlag(code[cursor])) cursor++;
297
368
  closed = true;
298
369
  break;
299
370
  }
@@ -305,15 +376,21 @@ function createCodePositionMap(code, onComment) {
305
376
  continue;
306
377
  }
307
378
  }
308
- if (/[$_\p{ID_Start}]/u.test(char)) {
379
+ if (isIdentifierStart(char)) {
309
380
  const start = index++;
310
- while (/[$_\u200C\u200D\p{ID_Continue}]/u.test(code[index] || "")) index++;
311
- canStartRegex = REGEX_PREFIX_KEYWORDS.has(code.slice(start, index));
381
+ while (isIdentifierPart(code[index])) index++;
382
+ const word = code.slice(start, index);
383
+ if (CONTROL_PAREN_KEYWORDS.has(word)) {
384
+ let previous = start - 1;
385
+ while (previous >= 0 && (isWhitespace(code[previous]) || !positions[previous])) previous--;
386
+ if (code[previous] !== ".") pendingControlParen = word;
387
+ } else if (word === "await" && controlKeyword === "for") pendingControlParen = controlKeyword;
388
+ canStartRegex = REGEX_PREFIX_KEYWORDS.has(word);
312
389
  continue;
313
390
  }
314
- if (/\d/.test(char)) {
391
+ if (isAsciiDigit(char.charCodeAt(0))) {
315
392
  index++;
316
- while (/[\w.]/.test(code[index] || "")) index++;
393
+ while (isNumberPart(code[index])) index++;
317
394
  canStartRegex = false;
318
395
  continue;
319
396
  }
@@ -325,10 +402,27 @@ function createCodePositionMap(code, onComment) {
325
402
  index++;
326
403
  continue;
327
404
  }
328
- if (char === ")" || char === "]" || char === "}") canStartRegex = false;
405
+ const expression = templateExpressions.at(-1);
406
+ if (expression && char === "{") expression.braceDepth++;
407
+ else if (expression && char === "}") {
408
+ if (expression.braceDepth === 0) {
409
+ templateStart = expression.start;
410
+ templateExpressions.pop();
411
+ index++;
412
+ continue;
413
+ }
414
+ expression.braceDepth--;
415
+ }
416
+ if (char === "(") {
417
+ controlParens.push(controlKeyword !== void 0);
418
+ canStartRegex = true;
419
+ } else if (char === ")") canStartRegex = controlParens.pop() === true;
420
+ else if (char === "]" || char === "}") canStartRegex = false;
329
421
  else if (char !== ".") canStartRegex = true;
330
422
  index++;
331
423
  }
424
+ const unfinishedTemplateStart = templateExpressions[0]?.start ?? templateStart;
425
+ if (unfinishedTemplateStart !== void 0) mask(unfinishedTemplateStart, code.length);
332
426
  return positions;
333
427
  }
334
428
  //#endregion
@@ -363,4 +457,4 @@ const moduleFederationConsole = {
363
457
  const mfWarn = moduleFederationConsole.warn;
364
458
  const mfError = moduleFederationConsole.error;
365
459
  //#endregion
366
- export { CodeRewriter as a, isAbsoluteUrl as c, resolveHashPlaceholderFileName as d, createCodePositionMap as i, normalizePathForImport as l, mfError as n, createSourceMap as o, mfWarn as r, EXTERNAL_URL_RE as s, createModuleFederationError as t, rebaseImport as u };
460
+ export { CodeRewriter as a, isAbsoluteUrl as c, rebaseImport as d, resolveHashPlaceholderFileName as f, createCodePositionMap as i, isHttpUrl as l, mfError as n, createSourceMap as o, mfWarn as r, EXTERNAL_URL_RE as s, createModuleFederationError as t, normalizePathForImport as u };
@@ -1,5 +1,5 @@
1
- import { l as normalizePathForImport, n as mfError, t as createModuleFederationError } from "./logger-DOwfTlw5.js";
2
- import { _ as resolveImportPath, d as hasPackageDependency } from "./dtsConstants-BQdFpgKb.js";
1
+ import { l as isHttpUrl, n as mfError, t as createModuleFederationError, u as normalizePathForImport } from "./logger-D67aJYOe.js";
2
+ import { p as hasPackageDependency, r as watchFileEvents, y as resolveImportPath } from "./dtsConstants-CDuC8Bb7.js";
3
3
  import fs from "fs";
4
4
  import * as path$1 from "node:path";
5
5
  import { normalizeOptions } from "@module-federation/sdk";
@@ -113,7 +113,7 @@ const resolveDtsPluginOptions = (dts, options, context) => {
113
113
  };
114
114
  };
115
115
  const getBasePath = (base) => {
116
- if (base.startsWith("http://") || base.startsWith("https://")) return new URL(base).pathname.replace(/\/$/, "") || "/";
116
+ if (isHttpUrl(base)) return new URL(base).pathname.replace(/\/$/, "") || "/";
117
117
  return base.replace(/\/$/, "") || "/";
118
118
  };
119
119
  const joinBaseAndAsset = (base, assetFileName) => {
@@ -262,15 +262,11 @@ function pluginDts(options) {
262
262
  clearTimeout(updateTimer);
263
263
  updateTimer = setTimeout(() => devWorker?.update(), UPDATE_DEBOUNCE_MS);
264
264
  };
265
- server.watcher.on("change", update);
266
- server.watcher.on("add", update);
267
- server.watcher.on("unlink", update);
265
+ const stopWatching = watchFileEvents(server.watcher, update);
268
266
  server.httpServer?.once("close", () => {
269
267
  clearTimeout(updateTimer);
270
268
  devWorker?.exit();
271
- server.watcher.off("change", update);
272
- server.watcher.off("add", update);
273
- server.watcher.off("unlink", update);
269
+ stopWatching();
274
270
  });
275
271
  };
276
272
  startDevWorker().catch((error) => {
@@ -1,3 +1,5 @@
1
+ import { u as normalizePathForImport } from "./logger-D67aJYOe.js";
2
+ import * as path$1 from "node:path";
1
3
  //#region src/utils/pathNormalization.ts
2
4
  const COMMON_SHARED_SUBPATHS = {
3
5
  react: [
@@ -127,6 +129,11 @@ function resolvePublicPath(options, viteBase, originalBase) {
127
129
  }
128
130
  return "auto";
129
131
  }
132
+ /** Relative `./`-prefixed import specifier from `fromFile` to `targetFile`. */
133
+ function toRelativeImport(fromFile, targetFile) {
134
+ const relative = normalizePathForImport(path$1.relative(path$1.dirname(fromFile), targetFile));
135
+ return relative.startsWith(".") ? relative : `./${relative}`;
136
+ }
130
137
  //#endregion
131
138
  //#region src/utils/sharedKeyMatcher.ts
132
139
  function getSharedRequest(key, shareItem) {
@@ -218,4 +225,4 @@ function getSharedKeyMatcher(shared) {
218
225
  return matcher;
219
226
  }
220
227
  //#endregion
221
- export { removeTrailingSlash as _, matchesSharedSource as a, stripViteFsPrefix as b, filterId as c, getNodeModulesSuffix as d, isAssetLikeImport as f, normalizeNodeModulePath as g, isViteOptimizableEntry as h, invalidateSharedKeyMatcher as i, getBasePath as l, isNuxtClientBase as m, getSharedRequest as n, VITE_FS_PREFIX as o, isNodeModulePath as p, getSharedRuntimeKey as r, ensureTrailingSlash as s, findSharedKey as t, getCommonSharedSubpaths as u, resolvePublicPath as v, stripQueryAndHash as y };
228
+ export { removeTrailingSlash as _, matchesSharedSource as a, stripViteFsPrefix as b, filterId as c, getNodeModulesSuffix as d, isAssetLikeImport as f, normalizeNodeModulePath as g, isViteOptimizableEntry as h, invalidateSharedKeyMatcher as i, getBasePath as l, isNuxtClientBase as m, getSharedRequest as n, VITE_FS_PREFIX as o, isNodeModulePath as p, getSharedRuntimeKey as r, ensureTrailingSlash as s, findSharedKey as t, getCommonSharedSubpaths as u, resolvePublicPath as v, toRelativeImport as x, stripQueryAndHash as y };
@@ -1,4 +1,4 @@
1
- import { a as CodeRewriter, i as createCodePositionMap, r as mfWarn, s as EXTERNAL_URL_RE } from "./logger-DOwfTlw5.js";
1
+ import { a as CodeRewriter, i as createCodePositionMap, l as isHttpUrl, r as mfWarn, s as EXTERNAL_URL_RE } from "./logger-D67aJYOe.js";
2
2
  import { simpleJoinRemoteEntry } from "@module-federation/sdk";
3
3
  //#region src/utils/fetchWithTimeout.ts
4
4
  const DEFAULT_SSR_FETCH_TIMEOUT_MS = 1e4;
@@ -57,6 +57,10 @@ var SsrFetchBodyTooLargeError = class extends Error {
57
57
  function isSsrFetchBodyTooLargeError(error) {
58
58
  return error instanceof SsrFetchBodyTooLargeError;
59
59
  }
60
+ /** A short single-line excerpt of a response body for error messages. */
61
+ function getBodyPreview(body) {
62
+ return body.slice(0, 240).replace(/\s+/g, " ").trim();
63
+ }
60
64
  /**
61
65
  * Read a response body as text, rejecting when it exceeds `maxBytes`.
62
66
  * Set `maxBytes` to 0 (or a non-finite value) to disable the limit.
@@ -99,15 +103,6 @@ async function readResponseTextBounded(res, maxBytes = DEFAULT_SSR_FETCH_MAX_BYT
99
103
  return new TextDecoder().decode(merged);
100
104
  }
101
105
  //#endregion
102
- //#region src/utils/url.ts
103
- function getUrlOrigin(value) {
104
- try {
105
- return new URL(value).origin;
106
- } catch {
107
- return;
108
- }
109
- }
110
- //#endregion
111
106
  //#region src/utils/ssrEntryLoader.ts
112
107
  /**
113
108
  * MF runtime plugin that intercepts the `loadEntry` lifecycle hook on the
@@ -230,8 +225,9 @@ async function getOrCreateRunner(remoteOrigin, resolvedShared, fetchTimeoutMs, f
230
225
  headers: { "Content-Type": "application/json" },
231
226
  body: JSON.stringify(payload)
232
227
  }, fetchTimeoutMs), fetchMaxBytes, runnerEndpoint);
233
- const result = parseRunnerInvokeResult(JSON.parse(text));
234
- if ("error" in result && payload.data.name === "fetchModule") {
228
+ const data = JSON.parse(text);
229
+ const result = parseRunnerInvokeResult(data);
230
+ if (("error" in result || isPlainObject(data) && data.shared === true) && payload.data.name === "fetchModule") {
235
231
  const sharedExternal = await resolveSharedExternal(payload.data.data[0], resolvedShared);
236
232
  if (sharedExternal) return { result: sharedExternal };
237
233
  }
@@ -326,9 +322,6 @@ var SsrEntryHttpError = class extends Error {
326
322
  this.name = "SsrEntryHttpError";
327
323
  }
328
324
  };
329
- function getBodyPreview(body) {
330
- return body.slice(0, 240).replace(/\s+/g, " ").trim();
331
- }
332
325
  function isSsrEntryHttpError(error) {
333
326
  return error instanceof SsrEntryHttpError;
334
327
  }
@@ -540,9 +533,10 @@ function scheduleVmCacheCleanup(remoteEntryUrl) {
540
533
  */
541
534
  async function clearRunnerCaches(remoteEntryUrl) {
542
535
  let remoteOrigin;
543
- if (remoteEntryUrl) {
544
- remoteOrigin = getUrlOrigin(remoteEntryUrl);
545
- if (!remoteOrigin) return;
536
+ if (remoteEntryUrl) try {
537
+ remoteOrigin = new URL(remoteEntryUrl).origin;
538
+ } catch {
539
+ return;
546
540
  }
547
541
  await Promise.all([...runnerCache.values()].filter((cached) => !remoteOrigin || cached.remoteOrigin === remoteOrigin).map(async (cached) => {
548
542
  try {
@@ -751,7 +745,7 @@ function transformSsrCode(code, base, specifiers, sharedPkgMap, requireShimUrl,
751
745
  }
752
746
  const resolvedShared = sharedPkgMap?.get(value);
753
747
  const relativeUrl = isRelativeSpecifier(value) ? new URL(value, base).href : void 0;
754
- const absoluteHttpUrl = value.startsWith("http://") || value.startsWith("https://") ? value : void 0;
748
+ const absoluteHttpUrl = isHttpUrl(value) ? value : void 0;
755
749
  const httpUrl = relativeUrl ?? absoluteHttpUrl;
756
750
  const replacement = (httpUrl ? tempFileUrlMap?.get(httpUrl) : void 0) ?? relativeUrl ?? (resolvedShared && `file://${resolvedShared}`);
757
751
  if (replacement) rewriter.overwrite(start, end, `"${replacement}"`);
@@ -773,7 +767,8 @@ function getTempFileImportUrl(filePath, versionKey) {
773
767
  * a remote redeploy (new manifest → new key) produces new files and bypasses
774
768
  * Node's ESM module cache instead of serving the stale build.
775
769
  */
776
- async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, versionKey = UNVERSIONED, fetchTimeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS, contextKey = "default", fetchMaxBytes = DEFAULT_SSR_FETCH_MAX_BYTES, extension = ".mjs", owner) {
770
+ async function fetchEsmToTempFile(url, graph) {
771
+ const { tmpDir, visited, pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey, fetchMaxBytes, extension, owner } = graph;
777
772
  const cacheKey = JSON.stringify([
778
773
  fetchTimeoutMs,
779
774
  fetchMaxBytes,
@@ -795,7 +790,8 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
795
790
  const tmpFilePromise = (async () => {
796
791
  const { createHash } = await _crypto();
797
792
  const { join } = await _path();
798
- return join(tmpDir, `${createHash("sha1").update(cacheKey).digest("hex").slice(0, 12)}${extension}`);
793
+ const hash = createHash("sha1").update(cacheKey).digest("hex").slice(0, 12);
794
+ return join(tmpDir, `${hash}${extension}`);
799
795
  })();
800
796
  tempFilePathCache.set(cacheKey, tmpFilePromise);
801
797
  const promise = (async () => {
@@ -808,8 +804,8 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
808
804
  const specifiers = findSsrModuleSpecifiers(code);
809
805
  const relImports = specifiers.map(({ value }) => value).filter((value) => isRelativeSpecifier(value) && !isVitePreloadHelperSpecifier(value)).map((value) => new URL(value, base).href);
810
806
  const subMap = /* @__PURE__ */ new Map();
811
- await Promise.all([...new Set(relImports)].filter((u) => u.startsWith("http://") || u.startsWith("https://")).map(async (u) => {
812
- const tmpPath = await fetchEsmToTempFile(u, tmpDir, visited, pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey, fetchMaxBytes, extension, owner);
807
+ await Promise.all([...new Set(relImports)].filter(isHttpUrl).map(async (u) => {
808
+ const tmpPath = await fetchEsmToTempFile(u, graph);
813
809
  subMap.set(u, getTempFileImportUrl(tmpPath, versionKey));
814
810
  }));
815
811
  const requireShimUrl = sharedPkgMap?.size && specifiers.some(({ value }) => isNodeModuleSpecifier(value)) ? await getRequireShimUrl(tmpDir, sharedPkgMap, contextKey) : void 0;
@@ -834,9 +830,18 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
834
830
  });
835
831
  return promise;
836
832
  }
837
- async function fetchEsmGraphToTempFile(url, tmpDir, sharedPkgMap, versionKey = UNVERSIONED, fetchTimeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS, contextKey = "default", fetchMaxBytes = DEFAULT_SSR_FETCH_MAX_BYTES, extension = ".mjs", owner) {
833
+ async function fetchEsmGraphToTempFile(url, { versionKey = UNVERSIONED, fetchTimeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS, contextKey = "default", fetchMaxBytes = DEFAULT_SSR_FETCH_MAX_BYTES, extension = ".mjs", ...rest }) {
838
834
  const pending = /* @__PURE__ */ new Set();
839
- const rootFile = await fetchEsmToTempFile(url, tmpDir, /* @__PURE__ */ new Map(), pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey, fetchMaxBytes, extension, owner);
835
+ const rootFile = await fetchEsmToTempFile(url, {
836
+ ...rest,
837
+ versionKey,
838
+ fetchTimeoutMs,
839
+ contextKey,
840
+ fetchMaxBytes,
841
+ extension,
842
+ visited: /* @__PURE__ */ new Map(),
843
+ pending
844
+ });
840
845
  await Promise.all(pending);
841
846
  return rootFile;
842
847
  }
@@ -848,7 +853,7 @@ async function importTempModule(filePath, versionKey) {
848
853
  }
849
854
  let warnedVmUnavailable = false;
850
855
  function getVmStrategyModule() {
851
- if (!loaderState.vmStrategyModulePromise) loaderState.vmStrategyModulePromise = import("./ssrVmStrategy-BkyvcG4s.js");
856
+ if (!loaderState.vmStrategyModulePromise) loaderState.vmStrategyModulePromise = import("./ssrVmStrategy-BCaiSEbA.js");
852
857
  return loaderState.vmStrategyModulePromise;
853
858
  }
854
859
  /**
@@ -889,7 +894,7 @@ async function loadSSRRemoteEntry(ssrEntry, options, rootEntryUrl) {
889
894
  return req(url);
890
895
  } catch {}
891
896
  }
892
- if (url.startsWith("http://") || url.startsWith("https://")) {
897
+ if (isHttpUrl(url)) {
893
898
  const urlObj = new URL(url);
894
899
  if (urlObj.pathname.includes("/__mf_ssr__/")) {
895
900
  const remoteOrigin = urlObj.origin;
@@ -919,7 +924,16 @@ async function loadSSRRemoteEntry(ssrEntry, options, rootEntryUrl) {
919
924
  const isCommonJs = type === "commonjs-module" || type === "commonjs";
920
925
  const extension = isCommonJs ? ".cjs" : ".mjs";
921
926
  try {
922
- const tmpFile = await fetchEsmGraphToTempFile(url, cacheDir, sharedPkgMap, versionKey, options.fetchTimeoutMs, getSsrTransformContextKey(resolvedShared, options.shareScopeName), options.fetchMaxBytes, extension, rootEntryUrl);
927
+ const tmpFile = await fetchEsmGraphToTempFile(url, {
928
+ tmpDir: cacheDir,
929
+ sharedPkgMap,
930
+ versionKey,
931
+ fetchTimeoutMs: options.fetchTimeoutMs,
932
+ contextKey: getSsrTransformContextKey(resolvedShared, options.shareScopeName),
933
+ fetchMaxBytes: options.fetchMaxBytes,
934
+ extension,
935
+ owner: rootEntryUrl
936
+ });
923
937
  if (isCommonJs) return (await _module()).createRequire(import.meta.url)(tmpFile);
924
938
  return await importTempModule(tmpFile, versionKey);
925
939
  } catch (error) {
@@ -937,6 +951,42 @@ async function loadSSRRemoteEntry(ssrEntry, options, rootEntryUrl) {
937
951
  return null;
938
952
  }
939
953
  }
954
+ /**
955
+ * Build-time `resolvedShared` paths point into the build machine's
956
+ * node_modules. A traced or relocated server output imports shared packages
957
+ * from its own copy, so pinning remotes to the build paths loads a second
958
+ * instance (two Reacts: invalid hook call) or, once the build directory is
959
+ * gone, nothing at all (ERR_MODULE_NOT_FOUND).
960
+ *
961
+ * Each specifier takes the first hit of a fixed order, independent of import
962
+ * order or timing:
963
+ * 1. resolved from the real path of the server entry (`process.argv[1]`),
964
+ * which is where Node resolves the host's own bare imports from, unless
965
+ * it is a CLI inside node_modules (e.g. `vite preview`);
966
+ * 2. resolved from `process.cwd()`, for launchers whose `argv[1]` is not the
967
+ * server entry or is missing;
968
+ * 3. the build-time path.
969
+ */
970
+ async function rebaseResolvedShared(resolvedShared) {
971
+ const { createRequire } = await _module();
972
+ const { realpathSync } = await _fs();
973
+ const { join } = await _path();
974
+ const requires = [];
975
+ try {
976
+ const entry = process.argv[1] && realpathSync(process.argv[1]);
977
+ if (entry && !/[\\/]node_modules[\\/]/.test(entry)) requires.push(createRequire(entry));
978
+ } catch {}
979
+ requires.push(createRequire(join(process.cwd(), "noop.js")));
980
+ const rebased = {};
981
+ for (const [specifier, buildPath] of Object.entries(resolvedShared)) {
982
+ rebased[specifier] = buildPath;
983
+ for (const require of requires) try {
984
+ rebased[specifier] = require.resolve(specifier);
985
+ break;
986
+ } catch {}
987
+ }
988
+ return rebased;
989
+ }
940
990
  function ssrEntryLoaderPlugin(options = {}) {
941
991
  const resolved = {
942
992
  resolvedShared: options.resolvedShared ?? {},
@@ -947,10 +997,17 @@ function ssrEntryLoaderPlugin(options = {}) {
947
997
  fetchMaxBytes: options.fetchMaxBytes ?? 10485760,
948
998
  cacheContext: {}
949
999
  };
1000
+ let rebased;
950
1001
  return {
951
1002
  name: "mf-vite:ssr-entry-loader",
952
1003
  async loadEntry({ remoteInfo, origin }) {
953
1004
  if (!isNodeServer()) return;
1005
+ if (options.rebaseSharedAtRuntime) {
1006
+ rebased ??= rebaseResolvedShared(resolved.resolvedShared).then((map) => {
1007
+ resolved.resolvedShared = map;
1008
+ }, () => {});
1009
+ await rebased;
1010
+ }
954
1011
  const loadOptions = origin ? {
955
1012
  ...resolved,
956
1013
  cacheContext: origin,
@@ -968,4 +1025,4 @@ function ssrEntryLoaderPlugin(options = {}) {
968
1025
  };
969
1026
  }
970
1027
  //#endregion
971
- export { ssrEntryLoaderPlugin as a, fetchWithTimeout as c, revalidate as i, readResponseTextBounded as l, SsrEntryHttpError as n, DEFAULT_SSR_FETCH_MAX_BYTES as o, neutralizeBrowserPreloadHelpers as r, DEFAULT_SSR_FETCH_TIMEOUT_MS as s, SSR_ENTRY_LOADER_STATE_KEY as t };
1028
+ export { ssrEntryLoaderPlugin as a, fetchWithTimeout as c, revalidate as i, getBodyPreview as l, SsrEntryHttpError as n, DEFAULT_SSR_FETCH_MAX_BYTES as o, neutralizeBrowserPreloadHelpers as r, DEFAULT_SSR_FETCH_TIMEOUT_MS as s, SSR_ENTRY_LOADER_STATE_KEY as t, readResponseTextBounded as u };
@@ -1,5 +1,6 @@
1
- import { t as findSharedKey } from "./sharedKeyMatcher-CHp4QRNq.js";
2
- import { c as fetchWithTimeout, l as readResponseTextBounded, n as SsrEntryHttpError, r as neutralizeBrowserPreloadHelpers } from "./ssrEntryLoader-CHdWk8Yg.js";
1
+ import { l as isHttpUrl } from "./logger-D67aJYOe.js";
2
+ import { t as findSharedKey } from "./sharedKeyMatcher-C04bVN1q.js";
3
+ import { c as fetchWithTimeout, l as getBodyPreview, n as SsrEntryHttpError, r as neutralizeBrowserPreloadHelpers, u as readResponseTextBounded } from "./ssrEntryLoader-Bh2Tq1cZ.js";
3
4
  //#region src/utils/ssrVmStrategy.ts
4
5
  /**
5
6
  * vm.SourceTextModule strategy for loading remote SSR entries.
@@ -163,18 +164,12 @@ function clearVmStrategyCaches(remoteEntryUrl) {
163
164
  clearOwnedVmCache(httpModuleCache, httpModuleCacheOwners, remoteEntryUrl);
164
165
  clearOwnedVmCache(namespaceCache, namespaceCacheOwners, remoteEntryUrl);
165
166
  }
166
- function getBodyPreview(body) {
167
- return body.slice(0, 240).replace(/\s+/g, " ").trim();
168
- }
169
167
  async function fetchModuleSource(url, fetchTimeoutMs, fetchMaxBytes) {
170
168
  const res = await fetchWithTimeout(url, {}, fetchTimeoutMs);
171
169
  const text = await readResponseTextBounded(res, fetchMaxBytes ?? 10485760, url);
172
170
  if (!res.ok) throw new SsrEntryHttpError(url, res.status, res.statusText, getBodyPreview(text));
173
171
  return neutralizeBrowserPreloadHelpers(text);
174
172
  }
175
- function isHttpUrl(value) {
176
- return value.startsWith("http://") || value.startsWith("https://");
177
- }
178
173
  /** Resolve a specifier against the referencing module's URL; null for bare specifiers. */
179
174
  function resolveSpecifierUrl(specifier, referencerUrl) {
180
175
  if (isHttpUrl(specifier)) return specifier;
@@ -1,2 +1,2 @@
1
- import { a as ssrEntryLoaderPlugin, i as revalidate, n as SsrEntryHttpError, r as neutralizeBrowserPreloadHelpers, t as SSR_ENTRY_LOADER_STATE_KEY } from "../ssrEntryLoader-CHdWk8Yg.js";
1
+ import { a as ssrEntryLoaderPlugin, i as revalidate, n as SsrEntryHttpError, r as neutralizeBrowserPreloadHelpers, t as SSR_ENTRY_LOADER_STATE_KEY } from "../ssrEntryLoader-Bh2Tq1cZ.js";
2
2
  export { SSR_ENTRY_LOADER_STATE_KEY, 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.23.5",
3
+ "version": "1.23.6",
4
4
  "description": "Vite plugin for Module Federation",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -74,7 +74,7 @@
74
74
  "homepage": "https://github.com/module-federation/vite#readme",
75
75
  "packageManager": "pnpm@10.28.2",
76
76
  "peerDependencies": {
77
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
77
+ "vite": "^5.1.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
78
78
  },
79
79
  "dependencies": {
80
80
  "@module-federation/dts-plugin": "2.9.2",
@@ -90,7 +90,7 @@
90
90
  "rollup": "4.62.3",
91
91
  "tsdown": "0.22.14",
92
92
  "typescript": "7.0.2",
93
- "vite": "8.2.0",
94
- "vitest": "4.1.11"
93
+ "vite": "8.2.4",
94
+ "vitest": "4.1.12"
95
95
  }
96
96
  }