@module-federation/vite 1.23.4 → 1.23.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -1
- package/lib/{dtsConstants-DSTzyKSG.js → dtsConstants-CDuC8Bb7.js} +173 -33
- package/lib/index.js +992 -776
- package/lib/{logger-DOwfTlw5.js → logger-D67aJYOe.js} +110 -16
- package/lib/{pluginDts-CVyHPAEq.js → pluginDts-rZMRTCTz.js} +5 -9
- package/lib/{sharedKeyMatcher-Od_nYxJA.js → sharedKeyMatcher-C04bVN1q.js} +8 -1
- package/lib/{ssrEntryLoader-DjZj-5Lw.js → ssrEntryLoader-Bh2Tq1cZ.js} +115 -44
- package/lib/{ssrVmStrategy-Dk5xXVvR.js → ssrVmStrategy-BCaiSEbA.js} +3 -8
- package/lib/utils/ssrEntryLoader.d.ts +2 -1
- package/lib/utils/ssrEntryLoader.js +2 -2
- package/package.json +4 -4
|
@@ -39,6 +39,9 @@ function normalizePathForImport(path) {
|
|
|
39
39
|
return path.replace(/\\/g, "/");
|
|
40
40
|
}
|
|
41
41
|
const EXTERNAL_URL_RE = /^(?:[a-z]+:|\/\/)/i;
|
|
42
|
+
function isHttpUrl(value) {
|
|
43
|
+
return value.startsWith("http://") || value.startsWith("https://");
|
|
44
|
+
}
|
|
42
45
|
function isAbsoluteUrl(src) {
|
|
43
46
|
if (/^[a-z]:[\\/]/i.test(src)) return false;
|
|
44
47
|
return EXTERNAL_URL_RE.test(src);
|
|
@@ -205,28 +208,91 @@ const REGEX_PREFIX_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
205
208
|
"void",
|
|
206
209
|
"yield"
|
|
207
210
|
]);
|
|
211
|
+
const CONTROL_PAREN_KEYWORDS = /* @__PURE__ */ new Set([
|
|
212
|
+
"if",
|
|
213
|
+
"while",
|
|
214
|
+
"for",
|
|
215
|
+
"with",
|
|
216
|
+
"switch",
|
|
217
|
+
"catch"
|
|
218
|
+
]);
|
|
219
|
+
function isWhitespace(char) {
|
|
220
|
+
if (char === void 0) return false;
|
|
221
|
+
const code = char.charCodeAt(0);
|
|
222
|
+
if (code < 128) return code === 32 || code >= 9 && code <= 13;
|
|
223
|
+
return /\s/.test(char);
|
|
224
|
+
}
|
|
225
|
+
function isAsciiLetter(code) {
|
|
226
|
+
return code >= 97 && code <= 122 || code >= 65 && code <= 90;
|
|
227
|
+
}
|
|
228
|
+
function isAsciiDigit(code) {
|
|
229
|
+
return code >= 48 && code <= 57;
|
|
230
|
+
}
|
|
231
|
+
function isIdentifierStart(char) {
|
|
232
|
+
const code = char.charCodeAt(0);
|
|
233
|
+
if (code < 128) return isAsciiLetter(code) || code === 36 || code === 95;
|
|
234
|
+
return /[$_\p{ID_Start}]/u.test(char);
|
|
235
|
+
}
|
|
236
|
+
function isIdentifierPart(char) {
|
|
237
|
+
if (char === void 0) return false;
|
|
238
|
+
const code = char.charCodeAt(0);
|
|
239
|
+
if (code < 128) return isAsciiLetter(code) || isAsciiDigit(code) || code === 36 || code === 95;
|
|
240
|
+
return /[$_\u200C\u200D\p{ID_Continue}]/u.test(char);
|
|
241
|
+
}
|
|
242
|
+
function isRegexFlag(char) {
|
|
243
|
+
if (char === void 0) return false;
|
|
244
|
+
const code = char.charCodeAt(0);
|
|
245
|
+
if (code < 128) return isAsciiLetter(code) || isAsciiDigit(code) || code === 36 || code === 95;
|
|
246
|
+
return /[$_\p{ID_Continue}]/u.test(char);
|
|
247
|
+
}
|
|
248
|
+
function isNumberPart(char) {
|
|
249
|
+
if (char === void 0) return false;
|
|
250
|
+
const code = char.charCodeAt(0);
|
|
251
|
+
return isAsciiLetter(code) || isAsciiDigit(code) || code === 95 || code === 46;
|
|
252
|
+
}
|
|
208
253
|
function isJsxClosingTagSlash(code, slashIndex) {
|
|
209
254
|
if (code[slashIndex - 1] !== "<") return false;
|
|
210
255
|
let cursor = slashIndex + 1;
|
|
211
|
-
while (
|
|
256
|
+
while (isWhitespace(code[cursor])) cursor++;
|
|
212
257
|
if (code[cursor] === ">") return true;
|
|
213
258
|
const tagStart = cursor;
|
|
214
259
|
while (/[-:.$_\u200C\u200D\p{ID_Continue}]/u.test(code[cursor] || "")) cursor++;
|
|
215
260
|
if (cursor === tagStart) return false;
|
|
216
|
-
while (
|
|
261
|
+
while (isWhitespace(code[cursor])) cursor++;
|
|
217
262
|
return code[cursor] === ">";
|
|
218
263
|
}
|
|
219
264
|
/** Mark comments, string/template literals, and regular expressions as non-code. */
|
|
220
265
|
function createCodePositionMap(code, onComment) {
|
|
221
|
-
const positions =
|
|
266
|
+
const positions = new Uint8Array(code.length).fill(1);
|
|
222
267
|
const mask = (start, end) => {
|
|
223
|
-
|
|
268
|
+
positions.fill(0, start, end);
|
|
224
269
|
};
|
|
225
270
|
let canStartRegex = true;
|
|
271
|
+
let pendingControlParen;
|
|
272
|
+
const controlParens = [];
|
|
273
|
+
let templateStart;
|
|
274
|
+
const templateExpressions = [];
|
|
226
275
|
for (let index = 0; index < code.length;) {
|
|
227
276
|
const char = code[index];
|
|
228
277
|
const next = code[index + 1];
|
|
229
|
-
if (
|
|
278
|
+
if (templateStart !== void 0) {
|
|
279
|
+
if (char === "\\") index += 2;
|
|
280
|
+
else if (char === "`") {
|
|
281
|
+
mask(templateStart, ++index);
|
|
282
|
+
templateStart = void 0;
|
|
283
|
+
canStartRegex = false;
|
|
284
|
+
} else if (char === "$" && next === "{") {
|
|
285
|
+
templateExpressions.push({
|
|
286
|
+
start: templateStart,
|
|
287
|
+
braceDepth: 0
|
|
288
|
+
});
|
|
289
|
+
templateStart = void 0;
|
|
290
|
+
canStartRegex = true;
|
|
291
|
+
index += 2;
|
|
292
|
+
} else index++;
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
if (isWhitespace(char)) {
|
|
230
296
|
index++;
|
|
231
297
|
continue;
|
|
232
298
|
}
|
|
@@ -247,7 +313,13 @@ function createCodePositionMap(code, onComment) {
|
|
|
247
313
|
onComment?.(start, index);
|
|
248
314
|
continue;
|
|
249
315
|
}
|
|
250
|
-
|
|
316
|
+
const controlKeyword = pendingControlParen;
|
|
317
|
+
pendingControlParen = void 0;
|
|
318
|
+
if (char === "`") {
|
|
319
|
+
templateStart = index++;
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
if (char === "\"" || char === "'") {
|
|
251
323
|
const quote = char;
|
|
252
324
|
const start = index++;
|
|
253
325
|
while (index < code.length) {
|
|
@@ -265,8 +337,7 @@ function createCodePositionMap(code, onComment) {
|
|
|
265
337
|
canStartRegex = false;
|
|
266
338
|
continue;
|
|
267
339
|
}
|
|
268
|
-
|
|
269
|
-
if (char === "/" && canStartRegex && !closesJsxTag) {
|
|
340
|
+
if (char === "/" && canStartRegex && !isJsxClosingTagSlash(code, index)) {
|
|
270
341
|
const start = index;
|
|
271
342
|
let cursor = index + 1;
|
|
272
343
|
let escaped = false;
|
|
@@ -293,7 +364,7 @@ function createCodePositionMap(code, onComment) {
|
|
|
293
364
|
}
|
|
294
365
|
if (regexChar === "/" && !inCharacterClass) {
|
|
295
366
|
cursor++;
|
|
296
|
-
while (
|
|
367
|
+
while (isRegexFlag(code[cursor])) cursor++;
|
|
297
368
|
closed = true;
|
|
298
369
|
break;
|
|
299
370
|
}
|
|
@@ -305,15 +376,21 @@ function createCodePositionMap(code, onComment) {
|
|
|
305
376
|
continue;
|
|
306
377
|
}
|
|
307
378
|
}
|
|
308
|
-
if (
|
|
379
|
+
if (isIdentifierStart(char)) {
|
|
309
380
|
const start = index++;
|
|
310
|
-
while (
|
|
311
|
-
|
|
381
|
+
while (isIdentifierPart(code[index])) index++;
|
|
382
|
+
const word = code.slice(start, index);
|
|
383
|
+
if (CONTROL_PAREN_KEYWORDS.has(word)) {
|
|
384
|
+
let previous = start - 1;
|
|
385
|
+
while (previous >= 0 && (isWhitespace(code[previous]) || !positions[previous])) previous--;
|
|
386
|
+
if (code[previous] !== ".") pendingControlParen = word;
|
|
387
|
+
} else if (word === "await" && controlKeyword === "for") pendingControlParen = controlKeyword;
|
|
388
|
+
canStartRegex = REGEX_PREFIX_KEYWORDS.has(word);
|
|
312
389
|
continue;
|
|
313
390
|
}
|
|
314
|
-
if (
|
|
391
|
+
if (isAsciiDigit(char.charCodeAt(0))) {
|
|
315
392
|
index++;
|
|
316
|
-
while (
|
|
393
|
+
while (isNumberPart(code[index])) index++;
|
|
317
394
|
canStartRegex = false;
|
|
318
395
|
continue;
|
|
319
396
|
}
|
|
@@ -325,10 +402,27 @@ function createCodePositionMap(code, onComment) {
|
|
|
325
402
|
index++;
|
|
326
403
|
continue;
|
|
327
404
|
}
|
|
328
|
-
|
|
405
|
+
const expression = templateExpressions.at(-1);
|
|
406
|
+
if (expression && char === "{") expression.braceDepth++;
|
|
407
|
+
else if (expression && char === "}") {
|
|
408
|
+
if (expression.braceDepth === 0) {
|
|
409
|
+
templateStart = expression.start;
|
|
410
|
+
templateExpressions.pop();
|
|
411
|
+
index++;
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
expression.braceDepth--;
|
|
415
|
+
}
|
|
416
|
+
if (char === "(") {
|
|
417
|
+
controlParens.push(controlKeyword !== void 0);
|
|
418
|
+
canStartRegex = true;
|
|
419
|
+
} else if (char === ")") canStartRegex = controlParens.pop() === true;
|
|
420
|
+
else if (char === "]" || char === "}") canStartRegex = false;
|
|
329
421
|
else if (char !== ".") canStartRegex = true;
|
|
330
422
|
index++;
|
|
331
423
|
}
|
|
424
|
+
const unfinishedTemplateStart = templateExpressions[0]?.start ?? templateStart;
|
|
425
|
+
if (unfinishedTemplateStart !== void 0) mask(unfinishedTemplateStart, code.length);
|
|
332
426
|
return positions;
|
|
333
427
|
}
|
|
334
428
|
//#endregion
|
|
@@ -363,4 +457,4 @@ const moduleFederationConsole = {
|
|
|
363
457
|
const mfWarn = moduleFederationConsole.warn;
|
|
364
458
|
const mfError = moduleFederationConsole.error;
|
|
365
459
|
//#endregion
|
|
366
|
-
export { CodeRewriter as a, isAbsoluteUrl as c,
|
|
460
|
+
export { CodeRewriter as a, isAbsoluteUrl as c, rebaseImport as d, resolveHashPlaceholderFileName as f, createCodePositionMap as i, isHttpUrl as l, mfError as n, createSourceMap as o, mfWarn as r, EXTERNAL_URL_RE as s, createModuleFederationError as t, normalizePathForImport as u };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { l as
|
|
2
|
-
import {
|
|
1
|
+
import { l as isHttpUrl, n as mfError, t as createModuleFederationError, u as normalizePathForImport } from "./logger-D67aJYOe.js";
|
|
2
|
+
import { p as hasPackageDependency, r as watchFileEvents, y as resolveImportPath } from "./dtsConstants-CDuC8Bb7.js";
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
5
5
|
import { normalizeOptions } from "@module-federation/sdk";
|
|
@@ -113,7 +113,7 @@ const resolveDtsPluginOptions = (dts, options, context) => {
|
|
|
113
113
|
};
|
|
114
114
|
};
|
|
115
115
|
const getBasePath = (base) => {
|
|
116
|
-
if (
|
|
116
|
+
if (isHttpUrl(base)) return new URL(base).pathname.replace(/\/$/, "") || "/";
|
|
117
117
|
return base.replace(/\/$/, "") || "/";
|
|
118
118
|
};
|
|
119
119
|
const joinBaseAndAsset = (base, assetFileName) => {
|
|
@@ -262,15 +262,11 @@ function pluginDts(options) {
|
|
|
262
262
|
clearTimeout(updateTimer);
|
|
263
263
|
updateTimer = setTimeout(() => devWorker?.update(), UPDATE_DEBOUNCE_MS);
|
|
264
264
|
};
|
|
265
|
-
server.watcher
|
|
266
|
-
server.watcher.on("add", update);
|
|
267
|
-
server.watcher.on("unlink", update);
|
|
265
|
+
const stopWatching = watchFileEvents(server.watcher, update);
|
|
268
266
|
server.httpServer?.once("close", () => {
|
|
269
267
|
clearTimeout(updateTimer);
|
|
270
268
|
devWorker?.exit();
|
|
271
|
-
|
|
272
|
-
server.watcher.off("add", update);
|
|
273
|
-
server.watcher.off("unlink", update);
|
|
269
|
+
stopWatching();
|
|
274
270
|
});
|
|
275
271
|
};
|
|
276
272
|
startDevWorker().catch((error) => {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { u as normalizePathForImport } from "./logger-D67aJYOe.js";
|
|
2
|
+
import * as path$1 from "node:path";
|
|
1
3
|
//#region src/utils/pathNormalization.ts
|
|
2
4
|
const COMMON_SHARED_SUBPATHS = {
|
|
3
5
|
react: [
|
|
@@ -127,6 +129,11 @@ function resolvePublicPath(options, viteBase, originalBase) {
|
|
|
127
129
|
}
|
|
128
130
|
return "auto";
|
|
129
131
|
}
|
|
132
|
+
/** Relative `./`-prefixed import specifier from `fromFile` to `targetFile`. */
|
|
133
|
+
function toRelativeImport(fromFile, targetFile) {
|
|
134
|
+
const relative = normalizePathForImport(path$1.relative(path$1.dirname(fromFile), targetFile));
|
|
135
|
+
return relative.startsWith(".") ? relative : `./${relative}`;
|
|
136
|
+
}
|
|
130
137
|
//#endregion
|
|
131
138
|
//#region src/utils/sharedKeyMatcher.ts
|
|
132
139
|
function getSharedRequest(key, shareItem) {
|
|
@@ -218,4 +225,4 @@ function getSharedKeyMatcher(shared) {
|
|
|
218
225
|
return matcher;
|
|
219
226
|
}
|
|
220
227
|
//#endregion
|
|
221
|
-
export {
|
|
228
|
+
export { removeTrailingSlash as _, matchesSharedSource as a, stripViteFsPrefix as b, filterId as c, getNodeModulesSuffix as d, isAssetLikeImport as f, normalizeNodeModulePath as g, isViteOptimizableEntry as h, invalidateSharedKeyMatcher as i, getBasePath as l, isNuxtClientBase as m, getSharedRequest as n, VITE_FS_PREFIX as o, isNodeModulePath as p, getSharedRuntimeKey as r, ensureTrailingSlash as s, findSharedKey as t, getCommonSharedSubpaths as u, resolvePublicPath as v, toRelativeImport as x, stripQueryAndHash as y };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as CodeRewriter, i as createCodePositionMap, r as mfWarn, s as EXTERNAL_URL_RE } from "./logger-
|
|
1
|
+
import { a as CodeRewriter, i as createCodePositionMap, l as isHttpUrl, r as mfWarn, s as EXTERNAL_URL_RE } from "./logger-D67aJYOe.js";
|
|
2
2
|
import { simpleJoinRemoteEntry } from "@module-federation/sdk";
|
|
3
3
|
//#region src/utils/fetchWithTimeout.ts
|
|
4
4
|
const DEFAULT_SSR_FETCH_TIMEOUT_MS = 1e4;
|
|
@@ -57,6 +57,10 @@ var SsrFetchBodyTooLargeError = class extends Error {
|
|
|
57
57
|
function isSsrFetchBodyTooLargeError(error) {
|
|
58
58
|
return error instanceof SsrFetchBodyTooLargeError;
|
|
59
59
|
}
|
|
60
|
+
/** A short single-line excerpt of a response body for error messages. */
|
|
61
|
+
function getBodyPreview(body) {
|
|
62
|
+
return body.slice(0, 240).replace(/\s+/g, " ").trim();
|
|
63
|
+
}
|
|
60
64
|
/**
|
|
61
65
|
* Read a response body as text, rejecting when it exceeds `maxBytes`.
|
|
62
66
|
* Set `maxBytes` to 0 (or a non-finite value) to disable the limit.
|
|
@@ -99,15 +103,6 @@ async function readResponseTextBounded(res, maxBytes = DEFAULT_SSR_FETCH_MAX_BYT
|
|
|
99
103
|
return new TextDecoder().decode(merged);
|
|
100
104
|
}
|
|
101
105
|
//#endregion
|
|
102
|
-
//#region src/utils/url.ts
|
|
103
|
-
function getUrlOrigin(value) {
|
|
104
|
-
try {
|
|
105
|
-
return new URL(value).origin;
|
|
106
|
-
} catch {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
//#endregion
|
|
111
106
|
//#region src/utils/ssrEntryLoader.ts
|
|
112
107
|
/**
|
|
113
108
|
* MF runtime plugin that intercepts the `loadEntry` lifecycle hook on the
|
|
@@ -146,7 +141,23 @@ async function nodeImport(id) {
|
|
|
146
141
|
const isNodeServer = () => {
|
|
147
142
|
return import.meta.env?.SSR ?? typeof globalThis.process?.versions?.node === "string";
|
|
148
143
|
};
|
|
149
|
-
const
|
|
144
|
+
const SSR_ENTRY_LOADER_STATE_KEY = Symbol.for("module-federation.vite.ssrEntryLoader.state");
|
|
145
|
+
function getLoaderState() {
|
|
146
|
+
const holder = globalThis;
|
|
147
|
+
const state = holder[SSR_ENTRY_LOADER_STATE_KEY] ??= {};
|
|
148
|
+
state.runnerCache ??= /* @__PURE__ */ new Map();
|
|
149
|
+
state.unversionedGenerations ??= /* @__PURE__ */ new Map();
|
|
150
|
+
state.unversionedGlobalGeneration ??= 0;
|
|
151
|
+
state.ssrEntryCache ??= /* @__PURE__ */ new Map();
|
|
152
|
+
state.manifestFetchCache ??= /* @__PURE__ */ new Map();
|
|
153
|
+
state.tempFileCache ??= /* @__PURE__ */ new Map();
|
|
154
|
+
state.tempFilePathCache ??= /* @__PURE__ */ new Map();
|
|
155
|
+
state.tempFileRecords ??= /* @__PURE__ */ new Map();
|
|
156
|
+
state.scheduledTempFileCleanup ??= /* @__PURE__ */ new Set();
|
|
157
|
+
return state;
|
|
158
|
+
}
|
|
159
|
+
const loaderState = getLoaderState();
|
|
160
|
+
const runnerCache = loaderState.runnerCache;
|
|
150
161
|
function getSortedRecordEntries(record) {
|
|
151
162
|
return Object.entries(record).sort(([left], [right]) => left.localeCompare(right));
|
|
152
163
|
}
|
|
@@ -214,8 +225,9 @@ async function getOrCreateRunner(remoteOrigin, resolvedShared, fetchTimeoutMs, f
|
|
|
214
225
|
headers: { "Content-Type": "application/json" },
|
|
215
226
|
body: JSON.stringify(payload)
|
|
216
227
|
}, fetchTimeoutMs), fetchMaxBytes, runnerEndpoint);
|
|
217
|
-
const
|
|
218
|
-
|
|
228
|
+
const data = JSON.parse(text);
|
|
229
|
+
const result = parseRunnerInvokeResult(data);
|
|
230
|
+
if (("error" in result || isPlainObject(data) && data.shared === true) && payload.data.name === "fetchModule") {
|
|
219
231
|
const sharedExternal = await resolveSharedExternal(payload.data.data[0], resolvedShared);
|
|
220
232
|
if (sharedExternal) return { result: sharedExternal };
|
|
221
233
|
}
|
|
@@ -271,10 +283,9 @@ function parseRunnerInvokeResult(data) {
|
|
|
271
283
|
* advance a process-local generation so the next import is fresh.
|
|
272
284
|
*/
|
|
273
285
|
const UNVERSIONED = "unversioned";
|
|
274
|
-
const unversionedGenerations =
|
|
275
|
-
let unversionedGlobalGeneration = 0;
|
|
286
|
+
const unversionedGenerations = loaderState.unversionedGenerations;
|
|
276
287
|
function getUnversionedVersionKey(remoteEntryUrl) {
|
|
277
|
-
return `${UNVERSIONED}-${unversionedGlobalGeneration}-${unversionedGenerations.get(remoteEntryUrl) ?? 0}`;
|
|
288
|
+
return `${UNVERSIONED}-${loaderState.unversionedGlobalGeneration}-${unversionedGenerations.get(remoteEntryUrl) ?? 0}`;
|
|
278
289
|
}
|
|
279
290
|
function bumpUnversionedGeneration(remoteEntryUrl) {
|
|
280
291
|
unversionedGenerations.set(remoteEntryUrl, (unversionedGenerations.get(remoteEntryUrl) ?? 0) + 1);
|
|
@@ -292,8 +303,8 @@ function computeManifestVersionKey(manifest) {
|
|
|
292
303
|
const contentHash = hashString(JSON.stringify(manifest));
|
|
293
304
|
return buildVersion ? `${buildVersion}-${contentHash}` : contentHash;
|
|
294
305
|
}
|
|
295
|
-
const ssrEntryCache =
|
|
296
|
-
const manifestFetchCache =
|
|
306
|
+
const ssrEntryCache = loaderState.ssrEntryCache;
|
|
307
|
+
const manifestFetchCache = loaderState.manifestFetchCache;
|
|
297
308
|
function makeUrlCacheKey(url, fetchTimeoutMs, fetchMaxBytes) {
|
|
298
309
|
return `${fetchTimeoutMs}::${fetchMaxBytes}::${url}`;
|
|
299
310
|
}
|
|
@@ -311,9 +322,6 @@ var SsrEntryHttpError = class extends Error {
|
|
|
311
322
|
this.name = "SsrEntryHttpError";
|
|
312
323
|
}
|
|
313
324
|
};
|
|
314
|
-
function getBodyPreview(body) {
|
|
315
|
-
return body.slice(0, 240).replace(/\s+/g, " ").trim();
|
|
316
|
-
}
|
|
317
325
|
function isSsrEntryHttpError(error) {
|
|
318
326
|
return error instanceof SsrEntryHttpError;
|
|
319
327
|
}
|
|
@@ -514,8 +522,8 @@ function invalidateRemoteCaches(remoteEntryUrl) {
|
|
|
514
522
|
* static import cycle between the two SSR strategies.
|
|
515
523
|
*/
|
|
516
524
|
function scheduleVmCacheCleanup(remoteEntryUrl) {
|
|
517
|
-
if (!vmStrategyModulePromise) return;
|
|
518
|
-
vmStrategyModulePromise.then(({ clearVmStrategyCaches }) => clearVmStrategyCaches(remoteEntryUrl)).catch(() => {});
|
|
525
|
+
if (!loaderState.vmStrategyModulePromise) return;
|
|
526
|
+
loaderState.vmStrategyModulePromise.then(({ clearVmStrategyCaches }) => clearVmStrategyCaches(remoteEntryUrl)).catch(() => {});
|
|
519
527
|
}
|
|
520
528
|
/**
|
|
521
529
|
* A dev-mode ModuleRunner is created per origin (one Vite dev server) and is
|
|
@@ -525,9 +533,10 @@ function scheduleVmCacheCleanup(remoteEntryUrl) {
|
|
|
525
533
|
*/
|
|
526
534
|
async function clearRunnerCaches(remoteEntryUrl) {
|
|
527
535
|
let remoteOrigin;
|
|
528
|
-
if (remoteEntryUrl) {
|
|
529
|
-
remoteOrigin =
|
|
530
|
-
|
|
536
|
+
if (remoteEntryUrl) try {
|
|
537
|
+
remoteOrigin = new URL(remoteEntryUrl).origin;
|
|
538
|
+
} catch {
|
|
539
|
+
return;
|
|
531
540
|
}
|
|
532
541
|
await Promise.all([...runnerCache.values()].filter((cached) => !remoteOrigin || cached.remoteOrigin === remoteOrigin).map(async (cached) => {
|
|
533
542
|
try {
|
|
@@ -575,7 +584,7 @@ function revalidate(remoteEntryUrl) {
|
|
|
575
584
|
for (const key of manifestFetchCache.keys()) if (key.endsWith(`::${manifestUrl}`)) manifestFetchCache.delete(key);
|
|
576
585
|
invalidateRemoteCaches(remoteEntryUrl);
|
|
577
586
|
} else {
|
|
578
|
-
unversionedGlobalGeneration += 1;
|
|
587
|
+
loaderState.unversionedGlobalGeneration += 1;
|
|
579
588
|
ssrEntryCache.clear();
|
|
580
589
|
manifestFetchCache.clear();
|
|
581
590
|
invalidateAllRemoteCaches();
|
|
@@ -585,11 +594,11 @@ function revalidate(remoteEntryUrl) {
|
|
|
585
594
|
instance?.moduleCache?.clear?.();
|
|
586
595
|
} catch {}
|
|
587
596
|
}
|
|
588
|
-
const tempFileCache =
|
|
589
|
-
const tempFilePathCache =
|
|
597
|
+
const tempFileCache = loaderState.tempFileCache;
|
|
598
|
+
const tempFilePathCache = loaderState.tempFilePathCache;
|
|
590
599
|
const TEMP_FILE_CLEANUP_DELAY_MS = 3e4;
|
|
591
|
-
const tempFileRecords =
|
|
592
|
-
const scheduledTempFileCleanup =
|
|
600
|
+
const tempFileRecords = loaderState.tempFileRecords;
|
|
601
|
+
const scheduledTempFileCleanup = loaderState.scheduledTempFileCleanup;
|
|
593
602
|
function scheduleTempFileCleanup(records) {
|
|
594
603
|
for (const record of records) {
|
|
595
604
|
if (scheduledTempFileCleanup.has(record.cacheKey)) continue;
|
|
@@ -736,7 +745,7 @@ function transformSsrCode(code, base, specifiers, sharedPkgMap, requireShimUrl,
|
|
|
736
745
|
}
|
|
737
746
|
const resolvedShared = sharedPkgMap?.get(value);
|
|
738
747
|
const relativeUrl = isRelativeSpecifier(value) ? new URL(value, base).href : void 0;
|
|
739
|
-
const absoluteHttpUrl =
|
|
748
|
+
const absoluteHttpUrl = isHttpUrl(value) ? value : void 0;
|
|
740
749
|
const httpUrl = relativeUrl ?? absoluteHttpUrl;
|
|
741
750
|
const replacement = (httpUrl ? tempFileUrlMap?.get(httpUrl) : void 0) ?? relativeUrl ?? (resolvedShared && `file://${resolvedShared}`);
|
|
742
751
|
if (replacement) rewriter.overwrite(start, end, `"${replacement}"`);
|
|
@@ -758,7 +767,8 @@ function getTempFileImportUrl(filePath, versionKey) {
|
|
|
758
767
|
* a remote redeploy (new manifest → new key) produces new files and bypasses
|
|
759
768
|
* Node's ESM module cache instead of serving the stale build.
|
|
760
769
|
*/
|
|
761
|
-
async function fetchEsmToTempFile(url,
|
|
770
|
+
async function fetchEsmToTempFile(url, graph) {
|
|
771
|
+
const { tmpDir, visited, pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey, fetchMaxBytes, extension, owner } = graph;
|
|
762
772
|
const cacheKey = JSON.stringify([
|
|
763
773
|
fetchTimeoutMs,
|
|
764
774
|
fetchMaxBytes,
|
|
@@ -780,7 +790,8 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
|
|
|
780
790
|
const tmpFilePromise = (async () => {
|
|
781
791
|
const { createHash } = await _crypto();
|
|
782
792
|
const { join } = await _path();
|
|
783
|
-
|
|
793
|
+
const hash = createHash("sha1").update(cacheKey).digest("hex").slice(0, 12);
|
|
794
|
+
return join(tmpDir, `${hash}${extension}`);
|
|
784
795
|
})();
|
|
785
796
|
tempFilePathCache.set(cacheKey, tmpFilePromise);
|
|
786
797
|
const promise = (async () => {
|
|
@@ -793,8 +804,8 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
|
|
|
793
804
|
const specifiers = findSsrModuleSpecifiers(code);
|
|
794
805
|
const relImports = specifiers.map(({ value }) => value).filter((value) => isRelativeSpecifier(value) && !isVitePreloadHelperSpecifier(value)).map((value) => new URL(value, base).href);
|
|
795
806
|
const subMap = /* @__PURE__ */ new Map();
|
|
796
|
-
await Promise.all([...new Set(relImports)].filter(
|
|
797
|
-
const tmpPath = await fetchEsmToTempFile(u,
|
|
807
|
+
await Promise.all([...new Set(relImports)].filter(isHttpUrl).map(async (u) => {
|
|
808
|
+
const tmpPath = await fetchEsmToTempFile(u, graph);
|
|
798
809
|
subMap.set(u, getTempFileImportUrl(tmpPath, versionKey));
|
|
799
810
|
}));
|
|
800
811
|
const requireShimUrl = sharedPkgMap?.size && specifiers.some(({ value }) => isNodeModuleSpecifier(value)) ? await getRequireShimUrl(tmpDir, sharedPkgMap, contextKey) : void 0;
|
|
@@ -819,9 +830,18 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
|
|
|
819
830
|
});
|
|
820
831
|
return promise;
|
|
821
832
|
}
|
|
822
|
-
async function fetchEsmGraphToTempFile(url,
|
|
833
|
+
async function fetchEsmGraphToTempFile(url, { versionKey = UNVERSIONED, fetchTimeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS, contextKey = "default", fetchMaxBytes = DEFAULT_SSR_FETCH_MAX_BYTES, extension = ".mjs", ...rest }) {
|
|
823
834
|
const pending = /* @__PURE__ */ new Set();
|
|
824
|
-
const rootFile = await fetchEsmToTempFile(url,
|
|
835
|
+
const rootFile = await fetchEsmToTempFile(url, {
|
|
836
|
+
...rest,
|
|
837
|
+
versionKey,
|
|
838
|
+
fetchTimeoutMs,
|
|
839
|
+
contextKey,
|
|
840
|
+
fetchMaxBytes,
|
|
841
|
+
extension,
|
|
842
|
+
visited: /* @__PURE__ */ new Map(),
|
|
843
|
+
pending
|
|
844
|
+
});
|
|
825
845
|
await Promise.all(pending);
|
|
826
846
|
return rootFile;
|
|
827
847
|
}
|
|
@@ -832,10 +852,9 @@ async function importTempModule(filePath, versionKey) {
|
|
|
832
852
|
);
|
|
833
853
|
}
|
|
834
854
|
let warnedVmUnavailable = false;
|
|
835
|
-
let vmStrategyModulePromise;
|
|
836
855
|
function getVmStrategyModule() {
|
|
837
|
-
if (!vmStrategyModulePromise) vmStrategyModulePromise = import("./ssrVmStrategy-
|
|
838
|
-
return vmStrategyModulePromise;
|
|
856
|
+
if (!loaderState.vmStrategyModulePromise) loaderState.vmStrategyModulePromise = import("./ssrVmStrategy-BCaiSEbA.js");
|
|
857
|
+
return loaderState.vmStrategyModulePromise;
|
|
839
858
|
}
|
|
840
859
|
/**
|
|
841
860
|
* Non-HTTP failures keep falling back (to temp-file after vm, to the federation
|
|
@@ -875,7 +894,7 @@ async function loadSSRRemoteEntry(ssrEntry, options, rootEntryUrl) {
|
|
|
875
894
|
return req(url);
|
|
876
895
|
} catch {}
|
|
877
896
|
}
|
|
878
|
-
if (
|
|
897
|
+
if (isHttpUrl(url)) {
|
|
879
898
|
const urlObj = new URL(url);
|
|
880
899
|
if (urlObj.pathname.includes("/__mf_ssr__/")) {
|
|
881
900
|
const remoteOrigin = urlObj.origin;
|
|
@@ -905,7 +924,16 @@ async function loadSSRRemoteEntry(ssrEntry, options, rootEntryUrl) {
|
|
|
905
924
|
const isCommonJs = type === "commonjs-module" || type === "commonjs";
|
|
906
925
|
const extension = isCommonJs ? ".cjs" : ".mjs";
|
|
907
926
|
try {
|
|
908
|
-
const tmpFile = await fetchEsmGraphToTempFile(url,
|
|
927
|
+
const tmpFile = await fetchEsmGraphToTempFile(url, {
|
|
928
|
+
tmpDir: cacheDir,
|
|
929
|
+
sharedPkgMap,
|
|
930
|
+
versionKey,
|
|
931
|
+
fetchTimeoutMs: options.fetchTimeoutMs,
|
|
932
|
+
contextKey: getSsrTransformContextKey(resolvedShared, options.shareScopeName),
|
|
933
|
+
fetchMaxBytes: options.fetchMaxBytes,
|
|
934
|
+
extension,
|
|
935
|
+
owner: rootEntryUrl
|
|
936
|
+
});
|
|
909
937
|
if (isCommonJs) return (await _module()).createRequire(import.meta.url)(tmpFile);
|
|
910
938
|
return await importTempModule(tmpFile, versionKey);
|
|
911
939
|
} catch (error) {
|
|
@@ -923,6 +951,42 @@ async function loadSSRRemoteEntry(ssrEntry, options, rootEntryUrl) {
|
|
|
923
951
|
return null;
|
|
924
952
|
}
|
|
925
953
|
}
|
|
954
|
+
/**
|
|
955
|
+
* Build-time `resolvedShared` paths point into the build machine's
|
|
956
|
+
* node_modules. A traced or relocated server output imports shared packages
|
|
957
|
+
* from its own copy, so pinning remotes to the build paths loads a second
|
|
958
|
+
* instance (two Reacts: invalid hook call) or, once the build directory is
|
|
959
|
+
* gone, nothing at all (ERR_MODULE_NOT_FOUND).
|
|
960
|
+
*
|
|
961
|
+
* Each specifier takes the first hit of a fixed order, independent of import
|
|
962
|
+
* order or timing:
|
|
963
|
+
* 1. resolved from the real path of the server entry (`process.argv[1]`),
|
|
964
|
+
* which is where Node resolves the host's own bare imports from, unless
|
|
965
|
+
* it is a CLI inside node_modules (e.g. `vite preview`);
|
|
966
|
+
* 2. resolved from `process.cwd()`, for launchers whose `argv[1]` is not the
|
|
967
|
+
* server entry or is missing;
|
|
968
|
+
* 3. the build-time path.
|
|
969
|
+
*/
|
|
970
|
+
async function rebaseResolvedShared(resolvedShared) {
|
|
971
|
+
const { createRequire } = await _module();
|
|
972
|
+
const { realpathSync } = await _fs();
|
|
973
|
+
const { join } = await _path();
|
|
974
|
+
const requires = [];
|
|
975
|
+
try {
|
|
976
|
+
const entry = process.argv[1] && realpathSync(process.argv[1]);
|
|
977
|
+
if (entry && !/[\\/]node_modules[\\/]/.test(entry)) requires.push(createRequire(entry));
|
|
978
|
+
} catch {}
|
|
979
|
+
requires.push(createRequire(join(process.cwd(), "noop.js")));
|
|
980
|
+
const rebased = {};
|
|
981
|
+
for (const [specifier, buildPath] of Object.entries(resolvedShared)) {
|
|
982
|
+
rebased[specifier] = buildPath;
|
|
983
|
+
for (const require of requires) try {
|
|
984
|
+
rebased[specifier] = require.resolve(specifier);
|
|
985
|
+
break;
|
|
986
|
+
} catch {}
|
|
987
|
+
}
|
|
988
|
+
return rebased;
|
|
989
|
+
}
|
|
926
990
|
function ssrEntryLoaderPlugin(options = {}) {
|
|
927
991
|
const resolved = {
|
|
928
992
|
resolvedShared: options.resolvedShared ?? {},
|
|
@@ -933,10 +997,17 @@ function ssrEntryLoaderPlugin(options = {}) {
|
|
|
933
997
|
fetchMaxBytes: options.fetchMaxBytes ?? 10485760,
|
|
934
998
|
cacheContext: {}
|
|
935
999
|
};
|
|
1000
|
+
let rebased;
|
|
936
1001
|
return {
|
|
937
1002
|
name: "mf-vite:ssr-entry-loader",
|
|
938
1003
|
async loadEntry({ remoteInfo, origin }) {
|
|
939
1004
|
if (!isNodeServer()) return;
|
|
1005
|
+
if (options.rebaseSharedAtRuntime) {
|
|
1006
|
+
rebased ??= rebaseResolvedShared(resolved.resolvedShared).then((map) => {
|
|
1007
|
+
resolved.resolvedShared = map;
|
|
1008
|
+
}, () => {});
|
|
1009
|
+
await rebased;
|
|
1010
|
+
}
|
|
940
1011
|
const loadOptions = origin ? {
|
|
941
1012
|
...resolved,
|
|
942
1013
|
cacheContext: origin,
|
|
@@ -954,4 +1025,4 @@ function ssrEntryLoaderPlugin(options = {}) {
|
|
|
954
1025
|
};
|
|
955
1026
|
}
|
|
956
1027
|
//#endregion
|
|
957
|
-
export {
|
|
1028
|
+
export { ssrEntryLoaderPlugin as a, fetchWithTimeout as c, revalidate as i, getBodyPreview as l, SsrEntryHttpError as n, DEFAULT_SSR_FETCH_MAX_BYTES as o, neutralizeBrowserPreloadHelpers as r, DEFAULT_SSR_FETCH_TIMEOUT_MS as s, SSR_ENTRY_LOADER_STATE_KEY as t, readResponseTextBounded as u };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { l as isHttpUrl } from "./logger-D67aJYOe.js";
|
|
2
|
+
import { t as findSharedKey } from "./sharedKeyMatcher-C04bVN1q.js";
|
|
3
|
+
import { c as fetchWithTimeout, l as getBodyPreview, n as SsrEntryHttpError, r as neutralizeBrowserPreloadHelpers, u as readResponseTextBounded } from "./ssrEntryLoader-Bh2Tq1cZ.js";
|
|
3
4
|
//#region src/utils/ssrVmStrategy.ts
|
|
4
5
|
/**
|
|
5
6
|
* vm.SourceTextModule strategy for loading remote SSR entries.
|
|
@@ -163,18 +164,12 @@ function clearVmStrategyCaches(remoteEntryUrl) {
|
|
|
163
164
|
clearOwnedVmCache(httpModuleCache, httpModuleCacheOwners, remoteEntryUrl);
|
|
164
165
|
clearOwnedVmCache(namespaceCache, namespaceCacheOwners, remoteEntryUrl);
|
|
165
166
|
}
|
|
166
|
-
function getBodyPreview(body) {
|
|
167
|
-
return body.slice(0, 240).replace(/\s+/g, " ").trim();
|
|
168
|
-
}
|
|
169
167
|
async function fetchModuleSource(url, fetchTimeoutMs, fetchMaxBytes) {
|
|
170
168
|
const res = await fetchWithTimeout(url, {}, fetchTimeoutMs);
|
|
171
169
|
const text = await readResponseTextBounded(res, fetchMaxBytes ?? 10485760, url);
|
|
172
170
|
if (!res.ok) throw new SsrEntryHttpError(url, res.status, res.statusText, getBodyPreview(text));
|
|
173
171
|
return neutralizeBrowserPreloadHelpers(text);
|
|
174
172
|
}
|
|
175
|
-
function isHttpUrl(value) {
|
|
176
|
-
return value.startsWith("http://") || value.startsWith("https://");
|
|
177
|
-
}
|
|
178
173
|
/** Resolve a specifier against the referencing module's URL; null for bare specifiers. */
|
|
179
174
|
function resolveSpecifierUrl(specifier, referencerUrl) {
|
|
180
175
|
if (isHttpUrl(specifier)) return specifier;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { i as SsrEntryLoaderConfig } from "../normalizeModuleFederationOptions-DNUlv-AL.js";
|
|
2
2
|
//#region src/utils/ssrEntryLoader.d.ts
|
|
3
|
+
declare const SSR_ENTRY_LOADER_STATE_KEY: unique symbol;
|
|
3
4
|
interface RemoteInfo {
|
|
4
5
|
name: string;
|
|
5
6
|
entry: string;
|
|
@@ -64,4 +65,4 @@ declare function ssrEntryLoaderPlugin(options?: SsrEntryLoaderOptions): {
|
|
|
64
65
|
} | undefined>;
|
|
65
66
|
};
|
|
66
67
|
//#endregion
|
|
67
|
-
export { SsrEntryHttpError, ssrEntryLoaderPlugin as default, neutralizeBrowserPreloadHelpers, revalidate };
|
|
68
|
+
export { SSR_ENTRY_LOADER_STATE_KEY, SsrEntryHttpError, ssrEntryLoaderPlugin as default, neutralizeBrowserPreloadHelpers, revalidate };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { SsrEntryHttpError, ssrEntryLoaderPlugin as default, neutralizeBrowserPreloadHelpers, revalidate };
|
|
1
|
+
import { a as ssrEntryLoaderPlugin, i as revalidate, n as SsrEntryHttpError, r as neutralizeBrowserPreloadHelpers, t as SSR_ENTRY_LOADER_STATE_KEY } from "../ssrEntryLoader-Bh2Tq1cZ.js";
|
|
2
|
+
export { SSR_ENTRY_LOADER_STATE_KEY, SsrEntryHttpError, ssrEntryLoaderPlugin as default, neutralizeBrowserPreloadHelpers, revalidate };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@module-federation/vite",
|
|
3
|
-
"version": "1.23.
|
|
3
|
+
"version": "1.23.6",
|
|
4
4
|
"description": "Vite plugin for Module Federation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"homepage": "https://github.com/module-federation/vite#readme",
|
|
75
75
|
"packageManager": "pnpm@10.28.2",
|
|
76
76
|
"peerDependencies": {
|
|
77
|
-
"vite": "^5.
|
|
77
|
+
"vite": "^5.1.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
80
|
"@module-federation/dts-plugin": "2.9.2",
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"rollup": "4.62.3",
|
|
91
91
|
"tsdown": "0.22.14",
|
|
92
92
|
"typescript": "7.0.2",
|
|
93
|
-
"vite": "8.2.
|
|
94
|
-
"vitest": "4.1.
|
|
93
|
+
"vite": "8.2.4",
|
|
94
|
+
"vitest": "4.1.12"
|
|
95
95
|
}
|
|
96
96
|
}
|