@module-federation/vite 1.23.1 → 1.23.3
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 +51 -0
- package/lib/{dtsConstants-Bs4FukGL.js → dtsConstants-DSTzyKSG.js} +12 -3
- package/lib/index.d.ts +1 -260
- package/lib/index.js +629 -143
- package/lib/{logger--uKHOVjR.js → logger-DOwfTlw5.js} +1 -1
- package/lib/normalizeModuleFederationOptions-DNUlv-AL.d.ts +303 -0
- package/lib/{pluginDts-DxgS2FEd.js → pluginDts-CVyHPAEq.js} +3 -3
- package/lib/{ssrEntryLoader-DmqLXUmm.js → ssrEntryLoader-DjZj-5Lw.js} +61 -28
- package/lib/{ssrVmStrategy-B_e3yqa2.js → ssrVmStrategy-Dk5xXVvR.js} +15 -20
- package/lib/utils/ssrEntryLoader.d.ts +2 -59
- package/lib/utils/ssrEntryLoader.js +1 -1
- package/package.json +1 -1
|
@@ -363,4 +363,4 @@ const moduleFederationConsole = {
|
|
|
363
363
|
const mfWarn = moduleFederationConsole.warn;
|
|
364
364
|
const mfError = moduleFederationConsole.error;
|
|
365
365
|
//#endregion
|
|
366
|
-
export { CodeRewriter as a,
|
|
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 };
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { moduleFederationPlugin } from "@module-federation/sdk";
|
|
2
|
+
import { ShareStrategy } from "@module-federation/runtime/types";
|
|
3
|
+
//#region src/utils/normalizeModuleFederationOptions.d.ts
|
|
4
|
+
interface RemoteObjectConfig {
|
|
5
|
+
type?: string;
|
|
6
|
+
name: string;
|
|
7
|
+
internalName?: string;
|
|
8
|
+
entry: string;
|
|
9
|
+
entryGlobalName?: string;
|
|
10
|
+
shareScope?: string | string[];
|
|
11
|
+
}
|
|
12
|
+
interface TreeShakingConfig {
|
|
13
|
+
mode: 'server-calc' | 'runtime-infer';
|
|
14
|
+
usedExports?: string[];
|
|
15
|
+
}
|
|
16
|
+
interface PluginManifestOptions {
|
|
17
|
+
filePath?: string;
|
|
18
|
+
disableAssetsAnalyze?: boolean;
|
|
19
|
+
fileName?: string;
|
|
20
|
+
additionalData?: (options: {
|
|
21
|
+
stats: Record<string, unknown>;
|
|
22
|
+
manifest?: Record<string, unknown>;
|
|
23
|
+
pluginOptions: Record<string, unknown>;
|
|
24
|
+
compiler?: unknown;
|
|
25
|
+
compilation?: unknown;
|
|
26
|
+
bundler: 'vite';
|
|
27
|
+
}) => Promise<Record<string, unknown> | void> | Record<string, unknown> | void;
|
|
28
|
+
}
|
|
29
|
+
type ModuleFederationOptions = {
|
|
30
|
+
exposes?: Record<string, string | {
|
|
31
|
+
import: string;
|
|
32
|
+
}> | undefined;
|
|
33
|
+
filename?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Exact file name of the SSR remote entry emitted next to `filename`.
|
|
36
|
+
* Defaults to `<filename base>.ssr<ext>` so it never clobbers the browser
|
|
37
|
+
* entry when both builds share an output directory. `[hash]` is not supported.
|
|
38
|
+
*/
|
|
39
|
+
ssrFilename?: string;
|
|
40
|
+
library?: any;
|
|
41
|
+
name: string;
|
|
42
|
+
remotes?: Record<string, string | RemoteObjectConfig> | undefined;
|
|
43
|
+
runtime?: any;
|
|
44
|
+
shareScope?: string | string[];
|
|
45
|
+
/**
|
|
46
|
+
* Override the public path used for remote entries
|
|
47
|
+
* Defaults to Vite's base config or "auto" if base is empty
|
|
48
|
+
*/
|
|
49
|
+
publicPath?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Controls whether all CSS assets from the bundle should be added to every exposed module.
|
|
52
|
+
* When false (default), the plugin will not process any CSS assets.
|
|
53
|
+
* When true, all CSS assets are bundled into every exposed module.
|
|
54
|
+
*/
|
|
55
|
+
bundleAllCSS?: boolean;
|
|
56
|
+
/** Directory reserved for deploy-service generated secondary shared artifacts. */
|
|
57
|
+
treeShakingDir?: string;
|
|
58
|
+
/** Whether inferred usedExports metadata is injected into generated runtime records. */
|
|
59
|
+
injectTreeShakingUsedExports?: boolean;
|
|
60
|
+
treeShakingSharedPlugins?: string[];
|
|
61
|
+
treeShakingSharedExcludePlugins?: string[];
|
|
62
|
+
shared?: string[] | Record<string, string | {
|
|
63
|
+
name?: string;
|
|
64
|
+
version?: string;
|
|
65
|
+
shareScope?: string;
|
|
66
|
+
request?: moduleFederationPlugin.SharedConfig['request'];
|
|
67
|
+
shareKey?: moduleFederationPlugin.SharedConfig['shareKey'];
|
|
68
|
+
singleton?: boolean;
|
|
69
|
+
eager?: boolean;
|
|
70
|
+
requiredVersion?: moduleFederationPlugin.SharedConfig['requiredVersion'];
|
|
71
|
+
strictVersion?: boolean;
|
|
72
|
+
allowNodeModulesSuffixMatch?: boolean;
|
|
73
|
+
/** Suppress the missing local dependency warning for `import: false` shares. */
|
|
74
|
+
suppressMissingImportWarning?: boolean;
|
|
75
|
+
treeShaking?: TreeShakingConfig;
|
|
76
|
+
import?: moduleFederationPlugin.SharedConfig['import'];
|
|
77
|
+
}> | undefined;
|
|
78
|
+
runtimePlugins?: Array<string | [string, Record<string, unknown>]>;
|
|
79
|
+
getPublicPath?: string;
|
|
80
|
+
implementation?: string;
|
|
81
|
+
manifest?: PluginManifestOptions | boolean;
|
|
82
|
+
dev?: boolean | PluginDevOptions;
|
|
83
|
+
dts?: boolean | PluginDtsOptions;
|
|
84
|
+
shareStrategy?: ShareStrategy;
|
|
85
|
+
ignoreOrigin?: boolean;
|
|
86
|
+
virtualModuleDir?: string;
|
|
87
|
+
hostInitInjectLocation?: HostInitInjectLocationOptions;
|
|
88
|
+
/**
|
|
89
|
+
* Timeout for parsing modules in seconds.
|
|
90
|
+
* Defaults to 10 seconds.
|
|
91
|
+
*/
|
|
92
|
+
moduleParseTimeout?: number;
|
|
93
|
+
/**
|
|
94
|
+
* Idle timeout for parsing modules in seconds. When set, the timeout resets
|
|
95
|
+
* on every parsed module and only fires when there has been no module activity
|
|
96
|
+
* for the configured duration. Prefer this over `moduleParseTimeout` for large
|
|
97
|
+
* codebases where the total build time may exceed the fixed timeout.
|
|
98
|
+
*/
|
|
99
|
+
moduleParseIdleTimeout?: number;
|
|
100
|
+
/**
|
|
101
|
+
* Allows generate additional remoteEntry file for "var" host environment
|
|
102
|
+
*/
|
|
103
|
+
varFilename?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Target environment for the build to enable effective tree-shaking.
|
|
106
|
+
*
|
|
107
|
+
* @see https://module-federation.io/configure/experiments#target
|
|
108
|
+
* @default 'web' (or 'node' if build.ssr is enabled)
|
|
109
|
+
*/
|
|
110
|
+
target?: 'web' | 'node';
|
|
111
|
+
/**
|
|
112
|
+
* Removes remote-consumption support from the federation runtime.
|
|
113
|
+
* Only enable this for builds that never load remotes.
|
|
114
|
+
*
|
|
115
|
+
* @default false
|
|
116
|
+
*/
|
|
117
|
+
disableRemote?: boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Removes shared-dependency support from the federation runtime.
|
|
120
|
+
* Only enable this when the build has no shared dependencies.
|
|
121
|
+
*
|
|
122
|
+
* @default false
|
|
123
|
+
*/
|
|
124
|
+
disableShared?: boolean;
|
|
125
|
+
/**
|
|
126
|
+
* Removes snapshot support, including manifest-based remotes, preload,
|
|
127
|
+
* dynamic type hints, HMR, and devtools integration.
|
|
128
|
+
*
|
|
129
|
+
* @default false (true for Node/SSR builds)
|
|
130
|
+
*/
|
|
131
|
+
disableSnapshot?: boolean;
|
|
132
|
+
/**
|
|
133
|
+
* Additional packages to mark as external in the SSR remote entry build.
|
|
134
|
+
* Shared packages and MF runtime packages are external by default. Use this to
|
|
135
|
+
* add any other Node-only packages that should not be bundled into the SSR entry.
|
|
136
|
+
* To emit a self-contained SSR entry (loadable by hosts that cannot resolve the
|
|
137
|
+
* MF runtime from Node, such as the `@module-federation/sdk` reference loader),
|
|
138
|
+
* opt the MF runtime packages back in through Vite's `ssr.noExternal`.
|
|
139
|
+
*/
|
|
140
|
+
ssrExternals?: string[];
|
|
141
|
+
/**
|
|
142
|
+
* Options for the auto-injected `@module-federation/vite/ssrEntryLoader`.
|
|
143
|
+
* When omitted, the loader uses the `'temp-file'` strategy. Set
|
|
144
|
+
* `strategy: 'vm'` to opt into `vm.SourceTextModule` evaluation while keeping
|
|
145
|
+
* the computed `resolvedShared` map. Optional `maxAgeMs`, `fetchTimeoutMs`,
|
|
146
|
+
* and `fetchMaxBytes` are forwarded to the loader when set.
|
|
147
|
+
*/
|
|
148
|
+
ssrEntryLoader?: SsrEntryLoaderConfig;
|
|
149
|
+
/**
|
|
150
|
+
* Experimental Module Federation capabilities.
|
|
151
|
+
*
|
|
152
|
+
* @see https://module-federation.io/configure/experiments
|
|
153
|
+
*/
|
|
154
|
+
experiments?: PluginExperimentsOptions;
|
|
155
|
+
};
|
|
156
|
+
interface PluginExperimentsOptions {
|
|
157
|
+
/**
|
|
158
|
+
* Treat `@module-federation/runtime-core` as an external that reads
|
|
159
|
+
* `globalThis._FEDERATION_RUNTIME_CORE` at runtime. Pair with a host that
|
|
160
|
+
* sets `provideExternalRuntime: true`.
|
|
161
|
+
*/
|
|
162
|
+
externalRuntime?: boolean;
|
|
163
|
+
/**
|
|
164
|
+
* Injects a local runtime plugin that publishes `runtime-core` on
|
|
165
|
+
* `globalThis._FEDERATION_RUNTIME_CORE`. Set it on exactly one container
|
|
166
|
+
* per page; that container may also `exposes`.
|
|
167
|
+
*/
|
|
168
|
+
provideExternalRuntime?: boolean;
|
|
169
|
+
/** Generate the React SSR/hydration island capability for eligible exposes. */
|
|
170
|
+
ssrMode?: 'ISLAND';
|
|
171
|
+
/**
|
|
172
|
+
* The host provides every shared dependency; remotes bring none. Shared keys
|
|
173
|
+
* are resolved by a native browser import map instead of the Module
|
|
174
|
+
* Federation runtime: the host emits one entry chunk per shared key and
|
|
175
|
+
* injects `<script type="importmap">`, remotes keep shared imports as bare
|
|
176
|
+
* specifiers and emit one fixed-name entry per expose plus a standard
|
|
177
|
+
* `mf-manifest.json` (without `remoteEntry`) the host maps from.
|
|
178
|
+
*
|
|
179
|
+
* Shared modules become ordinary static ES imports, so there is no
|
|
180
|
+
* `loadShare` glue and no `eager` is needed for code that reads a shared
|
|
181
|
+
* value at module-evaluation time. There is no version negotiation and no
|
|
182
|
+
* runtime API: `requiredVersion`, `strictVersion`, `shareStrategy`,
|
|
183
|
+
* `runtimePlugins` and `manifest` are ignored.
|
|
184
|
+
*
|
|
185
|
+
* @see https://github.com/module-federation/vite/issues/1381
|
|
186
|
+
*/
|
|
187
|
+
hostProvidesAllShared?: boolean;
|
|
188
|
+
}
|
|
189
|
+
type SsrEntryLoaderStrategy = 'temp-file' | 'vm';
|
|
190
|
+
type SsrEntryLoaderConfig = {
|
|
191
|
+
/**
|
|
192
|
+
* How the auto-injected `@module-federation/vite/ssrEntryLoader` evaluates
|
|
193
|
+
* remote SSR entries.
|
|
194
|
+
*
|
|
195
|
+
* - `'temp-file'` (default when omitted): fetch the ESM graph, rewrite
|
|
196
|
+
* specifiers, write temp files and `import()` them. Works on stock Node;
|
|
197
|
+
* shared packages are pinned to the host's copies via `resolvedShared`
|
|
198
|
+
* (no version negotiation).
|
|
199
|
+
* - `'vm'`: evaluate the graph with `vm.SourceTextModule` and link bare
|
|
200
|
+
* shared imports through the host's federation share scope (`loadShare`),
|
|
201
|
+
* restoring version negotiation. Requires `--experimental-vm-modules`; the
|
|
202
|
+
* loader emits a single warning and falls back to `'temp-file'` when that
|
|
203
|
+
* API is unavailable.
|
|
204
|
+
*/
|
|
205
|
+
strategy?: SsrEntryLoaderStrategy;
|
|
206
|
+
/**
|
|
207
|
+
* Re-check each remote's manifest when the cached SSR entry resolution is
|
|
208
|
+
* older than this many milliseconds. When the manifest's version changes
|
|
209
|
+
* (remote redeployed at the same URL), the loader drops its caches for that
|
|
210
|
+
* remote so subsequent loads use the new build. Omit to cache until process
|
|
211
|
+
* exit or an explicit `revalidate()` call. Only manifest-resolved entries
|
|
212
|
+
* can be revalidated this way — convention-resolved entries have no version
|
|
213
|
+
* source.
|
|
214
|
+
*/
|
|
215
|
+
maxAgeMs?: number;
|
|
216
|
+
/**
|
|
217
|
+
* Maximum time in milliseconds for each SSR network request. Defaults to
|
|
218
|
+
* 10 seconds. Set to `0` to disable the timeout.
|
|
219
|
+
*/
|
|
220
|
+
fetchTimeoutMs?: number;
|
|
221
|
+
/**
|
|
222
|
+
* Maximum response body size in bytes for each SSR network request. Defaults
|
|
223
|
+
* to 10 MiB. Set to `0` to disable the limit.
|
|
224
|
+
*/
|
|
225
|
+
fetchMaxBytes?: number;
|
|
226
|
+
};
|
|
227
|
+
type HostInitInjectLocationOptions = 'entry' | 'html';
|
|
228
|
+
interface PluginDevOptions {
|
|
229
|
+
disableLiveReload?: boolean;
|
|
230
|
+
disableHotTypesReload?: boolean;
|
|
231
|
+
disableDynamicRemoteTypeHints?: boolean;
|
|
232
|
+
/**
|
|
233
|
+
* Controls cross-federation HMR for remote modules.
|
|
234
|
+
*
|
|
235
|
+
* - `false` / `undefined` — HMR disabled (default).
|
|
236
|
+
* - `true` — HMR enabled with auto-detected strategy. When a framework
|
|
237
|
+
* plugin with cross-federation HMR support is detected, broadcast/relay
|
|
238
|
+
* is suppressed and the framework's native HMR handles updates:
|
|
239
|
+
* - React (`@vitejs/plugin-react` / `@vitejs/plugin-react-swc`) — the
|
|
240
|
+
* plugin serves a `/@react-refresh` proxy on remotes that delegates
|
|
241
|
+
* to the host's `RefreshRuntime`, unifying the component registry.
|
|
242
|
+
* - Vue (`@vitejs/plugin-vue` / `@vitejs/plugin-vue-jsx`) — the plugin
|
|
243
|
+
* injects a `__VUE_HMR_RUNTIME__` guard into the host page so the
|
|
244
|
+
* first-loaded (host) Vue runtime is pinned and remote-loaded Vue
|
|
245
|
+
* copies cannot overwrite it.
|
|
246
|
+
* For any host, the plugin also injects a script that clears the
|
|
247
|
+
* federation `moduleCache` on `vite:beforeUpdate` so subsequent
|
|
248
|
+
* `loadRemote()` calls return the freshly patched module.
|
|
249
|
+
* Other frameworks fall back to full page reloads.
|
|
250
|
+
* - `'full-reload'` — HMR enabled, always use full page reloads even when
|
|
251
|
+
* a framework with native cross-federation HMR is detected.
|
|
252
|
+
*/
|
|
253
|
+
remoteHmr?: boolean | 'full-reload';
|
|
254
|
+
}
|
|
255
|
+
interface RemoteTypeUrl {
|
|
256
|
+
alias?: string;
|
|
257
|
+
api: string;
|
|
258
|
+
zip: string;
|
|
259
|
+
}
|
|
260
|
+
interface RemoteTypeUrls {
|
|
261
|
+
[remoteName: string]: RemoteTypeUrl;
|
|
262
|
+
}
|
|
263
|
+
interface PluginDtsOptions {
|
|
264
|
+
generateTypes?: boolean | DtsRemoteOptions;
|
|
265
|
+
consumeTypes?: boolean | DtsHostOptions;
|
|
266
|
+
tsConfigPath?: string;
|
|
267
|
+
extraOptions?: Record<string, unknown>;
|
|
268
|
+
implementation?: string;
|
|
269
|
+
cwd?: string;
|
|
270
|
+
displayErrorInTerminal?: boolean;
|
|
271
|
+
}
|
|
272
|
+
interface DtsRemoteOptions {
|
|
273
|
+
tsConfigPath?: string;
|
|
274
|
+
typesFolder?: string;
|
|
275
|
+
compiledTypesFolder?: string;
|
|
276
|
+
deleteTypesFolder?: boolean;
|
|
277
|
+
additionalFilesToCompile?: string[];
|
|
278
|
+
compilerInstance?: 'tsc' | 'vue-tsc' | 'tspc' | string;
|
|
279
|
+
compileInChildProcess?: boolean;
|
|
280
|
+
generateAPITypes?: boolean;
|
|
281
|
+
extractThirdParty?: boolean | {
|
|
282
|
+
exclude?: Array<string | RegExp>;
|
|
283
|
+
};
|
|
284
|
+
extractRemoteTypes?: boolean;
|
|
285
|
+
abortOnError?: boolean;
|
|
286
|
+
deleteTsConfig?: boolean;
|
|
287
|
+
afterGenerate?: (options: moduleFederationPlugin.DtsGenerateTypesHookOptions) => Promise<void> | void;
|
|
288
|
+
}
|
|
289
|
+
interface DtsHostOptions {
|
|
290
|
+
typesFolder?: string;
|
|
291
|
+
abortOnError?: boolean;
|
|
292
|
+
remoteTypesFolder?: string;
|
|
293
|
+
deleteTypesFolder?: boolean;
|
|
294
|
+
maxRetries?: number;
|
|
295
|
+
consumeAPITypes?: boolean;
|
|
296
|
+
runtimePkgs?: string[];
|
|
297
|
+
remoteTypeUrls?: (() => Promise<RemoteTypeUrls>) | RemoteTypeUrls;
|
|
298
|
+
timeout?: number;
|
|
299
|
+
family?: 0 | 4 | 6;
|
|
300
|
+
typesOnBuild?: boolean;
|
|
301
|
+
}
|
|
302
|
+
//#endregion
|
|
303
|
+
export { SsrEntryLoaderStrategy as a, SsrEntryLoaderConfig as i, PluginExperimentsOptions as n, TreeShakingConfig as o, PluginManifestOptions as r, ModuleFederationOptions as t };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { g as resolveImportPath, u as hasPackageDependency } from "./dtsConstants-
|
|
1
|
+
import { l as normalizePathForImport, n as mfError, t as createModuleFederationError } from "./logger-DOwfTlw5.js";
|
|
2
|
+
import { g as resolveImportPath, u as hasPackageDependency } from "./dtsConstants-DSTzyKSG.js";
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
5
|
-
import os from "os";
|
|
6
5
|
import { normalizeOptions } from "@module-federation/sdk";
|
|
6
|
+
import os from "os";
|
|
7
7
|
import { consumeTypesAPI, generateTypesAPI, isTSProject, normalizeConsumeTypesOptions, normalizeDtsOptions, normalizeGenerateTypesOptions } from "@module-federation/dts-plugin";
|
|
8
8
|
import { rpc } from "@module-federation/dts-plugin/core";
|
|
9
9
|
//#region src/plugins/pluginDts.ts
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { a as CodeRewriter, i as createCodePositionMap, r as mfWarn, s as EXTERNAL_URL_RE } from "./logger
|
|
1
|
+
import { a as CodeRewriter, i as createCodePositionMap, r as mfWarn, s as EXTERNAL_URL_RE } from "./logger-DOwfTlw5.js";
|
|
2
|
+
import { simpleJoinRemoteEntry } from "@module-federation/sdk";
|
|
2
3
|
//#region src/utils/fetchWithTimeout.ts
|
|
3
4
|
const DEFAULT_SSR_FETCH_TIMEOUT_MS = 1e4;
|
|
4
5
|
const DEFAULT_SSR_FETCH_MAX_BYTES = 10 * 1024 * 1024;
|
|
@@ -361,15 +362,14 @@ function getEntryFilename(entryUrl) {
|
|
|
361
362
|
}
|
|
362
363
|
function resolveEntryAssetUrl(entry, manifestUrl) {
|
|
363
364
|
const base = manifestUrl.replace(/\/[^/]+$/, "/");
|
|
364
|
-
return new URL(
|
|
365
|
+
return new URL(simpleJoinRemoteEntry(entry.path || "", entry.name), base).href;
|
|
365
366
|
}
|
|
366
367
|
function resolveSSREntryUrl(manifest, manifestUrl) {
|
|
367
368
|
const entry = parseManifestEntry(manifest.metaData?.ssrRemoteEntry);
|
|
368
369
|
if (!entry) return null;
|
|
369
370
|
const base = manifestUrl.replace(/\/[^/]+$/, "/");
|
|
370
|
-
const entryPath = entry.path + entry.name;
|
|
371
371
|
return {
|
|
372
|
-
url: new URL(
|
|
372
|
+
url: new URL(simpleJoinRemoteEntry(entry.path, entry.name), base).href,
|
|
373
373
|
type: entry.type,
|
|
374
374
|
versionKey: computeManifestVersionKey(manifest)
|
|
375
375
|
};
|
|
@@ -483,25 +483,30 @@ async function getSSREntry(remoteEntryUrl, maxAgeMs, fetchTimeoutMs, fetchMaxByt
|
|
|
483
483
|
return record.promise;
|
|
484
484
|
}
|
|
485
485
|
/**
|
|
486
|
-
* Drop
|
|
487
|
-
* being reused.
|
|
488
|
-
*
|
|
486
|
+
* Drop a remote graph's temp-file caches after a version change so old
|
|
487
|
+
* artifacts stop being reused. A generated module can be shared by multiple
|
|
488
|
+
* remote graphs, so cleanup is scoped by graph owner rather than URL origin.
|
|
489
489
|
*/
|
|
490
490
|
function dropRemoteTempFileCaches(remoteEntryUrl) {
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
for (const [key] of tempFileCache) if (JSON.parse(key).find((part) => typeof part === "string" && /^https?:\/\//.test(part))?.startsWith(origin)) {
|
|
491
|
+
const staleRecords = [];
|
|
492
|
+
for (const [key, record] of tempFileRecords) {
|
|
493
|
+
if (!record.owners.delete(remoteEntryUrl) || record.owners.size > 0) continue;
|
|
495
494
|
tempFileCache.delete(key);
|
|
496
495
|
tempFilePathCache.delete(key);
|
|
496
|
+
staleRecords.push(record);
|
|
497
497
|
}
|
|
498
498
|
scheduleTempFileCleanup(staleRecords);
|
|
499
499
|
}
|
|
500
|
-
/**
|
|
501
|
-
|
|
500
|
+
/**
|
|
501
|
+
* Invalidate all SSR loader caches owned by a remote. The runtime loading map
|
|
502
|
+
* is cleared synchronously so `revalidate()` can safely clear module caches
|
|
503
|
+
* immediately after invoking this function.
|
|
504
|
+
*/
|
|
505
|
+
function invalidateRemoteCaches(remoteEntryUrl) {
|
|
506
|
+
invalidateRuntimeRemoteEntry(remoteEntryUrl);
|
|
502
507
|
dropRemoteTempFileCaches(remoteEntryUrl);
|
|
503
508
|
scheduleVmCacheCleanup(remoteEntryUrl);
|
|
504
|
-
|
|
509
|
+
return clearRunnerCaches(remoteEntryUrl);
|
|
505
510
|
}
|
|
506
511
|
/**
|
|
507
512
|
* The VM strategy owns separate in-memory module-graph caches. Keep their
|
|
@@ -512,6 +517,12 @@ function scheduleVmCacheCleanup(remoteEntryUrl) {
|
|
|
512
517
|
if (!vmStrategyModulePromise) return;
|
|
513
518
|
vmStrategyModulePromise.then(({ clearVmStrategyCaches }) => clearVmStrategyCaches(remoteEntryUrl)).catch(() => {});
|
|
514
519
|
}
|
|
520
|
+
/**
|
|
521
|
+
* A dev-mode ModuleRunner is created per origin (one Vite dev server) and is
|
|
522
|
+
* shared by every remote that server hosts, so its module cache can only be
|
|
523
|
+
* cleared as a whole. Origin scoping is therefore the finest granularity here;
|
|
524
|
+
* clearing only costs a re-evaluation, no generated files are removed.
|
|
525
|
+
*/
|
|
515
526
|
async function clearRunnerCaches(remoteEntryUrl) {
|
|
516
527
|
let remoteOrigin;
|
|
517
528
|
if (remoteEntryUrl) {
|
|
@@ -526,7 +537,9 @@ async function clearRunnerCaches(remoteEntryUrl) {
|
|
|
526
537
|
}
|
|
527
538
|
/** Invalidate all SSR loader caches across every remote. */
|
|
528
539
|
function invalidateAllRemoteCaches() {
|
|
540
|
+
invalidateRuntimeRemoteEntry();
|
|
529
541
|
const staleRecords = [...tempFileRecords.values()];
|
|
542
|
+
for (const record of staleRecords) record.owners.clear();
|
|
530
543
|
tempFileCache.clear();
|
|
531
544
|
tempFilePathCache.clear();
|
|
532
545
|
scheduleTempFileCleanup(staleRecords);
|
|
@@ -534,6 +547,17 @@ function invalidateAllRemoteCaches() {
|
|
|
534
547
|
clearRunnerCaches();
|
|
535
548
|
}
|
|
536
549
|
/**
|
|
550
|
+
* runtime-core deduplicates remote entry loads in a process-global map. The
|
|
551
|
+
* SSR loader's module cache invalidation must evict the matching runtime entry
|
|
552
|
+
* too, otherwise the next loadRemote() returns the pre-revalidation container
|
|
553
|
+
* without invoking this loader again.
|
|
554
|
+
*/
|
|
555
|
+
function invalidateRuntimeRemoteEntry(remoteEntryUrl) {
|
|
556
|
+
const globalLoading = globalThis.__GLOBAL_LOADING_REMOTE_ENTRY__;
|
|
557
|
+
if (!globalLoading) return;
|
|
558
|
+
for (const key of Object.keys(globalLoading)) if (remoteEntryUrl === void 0 || key === remoteEntryUrl || key.endsWith(`:${remoteEntryUrl}`)) delete globalLoading[key];
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
537
561
|
* Drop the loader's caches so the next `loadEntry` re-resolves and re-fetches
|
|
538
562
|
* remote SSR entries. Pass a remote entry URL to scope the invalidation to one
|
|
539
563
|
* remote; call with no arguments to invalidate everything.
|
|
@@ -579,6 +603,7 @@ function scheduleTempFileCleanup(records) {
|
|
|
579
603
|
async function cleanupTempFileRecord(record) {
|
|
580
604
|
try {
|
|
581
605
|
await record.promise.catch(() => void 0);
|
|
606
|
+
if (record.owners.size > 0) return;
|
|
582
607
|
if (tempFileRecords.get(record.cacheKey) !== record) return;
|
|
583
608
|
const filePath = await record.filePathPromise;
|
|
584
609
|
const { rmSync } = await _fs();
|
|
@@ -733,7 +758,7 @@ function getTempFileImportUrl(filePath, versionKey) {
|
|
|
733
758
|
* a remote redeploy (new manifest → new key) produces new files and bypasses
|
|
734
759
|
* Node's ESM module cache instead of serving the stale build.
|
|
735
760
|
*/
|
|
736
|
-
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") {
|
|
761
|
+
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) {
|
|
737
762
|
const cacheKey = JSON.stringify([
|
|
738
763
|
fetchTimeoutMs,
|
|
739
764
|
fetchMaxBytes,
|
|
@@ -745,6 +770,7 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
|
|
|
745
770
|
if (visited.has(url)) return visited.get(url);
|
|
746
771
|
const cached = tempFileCache.get(cacheKey);
|
|
747
772
|
if (cached) {
|
|
773
|
+
if (owner) tempFileRecords.get(cacheKey)?.owners.add(owner);
|
|
748
774
|
pending.add(cached);
|
|
749
775
|
const reserved = tempFilePathCache.get(cacheKey);
|
|
750
776
|
const tmpFile = reserved ? await reserved : await cached;
|
|
@@ -768,7 +794,7 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
|
|
|
768
794
|
const relImports = specifiers.map(({ value }) => value).filter((value) => isRelativeSpecifier(value) && !isVitePreloadHelperSpecifier(value)).map((value) => new URL(value, base).href);
|
|
769
795
|
const subMap = /* @__PURE__ */ new Map();
|
|
770
796
|
await Promise.all([...new Set(relImports)].filter((u) => u.startsWith("http://") || u.startsWith("https://")).map(async (u) => {
|
|
771
|
-
const tmpPath = await fetchEsmToTempFile(u, tmpDir, visited, pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey, fetchMaxBytes, extension);
|
|
797
|
+
const tmpPath = await fetchEsmToTempFile(u, tmpDir, visited, pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey, fetchMaxBytes, extension, owner);
|
|
772
798
|
subMap.set(u, getTempFileImportUrl(tmpPath, versionKey));
|
|
773
799
|
}));
|
|
774
800
|
const requireShimUrl = sharedPkgMap?.size && specifiers.some(({ value }) => isNodeModuleSpecifier(value)) ? await getRequireShimUrl(tmpDir, sharedPkgMap, contextKey) : void 0;
|
|
@@ -781,7 +807,7 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
|
|
|
781
807
|
cacheKey,
|
|
782
808
|
filePathPromise: tmpFilePromise,
|
|
783
809
|
promise,
|
|
784
|
-
|
|
810
|
+
owners: owner ? /* @__PURE__ */ new Set([owner]) : /* @__PURE__ */ new Set()
|
|
785
811
|
};
|
|
786
812
|
tempFileRecords.set(cacheKey, record);
|
|
787
813
|
tempFileCache.set(cacheKey, promise);
|
|
@@ -793,9 +819,9 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
|
|
|
793
819
|
});
|
|
794
820
|
return promise;
|
|
795
821
|
}
|
|
796
|
-
async function fetchEsmGraphToTempFile(url, tmpDir, sharedPkgMap, versionKey = UNVERSIONED, fetchTimeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS, contextKey = "default", fetchMaxBytes = DEFAULT_SSR_FETCH_MAX_BYTES, extension = ".mjs") {
|
|
822
|
+
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) {
|
|
797
823
|
const pending = /* @__PURE__ */ new Set();
|
|
798
|
-
const rootFile = await fetchEsmToTempFile(url, tmpDir, /* @__PURE__ */ new Map(), pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey, fetchMaxBytes, extension);
|
|
824
|
+
const rootFile = await fetchEsmToTempFile(url, tmpDir, /* @__PURE__ */ new Map(), pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey, fetchMaxBytes, extension, owner);
|
|
799
825
|
await Promise.all(pending);
|
|
800
826
|
return rootFile;
|
|
801
827
|
}
|
|
@@ -808,7 +834,7 @@ async function importTempModule(filePath, versionKey) {
|
|
|
808
834
|
let warnedVmUnavailable = false;
|
|
809
835
|
let vmStrategyModulePromise;
|
|
810
836
|
function getVmStrategyModule() {
|
|
811
|
-
if (!vmStrategyModulePromise) vmStrategyModulePromise = import("./ssrVmStrategy-
|
|
837
|
+
if (!vmStrategyModulePromise) vmStrategyModulePromise = import("./ssrVmStrategy-Dk5xXVvR.js");
|
|
812
838
|
return vmStrategyModulePromise;
|
|
813
839
|
}
|
|
814
840
|
/**
|
|
@@ -819,7 +845,7 @@ function getVmStrategyModule() {
|
|
|
819
845
|
function warnStrategyFallback(strategy, url, fallback, error) {
|
|
820
846
|
mfWarn(`SSR entry loader: strategy "${strategy}" failed to load ${url}; falling back to ${fallback}.`, error);
|
|
821
847
|
}
|
|
822
|
-
async function tryVmStrategy(ssrEntry, options) {
|
|
848
|
+
async function tryVmStrategy(ssrEntry, options, rootEntryUrl) {
|
|
823
849
|
const { loadViaVmStrategy, isVmStrategyAvailable } = await getVmStrategyModule();
|
|
824
850
|
if (!await isVmStrategyAvailable()) {
|
|
825
851
|
if (!warnedVmUnavailable) {
|
|
@@ -835,10 +861,11 @@ async function tryVmStrategy(ssrEntry, options) {
|
|
|
835
861
|
fetchTimeoutMs: options.fetchTimeoutMs,
|
|
836
862
|
fetchMaxBytes: options.fetchMaxBytes,
|
|
837
863
|
cacheContext: options.cacheContext,
|
|
838
|
-
federationInstance: options.federationInstance
|
|
864
|
+
federationInstance: options.federationInstance,
|
|
865
|
+
rootEntryUrl
|
|
839
866
|
});
|
|
840
867
|
}
|
|
841
|
-
async function loadSSRRemoteEntry(ssrEntry, options) {
|
|
868
|
+
async function loadSSRRemoteEntry(ssrEntry, options, rootEntryUrl) {
|
|
842
869
|
const { url, type, versionKey } = ssrEntry;
|
|
843
870
|
const { resolvedShared } = options;
|
|
844
871
|
if (type === "commonjs-module" || type === "commonjs") {
|
|
@@ -865,7 +892,7 @@ async function loadSSRRemoteEntry(ssrEntry, options) {
|
|
|
865
892
|
}
|
|
866
893
|
}
|
|
867
894
|
if (options.strategy === "vm") try {
|
|
868
|
-
const fromVm = await tryVmStrategy(ssrEntry, options);
|
|
895
|
+
const fromVm = await tryVmStrategy(ssrEntry, options, rootEntryUrl);
|
|
869
896
|
if (fromVm) return fromVm;
|
|
870
897
|
} catch (error) {
|
|
871
898
|
if (isSsrEntryHttpError(error) || isSsrFetchBodyTooLargeError(error)) throw error;
|
|
@@ -875,9 +902,12 @@ async function loadSSRRemoteEntry(ssrEntry, options) {
|
|
|
875
902
|
const cacheDir = await getSSRCacheDir();
|
|
876
903
|
mkdirSync(cacheDir, { recursive: true });
|
|
877
904
|
const sharedPkgMap = new Map(Object.entries(resolvedShared));
|
|
878
|
-
const
|
|
905
|
+
const isCommonJs = type === "commonjs-module" || type === "commonjs";
|
|
906
|
+
const extension = isCommonJs ? ".cjs" : ".mjs";
|
|
879
907
|
try {
|
|
880
|
-
|
|
908
|
+
const tmpFile = await fetchEsmGraphToTempFile(url, cacheDir, sharedPkgMap, versionKey, options.fetchTimeoutMs, getSsrTransformContextKey(resolvedShared, options.shareScopeName), options.fetchMaxBytes, extension, rootEntryUrl);
|
|
909
|
+
if (isCommonJs) return (await _module()).createRequire(import.meta.url)(tmpFile);
|
|
910
|
+
return await importTempModule(tmpFile, versionKey);
|
|
881
911
|
} catch (error) {
|
|
882
912
|
if (isSsrEntryHttpError(error) || isSsrFetchBodyTooLargeError(error)) throw error;
|
|
883
913
|
warnStrategyFallback("temp-file", url, "the federation runtime's loader", error);
|
|
@@ -914,11 +944,14 @@ function ssrEntryLoaderPlugin(options = {}) {
|
|
|
914
944
|
} : resolved;
|
|
915
945
|
const ssrEntry = await getSSREntry(remoteInfo.entry, loadOptions.maxAgeMs, loadOptions.fetchTimeoutMs, loadOptions.fetchMaxBytes);
|
|
916
946
|
if (!ssrEntry) return;
|
|
917
|
-
const mod = await loadSSRRemoteEntry(ssrEntry
|
|
947
|
+
const mod = await loadSSRRemoteEntry(ssrEntry.url === remoteInfo.entry && remoteInfo.type ? {
|
|
948
|
+
...ssrEntry,
|
|
949
|
+
type: remoteInfo.type
|
|
950
|
+
} : ssrEntry, loadOptions, remoteInfo.entry);
|
|
918
951
|
if (!mod) return;
|
|
919
952
|
return mod;
|
|
920
953
|
}
|
|
921
954
|
};
|
|
922
955
|
}
|
|
923
956
|
//#endregion
|
|
924
|
-
export {
|
|
957
|
+
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,5 +1,5 @@
|
|
|
1
1
|
import { t as findSharedKey } from "./sharedKeyMatcher-Od_nYxJA.js";
|
|
2
|
-
import {
|
|
2
|
+
import { c as readResponseTextBounded, n as neutralizeBrowserPreloadHelpers, s as fetchWithTimeout, t as SsrEntryHttpError } from "./ssrEntryLoader-DjZj-5Lw.js";
|
|
3
3
|
//#region src/utils/ssrVmStrategy.ts
|
|
4
4
|
/**
|
|
5
5
|
* vm.SourceTextModule strategy for loading remote SSR entries.
|
|
@@ -144,30 +144,24 @@ function addVmCacheOwner(ownersByCacheKey, cacheKey, rootEntryUrl) {
|
|
|
144
144
|
owners.add(rootEntryUrl);
|
|
145
145
|
ownersByCacheKey.set(cacheKey, owners);
|
|
146
146
|
}
|
|
147
|
-
function clearOwnedVmCache(cache, ownersByCacheKey,
|
|
147
|
+
function clearOwnedVmCache(cache, ownersByCacheKey, remoteEntryUrl) {
|
|
148
148
|
for (const [cacheKey, owners] of ownersByCacheKey) {
|
|
149
|
-
if (!
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
for (const owner of owners) if (getUrlOrigin(owner) === remoteOrigin) owners.delete(owner);
|
|
155
|
-
if (owners.size === 0) {
|
|
156
|
-
cache.delete(cacheKey);
|
|
157
|
-
ownersByCacheKey.delete(cacheKey);
|
|
158
|
-
}
|
|
149
|
+
if (remoteEntryUrl !== void 0 && !owners.delete(remoteEntryUrl)) continue;
|
|
150
|
+
if (remoteEntryUrl !== void 0 && owners.size > 0) continue;
|
|
151
|
+
cache.delete(cacheKey);
|
|
152
|
+
ownersByCacheKey.delete(cacheKey);
|
|
159
153
|
}
|
|
160
154
|
}
|
|
161
155
|
/**
|
|
162
156
|
* Drop cached VM module graphs after a remote revalidation. A module graph can
|
|
163
|
-
* contain URLs from another origin,
|
|
164
|
-
*
|
|
157
|
+
* contain URLs from another origin, and one origin can serve several remotes,
|
|
158
|
+
* so ownership is tracked by the owning remote entry URL rather than inferred
|
|
159
|
+
* from each module URL. A module shared by several graphs stays cached while
|
|
160
|
+
* another remote still owns it.
|
|
165
161
|
*/
|
|
166
162
|
function clearVmStrategyCaches(remoteEntryUrl) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
clearOwnedVmCache(httpModuleCache, httpModuleCacheOwners, remoteOrigin);
|
|
170
|
-
clearOwnedVmCache(namespaceCache, namespaceCacheOwners, remoteOrigin);
|
|
163
|
+
clearOwnedVmCache(httpModuleCache, httpModuleCacheOwners, remoteEntryUrl);
|
|
164
|
+
clearOwnedVmCache(namespaceCache, namespaceCacheOwners, remoteEntryUrl);
|
|
171
165
|
}
|
|
172
166
|
function getBodyPreview(body) {
|
|
173
167
|
return body.slice(0, 240).replace(/\s+/g, " ").trim();
|
|
@@ -243,12 +237,13 @@ async function importDynamically(vm, specifier, referencingModule, options) {
|
|
|
243
237
|
async function loadViaVmStrategy(entryUrl, options) {
|
|
244
238
|
const vm = await getVmApi();
|
|
245
239
|
if (!vm) return null;
|
|
240
|
+
const rootEntryUrl = options.rootEntryUrl ?? entryUrl;
|
|
246
241
|
const graphOptions = {
|
|
247
242
|
...options,
|
|
248
|
-
rootEntryUrl
|
|
243
|
+
rootEntryUrl
|
|
249
244
|
};
|
|
250
245
|
const cacheKey = `${getVmCacheContextKey(options)}::${options.versionKey}::${entryUrl}`;
|
|
251
|
-
addVmCacheOwner(namespaceCacheOwners, cacheKey,
|
|
246
|
+
addVmCacheOwner(namespaceCacheOwners, cacheKey, rootEntryUrl);
|
|
252
247
|
if (!namespaceCache.has(cacheKey)) namespaceCache.set(cacheKey, (async () => {
|
|
253
248
|
const entryModule = await getHttpModule(vm, entryUrl, graphOptions);
|
|
254
249
|
const linker = (specifier, referencingModule) => linkModule(vm, specifier, referencingModule, graphOptions);
|