@module-federation/vite 1.18.1 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -102,6 +102,7 @@ let packageDetectionCwd;
102
102
  function getDependencyCacheKey(cwd, dependencyName) {
103
103
  return `${cwd}:${dependencyName}`;
104
104
  }
105
+ const installedPackageJsonCache = /* @__PURE__ */ new Map();
105
106
  function setPackageDetectionCwd(cwd) {
106
107
  packageDetectionCwd = cwd;
107
108
  }
@@ -398,6 +399,13 @@ const sharedCacheHelperCode = `const __mfGetSharedCacheDescriptor = (pkg, single
398
399
  function getInstalledPackageJson(pkg, opts) {
399
400
  const cwd = opts?.cwd || getPackageDetectionCwd();
400
401
  const packageName = opts?.packageName || getPackageName(pkg);
402
+ const cacheKey = `${cwd}\0${pkg}\0${packageName}\0${opts?.fromResolvedEntry ?? ""}`;
403
+ if (installedPackageJsonCache.has(cacheKey)) return installedPackageJsonCache.get(cacheKey);
404
+ const result = resolveInstalledPackageJson(pkg, cwd, packageName, opts);
405
+ installedPackageJsonCache.set(cacheKey, result);
406
+ return result;
407
+ }
408
+ function resolveInstalledPackageJson(pkg, cwd, packageName, opts) {
401
409
  const tryReadPackageJson = (packageJsonPath) => {
402
410
  if (!existsSync(packageJsonPath)) return void 0;
403
411
  try {
@@ -1,5 +1,6 @@
1
1
  //#region src/utils/fetchWithTimeout.ts
2
2
  const DEFAULT_SSR_FETCH_TIMEOUT_MS = 1e4;
3
+ const DEFAULT_SSR_FETCH_MAX_BYTES = 10 * 1024 * 1024;
3
4
  function getFetchUrl(input) {
4
5
  const raw = typeof input === "string" || input instanceof URL ? String(input) : input.url;
5
6
  return new URL(raw);
@@ -10,6 +11,11 @@ function getSecureFetchUrl(input) {
10
11
  if (url.protocol !== "https:" && !(url.protocol === "http:" && isLoopback)) throw new TypeError(`Refusing to fetch SSR resource over an insecure connection: ${url}`);
11
12
  return url;
12
13
  }
14
+ function isAbortLikeError(error) {
15
+ if (!error || typeof error !== "object") return false;
16
+ const name = error.name;
17
+ return name === "AbortError" || name === "TimeoutError";
18
+ }
13
19
  /** Fetch with a bounded wait. Set timeoutMs to 0 to disable the timeout. */
14
20
  async function fetchWithTimeout(input, init = {}, timeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS) {
15
21
  const inputUrl = getSecureFetchUrl(input);
@@ -29,11 +35,67 @@ async function fetchWithTimeout(input, init = {}, timeoutMs = DEFAULT_SSR_FETCH_
29
35
  try {
30
36
  return await request(inputUrl);
31
37
  } catch (error) {
32
- if (inputUrl.hostname !== "localhost") throw error;
38
+ if (inputUrl.hostname !== "localhost" || isAbortLikeError(error)) throw error;
33
39
  inputUrl.hostname = "[::1]";
34
40
  return request(inputUrl);
35
41
  }
36
42
  }
43
+ var SsrFetchBodyTooLargeError = class extends Error {
44
+ url;
45
+ maxBytes;
46
+ declaredBytes;
47
+ constructor(url, maxBytes, declaredBytes) {
48
+ super(declaredBytes != null ? `SSR response from ${url} declared ${declaredBytes} bytes which exceeds the ${maxBytes}-byte limit` : `SSR response from ${url} exceeded the ${maxBytes}-byte limit`);
49
+ this.name = "SsrFetchBodyTooLargeError";
50
+ this.url = url;
51
+ this.maxBytes = maxBytes;
52
+ this.declaredBytes = declaredBytes;
53
+ }
54
+ };
55
+ function isSsrFetchBodyTooLargeError(error) {
56
+ return error instanceof SsrFetchBodyTooLargeError;
57
+ }
58
+ /**
59
+ * Read a response body as text, rejecting when it exceeds `maxBytes`.
60
+ * Set `maxBytes` to 0 (or a non-finite value) to disable the limit.
61
+ */
62
+ async function readResponseTextBounded(res, maxBytes = DEFAULT_SSR_FETCH_MAX_BYTES, url = res.url || "unknown") {
63
+ if (!Number.isFinite(maxBytes) || maxBytes <= 0) return res.text();
64
+ const contentLengthHeader = res.headers?.get?.("content-length") ?? null;
65
+ if (contentLengthHeader != null) {
66
+ const declaredBytes = Number(contentLengthHeader);
67
+ if (Number.isFinite(declaredBytes) && declaredBytes > maxBytes) {
68
+ try {
69
+ await res.body?.cancel();
70
+ } catch {}
71
+ throw new SsrFetchBodyTooLargeError(url, maxBytes, declaredBytes);
72
+ }
73
+ }
74
+ if (!res.body) return res.text();
75
+ const reader = res.body.getReader();
76
+ const chunks = [];
77
+ let total = 0;
78
+ while (true) {
79
+ const { done, value } = await reader.read();
80
+ if (done) break;
81
+ if (!value) continue;
82
+ total += value.byteLength;
83
+ if (total > maxBytes) {
84
+ try {
85
+ await reader.cancel();
86
+ } catch {}
87
+ throw new SsrFetchBodyTooLargeError(url, maxBytes);
88
+ }
89
+ chunks.push(value);
90
+ }
91
+ const merged = new Uint8Array(total);
92
+ let offset = 0;
93
+ for (const chunk of chunks) {
94
+ merged.set(chunk, offset);
95
+ offset += chunk.byteLength;
96
+ }
97
+ return new TextDecoder().decode(merged);
98
+ }
37
99
  //#endregion
38
100
  //#region src/utils/ssrEntryLoader.ts
39
101
  /**
@@ -93,8 +155,8 @@ async function getModuleRunnerModule() {
93
155
  * This is Vite 8+ only — older versions don't expose `vite/module-runner` or
94
156
  * the `/__mf_runner__` proxy endpoint.
95
157
  */
96
- async function getOrCreateRunner(remoteOrigin, fetchTimeoutMs) {
97
- const cacheKey = `${fetchTimeoutMs}::${remoteOrigin}`;
158
+ async function getOrCreateRunner(remoteOrigin, fetchTimeoutMs, fetchMaxBytes) {
159
+ const cacheKey = `${fetchTimeoutMs}::${fetchMaxBytes}::${remoteOrigin}`;
98
160
  if (runnerCache.has(cacheKey)) return runnerCache.get(cacheKey);
99
161
  const promise = (async () => {
100
162
  const viteRunner = await getModuleRunnerModule();
@@ -105,11 +167,12 @@ async function getOrCreateRunner(remoteOrigin, fetchTimeoutMs) {
105
167
  return new ModuleRunner({
106
168
  hmr: false,
107
169
  transport: { async invoke(payload) {
108
- return await (await fetchWithTimeout(runnerEndpoint, {
170
+ const text = await readResponseTextBounded(await fetchWithTimeout(runnerEndpoint, {
109
171
  method: "POST",
110
172
  headers: { "Content-Type": "application/json" },
111
173
  body: JSON.stringify(payload)
112
- }, fetchTimeoutMs)).json();
174
+ }, fetchTimeoutMs), fetchMaxBytes, runnerEndpoint);
175
+ return JSON.parse(text);
113
176
  } }
114
177
  }, new ESModulesEvaluator());
115
178
  } catch {
@@ -146,8 +209,8 @@ function computeManifestVersionKey(manifest) {
146
209
  }
147
210
  const ssrEntryCache = /* @__PURE__ */ new Map();
148
211
  const manifestFetchCache = /* @__PURE__ */ new Map();
149
- function makeUrlCacheKey(url, fetchTimeoutMs) {
150
- return `${fetchTimeoutMs}::${url}`;
212
+ function makeUrlCacheKey(url, fetchTimeoutMs, fetchMaxBytes) {
213
+ return `${fetchTimeoutMs}::${fetchMaxBytes}::${url}`;
151
214
  }
152
215
  var SsrEntryHttpError = class extends Error {
153
216
  constructor(url, status, statusText, bodyPreview) {
@@ -165,22 +228,26 @@ function getBodyPreview(body) {
165
228
  function isSsrEntryHttpError(error) {
166
229
  return error instanceof SsrEntryHttpError;
167
230
  }
168
- async function fetchManifest(manifestUrl, fetchTimeoutMs) {
231
+ async function fetchManifest(manifestUrl, fetchTimeoutMs, fetchMaxBytes) {
169
232
  try {
170
233
  const res = await fetchWithTimeout(manifestUrl, {}, fetchTimeoutMs);
171
234
  if (!res.ok) return null;
172
- return await res.json();
173
- } catch {
235
+ const text = await readResponseTextBounded(res, fetchMaxBytes, manifestUrl);
236
+ return JSON.parse(text);
237
+ } catch (error) {
238
+ if (isSsrFetchBodyTooLargeError(error)) throw error;
174
239
  return null;
175
240
  }
176
241
  }
177
- async function fetchManifestCached(manifestUrl, fetchTimeoutMs) {
178
- const cacheKey = makeUrlCacheKey(manifestUrl, fetchTimeoutMs);
242
+ async function fetchManifestCached(manifestUrl, fetchTimeoutMs, fetchMaxBytes) {
243
+ const cacheKey = makeUrlCacheKey(manifestUrl, fetchTimeoutMs, fetchMaxBytes);
179
244
  if (!manifestFetchCache.has(cacheKey)) {
180
- const promise = fetchManifest(manifestUrl, fetchTimeoutMs);
245
+ const promise = fetchManifest(manifestUrl, fetchTimeoutMs, fetchMaxBytes);
181
246
  manifestFetchCache.set(cacheKey, promise);
182
247
  promise.then((manifest) => {
183
248
  if (!manifest && manifestFetchCache.get(cacheKey) === promise) manifestFetchCache.delete(cacheKey);
249
+ }, () => {
250
+ if (manifestFetchCache.get(cacheKey) === promise) manifestFetchCache.delete(cacheKey);
184
251
  });
185
252
  }
186
253
  return manifestFetchCache.get(cacheKey);
@@ -239,9 +306,9 @@ function resolveAssetBaseUrl(entryUrl, manifest, manifestUrl) {
239
306
  if (!isManifestEntry(entryUrl)) return entryUrl;
240
307
  return new URL("remoteEntry.js", manifestUrl.replace(/\/[^/]+$/, "/")).href;
241
308
  }
242
- async function buildEntryContext(entryUrl, fetchTimeoutMs) {
309
+ async function buildEntryContext(entryUrl, fetchTimeoutMs, fetchMaxBytes) {
243
310
  const manifestUrl = getManifestUrl(entryUrl);
244
- const manifest = await fetchManifestCached(manifestUrl, fetchTimeoutMs);
311
+ const manifest = await fetchManifestCached(manifestUrl, fetchTimeoutMs, fetchMaxBytes);
245
312
  const assetBaseUrl = resolveAssetBaseUrl(entryUrl, manifest, manifestUrl);
246
313
  return {
247
314
  entryUrl,
@@ -279,7 +346,7 @@ async function resolveFirstReachableCandidate(candidates, fetchTimeoutMs) {
279
346
  }
280
347
  return null;
281
348
  }
282
- async function resolveSSREntryImpl(remoteEntryUrl, fetchTimeoutMs) {
349
+ async function resolveSSREntryImpl(remoteEntryUrl, fetchTimeoutMs, fetchMaxBytes) {
283
350
  if (isSsrEntry(remoteEntryUrl)) return {
284
351
  url: remoteEntryUrl,
285
352
  type: "module",
@@ -294,33 +361,35 @@ async function resolveSSREntryImpl(remoteEntryUrl, fetchTimeoutMs) {
294
361
  }, fetchTimeoutMs);
295
362
  if (fromServerBuild) return fromServerBuild;
296
363
  }
297
- const ctx = await buildEntryContext(remoteEntryUrl, fetchTimeoutMs);
364
+ const ctx = await buildEntryContext(remoteEntryUrl, fetchTimeoutMs, fetchMaxBytes);
298
365
  if (ctx.manifest) {
299
366
  const fromManifest = resolveSSREntryUrl(ctx.manifest, ctx.manifestUrl);
300
367
  if (fromManifest) return fromManifest;
301
368
  }
302
369
  return resolveFirstReachableCandidate(buildSsrEntryCandidates(ctx, { skipServerBuild: !isManifestEntry(remoteEntryUrl) }), fetchTimeoutMs);
303
370
  }
304
- function setSsrEntryCache(remoteEntryUrl, fetchTimeoutMs) {
305
- const cacheKey = makeUrlCacheKey(remoteEntryUrl, fetchTimeoutMs);
371
+ function setSsrEntryCache(remoteEntryUrl, fetchTimeoutMs, fetchMaxBytes) {
372
+ const cacheKey = makeUrlCacheKey(remoteEntryUrl, fetchTimeoutMs, fetchMaxBytes);
306
373
  const record = {
307
- promise: resolveSSREntryImpl(remoteEntryUrl, fetchTimeoutMs),
374
+ promise: resolveSSREntryImpl(remoteEntryUrl, fetchTimeoutMs, fetchMaxBytes),
308
375
  resolvedAt: Date.now()
309
376
  };
310
377
  ssrEntryCache.set(cacheKey, record);
311
378
  record.promise.then((entry) => {
312
379
  if (!entry && ssrEntryCache.get(cacheKey) === record) ssrEntryCache.delete(cacheKey);
380
+ }, () => {
381
+ if (ssrEntryCache.get(cacheKey) === record) ssrEntryCache.delete(cacheKey);
313
382
  });
314
383
  return record;
315
384
  }
316
- async function getSSREntry(remoteEntryUrl, maxAgeMs, fetchTimeoutMs) {
317
- const cacheKey = makeUrlCacheKey(remoteEntryUrl, fetchTimeoutMs);
385
+ async function getSSREntry(remoteEntryUrl, maxAgeMs, fetchTimeoutMs, fetchMaxBytes) {
386
+ const cacheKey = makeUrlCacheKey(remoteEntryUrl, fetchTimeoutMs, fetchMaxBytes);
318
387
  const cached = ssrEntryCache.get(cacheKey);
319
- if (!cached) return setSsrEntryCache(remoteEntryUrl, fetchTimeoutMs).promise;
388
+ if (!cached) return setSsrEntryCache(remoteEntryUrl, fetchTimeoutMs, fetchMaxBytes).promise;
320
389
  if (!(typeof maxAgeMs === "number" && maxAgeMs >= 0 && Date.now() - cached.resolvedAt >= maxAgeMs)) return cached.promise;
321
390
  const previous = await cached.promise.catch(() => null);
322
- manifestFetchCache.delete(makeUrlCacheKey(getManifestUrl(remoteEntryUrl), fetchTimeoutMs));
323
- const record = setSsrEntryCache(remoteEntryUrl, fetchTimeoutMs);
391
+ manifestFetchCache.delete(makeUrlCacheKey(getManifestUrl(remoteEntryUrl), fetchTimeoutMs, fetchMaxBytes));
392
+ const record = setSsrEntryCache(remoteEntryUrl, fetchTimeoutMs, fetchMaxBytes);
324
393
  const next = await record.promise.catch(() => null);
325
394
  if (previous && next && previous.versionKey !== next.versionKey) dropRemoteCaches(remoteEntryUrl);
326
395
  return record.promise;
@@ -337,7 +406,7 @@ function dropRemoteCaches(remoteEntryUrl) {
337
406
  } catch {
338
407
  return;
339
408
  }
340
- for (const [key] of tempFileCache) if (JSON.parse(key)[2].startsWith(origin)) {
409
+ for (const [key] of tempFileCache) if (JSON.parse(key).find((part) => typeof part === "string" && /^https?:\/\//.test(part))?.startsWith(origin)) {
341
410
  tempFileCache.delete(key);
342
411
  tempFilePathCache.delete(key);
343
412
  }
@@ -429,9 +498,10 @@ function isVitePreloadHelperSpecifier(specifier) {
429
498
  * a remote redeploy (new manifest → new key) produces new files and bypasses
430
499
  * Node's ESM module cache instead of serving the stale build.
431
500
  */
432
- async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, versionKey = UNVERSIONED, fetchTimeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS, contextKey = "default") {
501
+ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, versionKey = UNVERSIONED, fetchTimeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS, contextKey = "default", fetchMaxBytes = DEFAULT_SSR_FETCH_MAX_BYTES) {
433
502
  const cacheKey = JSON.stringify([
434
503
  fetchTimeoutMs,
504
+ fetchMaxBytes,
435
505
  versionKey,
436
506
  url,
437
507
  contextKey
@@ -440,7 +510,8 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
440
510
  const cached = tempFileCache.get(cacheKey);
441
511
  if (cached) {
442
512
  pending.add(cached);
443
- const tmpFile = await tempFilePathCache.get(cacheKey);
513
+ const reserved = tempFilePathCache.get(cacheKey);
514
+ const tmpFile = reserved ? await reserved : await cached;
444
515
  visited.set(url, tmpFile);
445
516
  return tmpFile;
446
517
  }
@@ -454,7 +525,7 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
454
525
  const tmpFile = await tmpFilePromise;
455
526
  visited.set(url, tmpFile);
456
527
  const res = await fetchWithTimeout(url, {}, fetchTimeoutMs);
457
- let code = await res.text();
528
+ let code = await readResponseTextBounded(res, fetchMaxBytes, url);
458
529
  if (!res.ok) throw new SsrEntryHttpError(url, res.status, res.statusText, getBodyPreview(code));
459
530
  const base = url.replace(/\/[^/]*$/, "/");
460
531
  const relImports = [];
@@ -463,7 +534,7 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
463
534
  while ((m = relRegex.exec(code)) !== null) if ((m[1].startsWith("./") || m[1].startsWith("../")) && !isVitePreloadHelperSpecifier(m[1])) relImports.push(new URL(m[1], base).href);
464
535
  const subMap = /* @__PURE__ */ new Map();
465
536
  await Promise.all([...new Set(relImports)].filter((u) => u.startsWith("http://") || u.startsWith("https://")).map(async (u) => {
466
- const tmpPath = await fetchEsmToTempFile(u, tmpDir, visited, pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey);
537
+ const tmpPath = await fetchEsmToTempFile(u, tmpDir, visited, pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey, fetchMaxBytes);
467
538
  subMap.set(u, `file://${tmpPath}`);
468
539
  }));
469
540
  code = transformSsrCode(code, base, sharedPkgMap);
@@ -480,9 +551,9 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
480
551
  });
481
552
  return promise;
482
553
  }
483
- async function fetchEsmGraphToTempFile(url, tmpDir, sharedPkgMap, versionKey = UNVERSIONED, fetchTimeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS, contextKey = "default") {
554
+ async function fetchEsmGraphToTempFile(url, tmpDir, sharedPkgMap, versionKey = UNVERSIONED, fetchTimeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS, contextKey = "default", fetchMaxBytes = DEFAULT_SSR_FETCH_MAX_BYTES) {
484
555
  const pending = /* @__PURE__ */ new Set();
485
- const rootFile = await fetchEsmToTempFile(url, tmpDir, /* @__PURE__ */ new Map(), pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey);
556
+ const rootFile = await fetchEsmToTempFile(url, tmpDir, /* @__PURE__ */ new Map(), pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey, fetchMaxBytes);
486
557
  await Promise.all(pending);
487
558
  return rootFile;
488
559
  }
@@ -494,7 +565,7 @@ async function importTempModule(filePath, versionKey) {
494
565
  }
495
566
  let warnedVmUnavailable = false;
496
567
  async function tryVmStrategy(ssrEntry, options) {
497
- const { loadViaVmStrategy, isVmStrategyAvailable } = await import("./ssrVmStrategy-ChF8MB7l.js");
568
+ const { loadViaVmStrategy, isVmStrategyAvailable } = await import("./ssrVmStrategy-Dpw20xiw.js");
498
569
  if (!await isVmStrategyAvailable()) {
499
570
  if (!warnedVmUnavailable) {
500
571
  warnedVmUnavailable = true;
@@ -507,6 +578,7 @@ async function tryVmStrategy(ssrEntry, options) {
507
578
  shareScopeName: options.shareScopeName,
508
579
  versionKey: ssrEntry.versionKey,
509
580
  fetchTimeoutMs: options.fetchTimeoutMs,
581
+ fetchMaxBytes: options.fetchMaxBytes,
510
582
  cacheContext: options.cacheContext,
511
583
  federationInstance: options.federationInstance
512
584
  });
@@ -525,14 +597,15 @@ async function loadSSRRemoteEntry(ssrEntry, options) {
525
597
  const urlObj = new URL(url);
526
598
  if (urlObj.pathname.includes("/__mf_ssr__/")) {
527
599
  const remoteOrigin = urlObj.origin;
528
- const runner = await getOrCreateRunner(remoteOrigin, options.fetchTimeoutMs);
600
+ const runner = await getOrCreateRunner(remoteOrigin, options.fetchTimeoutMs, options.fetchMaxBytes);
529
601
  if (!runner) {
530
602
  if (process.env.NODE_ENV !== "production") return null;
531
603
  } else try {
532
604
  const mod = await runner.import(urlObj.pathname);
533
605
  if (mod && typeof mod === "object" && "init" in mod) return mod;
534
606
  if (process.env.NODE_ENV !== "production") return null;
535
- } catch {
607
+ } catch (error) {
608
+ if (isSsrFetchBodyTooLargeError(error)) throw error;
536
609
  if (process.env.NODE_ENV !== "production") return null;
537
610
  }
538
611
  }
@@ -540,16 +613,16 @@ async function loadSSRRemoteEntry(ssrEntry, options) {
540
613
  const fromVm = await tryVmStrategy(ssrEntry, options);
541
614
  if (fromVm) return fromVm;
542
615
  } catch (error) {
543
- if (isSsrEntryHttpError(error)) throw error;
616
+ if (isSsrEntryHttpError(error) || isSsrFetchBodyTooLargeError(error)) throw error;
544
617
  }
545
618
  const { mkdirSync } = await _fs();
546
619
  const cacheDir = await getSSRCacheDir();
547
620
  mkdirSync(cacheDir, { recursive: true });
548
621
  const sharedPkgMap = new Map(Object.entries(resolvedShared));
549
622
  try {
550
- return await importTempModule(await fetchEsmGraphToTempFile(url, cacheDir, sharedPkgMap, versionKey, options.fetchTimeoutMs, getSsrTransformContextKey(resolvedShared, options.shareScopeName)), versionKey);
623
+ return await importTempModule(await fetchEsmGraphToTempFile(url, cacheDir, sharedPkgMap, versionKey, options.fetchTimeoutMs, getSsrTransformContextKey(resolvedShared, options.shareScopeName), options.fetchMaxBytes), versionKey);
551
624
  } catch (error) {
552
- if (isSsrEntryHttpError(error)) throw error;
625
+ if (isSsrEntryHttpError(error) || isSsrFetchBodyTooLargeError(error)) throw error;
553
626
  return null;
554
627
  }
555
628
  }
@@ -569,6 +642,7 @@ function ssrEntryLoaderPlugin(options = {}) {
569
642
  shareScopeName: options.shareScopeName ?? "default",
570
643
  maxAgeMs: options.maxAgeMs,
571
644
  fetchTimeoutMs: options.fetchTimeoutMs ?? 1e4,
645
+ fetchMaxBytes: options.fetchMaxBytes ?? 10485760,
572
646
  cacheContext: {}
573
647
  };
574
648
  return {
@@ -580,7 +654,7 @@ function ssrEntryLoaderPlugin(options = {}) {
580
654
  cacheContext: origin,
581
655
  federationInstance: origin
582
656
  } : resolved;
583
- const ssrEntry = await getSSREntry(remoteInfo.entry, loadOptions.maxAgeMs, loadOptions.fetchTimeoutMs);
657
+ const ssrEntry = await getSSREntry(remoteInfo.entry, loadOptions.maxAgeMs, loadOptions.fetchTimeoutMs, loadOptions.fetchMaxBytes);
584
658
  if (!ssrEntry) return;
585
659
  const mod = await loadSSRRemoteEntry(ssrEntry, loadOptions);
586
660
  if (!mod) return;
@@ -589,4 +663,4 @@ function ssrEntryLoaderPlugin(options = {}) {
589
663
  };
590
664
  }
591
665
  //#endregion
592
- export { DEFAULT_SSR_FETCH_TIMEOUT_MS as a, ssrEntryLoaderPlugin as i, neutralizeBrowserPreloadHelpers as n, fetchWithTimeout as o, revalidate as r, SsrEntryHttpError as t };
666
+ export { DEFAULT_SSR_FETCH_MAX_BYTES as a, readResponseTextBounded as c, ssrEntryLoaderPlugin as i, neutralizeBrowserPreloadHelpers as n, DEFAULT_SSR_FETCH_TIMEOUT_MS as o, revalidate as r, fetchWithTimeout as s, SsrEntryHttpError as t };
@@ -1,4 +1,4 @@
1
- import { n as neutralizeBrowserPreloadHelpers, o as fetchWithTimeout, t as SsrEntryHttpError } from "./ssrEntryLoader-DgsCQOqq.js";
1
+ import { c as readResponseTextBounded, n as neutralizeBrowserPreloadHelpers, s as fetchWithTimeout, t as SsrEntryHttpError } from "./ssrEntryLoader-CuZVKlRm.js";
2
2
  //#region src/utils/ssrVmStrategy.ts
3
3
  /**
4
4
  * vm.SourceTextModule strategy for loading remote SSR entries.
@@ -104,9 +104,9 @@ function getVmCacheContextKey(options) {
104
104
  function getBodyPreview(body) {
105
105
  return body.slice(0, 240).replace(/\s+/g, " ").trim();
106
106
  }
107
- async function fetchModuleSource(url, fetchTimeoutMs) {
107
+ async function fetchModuleSource(url, fetchTimeoutMs, fetchMaxBytes) {
108
108
  const res = await fetchWithTimeout(url, {}, fetchTimeoutMs);
109
- const text = await res.text();
109
+ const text = await readResponseTextBounded(res, fetchMaxBytes ?? 10485760, url);
110
110
  if (!res.ok) throw new SsrEntryHttpError(url, res.status, res.statusText, getBodyPreview(text));
111
111
  return neutralizeBrowserPreloadHelpers(text);
112
112
  }
@@ -123,11 +123,12 @@ function getHttpModule(vm, url, options) {
123
123
  const cacheKey = JSON.stringify([
124
124
  getVmCacheContextKey(options),
125
125
  options.fetchTimeoutMs ?? 1e4,
126
+ options.fetchMaxBytes ?? 10485760,
126
127
  options.versionKey,
127
128
  url
128
129
  ]);
129
130
  if (!httpModuleCache.has(cacheKey)) httpModuleCache.set(cacheKey, (async () => {
130
- const code = await fetchModuleSource(url, options.fetchTimeoutMs);
131
+ const code = await fetchModuleSource(url, options.fetchTimeoutMs, options.fetchMaxBytes);
131
132
  return new vm.SourceTextModule(code, {
132
133
  identifier: url,
133
134
  initializeImportMeta(meta) {
@@ -105,6 +105,11 @@ interface SsrEntryLoaderOptions {
105
105
  * 10 seconds. Set to `0` to disable the timeout.
106
106
  */
107
107
  fetchTimeoutMs?: number;
108
+ /**
109
+ * Maximum response body size in bytes for each SSR network request. Defaults
110
+ * to 10 MiB. Set to `0` to disable the limit.
111
+ */
112
+ fetchMaxBytes?: number;
108
113
  }
109
114
  declare function ssrEntryLoaderPlugin(options?: SsrEntryLoaderOptions): {
110
115
  name: string;
@@ -1,2 +1,2 @@
1
- import { i as ssrEntryLoaderPlugin, n as neutralizeBrowserPreloadHelpers, r as revalidate, t as SsrEntryHttpError } from "../ssrEntryLoader-DgsCQOqq.js";
1
+ import { i as ssrEntryLoaderPlugin, n as neutralizeBrowserPreloadHelpers, r as revalidate, t as SsrEntryHttpError } from "../ssrEntryLoader-CuZVKlRm.js";
2
2
  export { SsrEntryHttpError, ssrEntryLoaderPlugin as default, neutralizeBrowserPreloadHelpers, revalidate };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/vite",
3
- "version": "1.18.1",
3
+ "version": "1.19.0",
4
4
  "description": "Vite plugin for Module Federation",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -86,4 +86,4 @@
86
86
  "vite": "8.1.0",
87
87
  "vitest": "4.0.18"
88
88
  }
89
- }
89
+ }