@module-federation/vite 1.18.2 → 1.19.1
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 +26 -0
- package/lib/index.d.ts +21 -0
- package/lib/index.js +125 -36
- package/lib/{pluginDts-CGDIZCsD.js → pluginDts-9RTNVO8v.js} +10 -2
- package/lib/{ssrEntryLoader-DgsCQOqq.js → ssrEntryLoader-CuZVKlRm.js} +114 -40
- package/lib/{ssrVmStrategy-ChF8MB7l.js → ssrVmStrategy-Dpw20xiw.js} +5 -4
- package/lib/utils/ssrEntryLoader.d.ts +5 -0
- package/lib/utils/ssrEntryLoader.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -70,6 +70,10 @@ With **@module-federation/vite**, the process becomes delightfully simple, you w
|
|
|
70
70
|
> This example is with [Vue.js](https://vuejs.org/)</br>
|
|
71
71
|
> The @module-federation/vite configuration remains the same for different frameworks.
|
|
72
72
|
|
|
73
|
+
## Migrating from OriginJS
|
|
74
|
+
|
|
75
|
+
Migrating from `@originjs/vite-plugin-federation` requires an explicit remote-entry format and runtime review, particularly for dynamic remotes, shared dependencies, and mixed bundlers. See the [OriginJS migration guide](./docs/MIGRATING_FROM_ORIGINJS.md) for step-by-step migration and incremental deployment guidance.
|
|
76
|
+
|
|
73
77
|
## Dedicated configuration file
|
|
74
78
|
|
|
75
79
|
You can keep Module Federation options in `module-federation.config.ts`.
|
|
@@ -221,6 +225,28 @@ You can specify the place the host initialization file is injected with the **ho
|
|
|
221
225
|
The **moduleParseTimeout** option allows you to configure the maximum time to wait for module parsing during the build process.
|
|
222
226
|
The **moduleParseIdleTimeout** option is an alternative that resets the timer on every parsed module. It only fires when there has been no module activity for the configured duration, making it suitable for large codebases where the total build time exceeds the fixed timeout.
|
|
223
227
|
|
|
228
|
+
## Runtime capability optimization
|
|
229
|
+
|
|
230
|
+
Runtime features that a build never uses can be removed at build time:
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
federation({
|
|
234
|
+
name: "remote",
|
|
235
|
+
exposes: {
|
|
236
|
+
"./remote-app": "./src/App.vue",
|
|
237
|
+
},
|
|
238
|
+
disableRemote: true,
|
|
239
|
+
disableShared: true,
|
|
240
|
+
disableSnapshot: true,
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
- `disableRemote` removes remote-consumption support. Do not enable it when `remotes` are configured.
|
|
245
|
+
- `disableShared` removes shared-dependency support. Do not enable it when `shared` dependencies are configured.
|
|
246
|
+
- `disableSnapshot` removes snapshot support, including manifest-based remotes, preload, dynamic type hints, HMR, and devtools integration.
|
|
247
|
+
|
|
248
|
+
All three options default to `false`, except `disableSnapshot`, which defaults to `true` for Node/SSR builds. An explicitly configured Vite `define` value takes precedence over the corresponding option.
|
|
249
|
+
|
|
224
250
|
## Load the Remote App
|
|
225
251
|
|
|
226
252
|
In your host app, you can now import and use the remote app with **defineAsyncComponent**
|
package/lib/index.d.ts
CHANGED
|
@@ -96,6 +96,27 @@ type ModuleFederationOptions = {
|
|
|
96
96
|
* @default 'web' (or 'node' if build.ssr is enabled)
|
|
97
97
|
*/
|
|
98
98
|
target?: 'web' | 'node';
|
|
99
|
+
/**
|
|
100
|
+
* Removes remote-consumption support from the federation runtime.
|
|
101
|
+
* Only enable this for builds that never load remotes.
|
|
102
|
+
*
|
|
103
|
+
* @default false
|
|
104
|
+
*/
|
|
105
|
+
disableRemote?: boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Removes shared-dependency support from the federation runtime.
|
|
108
|
+
* Only enable this when the build has no shared dependencies.
|
|
109
|
+
*
|
|
110
|
+
* @default false
|
|
111
|
+
*/
|
|
112
|
+
disableShared?: boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Removes snapshot support, including manifest-based remotes, preload,
|
|
115
|
+
* dynamic type hints, HMR, and devtools integration.
|
|
116
|
+
*
|
|
117
|
+
* @default false (true for Node/SSR builds)
|
|
118
|
+
*/
|
|
119
|
+
disableSnapshot?: boolean;
|
|
99
120
|
/**
|
|
100
121
|
* Additional packages to mark as external in the SSR remote entry build.
|
|
101
122
|
* Shared packages and MF runtime packages are always external. Use this to
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as createModuleFederationError, a as getIsRolldown, b as rebaseImport, c as getPackageNameFromNodeModulePath, d as isNuxtProjectRoot, f as packageNameDecode, g as sharedCacheHelperCode, h as setPackageDetectionCwd, i as getInstalledPackageJson, l as getSharedCacheDescriptor, m as resolveImportPath, o as getPackageDetectionCwd, p as packageNameEncode, r as getInstalledPackageEntry, s as getPackageName, u as hasPackageDependency, v as mfWarn, y as normalizePathForImport } from "./pluginDts-
|
|
1
|
+
import { _ as createModuleFederationError, a as getIsRolldown, b as rebaseImport, c as getPackageNameFromNodeModulePath, d as isNuxtProjectRoot, f as packageNameDecode, g as sharedCacheHelperCode, h as setPackageDetectionCwd, i as getInstalledPackageJson, l as getSharedCacheDescriptor, m as resolveImportPath, o as getPackageDetectionCwd, p as packageNameEncode, r as getInstalledPackageEntry, s as getPackageName, u as hasPackageDependency, v as mfWarn, y as normalizePathForImport } from "./pluginDts-9RTNVO8v.js";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import * as fs$2 from "fs";
|
|
4
4
|
import { existsSync, readFileSync, realpathSync, statSync, writeFileSync } from "fs";
|
|
@@ -237,6 +237,10 @@ const ASSET_LIKE_IMPORT_RE = new RegExp(`\\.(${[...[
|
|
|
237
237
|
function isAssetLikeImport(source) {
|
|
238
238
|
return ASSET_LIKE_IMPORT_RE.test(source);
|
|
239
239
|
}
|
|
240
|
+
const VITE_OPTIMIZABLE_ENTRY_RE = /\.[cm]?[jt]s$/;
|
|
241
|
+
function isViteOptimizableEntry(resolvedPath) {
|
|
242
|
+
return VITE_OPTIMIZABLE_ENTRY_RE.test(resolvedPath);
|
|
243
|
+
}
|
|
240
244
|
function removeTrailingSlash(value) {
|
|
241
245
|
return value.endsWith("/") ? value.slice(0, -1) : value;
|
|
242
246
|
}
|
|
@@ -544,7 +548,10 @@ function normalizeModuleFederationOptions(options) {
|
|
|
544
548
|
moduleParseTimeout: options.moduleParseTimeout || 10,
|
|
545
549
|
moduleParseIdleTimeout: options.moduleParseIdleTimeout,
|
|
546
550
|
varFilename: options.varFilename,
|
|
547
|
-
target: options.target
|
|
551
|
+
target: options.target,
|
|
552
|
+
disableRemote: options.disableRemote,
|
|
553
|
+
disableShared: options.disableShared,
|
|
554
|
+
disableSnapshot: options.disableSnapshot
|
|
548
555
|
};
|
|
549
556
|
explicitSharedKeysByOptions.set(normalized, new Set(explicitSharedKeys));
|
|
550
557
|
return config = normalized;
|
|
@@ -2780,7 +2787,7 @@ const externalSharedProviderSelectionHelperCode = `const __mfSelectExternalShare
|
|
|
2780
2787
|
const candidates = Object.fromEntries(
|
|
2781
2788
|
Object.entries(versions || {}).filter(([, provider]) => !isLocalProvider(provider))
|
|
2782
2789
|
);
|
|
2783
|
-
if (localShare?.version) {
|
|
2790
|
+
if (localShare?.version && localShare.shareConfig?.import !== false) {
|
|
2784
2791
|
const sameVersionProvider = candidates[localShare.version];
|
|
2785
2792
|
// Runtime registration keeps an existing same-version record,
|
|
2786
2793
|
// even when it has only a getter and is not loaded yet. Model
|
|
@@ -4915,8 +4922,8 @@ function resolveReactRefreshRuntime(root) {
|
|
|
4915
4922
|
* falls back to this remote's local runtime when the remote is opened directly.
|
|
4916
4923
|
*/
|
|
4917
4924
|
const REACT_REFRESH_PROXY_MODULE = [
|
|
4918
|
-
`const
|
|
4919
|
-
`const __target = window.location.origin ===
|
|
4925
|
+
`const __remoteUrl = new URL(import.meta.url);`,
|
|
4926
|
+
`const __target = window.location.origin === __remoteUrl.origin ? new URL('.${LOCAL_REACT_REFRESH_PATH}', __remoteUrl).href : window.location.origin + '${REACT_REFRESH_PATH}';`,
|
|
4920
4927
|
`const __rt = await import(__target);`,
|
|
4921
4928
|
`export const injectIntoGlobalHook = __rt.injectIntoGlobalHook;`,
|
|
4922
4929
|
`export const register = __rt.register;`,
|
|
@@ -4933,14 +4940,14 @@ const reactAdapter = {
|
|
|
4933
4940
|
let reactRefreshRuntime;
|
|
4934
4941
|
server.middlewares.use((req, res, next) => {
|
|
4935
4942
|
const url = stripQuery(req.url);
|
|
4936
|
-
if (url
|
|
4943
|
+
if (url?.endsWith(LOCAL_REACT_REFRESH_PATH)) {
|
|
4937
4944
|
reactRefreshRuntime ??= resolveReactRefreshRuntime(server.config.root);
|
|
4938
4945
|
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
4939
4946
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
4940
4947
|
res.end(reactRefreshRuntime);
|
|
4941
4948
|
return;
|
|
4942
4949
|
}
|
|
4943
|
-
if (url
|
|
4950
|
+
if (!url?.endsWith(REACT_REFRESH_PATH)) return next();
|
|
4944
4951
|
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
4945
4952
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
4946
4953
|
res.end(REACT_REFRESH_PROXY_MODULE);
|
|
@@ -5630,6 +5637,35 @@ const chunkContainsCssModules = (modules) => {
|
|
|
5630
5637
|
return false;
|
|
5631
5638
|
};
|
|
5632
5639
|
/**
|
|
5640
|
+
* Analyzes assets associated with a chunk without mutating the output map.
|
|
5641
|
+
* The static-import traversal is cycle-safe and ignores missing bundle entries.
|
|
5642
|
+
*/
|
|
5643
|
+
const analyzeChunkAssets = (bundle, fileName, chunk) => {
|
|
5644
|
+
const dynamicAssets = [];
|
|
5645
|
+
const visited = /* @__PURE__ */ new Set();
|
|
5646
|
+
const queue = [fileName];
|
|
5647
|
+
for (let queueIndex = 0; queueIndex < queue.length; queueIndex++) {
|
|
5648
|
+
const currentFileName = queue[queueIndex];
|
|
5649
|
+
if (visited.has(currentFileName)) continue;
|
|
5650
|
+
visited.add(currentFileName);
|
|
5651
|
+
const currentChunk = bundle[currentFileName];
|
|
5652
|
+
if (!currentChunk || currentChunk.type !== "chunk") continue;
|
|
5653
|
+
for (const dynamicImport of currentChunk.dynamicImports ?? []) {
|
|
5654
|
+
if (!bundle[dynamicImport]) continue;
|
|
5655
|
+
dynamicAssets.push({
|
|
5656
|
+
fileName: dynamicImport,
|
|
5657
|
+
type: isCSSFile(dynamicImport) ? "css" : "js"
|
|
5658
|
+
});
|
|
5659
|
+
}
|
|
5660
|
+
for (const staticImport of currentChunk.imports ?? []) queue.push(staticImport);
|
|
5661
|
+
}
|
|
5662
|
+
return {
|
|
5663
|
+
importedCss: Array.from(chunk.viteMetadata?.importedCss ?? []),
|
|
5664
|
+
containsCssModules: chunkContainsCssModules(chunk.modules),
|
|
5665
|
+
dynamicAssets
|
|
5666
|
+
};
|
|
5667
|
+
};
|
|
5668
|
+
/**
|
|
5633
5669
|
* Processes module assets and tracks them in the files map
|
|
5634
5670
|
* @param bundle - The Rollup output bundle
|
|
5635
5671
|
* @param filesMap - The preload map to populate
|
|
@@ -5637,6 +5673,7 @@ const chunkContainsCssModules = (modules) => {
|
|
|
5637
5673
|
*/
|
|
5638
5674
|
const processModuleAssets = (bundle, filesMap, moduleMatcher, options = {}) => {
|
|
5639
5675
|
const bundleCssAssets = collectCssAssets(bundle);
|
|
5676
|
+
const chunkAnalysisCache = /* @__PURE__ */ new Map();
|
|
5640
5677
|
for (const [fileName, fileData] of Object.entries(bundle)) {
|
|
5641
5678
|
if (fileData.type !== "chunk") continue;
|
|
5642
5679
|
if (!fileData.modules) continue;
|
|
@@ -5649,27 +5686,19 @@ const processModuleAssets = (bundle, filesMap, moduleMatcher, options = {}) => {
|
|
|
5649
5686
|
}
|
|
5650
5687
|
const matchKey = comparableModulePaths.map(moduleMatcher).find(Boolean);
|
|
5651
5688
|
if (!matchKey) continue;
|
|
5689
|
+
let analysis = chunkAnalysisCache.get(fileName);
|
|
5690
|
+
if (!analysis) {
|
|
5691
|
+
analysis = analyzeChunkAssets(bundle, fileName, fileData);
|
|
5692
|
+
chunkAnalysisCache.set(fileName, analysis);
|
|
5693
|
+
}
|
|
5652
5694
|
trackAsset(filesMap, matchKey, fileName, false, "js");
|
|
5653
5695
|
let foundCssViaMetadata = false;
|
|
5654
|
-
|
|
5696
|
+
for (const cssFile of analysis.importedCss) {
|
|
5655
5697
|
trackAsset(filesMap, matchKey, cssFile, false, "css");
|
|
5656
5698
|
foundCssViaMetadata = true;
|
|
5657
5699
|
}
|
|
5658
|
-
if (!foundCssViaMetadata &&
|
|
5659
|
-
const
|
|
5660
|
-
const queue = [fileName];
|
|
5661
|
-
for (let queueIndex = 0; queueIndex < queue.length; queueIndex++) {
|
|
5662
|
-
const cur = queue[queueIndex];
|
|
5663
|
-
if (visited.has(cur)) continue;
|
|
5664
|
-
visited.add(cur);
|
|
5665
|
-
const chunk = bundle[cur];
|
|
5666
|
-
if (!chunk || chunk.type !== "chunk") continue;
|
|
5667
|
-
if (chunk.dynamicImports) for (const dynamicImport of chunk.dynamicImports) {
|
|
5668
|
-
if (!bundle[dynamicImport]) continue;
|
|
5669
|
-
trackAsset(filesMap, matchKey, dynamicImport, true, isCSSFile(dynamicImport) ? "css" : "js");
|
|
5670
|
-
}
|
|
5671
|
-
if (chunk.imports) for (const imp of chunk.imports) queue.push(imp);
|
|
5672
|
-
}
|
|
5700
|
+
if (!foundCssViaMetadata && analysis.containsCssModules) for (const cssAsset of Array.from(bundleCssAssets)) trackAsset(filesMap, matchKey, cssAsset, false, "css");
|
|
5701
|
+
for (const asset of analysis.dynamicAssets) trackAsset(filesMap, matchKey, asset.fileName, true, asset.type);
|
|
5673
5702
|
}
|
|
5674
5703
|
}
|
|
5675
5704
|
};
|
|
@@ -7759,6 +7788,44 @@ var normalizeOptimizeDeps_default = {
|
|
|
7759
7788
|
}
|
|
7760
7789
|
};
|
|
7761
7790
|
//#endregion
|
|
7791
|
+
//#region src/utils/runtimeCapabilityOptimization.ts
|
|
7792
|
+
const RUNTIME_CAPABILITIES = [
|
|
7793
|
+
{
|
|
7794
|
+
option: "disableRemote",
|
|
7795
|
+
define: "FEDERATION_OPTIMIZE_NO_REMOTE"
|
|
7796
|
+
},
|
|
7797
|
+
{
|
|
7798
|
+
option: "disableShared",
|
|
7799
|
+
define: "FEDERATION_OPTIMIZE_NO_SHARED"
|
|
7800
|
+
},
|
|
7801
|
+
{
|
|
7802
|
+
option: "disableSnapshot",
|
|
7803
|
+
define: "FEDERATION_OPTIMIZE_NO_SNAPSHOT_PLUGIN"
|
|
7804
|
+
}
|
|
7805
|
+
];
|
|
7806
|
+
function isEquivalentBooleanDefine(value, expected) {
|
|
7807
|
+
return String(value) === JSON.stringify(expected);
|
|
7808
|
+
}
|
|
7809
|
+
function applyRuntimeCapabilityDefines(define, options, { defaultDisableSnapshot, onConflict } = {}) {
|
|
7810
|
+
for (const capability of RUNTIME_CAPABILITIES) {
|
|
7811
|
+
const explicitValue = options[capability.option];
|
|
7812
|
+
const desiredValue = capability.option === "disableSnapshot" ? explicitValue ?? defaultDisableSnapshot : explicitValue;
|
|
7813
|
+
if (desiredValue === void 0) continue;
|
|
7814
|
+
if (!(capability.define in define)) {
|
|
7815
|
+
define[capability.define] = JSON.stringify(desiredValue);
|
|
7816
|
+
continue;
|
|
7817
|
+
}
|
|
7818
|
+
if (explicitValue !== void 0 && !isEquivalentBooleanDefine(define[capability.define], explicitValue)) onConflict?.(`${capability.define} define (${define[capability.define]}) differs from ${capability.option} option (${explicitValue}). The existing define will not be overridden.`);
|
|
7819
|
+
}
|
|
7820
|
+
if (!("FEDERATION_HAS_EXPOSES" in define)) define["FEDERATION_HAS_EXPOSES"] = JSON.stringify(Object.keys(options.exposes).length > 0);
|
|
7821
|
+
}
|
|
7822
|
+
function getRuntimeCapabilityConfigurationWarnings(options) {
|
|
7823
|
+
const warnings = [];
|
|
7824
|
+
if (options.disableRemote && Object.keys(options.remotes).length > 0) warnings.push("disableRemote is true, but remotes are configured. Remote loading will be unavailable at runtime.");
|
|
7825
|
+
if (options.disableShared && Object.keys(options.shared).length > 0) warnings.push("disableShared is true, but shared dependencies are configured. Shared dependency loading will be unavailable at runtime.");
|
|
7826
|
+
return warnings;
|
|
7827
|
+
}
|
|
7828
|
+
//#endregion
|
|
7762
7829
|
//#region src/index.ts
|
|
7763
7830
|
const patchedManualChunks = /* @__PURE__ */ new WeakSet();
|
|
7764
7831
|
const PRELOAD_HELPER_CHUNK = "vite-preload-helper";
|
|
@@ -7843,8 +7910,7 @@ function isFederationHtmlPreloadDependency(dep, includeSharedRuntime = false) {
|
|
|
7843
7910
|
}
|
|
7844
7911
|
function canResolveSharedSubpath(subpath, projectRoot) {
|
|
7845
7912
|
try {
|
|
7846
|
-
createRequire$1(pathToFileURL(path$1.join(projectRoot, "package.json"))).resolve(subpath);
|
|
7847
|
-
return true;
|
|
7913
|
+
return isViteOptimizableEntry(createRequire$1(pathToFileURL(path$1.join(projectRoot, "package.json"))).resolve(subpath));
|
|
7848
7914
|
} catch {
|
|
7849
7915
|
return false;
|
|
7850
7916
|
}
|
|
@@ -7974,6 +8040,7 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
7974
8040
|
if (!args.importer || args.namespace === "mf-shared") return;
|
|
7975
8041
|
if (isSharedResolverInternalImporter(args.importer)) return;
|
|
7976
8042
|
if (!findSharedKey(args.path, shared) || isAssetLikeImport(args.path)) return;
|
|
8043
|
+
if (getPackageNameFromNodeModulePath(args.importer) === getPackageName(args.path)) return;
|
|
7977
8044
|
return {
|
|
7978
8045
|
path: args.path,
|
|
7979
8046
|
namespace: "mf-shared"
|
|
@@ -8029,16 +8096,21 @@ export default __mfShared.default ?? __mfShared;`
|
|
|
8029
8096
|
const optimizeDeps = config.optimizeDeps ??= {};
|
|
8030
8097
|
optimizeDeps.include ??= [];
|
|
8031
8098
|
optimizeDeps.exclude ??= [];
|
|
8032
|
-
const shouldBypassOptimizeDep = isLitShare(key);
|
|
8099
|
+
const shouldBypassOptimizeDep = isLitShare(key) || !canResolveSharedSubpath(key, root);
|
|
8033
8100
|
if (optimizeDeps.include.includes(key)) optimizeDeps.exclude = optimizeDeps.exclude.filter((dep) => dep !== key);
|
|
8034
8101
|
else if (shouldBypassOptimizeDep) optimizeDeps.exclude.push(key);
|
|
8035
8102
|
else optimizeDeps.include.push(key);
|
|
8036
8103
|
for (const subpath of getCommonSharedSubpaths(key)) {
|
|
8104
|
+
const canResolveSubpath = canResolveSharedSubpath(subpath, root);
|
|
8105
|
+
if (subpath === "react/compiler-runtime" && !canResolveSubpath) {
|
|
8106
|
+
optimizeDeps.exclude.push(subpath);
|
|
8107
|
+
continue;
|
|
8108
|
+
}
|
|
8037
8109
|
getLoadShareModulePath(subpath, isRolldown, options);
|
|
8038
8110
|
writeLoadShareModule(subpath, shareItem, _command, isRolldown, options);
|
|
8039
8111
|
writePreBuildLibPath(subpath, shareItem, options);
|
|
8040
8112
|
addUsedShares(subpath, options);
|
|
8041
|
-
if (
|
|
8113
|
+
if (canResolveSubpath) optimizeDeps.include.push(subpath);
|
|
8042
8114
|
else optimizeDeps.exclude.push(subpath);
|
|
8043
8115
|
}
|
|
8044
8116
|
}
|
|
@@ -8086,9 +8158,18 @@ export default __mfShared.default ?? __mfShared;`
|
|
|
8086
8158
|
};
|
|
8087
8159
|
}
|
|
8088
8160
|
const SSR_ONLY_PLUGINS = new Set(["@module-federation/vite/ssrEntryLoader"]);
|
|
8161
|
+
function applyBuildTimeRuntimeDefines(define, options, { target, isAstro, defaultDisableSnapshot }) {
|
|
8162
|
+
const envTargetDefineValue = !options.target && isAstro ? "undefined" : JSON.stringify(target);
|
|
8163
|
+
if (!("ENV_TARGET" in define)) define.ENV_TARGET = envTargetDefineValue;
|
|
8164
|
+
applyRuntimeCapabilityDefines(define, options, {
|
|
8165
|
+
defaultDisableSnapshot,
|
|
8166
|
+
onConflict: mfWarn
|
|
8167
|
+
});
|
|
8168
|
+
if (options.target && define.ENV_TARGET !== JSON.stringify(options.target)) mfWarn(`ENV_TARGET define (${define.ENV_TARGET}) differs from target option ("${options.target}"). ENV_TARGET will not be overridden.`);
|
|
8169
|
+
}
|
|
8089
8170
|
function loadPluginDts(options) {
|
|
8090
8171
|
if (options.dts === false) return [];
|
|
8091
|
-
return [import("./pluginDts-
|
|
8172
|
+
return [import("./pluginDts-9RTNVO8v.js").then((n) => n.n).then(({ default: pluginDts }) => pluginDts(options))];
|
|
8092
8173
|
}
|
|
8093
8174
|
function federation(mfUserOptions) {
|
|
8094
8175
|
if (isTestEnv()) return [];
|
|
@@ -8102,6 +8183,7 @@ function federation(mfUserOptions) {
|
|
|
8102
8183
|
let command;
|
|
8103
8184
|
let desiredRolldownOutput;
|
|
8104
8185
|
let isSsrBuild = false;
|
|
8186
|
+
const emittedRuntimeCapabilityWarnings = /* @__PURE__ */ new Set();
|
|
8105
8187
|
return [
|
|
8106
8188
|
{
|
|
8107
8189
|
name: "vite:module-federation-virtual-modules",
|
|
@@ -8444,11 +8526,17 @@ function federation(mfUserOptions) {
|
|
|
8444
8526
|
}
|
|
8445
8527
|
const isAstro = hasPackageDependency("astro");
|
|
8446
8528
|
const resolvedTarget = options.target ?? (config.build?.ssr ? "node" : "web");
|
|
8447
|
-
const envTargetDefineValue = !options.target && isAstro ? "undefined" : JSON.stringify(resolvedTarget);
|
|
8448
8529
|
if (!config.define) config.define = {};
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8530
|
+
applyBuildTimeRuntimeDefines(config.define, options, {
|
|
8531
|
+
target: resolvedTarget,
|
|
8532
|
+
isAstro,
|
|
8533
|
+
defaultDisableSnapshot: resolvedTarget === "node" ? true : void 0
|
|
8534
|
+
});
|
|
8535
|
+
for (const warning of getRuntimeCapabilityConfigurationWarnings(options)) {
|
|
8536
|
+
if (emittedRuntimeCapabilityWarnings.has(warning)) continue;
|
|
8537
|
+
emittedRuntimeCapabilityWarnings.add(warning);
|
|
8538
|
+
mfWarn(warning);
|
|
8539
|
+
}
|
|
8452
8540
|
},
|
|
8453
8541
|
configResolved(config) {
|
|
8454
8542
|
if (!hasPackageDependency("nitro")) return;
|
|
@@ -8458,11 +8546,12 @@ function federation(mfUserOptions) {
|
|
|
8458
8546
|
configEnvironment(name, config) {
|
|
8459
8547
|
if (!(config.consumer === "server" || name === "ssr" || name === "server" || config.build?.ssr === true)) return;
|
|
8460
8548
|
const isAstro = hasPackageDependency("astro");
|
|
8461
|
-
const envTargetDefineValue = !options.target && isAstro ? "undefined" : JSON.stringify(options.target ?? "node");
|
|
8462
8549
|
config.define = { ...config.define ?? {} };
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8550
|
+
applyBuildTimeRuntimeDefines(config.define, options, {
|
|
8551
|
+
target: options.target ?? "node",
|
|
8552
|
+
isAstro,
|
|
8553
|
+
defaultDisableSnapshot: true
|
|
8554
|
+
});
|
|
8466
8555
|
}
|
|
8467
8556
|
},
|
|
8468
8557
|
...Manifest(options),
|
|
@@ -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 {
|
|
@@ -472,10 +480,10 @@ function getInstalledPackageEntry(pkg, opts) {
|
|
|
472
480
|
if (!installed) return void 0;
|
|
473
481
|
const cwd = opts?.cwd || getPackageDetectionCwd();
|
|
474
482
|
const packageName = opts?.packageName || getPackageName(pkg);
|
|
475
|
-
|
|
483
|
+
const packageJson = installed.packageJson;
|
|
484
|
+
if (pkg !== packageName && (opts?.resolveSubpathWithRequire !== false || packageJson.exports === void 0)) try {
|
|
476
485
|
return createRequire$1(pathToFileURL(path$1.join(cwd, "package.json"))).resolve(pkg);
|
|
477
486
|
} catch {}
|
|
478
|
-
const packageJson = installed.packageJson;
|
|
479
487
|
const explicitEntry = resolveExportsEntry(getPackageExportsTarget(pkg, packageName, packageJson.exports), opts?.conditions) || (typeof packageJson.module === "string" ? packageJson.module : void 0) || (typeof packageJson.main === "string" ? packageJson.main : void 0) || "index.js";
|
|
480
488
|
return path$1.join(installed.dir, explicitEntry);
|
|
481
489
|
}
|
|
@@ -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
|
-
|
|
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))
|
|
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
|
-
|
|
173
|
-
|
|
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)
|
|
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
|
|
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
|
|
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-
|
|
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 {
|
|
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,
|
|
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
|
|
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-
|
|
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 };
|