@module-federation/vite 1.15.5 → 1.16.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 +27 -0
- package/lib/index.cjs +1130 -887
- package/lib/index.d.cts +22 -6
- package/lib/index.d.mts +22 -6
- package/lib/index.mjs +1074 -813
- package/lib/packageUtils-CbbnJvKu.cjs +358 -0
- package/lib/packageUtils-DOekOsFz.mjs +250 -0
- package/lib/pluginDts-B5pcUmam.mjs +309 -0
- package/lib/pluginDts-BEOKyKQ-.cjs +311 -0
- package/lib/utils/ssrEntryLoader.cjs +301 -0
- package/lib/utils/ssrEntryLoader.d.cts +65 -0
- package/lib/utils/ssrEntryLoader.d.mts +66 -0
- package/lib/utils/ssrEntryLoader.mjs +301 -0
- package/package.json +12 -4
package/lib/index.cjs
CHANGED
|
@@ -1,34 +1,12 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
|
|
3
|
-
var __create = Object.create;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
-
var __copyProps = (to, from, except, desc) => {
|
|
10
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
-
key = keys[i];
|
|
12
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
-
get: ((k) => from[k]).bind(null, key),
|
|
14
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
-
value: mod,
|
|
21
|
-
enumerable: true
|
|
22
|
-
}) : target, mod));
|
|
23
|
-
//#endregion
|
|
2
|
+
const require_packageUtils = require("./packageUtils-CbbnJvKu.cjs");
|
|
24
3
|
let fs = require("fs");
|
|
25
|
-
fs = __toESM(fs);
|
|
4
|
+
fs = require_packageUtils.__toESM(fs);
|
|
26
5
|
let module$1 = require("module");
|
|
27
6
|
let pathe = require("pathe");
|
|
28
|
-
pathe = __toESM(pathe);
|
|
29
|
-
let
|
|
30
|
-
let
|
|
31
|
-
let _module_federation_dts_plugin_core = require("@module-federation/dts-plugin/core");
|
|
7
|
+
pathe = require_packageUtils.__toESM(pathe);
|
|
8
|
+
let vite = require("vite");
|
|
9
|
+
let node_crypto = require("node:crypto");
|
|
32
10
|
let url = require("url");
|
|
33
11
|
let es_module_lexer = require("es-module-lexer");
|
|
34
12
|
//#region src/utils/codeRewriter.ts
|
|
@@ -192,237 +170,6 @@ function injectEntryScript(html, initSrc) {
|
|
|
192
170
|
return html.replace("<head>", `<head><script type="module" src=${JSON.stringify(src)}><\/script>`);
|
|
193
171
|
}
|
|
194
172
|
//#endregion
|
|
195
|
-
//#region src/utils/logger.ts
|
|
196
|
-
const MODULE_FEDERATION_LOG_PREFIX = "[Module Federation]";
|
|
197
|
-
function formatModuleFederationMessage(message) {
|
|
198
|
-
return `${MODULE_FEDERATION_LOG_PREFIX} ${message}`;
|
|
199
|
-
}
|
|
200
|
-
function createModuleFederationError(message) {
|
|
201
|
-
return new Error(formatModuleFederationMessage(message));
|
|
202
|
-
}
|
|
203
|
-
function toConsoleArgs(message, rest = []) {
|
|
204
|
-
if (typeof message === "string") return [formatModuleFederationMessage(message), ...rest];
|
|
205
|
-
if (message === void 0) return [MODULE_FEDERATION_LOG_PREFIX, ...rest];
|
|
206
|
-
return [
|
|
207
|
-
MODULE_FEDERATION_LOG_PREFIX,
|
|
208
|
-
message,
|
|
209
|
-
...rest
|
|
210
|
-
];
|
|
211
|
-
}
|
|
212
|
-
const moduleFederationConsole = {
|
|
213
|
-
log(message, ...rest) {
|
|
214
|
-
console.log(...toConsoleArgs(message, rest));
|
|
215
|
-
},
|
|
216
|
-
warn(message, ...rest) {
|
|
217
|
-
console.warn(...toConsoleArgs(message, rest));
|
|
218
|
-
},
|
|
219
|
-
error(message, ...rest) {
|
|
220
|
-
console.error(...toConsoleArgs(message, rest));
|
|
221
|
-
}
|
|
222
|
-
};
|
|
223
|
-
moduleFederationConsole.log;
|
|
224
|
-
const mfWarn = moduleFederationConsole.warn;
|
|
225
|
-
const mfError = moduleFederationConsole.error;
|
|
226
|
-
//#endregion
|
|
227
|
-
//#region src/utils/packageUtils.ts
|
|
228
|
-
const dependencyPresenceCache = /* @__PURE__ */ new Map();
|
|
229
|
-
let packageDetectionCwd;
|
|
230
|
-
function getDependencyCacheKey(cwd, dependencyName) {
|
|
231
|
-
return `${cwd}:${dependencyName}`;
|
|
232
|
-
}
|
|
233
|
-
function setPackageDetectionCwd(cwd) {
|
|
234
|
-
packageDetectionCwd = cwd;
|
|
235
|
-
}
|
|
236
|
-
function getPackageDetectionCwd() {
|
|
237
|
-
return packageDetectionCwd || process.cwd();
|
|
238
|
-
}
|
|
239
|
-
const DEFAULT_EXPORT_CONDITIONS = [
|
|
240
|
-
"browser",
|
|
241
|
-
"import",
|
|
242
|
-
"module",
|
|
243
|
-
"default",
|
|
244
|
-
"require"
|
|
245
|
-
];
|
|
246
|
-
function resolveExportsEntry(exportsField, conditions = DEFAULT_EXPORT_CONDITIONS) {
|
|
247
|
-
if (typeof exportsField === "string") return exportsField;
|
|
248
|
-
if (!exportsField || typeof exportsField !== "object") return void 0;
|
|
249
|
-
const record = exportsField;
|
|
250
|
-
const rootExport = record["."];
|
|
251
|
-
if (rootExport) return resolveExportsEntry(rootExport);
|
|
252
|
-
for (const condition of conditions) {
|
|
253
|
-
const target = resolveExportsEntry(record[condition], conditions);
|
|
254
|
-
if (target) return target;
|
|
255
|
-
}
|
|
256
|
-
for (const target of Object.values(record)) {
|
|
257
|
-
const resolved = resolveExportsEntry(target, conditions);
|
|
258
|
-
if (resolved) return resolved;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
function getPackageExportsTarget(pkg, packageName, exportsField) {
|
|
262
|
-
if (typeof exportsField === "string") return pkg === packageName ? exportsField : void 0;
|
|
263
|
-
if (!exportsField || typeof exportsField !== "object") return void 0;
|
|
264
|
-
const record = exportsField;
|
|
265
|
-
const subpath = pkg === packageName ? "." : `.${pkg.slice(packageName.length)}`;
|
|
266
|
-
if (subpath !== ".") return record[subpath];
|
|
267
|
-
return record["."] ?? (!Object.keys(record).some((key) => key.startsWith(".")) ? record : void 0);
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Escaping rules:
|
|
271
|
-
* Convert using the format __${mapping}__, where _ and $ are not allowed in npm package names but can be used in variable names.
|
|
272
|
-
* @ => 1
|
|
273
|
-
* / => 2
|
|
274
|
-
* - => 3
|
|
275
|
-
* . => 4
|
|
276
|
-
*/
|
|
277
|
-
/**
|
|
278
|
-
* Encodes a package name into a valid file name.
|
|
279
|
-
* @param {string} name - The package name, e.g., "@scope/xx-xx.xx".
|
|
280
|
-
* @returns {string} - The encoded file name.
|
|
281
|
-
*/
|
|
282
|
-
function packageNameEncode(name) {
|
|
283
|
-
if (typeof name !== "string") throw createModuleFederationError("A string package name is required");
|
|
284
|
-
return name.replace(/@/g, "_mf_0_").replace(/\//g, "_mf_1_").replace(/-/g, "_mf_2_").replace(/\./g, "_mf_3_");
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Decodes an encoded file name back to the original package name.
|
|
288
|
-
* @param {string} encoded - The encoded file name, e.g., "_mf_0_scope_mf_1_xx_mf_2_xx_mf_3_xx".
|
|
289
|
-
* @returns {string} - The decoded package name.
|
|
290
|
-
*/
|
|
291
|
-
function packageNameDecode(encoded) {
|
|
292
|
-
if (typeof encoded !== "string") throw createModuleFederationError("A string encoded file name is required");
|
|
293
|
-
return encoded.replace(/_mf_0_/g, "@").replace(/_mf_1_/g, "/").replace(/_mf_2_/g, "-").replace(/_mf_3_/g, ".");
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Removes any subpath from an npm package specifier and returns the package name only.
|
|
297
|
-
* @param {string} packageString - The package specifier, e.g., "@scope/pkg/runtime" or "react/jsx-runtime".
|
|
298
|
-
* @returns {string} - The base npm package name.
|
|
299
|
-
*/
|
|
300
|
-
function getPackageName(packageString) {
|
|
301
|
-
const match = packageString.match(/^(?:@[^/]+\/)?[^/]+/);
|
|
302
|
-
return match ? match[0] : packageString;
|
|
303
|
-
}
|
|
304
|
-
function getPackageNameFromNodeModulePath(source) {
|
|
305
|
-
const normalized = source.replace(/\\/g, "/");
|
|
306
|
-
const nodeModulesIndex = normalized.lastIndexOf("/node_modules/");
|
|
307
|
-
if (nodeModulesIndex < 0) return;
|
|
308
|
-
const parts = normalized.slice(nodeModulesIndex + 14).split("/");
|
|
309
|
-
if (!parts[0]) return;
|
|
310
|
-
if (parts[0].startsWith("@")) return parts[1] ? `${parts[0]}/${parts[1]}` : void 0;
|
|
311
|
-
return parts[0];
|
|
312
|
-
}
|
|
313
|
-
function getInstalledPackageJson(pkg, opts) {
|
|
314
|
-
const cwd = opts?.cwd || getPackageDetectionCwd();
|
|
315
|
-
const packageName = opts?.packageName || getPackageName(pkg);
|
|
316
|
-
const tryReadPackageJson = (packageJsonPath) => {
|
|
317
|
-
if (!(0, fs.existsSync)(packageJsonPath)) return void 0;
|
|
318
|
-
try {
|
|
319
|
-
return {
|
|
320
|
-
path: packageJsonPath,
|
|
321
|
-
dir: pathe.default.dirname(packageJsonPath),
|
|
322
|
-
packageJson: JSON.parse((0, fs.readFileSync)(packageJsonPath, "utf-8"))
|
|
323
|
-
};
|
|
324
|
-
} catch {
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
|
-
const findPackageInPnpmStore = (startDir) => {
|
|
329
|
-
let currentDir = startDir;
|
|
330
|
-
const rootDir = pathe.default.parse(currentDir).root;
|
|
331
|
-
while (true) {
|
|
332
|
-
const pnpmStoreDir = pathe.default.join(currentDir, "node_modules", ".pnpm");
|
|
333
|
-
if ((0, fs.existsSync)(pnpmStoreDir)) try {
|
|
334
|
-
for (const entry of (0, fs.readdirSync)(pnpmStoreDir, { withFileTypes: true })) {
|
|
335
|
-
if (!entry.isDirectory()) continue;
|
|
336
|
-
const candidate = tryReadPackageJson(pathe.default.join(pnpmStoreDir, entry.name, "node_modules", packageName, "package.json"));
|
|
337
|
-
if (candidate?.packageJson.name === packageName) return candidate;
|
|
338
|
-
}
|
|
339
|
-
} catch {}
|
|
340
|
-
if (currentDir === rootDir) break;
|
|
341
|
-
currentDir = pathe.default.dirname(currentDir);
|
|
342
|
-
}
|
|
343
|
-
};
|
|
344
|
-
try {
|
|
345
|
-
const projectRequire = (0, module$1.createRequire)(new URL(`file://${pathe.default.join(cwd, "package.json")}`));
|
|
346
|
-
let resolvedPath;
|
|
347
|
-
if (opts?.fromResolvedEntry) resolvedPath = opts.fromResolvedEntry;
|
|
348
|
-
else try {
|
|
349
|
-
resolvedPath = projectRequire.resolve(pkg);
|
|
350
|
-
} catch {
|
|
351
|
-
resolvedPath = projectRequire.resolve(packageName);
|
|
352
|
-
}
|
|
353
|
-
let currentDir = pathe.default.dirname(resolvedPath);
|
|
354
|
-
const rootDir = pathe.default.parse(currentDir).root;
|
|
355
|
-
while (true) {
|
|
356
|
-
const packageJsonPath = pathe.default.join(currentDir, "package.json");
|
|
357
|
-
if ((0, fs.existsSync)(packageJsonPath)) {
|
|
358
|
-
const packageJsonContent = (0, fs.readFileSync)(packageJsonPath, "utf-8");
|
|
359
|
-
try {
|
|
360
|
-
const packageJson = JSON.parse(packageJsonContent);
|
|
361
|
-
if (packageJson.name === packageName) return {
|
|
362
|
-
path: packageJsonPath,
|
|
363
|
-
dir: currentDir,
|
|
364
|
-
packageJson
|
|
365
|
-
};
|
|
366
|
-
} catch (error) {
|
|
367
|
-
if (!(error instanceof SyntaxError)) throw error;
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
if (currentDir === rootDir) break;
|
|
371
|
-
currentDir = pathe.default.dirname(currentDir);
|
|
372
|
-
}
|
|
373
|
-
} catch {
|
|
374
|
-
let currentDir = cwd;
|
|
375
|
-
const rootDir = pathe.default.parse(currentDir).root;
|
|
376
|
-
while (true) {
|
|
377
|
-
const directCandidate = tryReadPackageJson(pathe.default.join(currentDir, "node_modules", packageName, "package.json"));
|
|
378
|
-
if (directCandidate?.packageJson.name === packageName) return directCandidate;
|
|
379
|
-
if (currentDir === rootDir) break;
|
|
380
|
-
currentDir = pathe.default.dirname(currentDir);
|
|
381
|
-
}
|
|
382
|
-
return findPackageInPnpmStore(cwd);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
function getInstalledPackageEntry(pkg, opts) {
|
|
386
|
-
const installed = getInstalledPackageJson(pkg, opts);
|
|
387
|
-
if (!installed) return void 0;
|
|
388
|
-
const cwd = opts?.cwd || getPackageDetectionCwd();
|
|
389
|
-
const packageName = opts?.packageName || getPackageName(pkg);
|
|
390
|
-
if (pkg !== packageName && opts?.resolveSubpathWithRequire !== false) try {
|
|
391
|
-
return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(cwd, "package.json")}`)).resolve(pkg);
|
|
392
|
-
} catch {}
|
|
393
|
-
const packageJson = installed.packageJson;
|
|
394
|
-
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";
|
|
395
|
-
return pathe.default.join(installed.dir, explicitEntry);
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* Detect whether the current runtime is Vite 8+ by checking for a Vite version flag
|
|
399
|
-
* on the plugin hook context, with Rolldown metadata kept as a compatibility fallback.
|
|
400
|
-
*/
|
|
401
|
-
function getIsRolldown(ctx) {
|
|
402
|
-
const viteVersion = ctx?.meta?.viteVersion;
|
|
403
|
-
const viteMajor = Number(String(viteVersion ?? "").split(".")[0]);
|
|
404
|
-
return Number.isFinite(viteMajor) && viteMajor >= 8 || !!ctx?.meta?.rolldownVersion;
|
|
405
|
-
}
|
|
406
|
-
function hasPackageDependency(dependencyName, cwd = packageDetectionCwd || process.cwd()) {
|
|
407
|
-
const cacheKey = getDependencyCacheKey(cwd, dependencyName);
|
|
408
|
-
const cached = dependencyPresenceCache.get(cacheKey);
|
|
409
|
-
if (cached !== void 0) return cached;
|
|
410
|
-
try {
|
|
411
|
-
const packageJson = JSON.parse((0, fs.readFileSync)(pathe.default.join(cwd, "package.json"), "utf8"));
|
|
412
|
-
const hasDependency = [
|
|
413
|
-
packageJson.dependencies,
|
|
414
|
-
packageJson.devDependencies,
|
|
415
|
-
packageJson.peerDependencies,
|
|
416
|
-
packageJson.optionalDependencies
|
|
417
|
-
].some((deps) => !!deps?.[dependencyName]);
|
|
418
|
-
dependencyPresenceCache.set(cacheKey, hasDependency);
|
|
419
|
-
return hasDependency;
|
|
420
|
-
} catch {
|
|
421
|
-
dependencyPresenceCache.set(cacheKey, false);
|
|
422
|
-
return false;
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
//#endregion
|
|
426
173
|
//#region src/utils/normalizeModuleFederationOptions.ts
|
|
427
174
|
const INTERNAL_NAME_PREFIX = "__mfe_internal__";
|
|
428
175
|
function toInternalModuleFederationName(name) {
|
|
@@ -430,7 +177,7 @@ function toInternalModuleFederationName(name) {
|
|
|
430
177
|
}
|
|
431
178
|
function warnOnReservedInternalNamePrefix(name, kind) {
|
|
432
179
|
if (!name.startsWith(INTERNAL_NAME_PREFIX)) return;
|
|
433
|
-
mfWarn(`Reserved internal ${kind} prefix "${INTERNAL_NAME_PREFIX}" detected in public ${kind} "${name}". This prefix is reserved for internal module federation names and may cause conflicts.`);
|
|
180
|
+
require_packageUtils.mfWarn(`Reserved internal ${kind} prefix "${INTERNAL_NAME_PREFIX}" detected in public ${kind} "${name}". This prefix is reserved for internal module federation names and may cause conflicts.`);
|
|
434
181
|
}
|
|
435
182
|
function normalizeExposesItem(item) {
|
|
436
183
|
let importPath = "";
|
|
@@ -494,7 +241,7 @@ function normalizeRemoteItem(key, remote) {
|
|
|
494
241
|
* @returns {string | undefined}
|
|
495
242
|
*/
|
|
496
243
|
function searchPackageVersion(sharedName) {
|
|
497
|
-
const version = getInstalledPackageJson(sharedName
|
|
244
|
+
const version = require_packageUtils.getInstalledPackageJson(sharedName)?.packageJson.version;
|
|
498
245
|
return typeof version === "string" ? version : void 0;
|
|
499
246
|
}
|
|
500
247
|
function inferVersionFromRequiredVersion(requiredVersion) {
|
|
@@ -503,28 +250,13 @@ function inferVersionFromRequiredVersion(requiredVersion) {
|
|
|
503
250
|
}
|
|
504
251
|
function getLitExportSubpathShares(sharedName) {
|
|
505
252
|
if (sharedName !== "lit") return [];
|
|
506
|
-
const exportsField = getInstalledPackageJson(sharedName, { packageName: sharedName })?.packageJson.exports;
|
|
253
|
+
const exportsField = require_packageUtils.getInstalledPackageJson(sharedName, { packageName: sharedName })?.packageJson.exports;
|
|
507
254
|
if (!exportsField || typeof exportsField === "string") return [];
|
|
508
255
|
return Object.keys(exportsField).filter((key) => key.startsWith("./") && key !== "." && !key.includes("*")).map((key) => `${sharedName}/${key.slice(2)}`);
|
|
509
256
|
}
|
|
510
257
|
function normalizeShareItem(key, shareItem) {
|
|
511
|
-
let version;
|
|
512
258
|
const isImportFalse = typeof shareItem === "object" && shareItem.import === false;
|
|
513
|
-
|
|
514
|
-
try {
|
|
515
|
-
version = require(pathe.join(getPackageName(key), "package.json")).version;
|
|
516
|
-
} catch (e1) {
|
|
517
|
-
try {
|
|
518
|
-
const localPath = pathe.join(process.cwd(), "node_modules", getPackageName(key), "package.json");
|
|
519
|
-
version = require(localPath).version;
|
|
520
|
-
} catch (e2) {
|
|
521
|
-
version = searchPackageVersion(key);
|
|
522
|
-
if (!version && !isImportFalse) mfError(e1);
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
} catch (e) {
|
|
526
|
-
if (!isImportFalse) mfError(`Unexpected error resolving version for ${key}:`, e);
|
|
527
|
-
}
|
|
259
|
+
const version = (typeof shareItem === "object" ? shareItem.version || inferVersionFromRequiredVersion(shareItem.requiredVersion) : void 0) || searchPackageVersion(key);
|
|
528
260
|
if (typeof shareItem === "string") return {
|
|
529
261
|
name: shareItem,
|
|
530
262
|
version,
|
|
@@ -539,12 +271,12 @@ function normalizeShareItem(key, shareItem) {
|
|
|
539
271
|
return {
|
|
540
272
|
name: key,
|
|
541
273
|
from: "",
|
|
542
|
-
version
|
|
274
|
+
version,
|
|
543
275
|
scope: shareItem.shareScope || "default",
|
|
544
276
|
shareConfig: {
|
|
545
277
|
import: shareItem.import,
|
|
546
278
|
singleton: shareItem.singleton || false,
|
|
547
|
-
requiredVersion: shareItem.requiredVersion || (isImportFalse ? "*" : version ? `^${version}` : "*"),
|
|
279
|
+
requiredVersion: shareItem.requiredVersion || (isImportFalse || shareItem.version ? "*" : version ? `^${version}` : "*"),
|
|
548
280
|
strictVersion: !!shareItem.strictVersion
|
|
549
281
|
}
|
|
550
282
|
};
|
|
@@ -553,7 +285,7 @@ function normalizeShared(shared) {
|
|
|
553
285
|
explicitSharedKeys = /* @__PURE__ */ new Set();
|
|
554
286
|
if (!shared) {
|
|
555
287
|
const result = {};
|
|
556
|
-
const packageJsonPath = pathe.join(getPackageDetectionCwd(), "package.json");
|
|
288
|
+
const packageJsonPath = pathe.join(require_packageUtils.getPackageDetectionCwd(), "package.json");
|
|
557
289
|
try {
|
|
558
290
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
559
291
|
if (packageJson.name === "@module-federation/vite") return result;
|
|
@@ -572,11 +304,13 @@ function normalizeShared(shared) {
|
|
|
572
304
|
const result = {};
|
|
573
305
|
const sourceEntries = [];
|
|
574
306
|
if (Array.isArray(shared)) shared.forEach((key) => {
|
|
307
|
+
if (isModuleFederationRuntimePackage(key)) return;
|
|
575
308
|
result[key] = normalizeShareItem(key, key);
|
|
576
309
|
explicitSharedKeys.add(key);
|
|
577
310
|
sourceEntries.push([key, key]);
|
|
578
311
|
});
|
|
579
312
|
else if (typeof shared === "object") Object.keys(shared).forEach((key) => {
|
|
313
|
+
if (isModuleFederationRuntimePackage(key)) return;
|
|
580
314
|
const value = shared[key];
|
|
581
315
|
result[key] = normalizeShareItem(key, value);
|
|
582
316
|
explicitSharedKeys.add(key);
|
|
@@ -590,11 +324,14 @@ function normalizeShared(shared) {
|
|
|
590
324
|
});
|
|
591
325
|
return result;
|
|
592
326
|
}
|
|
327
|
+
function isModuleFederationRuntimePackage(key) {
|
|
328
|
+
return key === "@module-federation/runtime" || key === "@module-federation/runtime-core";
|
|
329
|
+
}
|
|
593
330
|
function shouldAutoShareDependency(key) {
|
|
594
|
-
const pkg = getInstalledPackageJson(key)?.packageJson;
|
|
331
|
+
const pkg = require_packageUtils.getInstalledPackageJson(key)?.packageJson;
|
|
595
332
|
if (!pkg) return false;
|
|
596
333
|
if (!pkg.browser && !pkg.exports && typeof pkg.module !== "string") return false;
|
|
597
|
-
if (key === "@module-federation/vite") return false;
|
|
334
|
+
if (key === "@module-federation/vite" || isModuleFederationRuntimePackage(key)) return false;
|
|
598
335
|
const entry = [
|
|
599
336
|
pkg.module,
|
|
600
337
|
pkg.main,
|
|
@@ -618,6 +355,18 @@ function normalizeManifest(manifest) {
|
|
|
618
355
|
}
|
|
619
356
|
let config;
|
|
620
357
|
let explicitSharedKeys = /* @__PURE__ */ new Set();
|
|
358
|
+
function resolveRuntimeImplementation() {
|
|
359
|
+
const fallback = require.resolve("@module-federation/runtime");
|
|
360
|
+
try {
|
|
361
|
+
const packageJsonPath = require.resolve("@module-federation/runtime/package.json");
|
|
362
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
363
|
+
const importExport = packageJson.exports?.["."];
|
|
364
|
+
const exportImport = typeof importExport === "object" ? typeof importExport.import === "string" ? importExport.import : importExport.import?.default : void 0;
|
|
365
|
+
const esmEntry = packageJson.module || exportImport;
|
|
366
|
+
if (esmEntry) return pathe.join(pathe.dirname(packageJsonPath), esmEntry);
|
|
367
|
+
} catch {}
|
|
368
|
+
return fallback;
|
|
369
|
+
}
|
|
621
370
|
function getNormalizeModuleFederationOptions() {
|
|
622
371
|
return config;
|
|
623
372
|
}
|
|
@@ -626,11 +375,11 @@ function isExplicitSharedKey(key) {
|
|
|
626
375
|
}
|
|
627
376
|
function getNormalizeShareItem(key) {
|
|
628
377
|
const options = getNormalizeModuleFederationOptions();
|
|
629
|
-
return options.shared[key] || options.shared[getPackageName(key)] || options.shared[getPackageName(key) + "/"];
|
|
378
|
+
return options.shared[key] || options.shared[require_packageUtils.getPackageName(key)] || options.shared[require_packageUtils.getPackageName(key) + "/"];
|
|
630
379
|
}
|
|
631
380
|
function normalizeModuleFederationOptions(options) {
|
|
632
381
|
warnOnReservedInternalNamePrefix(options.name, "containerName");
|
|
633
|
-
if (options.virtualModuleDir && options.virtualModuleDir.includes("/")) throw createModuleFederationError(`Invalid virtualModuleDir: "${options.virtualModuleDir}". The virtualModuleDir option cannot contain slashes (/). Please use a single directory name like '__mf__virtual__your_app_name'.`);
|
|
382
|
+
if (options.virtualModuleDir && options.virtualModuleDir.includes("/")) throw require_packageUtils.createModuleFederationError(`Invalid virtualModuleDir: "${options.virtualModuleDir}". The virtualModuleDir option cannot contain slashes (/). Please use a single directory name like '__mf__virtual__your_app_name'.`);
|
|
634
383
|
return config = {
|
|
635
384
|
exposes: normalizeExposes(options.exposes),
|
|
636
385
|
filename: options.filename || "remoteEntry-[hash]",
|
|
@@ -642,7 +391,7 @@ function normalizeModuleFederationOptions(options) {
|
|
|
642
391
|
shareScope: options.shareScope || "default",
|
|
643
392
|
shared: normalizeShared(options.shared),
|
|
644
393
|
runtimePlugins: options.runtimePlugins || [],
|
|
645
|
-
implementation: options.implementation ||
|
|
394
|
+
implementation: options.implementation || resolveRuntimeImplementation(),
|
|
646
395
|
manifest: normalizeManifest(options.manifest),
|
|
647
396
|
dev: options.dev,
|
|
648
397
|
dts: options.dts,
|
|
@@ -671,7 +420,7 @@ const patternMap = {};
|
|
|
671
420
|
const cacheMap = {};
|
|
672
421
|
function assertModuleFound(tag, str = "") {
|
|
673
422
|
const module = VirtualModule.findModule(tag, str);
|
|
674
|
-
if (!module) throw createModuleFederationError(`Module Federation shared module '${str}' not found. Please ensure it's installed as a dependency in your package.json.`);
|
|
423
|
+
if (!module) throw require_packageUtils.createModuleFederationError(`Module Federation shared module '${str}' not found. Please ensure it's installed as a dependency in your package.json.`);
|
|
675
424
|
return module;
|
|
676
425
|
}
|
|
677
426
|
var VirtualModule = class {
|
|
@@ -681,9 +430,9 @@ var VirtualModule = class {
|
|
|
681
430
|
inited = false;
|
|
682
431
|
code;
|
|
683
432
|
static findModule(tag, str = "") {
|
|
684
|
-
if (!patternMap[tag]) patternMap[tag] = new RegExp(`(.*${packageNameEncode(tag)}(.+?)${packageNameEncode(tag)}.*)`);
|
|
433
|
+
if (!patternMap[tag]) patternMap[tag] = new RegExp(`(.*${require_packageUtils.packageNameEncode(tag)}(.+?)${require_packageUtils.packageNameEncode(tag)}.*)`);
|
|
685
434
|
const moduleName = (str.match(patternMap[tag]) || [])[2];
|
|
686
|
-
if (moduleName) return cacheMap[tag][packageNameDecode(moduleName)];
|
|
435
|
+
if (moduleName) return cacheMap[tag][require_packageUtils.packageNameDecode(moduleName)];
|
|
687
436
|
}
|
|
688
437
|
static findById(id) {
|
|
689
438
|
const normalized = id.replace(/^\0+/, "").replace(/^\/@id\//, "").replace(/^__x00__/, "").replace(/[?#].*$/, "");
|
|
@@ -698,7 +447,7 @@ var VirtualModule = class {
|
|
|
698
447
|
}
|
|
699
448
|
getImportId() {
|
|
700
449
|
const { internalName: mfName } = getNormalizeModuleFederationOptions();
|
|
701
|
-
return `virtual:mf:${packageNameEncode(`${mfName}${this.tag}${this.name}${this.tag}`)}${this.suffix}`;
|
|
450
|
+
return `virtual:mf:${require_packageUtils.packageNameEncode(`${mfName}${this.tag}${this.name}${this.tag}`)}${this.suffix}`;
|
|
702
451
|
}
|
|
703
452
|
getResolvedId() {
|
|
704
453
|
return `\0${this.getImportId()}`;
|
|
@@ -856,11 +605,24 @@ function getDeferredInitPromiseCode() {
|
|
|
856
605
|
initReject = rj;
|
|
857
606
|
});`;
|
|
858
607
|
}
|
|
859
|
-
|
|
608
|
+
let _ssrRemotes = [];
|
|
609
|
+
function setSsrRemotes(remotes) {
|
|
610
|
+
_ssrRemotes = remotes;
|
|
611
|
+
}
|
|
612
|
+
function getSsrNoopResolveCode(enableSsrInit) {
|
|
613
|
+
if (!enableSsrInit) return "";
|
|
860
614
|
return `if (typeof window === 'undefined') {
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
615
|
+
var _noop = { loadRemote: function() { return Promise.resolve(undefined); }, loadShare: function() { return Promise.resolve(undefined); } };
|
|
616
|
+
import(/* @vite-ignore */ '@module-federation/runtime').then(function(runtimeMod) {
|
|
617
|
+
return import(/* @vite-ignore */ '@module-federation/vite/ssrEntryLoader').then(
|
|
618
|
+
function(loaderMod) { return [runtimeMod, [loaderMod.default()]]; },
|
|
619
|
+
function() { return [runtimeMod, []]; }
|
|
620
|
+
);
|
|
621
|
+
}).then(function(pair) {
|
|
622
|
+
var runtime = pair[0].init({ name: '__mf_ssr_host__', remotes: ${JSON.stringify(_ssrRemotes)}, shared: {}, plugins: pair[1] });
|
|
623
|
+
initResolve(runtime);
|
|
624
|
+
}, function() {
|
|
625
|
+
initResolve(_noop);
|
|
864
626
|
});
|
|
865
627
|
}`;
|
|
866
628
|
}
|
|
@@ -875,12 +637,12 @@ if (!${options.stateVar}) {
|
|
|
875
637
|
initResolve,
|
|
876
638
|
initReject,
|
|
877
639
|
};
|
|
878
|
-
${getSsrNoopResolveCode()}
|
|
640
|
+
${getSsrNoopResolveCode(options.enableSsrInit)}
|
|
879
641
|
}
|
|
880
642
|
const ${options.exposedConst} = ${options.stateVar}.${options.exposedProperty};
|
|
881
643
|
`;
|
|
882
644
|
}
|
|
883
|
-
function getRuntimeInitBootstrapCode() {
|
|
645
|
+
function getRuntimeInitBootstrapCode(enableSsrInit = false) {
|
|
884
646
|
return `
|
|
885
647
|
const globalKey = ${JSON.stringify(getRuntimeInitGlobalKey())};
|
|
886
648
|
const moduleCacheGlobalKey = ${JSON.stringify(MODULE_CACHE_GLOBAL_KEY)};
|
|
@@ -895,7 +657,7 @@ if (!globalThis[globalKey]) {
|
|
|
895
657
|
initReject,
|
|
896
658
|
moduleCache: globalThis[moduleCacheGlobalKey],
|
|
897
659
|
};
|
|
898
|
-
${getSsrNoopResolveCode()}
|
|
660
|
+
${getSsrNoopResolveCode(enableSsrInit)}
|
|
899
661
|
}
|
|
900
662
|
globalThis[globalKey].moduleCache ||= globalThis[moduleCacheGlobalKey];
|
|
901
663
|
globalThis[globalKey].moduleCache.share ||= {};
|
|
@@ -911,27 +673,29 @@ globalThis[__mfCacheGlobalKey].remote ||= {};
|
|
|
911
673
|
const __mfModuleCache = globalThis[__mfCacheGlobalKey];
|
|
912
674
|
`;
|
|
913
675
|
}
|
|
914
|
-
function getRuntimeInitPromiseBootstrapCode() {
|
|
676
|
+
function getRuntimeInitPromiseBootstrapCode(enableSsrInit = false) {
|
|
915
677
|
return getRuntimeInitStateBootstrapCode({
|
|
916
678
|
globalKeyVar: "__mfPromiseGlobalKey",
|
|
917
679
|
stateVar: "__mfPromiseState",
|
|
918
680
|
exposedConst: "initPromise",
|
|
919
|
-
exposedProperty: "initPromise"
|
|
681
|
+
exposedProperty: "initPromise",
|
|
682
|
+
enableSsrInit
|
|
920
683
|
});
|
|
921
684
|
}
|
|
922
|
-
function getRuntimeInitResolveBootstrapCode() {
|
|
685
|
+
function getRuntimeInitResolveBootstrapCode(enableSsrInit = false) {
|
|
923
686
|
return getRuntimeInitStateBootstrapCode({
|
|
924
687
|
globalKeyVar: "__mfResolveGlobalKey",
|
|
925
688
|
stateVar: "__mfResolveState",
|
|
926
689
|
exposedConst: "initResolve",
|
|
927
|
-
exposedProperty: "initResolve"
|
|
690
|
+
exposedProperty: "initResolve",
|
|
691
|
+
enableSsrInit
|
|
928
692
|
});
|
|
929
693
|
}
|
|
930
|
-
function writeRuntimeInitStatus(command) {
|
|
694
|
+
function writeRuntimeInitStatus(command, enableSsrInit = false) {
|
|
931
695
|
const exportStatement = command === "build" ? `const { initPromise, initResolve, initReject, moduleCache } = globalThis[globalKey];
|
|
932
696
|
export { initPromise, initResolve, initReject, moduleCache };` : `module.exports = globalThis[globalKey];`;
|
|
933
697
|
virtualRuntimeInitStatus.writeSync(`
|
|
934
|
-
${getRuntimeInitBootstrapCode()}
|
|
698
|
+
${getRuntimeInitBootstrapCode(enableSsrInit)}
|
|
935
699
|
${exportStatement}
|
|
936
700
|
`);
|
|
937
701
|
}
|
|
@@ -969,13 +733,13 @@ const JS_IDENTIFIER_PATTERN = `[\$_\\p{ID_Start}][\$_\\u200C\\u200D\\p{ID_Contin
|
|
|
969
733
|
const localRequire = (0, module$1.createRequire)(require("url").pathToFileURL(__filename).href);
|
|
970
734
|
function resolvePackageEntryFromProjectRoot(pkg) {
|
|
971
735
|
try {
|
|
972
|
-
return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
|
|
736
|
+
return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(require_packageUtils.getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
|
|
973
737
|
} catch {
|
|
974
738
|
return;
|
|
975
739
|
}
|
|
976
740
|
}
|
|
977
741
|
function getPackageEsmEntryPath(pkg) {
|
|
978
|
-
return getInstalledPackageEntry(pkg, {
|
|
742
|
+
return require_packageUtils.getInstalledPackageEntry(pkg, {
|
|
979
743
|
conditions: [
|
|
980
744
|
"browser",
|
|
981
745
|
"import",
|
|
@@ -1067,7 +831,7 @@ function getNamedExportsViaRegex(source, filePath, visited) {
|
|
|
1067
831
|
}
|
|
1068
832
|
function getPackageNamedExports(pkg) {
|
|
1069
833
|
try {
|
|
1070
|
-
const mod = (0, module$1.createRequire)(new URL(`file://${pathe.default.join(getPackageDetectionCwd(), "package.json")}`))(pkg);
|
|
834
|
+
const mod = (0, module$1.createRequire)(new URL(`file://${pathe.default.join(require_packageUtils.getPackageDetectionCwd(), "package.json")}`))(pkg);
|
|
1071
835
|
return Object.keys(mod).filter((k) => isValidEsmExportName(k));
|
|
1072
836
|
} catch {
|
|
1073
837
|
return getEsmNamedExports(pkg);
|
|
@@ -1075,10 +839,10 @@ function getPackageNamedExports(pkg) {
|
|
|
1075
839
|
}
|
|
1076
840
|
function getLocalProviderImportPath(pkg) {
|
|
1077
841
|
try {
|
|
1078
|
-
const resolved = (0, module$1.createRequire)(new URL(`file://${pathe.default.join(getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
|
|
842
|
+
const resolved = (0, module$1.createRequire)(new URL(`file://${pathe.default.join(require_packageUtils.getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
|
|
1079
843
|
return isWorkspaceFilePath(resolved) ? resolved : void 0;
|
|
1080
844
|
} catch {
|
|
1081
|
-
const resolved = getInstalledPackageEntry(pkg, {
|
|
845
|
+
const resolved = require_packageUtils.getInstalledPackageEntry(pkg, {
|
|
1082
846
|
conditions: [
|
|
1083
847
|
"browser",
|
|
1084
848
|
"import",
|
|
@@ -1091,12 +855,12 @@ function getLocalProviderImportPath(pkg) {
|
|
|
1091
855
|
}
|
|
1092
856
|
}
|
|
1093
857
|
function getProjectResolvedImportPath(pkg) {
|
|
1094
|
-
if (pkg === getPackageName(pkg)) {
|
|
858
|
+
if (pkg === require_packageUtils.getPackageName(pkg)) {
|
|
1095
859
|
const esmEntry = getPackageEsmEntryPath(pkg);
|
|
1096
860
|
if (esmEntry) return esmEntry;
|
|
1097
861
|
}
|
|
1098
862
|
try {
|
|
1099
|
-
return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
|
|
863
|
+
return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(require_packageUtils.getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
|
|
1100
864
|
} catch {
|
|
1101
865
|
return;
|
|
1102
866
|
}
|
|
@@ -1111,8 +875,8 @@ function isWorkspaceFilePath(resolved) {
|
|
|
1111
875
|
}
|
|
1112
876
|
function isWorkspacePackageEntry(pkg, resolved) {
|
|
1113
877
|
if (!resolved || !pathe.default.isAbsolute(resolved) || !isWorkspaceFilePath(resolved)) return false;
|
|
1114
|
-
return !!getInstalledPackageJson(pkg, {
|
|
1115
|
-
packageName: getPackageName(pkg),
|
|
878
|
+
return !!require_packageUtils.getInstalledPackageJson(pkg, {
|
|
879
|
+
packageName: require_packageUtils.getPackageName(pkg),
|
|
1116
880
|
fromResolvedEntry: resolved
|
|
1117
881
|
});
|
|
1118
882
|
}
|
|
@@ -1126,7 +890,7 @@ function tryResolveImportFromPackageRoot(pkg, root) {
|
|
|
1126
890
|
function getConcreteSharedImportSource(pkg, shareItem) {
|
|
1127
891
|
const configuredImport = shareItem?.shareConfig.import;
|
|
1128
892
|
if (typeof configuredImport === "string") return configuredImport;
|
|
1129
|
-
const projectRoot = getPackageDetectionCwd();
|
|
893
|
+
const projectRoot = require_packageUtils.getPackageDetectionCwd();
|
|
1130
894
|
if (tryResolveImportFromPackageRoot(pkg, projectRoot)) return;
|
|
1131
895
|
let currentDir = pathe.default.dirname(projectRoot);
|
|
1132
896
|
while (currentDir !== pathe.default.dirname(currentDir)) {
|
|
@@ -1254,7 +1018,7 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown) {
|
|
|
1254
1018
|
let exportLine;
|
|
1255
1019
|
if (namedExports.length > 0) exportLine = generateDeferredHostProvidedExports(namedExports, pkg);
|
|
1256
1020
|
else {
|
|
1257
|
-
mfWarn(`Shared dependency "${pkg}" has import: false but is not installed locally.\n Named imports (e.g. import { ... } from '${pkg}') will not work in production builds.\n Install it as a devDependency to enable named export detection.`);
|
|
1021
|
+
require_packageUtils.mfWarn(`Shared dependency "${pkg}" has import: false but is not installed locally.\n Named imports (e.g. import { ... } from '${pkg}') will not work in production builds.\n Install it as a devDependency to enable named export detection.`);
|
|
1258
1022
|
exportLine = generateDeferredHostProvidedExports([], pkg);
|
|
1259
1023
|
}
|
|
1260
1024
|
loadShareCacheMap[pkg].writeSync(`
|
|
@@ -1317,7 +1081,7 @@ function addUsedShares(pkg) {
|
|
|
1317
1081
|
const LOCAL_SHARED_IMPORT_MAP_ID = "virtual:mf-localSharedImportMap";
|
|
1318
1082
|
function getLocalSharedImportMapPath() {
|
|
1319
1083
|
const { internalName, name } = getNormalizeModuleFederationOptions();
|
|
1320
|
-
return `${LOCAL_SHARED_IMPORT_MAP_ID}:${packageNameEncode(internalName || name)}`;
|
|
1084
|
+
return `${LOCAL_SHARED_IMPORT_MAP_ID}:${require_packageUtils.packageNameEncode(internalName || name)}`;
|
|
1321
1085
|
}
|
|
1322
1086
|
function getResolvedLocalSharedImportMapId() {
|
|
1323
1087
|
return `\0${getLocalSharedImportMapPath()}`;
|
|
@@ -1335,8 +1099,8 @@ function writeLocalSharedImportMap() {
|
|
|
1335
1099
|
}
|
|
1336
1100
|
}
|
|
1337
1101
|
function shouldUseDirectReactImport() {
|
|
1338
|
-
const isVinext = hasPackageDependency("vinext");
|
|
1339
|
-
const isAstro = hasPackageDependency("astro");
|
|
1102
|
+
const isVinext = require_packageUtils.hasPackageDependency("vinext");
|
|
1103
|
+
const isAstro = require_packageUtils.hasPackageDependency("astro");
|
|
1340
1104
|
return isVinext || isAstro;
|
|
1341
1105
|
}
|
|
1342
1106
|
function getLocalSharedPackagePath(pkg, shareItem) {
|
|
@@ -1471,7 +1235,7 @@ const normalizeRuntimeShareCode = `const __mfNormalizeRuntimeShare = (mod) => {
|
|
|
1471
1235
|
let current = mod;
|
|
1472
1236
|
for (let i = 0; i < 5; i++) {
|
|
1473
1237
|
const defaultExport = current?.default;
|
|
1474
|
-
if (!defaultExport || typeof defaultExport !== "object") break;
|
|
1238
|
+
if (!defaultExport || typeof defaultExport !== "object" || Object.keys(defaultExport).length === 0) break;
|
|
1475
1239
|
const namedValues = Object.keys(current).filter((key) => key !== "default").map((key) => current[key]);
|
|
1476
1240
|
if (namedValues.length > 0 && namedValues.some((value) => value !== undefined)) break;
|
|
1477
1241
|
current = defaultExport;
|
|
@@ -1511,6 +1275,9 @@ const REMOTE_ENTRY_ID = "virtual:mf-REMOTE_ENTRY_ID";
|
|
|
1511
1275
|
function getRemoteEntryId(options) {
|
|
1512
1276
|
return `${REMOTE_ENTRY_ID}:${`${options.internalName}__${options.filename}`.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
|
|
1513
1277
|
}
|
|
1278
|
+
const SSR_ONLY_PLUGIN_SPECIFIERS = new Set(["@module-federation/vite/ssrEntryLoader"]);
|
|
1279
|
+
const isSsrOnlyPlugin = (importStatement) => [...SSR_ONLY_PLUGIN_SPECIFIERS].some((s) => importStatement.includes(s));
|
|
1280
|
+
const getSsrOnlyPluginSpecifier = (importStatement) => [...SSR_ONLY_PLUGIN_SPECIFIERS].find((s) => importStatement.includes(s));
|
|
1514
1281
|
function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(options), command = "build") {
|
|
1515
1282
|
const pluginImportNames = options.runtimePlugins.map((p, i) => {
|
|
1516
1283
|
if (typeof p === "string") return [
|
|
@@ -1534,7 +1301,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1534
1301
|
globalThis.__VUE_HMR_RUNTIME__ = { createRecord() {}, rerender() {}, reload() {} };
|
|
1535
1302
|
}
|
|
1536
1303
|
import {init as runtimeInit, loadRemote} from "@module-federation/runtime";
|
|
1537
|
-
${pluginImportNames.map((item) => item[1]).join("\n")}
|
|
1304
|
+
${pluginImportNames.filter((item) => !isSsrOnlyPlugin(item[1])).map((item) => item[1]).join("\n")}
|
|
1538
1305
|
${command === "build" ? getRuntimeInitResolveBootstrapCode() : getRuntimeInitBootstrapCode() + "\n const { initResolve } = globalThis[globalKey];"}
|
|
1539
1306
|
${getRuntimeModuleCacheBootstrapCode()}
|
|
1540
1307
|
const initTokens = {}
|
|
@@ -1582,11 +1349,19 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1582
1349
|
async function init(shared = {}, initScope = []) {
|
|
1583
1350
|
const {usedShared, usedRemotes} = await getLocalSharedImportMap()
|
|
1584
1351
|
${generateDirectSharedCacheSeedCode(command)}
|
|
1352
|
+
const __browserPlugins = [${pluginImportNames.filter((item) => !isSsrOnlyPlugin(item[1])).map((item) => `${item[0]}(${item[2]})`).join(", ")}];
|
|
1353
|
+
const __ssrPlugins = typeof globalThis.window === 'undefined'
|
|
1354
|
+
? await Promise.all([${pluginImportNames.filter((item) => isSsrOnlyPlugin(item[1])).map((item) => {
|
|
1355
|
+
const specifier = getSsrOnlyPluginSpecifier(item[1]);
|
|
1356
|
+
const opts = item[2];
|
|
1357
|
+
return `import(${JSON.stringify(specifier)}).then(m => (m.default ?? m)(${opts}))`;
|
|
1358
|
+
}).join(", ")}])
|
|
1359
|
+
: [];
|
|
1585
1360
|
const initRes = runtimeInit({
|
|
1586
1361
|
name: mfName,
|
|
1587
|
-
remotes: usedRemotes,
|
|
1362
|
+
remotes: ${options.shareStrategy === "loaded-first" ? "[]" : "usedRemotes"},
|
|
1588
1363
|
shared: usedShared,
|
|
1589
|
-
plugins: [
|
|
1364
|
+
plugins: [...__browserPlugins, ...__ssrPlugins],
|
|
1590
1365
|
${options.shareStrategy ? `shareStrategy: '${options.shareStrategy}'` : ""}
|
|
1591
1366
|
});
|
|
1592
1367
|
// handling circular init calls
|
|
@@ -1637,6 +1412,7 @@ const hostAutoInitModule = new VirtualModule("hostAutoInit", "__H_A_I__");
|
|
|
1637
1412
|
let currentHostAutoInitRemoteEntryId = REMOTE_ENTRY_ID;
|
|
1638
1413
|
let currentHostAutoInitCommand = "build";
|
|
1639
1414
|
function generateHostAutoInitCode(remoteEntryImport, _command = "build") {
|
|
1415
|
+
const shouldPreloadShares = getNormalizeModuleFederationOptions().shareStrategy !== "loaded-first";
|
|
1640
1416
|
return `
|
|
1641
1417
|
${getRuntimeModuleCacheBootstrapCode()}
|
|
1642
1418
|
let hostInitPromise;
|
|
@@ -1648,6 +1424,7 @@ function generateHostAutoInitCode(remoteEntryImport, _command = "build") {
|
|
|
1648
1424
|
const runtime = await remoteEntry.init();
|
|
1649
1425
|
const usedShared = ${generateUsedSharedPreloadConfig()};
|
|
1650
1426
|
${normalizeRuntimeShareCode}
|
|
1427
|
+
${shouldPreloadShares ? `
|
|
1651
1428
|
for (const [pkg, share] of Object.entries(usedShared)) {
|
|
1652
1429
|
if (__mfModuleCache.share[pkg] !== undefined) {
|
|
1653
1430
|
continue;
|
|
@@ -1661,6 +1438,7 @@ function generateHostAutoInitCode(remoteEntryImport, _command = "build") {
|
|
|
1661
1438
|
});
|
|
1662
1439
|
});
|
|
1663
1440
|
}
|
|
1441
|
+
` : ""}
|
|
1664
1442
|
const __mfRemotePreloads = [];
|
|
1665
1443
|
await Promise.all(__mfRemotePreloads);
|
|
1666
1444
|
return runtime;
|
|
@@ -1692,12 +1470,13 @@ function getHostAutoInitPath() {
|
|
|
1692
1470
|
//#region src/virtualModules/virtualRemotes.ts
|
|
1693
1471
|
const cacheRemoteMap = {};
|
|
1694
1472
|
const LOAD_REMOTE_TAG = "__loadRemote__";
|
|
1695
|
-
function getRemoteVirtualModule(remote, command) {
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
cacheRemoteMap[
|
|
1473
|
+
function getRemoteVirtualModule(remote, command, enableSsrInit = false) {
|
|
1474
|
+
const cacheKey = `${remote}__${command}__${enableSsrInit ? "ssr" : "no-ssr"}`;
|
|
1475
|
+
if (!cacheRemoteMap[cacheKey]) {
|
|
1476
|
+
cacheRemoteMap[cacheKey] = new VirtualModule(remote, LOAD_REMOTE_TAG, ".mjs");
|
|
1477
|
+
cacheRemoteMap[cacheKey].writeSync(generateRemotes(remote, command, enableSsrInit));
|
|
1699
1478
|
}
|
|
1700
|
-
return cacheRemoteMap[
|
|
1479
|
+
return cacheRemoteMap[cacheKey];
|
|
1701
1480
|
}
|
|
1702
1481
|
const usedRemotesMap = {};
|
|
1703
1482
|
function addUsedRemote(remoteKey, remoteModule) {
|
|
@@ -1707,40 +1486,93 @@ function addUsedRemote(remoteKey, remoteModule) {
|
|
|
1707
1486
|
function getUsedRemotesMap() {
|
|
1708
1487
|
return usedRemotesMap;
|
|
1709
1488
|
}
|
|
1710
|
-
function
|
|
1711
|
-
const
|
|
1489
|
+
function getRemoteFromId(id, remotes) {
|
|
1490
|
+
const remoteName = Object.keys(remotes).filter((name) => id === name || id.startsWith(name + "/")).sort((a, b) => b.length - a.length)[0];
|
|
1491
|
+
return remoteName ? remotes[remoteName] : void 0;
|
|
1492
|
+
}
|
|
1493
|
+
function generateRemotes(id, command, enableSsrInit = false) {
|
|
1494
|
+
const useReactProxy = require_packageUtils.hasPackageDependency("react");
|
|
1495
|
+
const options = getNormalizeModuleFederationOptions();
|
|
1496
|
+
const isLoadedFirst = options.shareStrategy === "loaded-first";
|
|
1497
|
+
const remote = getRemoteFromId(id, options.remotes);
|
|
1498
|
+
const registerRemoteCode = isLoadedFirst && remote ? `runtime.registerRemotes([${JSON.stringify({
|
|
1499
|
+
entryGlobalName: remote.entryGlobalName,
|
|
1500
|
+
name: remote.name,
|
|
1501
|
+
type: remote.type,
|
|
1502
|
+
entry: remote.entry,
|
|
1503
|
+
shareScope: remote.shareScope ?? "default"
|
|
1504
|
+
})}]);` : "";
|
|
1712
1505
|
const reactImportLine = useReactProxy ? `import __mfReactDefault from "react";
|
|
1713
1506
|
import * as __mfReactNamespace from "react";
|
|
1714
1507
|
const __mfReact = __mfReactDefault ?? __mfReactNamespace.default ?? __mfReactNamespace;` : "";
|
|
1715
1508
|
const importLine = command === "build" ? `${getRuntimeModuleCacheBootstrapCode()}
|
|
1716
|
-
import { hostInitPromise as __mfHostInitPromise } from ${JSON.stringify(getHostAutoInitPath())};` : `${getRuntimeInitBootstrapCode()}
|
|
1717
|
-
const { initPromise, moduleCache: __mfModuleCache } = globalThis[globalKey]
|
|
1509
|
+
import { hostInitPromise as __mfHostInitPromise } from ${JSON.stringify(getHostAutoInitPath())};` : `${getRuntimeInitBootstrapCode(enableSsrInit)}
|
|
1510
|
+
const { initPromise, initResolve, initReject, moduleCache: __mfModuleCache } = globalThis[globalKey];
|
|
1511
|
+
if (typeof window !== "undefined") {
|
|
1512
|
+
import(${JSON.stringify(getHostAutoInitPath())})
|
|
1513
|
+
.then((mod) => mod.hostInitPromise)
|
|
1514
|
+
.then(initResolve, initReject);
|
|
1515
|
+
}`;
|
|
1718
1516
|
const exportLine = command === "serve" ? `if (__mfRemotePending) {
|
|
1719
|
-
|
|
1720
|
-
|
|
1517
|
+
__mfRemotePending = __mfRemotePending.then((mod) => {
|
|
1518
|
+
if (mod !== undefined) exportModule = mod;
|
|
1519
|
+
return exportModule;
|
|
1520
|
+
});
|
|
1721
1521
|
}
|
|
1722
|
-
export
|
|
1723
|
-
export const __mf_remote_pending = Promise.resolve(exportModule);
|
|
1522
|
+
export { exportModule as __moduleExports };
|
|
1523
|
+
export const __mf_remote_pending = __mfRemotePending || Promise.resolve(exportModule);
|
|
1724
1524
|
export default exportModule?.__mf_is_remote_proxy ? exportModule : exportModule?.__esModule ? exportModule.default : exportModule.default ?? exportModule` : command === "build" ? `if (__mfRemotePending) {
|
|
1725
|
-
|
|
1726
|
-
|
|
1525
|
+
__mfRemotePending = __mfRemotePending.then((mod) => {
|
|
1526
|
+
if (mod !== undefined) exportModule = mod;
|
|
1527
|
+
return exportModule;
|
|
1528
|
+
});
|
|
1727
1529
|
}
|
|
1728
|
-
export
|
|
1729
|
-
export const __mf_remote_pending = Promise.resolve(exportModule);
|
|
1530
|
+
export { exportModule as __moduleExports };
|
|
1531
|
+
export const __mf_remote_pending = __mfRemotePending || Promise.resolve(exportModule);
|
|
1730
1532
|
export default exportModule?.__mf_is_remote_proxy ? exportModule : exportModule?.__esModule ? exportModule.default : exportModule.default ?? exportModule` : "export default exportModule";
|
|
1533
|
+
const remoteLoadRuntimePromise = command === "build" ? "__mfHostInitPromise" : "initPromise";
|
|
1534
|
+
const remoteLoadFailureHandler = command === "build" ? `.catch((error) => {
|
|
1535
|
+
delete __mfModuleCache.remote[pendingKey];
|
|
1536
|
+
throw error;
|
|
1537
|
+
})` : `.catch(() => {
|
|
1538
|
+
delete __mfModuleCache.remote[pendingKey];
|
|
1539
|
+
})`;
|
|
1731
1540
|
return `
|
|
1732
1541
|
${reactImportLine}
|
|
1733
1542
|
${importLine}
|
|
1734
|
-
${
|
|
1543
|
+
${`
|
|
1544
|
+
function __mfStartRemoteLoad() {
|
|
1545
|
+
${`
|
|
1546
|
+
const pendingKey = ${JSON.stringify(`__mf_pending__${id}`)};
|
|
1547
|
+
if (!__mfModuleCache.remote[pendingKey]) {
|
|
1548
|
+
__mfModuleCache.remote[pendingKey] = ${remoteLoadRuntimePromise}
|
|
1549
|
+
.then((runtime) => {
|
|
1550
|
+
${registerRemoteCode}
|
|
1551
|
+
return runtime.loadRemote(${JSON.stringify(id)});
|
|
1552
|
+
})
|
|
1553
|
+
.then((mod) => {
|
|
1554
|
+
__mfModuleCache.remote[${JSON.stringify(id)}] = mod;
|
|
1555
|
+
delete __mfModuleCache.remote[pendingKey];
|
|
1556
|
+
return mod;
|
|
1557
|
+
})
|
|
1558
|
+
${remoteLoadFailureHandler};
|
|
1559
|
+
}
|
|
1560
|
+
return __mfModuleCache.remote[pendingKey];`}
|
|
1561
|
+
}
|
|
1735
1562
|
function __mfCreateRemoteProxy(pendingPromise) {
|
|
1736
1563
|
const listeners = new Set();
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1564
|
+
const ensurePending = () => {
|
|
1565
|
+
pendingPromise ||= __mfStartRemoteLoad();
|
|
1566
|
+
pendingPromise?.finally(() => {
|
|
1567
|
+
for (const listener of listeners) listener();
|
|
1568
|
+
});
|
|
1569
|
+
return pendingPromise;
|
|
1570
|
+
};
|
|
1740
1571
|
const getModule = () => __mfModuleCache.remote[${JSON.stringify(id)}];
|
|
1741
1572
|
const proxyTarget = function (...args) {
|
|
1742
1573
|
${useReactProxy ? `const [, setVersion] = __mfReact.useState(0);
|
|
1743
1574
|
__mfReact.useEffect(() => {
|
|
1575
|
+
ensurePending();
|
|
1744
1576
|
const listener = () => setVersion((value) => value + 1);
|
|
1745
1577
|
listeners.add(listener);
|
|
1746
1578
|
if (getModule()) listener();
|
|
@@ -1751,18 +1583,33 @@ export default exportModule?.__mf_is_remote_proxy ? exportModule : exportModule?
|
|
|
1751
1583
|
if (fn !== undefined && fn !== null) {
|
|
1752
1584
|
${useReactProxy ? `return __mfReact.createElement(fn, args[0]);` : `return fn.apply(this, args);`}
|
|
1753
1585
|
}
|
|
1754
|
-
${useReactProxy ? `return null;` : `throw
|
|
1586
|
+
${useReactProxy ? `return null;` : `throw ensurePending();`}
|
|
1755
1587
|
};
|
|
1756
1588
|
return new Proxy(proxyTarget, {
|
|
1757
1589
|
get(_target, prop) {
|
|
1758
1590
|
if (prop === "__mf_is_remote_proxy") return true;
|
|
1759
1591
|
if (prop === "__esModule") return true;
|
|
1760
1592
|
if (prop === "then") return undefined;
|
|
1593
|
+
// Allow React's dev-mode console.warn to stringify the proxy without
|
|
1594
|
+
// throwing "Cannot convert object to primitive value".
|
|
1595
|
+
if (prop === Symbol.toPrimitive || prop === "toString")
|
|
1596
|
+
return () => "[MF remote proxy: pending]";
|
|
1761
1597
|
const mod = getModule();
|
|
1762
1598
|
if (mod) {
|
|
1763
1599
|
return prop in mod ? mod[prop] : mod.default?.[prop];
|
|
1764
1600
|
}
|
|
1765
|
-
|
|
1601
|
+
// When the module is pending and React.lazy() checks for "default",
|
|
1602
|
+
// return the proxy function itself so React renders it (returns null)
|
|
1603
|
+
// rather than crashing on undefined.
|
|
1604
|
+
${useReactProxy ? `if (prop === "default") return proxyTarget;
|
|
1605
|
+
return undefined;` : `throw ensurePending();`}
|
|
1606
|
+
},
|
|
1607
|
+
has(_target, prop) {
|
|
1608
|
+
const mod = getModule();
|
|
1609
|
+
if (mod) return prop in mod;
|
|
1610
|
+
// Tell React that "default" exists when module is pending so it
|
|
1611
|
+
// doesn't warn "lazy: Expected the result of a dynamic import()".
|
|
1612
|
+
${useReactProxy ? `return prop === "default" || prop === "__esModule" || prop === "__mf_is_remote_proxy";` : `return false;`}
|
|
1766
1613
|
},
|
|
1767
1614
|
ownKeys() {
|
|
1768
1615
|
const mod = getModule();
|
|
@@ -1790,40 +1637,12 @@ export default exportModule?.__mf_is_remote_proxy ? exportModule : exportModule?
|
|
|
1790
1637
|
return target.apply(thisArg, args);
|
|
1791
1638
|
}
|
|
1792
1639
|
});
|
|
1793
|
-
}`
|
|
1640
|
+
}`}
|
|
1794
1641
|
let __mfRemotePending;
|
|
1795
1642
|
let exportModule = __mfModuleCache.remote[${JSON.stringify(id)}]
|
|
1796
1643
|
if (exportModule === undefined) {
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
__mfModuleCache.remote[pendingKey] = initPromise
|
|
1800
|
-
.then((runtime) => runtime.loadRemote(${JSON.stringify(id)}))
|
|
1801
|
-
.then((mod) => {
|
|
1802
|
-
__mfModuleCache.remote[${JSON.stringify(id)}] = mod;
|
|
1803
|
-
delete __mfModuleCache.remote[pendingKey];
|
|
1804
|
-
return mod;
|
|
1805
|
-
})
|
|
1806
|
-
.catch(() => {
|
|
1807
|
-
delete __mfModuleCache.remote[pendingKey];
|
|
1808
|
-
});
|
|
1809
|
-
}` : ""}
|
|
1810
|
-
${command !== "build" ? `__mfRemotePending = __mfModuleCache.remote[pendingKey];
|
|
1811
|
-
exportModule = __mfCreateRemoteProxy(__mfRemotePending);` : `const pendingKey = ${JSON.stringify(`__mf_pending__${id}`)};
|
|
1812
|
-
if (!__mfModuleCache.remote[pendingKey]) {
|
|
1813
|
-
__mfModuleCache.remote[pendingKey] = __mfHostInitPromise
|
|
1814
|
-
.then((runtime) => runtime.loadRemote(${JSON.stringify(id)}))
|
|
1815
|
-
.then((mod) => {
|
|
1816
|
-
__mfModuleCache.remote[${JSON.stringify(id)}] = mod;
|
|
1817
|
-
delete __mfModuleCache.remote[pendingKey];
|
|
1818
|
-
return mod;
|
|
1819
|
-
})
|
|
1820
|
-
.catch((error) => {
|
|
1821
|
-
delete __mfModuleCache.remote[pendingKey];
|
|
1822
|
-
throw error;
|
|
1823
|
-
});
|
|
1824
|
-
}
|
|
1825
|
-
__mfRemotePending = __mfModuleCache.remote[pendingKey];
|
|
1826
|
-
exportModule = {};`}
|
|
1644
|
+
__mfRemotePending = __mfStartRemoteLoad();
|
|
1645
|
+
exportModule = __mfCreateRemoteProxy(__mfRemotePending);
|
|
1827
1646
|
}
|
|
1828
1647
|
${exportLine}
|
|
1829
1648
|
`;
|
|
@@ -1833,7 +1652,38 @@ export default exportModule?.__mf_is_remote_proxy ? exportModule : exportModule?
|
|
|
1833
1652
|
function getFirstHtmlEntryFile(entryFiles) {
|
|
1834
1653
|
return entryFiles.find((file) => file.endsWith(".html"));
|
|
1835
1654
|
}
|
|
1836
|
-
|
|
1655
|
+
function stripQueryAndHash(file) {
|
|
1656
|
+
return file.split(/[?#]/)[0];
|
|
1657
|
+
}
|
|
1658
|
+
function getBuildInput(config) {
|
|
1659
|
+
return config.build?.rollupOptions?.input ?? config.build?.rolldownOptions?.input;
|
|
1660
|
+
}
|
|
1661
|
+
function patchHashEntryFileName(output, entryName, fileName) {
|
|
1662
|
+
const originalEntryFileNames = output.entryFileNames;
|
|
1663
|
+
output.entryFileNames = (chunkInfo, ...args) => {
|
|
1664
|
+
if (chunkInfo?.name === entryName) return fileName;
|
|
1665
|
+
if (typeof originalEntryFileNames === "function") return originalEntryFileNames(chunkInfo, ...args);
|
|
1666
|
+
return originalEntryFileNames || "assets/[name]-[hash].js";
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
function patchHashEntryFileNames(config, entryName, fileName) {
|
|
1670
|
+
if (!fileName?.includes?.("[hash")) return;
|
|
1671
|
+
config.build ??= {};
|
|
1672
|
+
config.build.rollupOptions ??= {};
|
|
1673
|
+
config.build.rolldownOptions ??= {};
|
|
1674
|
+
const patchOutput = (output) => patchHashEntryFileName(output, entryName, fileName);
|
|
1675
|
+
const patchBundlerOutput = (bundlerOptions) => {
|
|
1676
|
+
const output = bundlerOptions.output;
|
|
1677
|
+
if (Array.isArray(output)) {
|
|
1678
|
+
output.forEach(patchOutput);
|
|
1679
|
+
return;
|
|
1680
|
+
}
|
|
1681
|
+
patchOutput(bundlerOptions.output ??= {});
|
|
1682
|
+
};
|
|
1683
|
+
patchBundlerOutput(config.build.rollupOptions);
|
|
1684
|
+
patchBundlerOutput(config.build.rolldownOptions);
|
|
1685
|
+
}
|
|
1686
|
+
const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClientInjected, skipTransformFor = [] }) => {
|
|
1837
1687
|
const DEV_HTML_PROXY_PREFIX = "virtual:mf-html-entry-proxy?";
|
|
1838
1688
|
const ENTRY_BOOTSTRAP_QUERY = "?mf-entry-bootstrap";
|
|
1839
1689
|
const waitsForInit = entryName === "hostInit";
|
|
@@ -1846,11 +1696,12 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
|
|
|
1846
1696
|
let viteConfig;
|
|
1847
1697
|
let clientInjected = forceClientInjected ?? false;
|
|
1848
1698
|
let emittedFileName;
|
|
1699
|
+
let skipTransformIds = /* @__PURE__ */ new Set();
|
|
1849
1700
|
function skipSvelteKitSsrBuild() {
|
|
1850
|
-
return (_command === "build" || viteConfig?.command === "build") && viteConfig?.build?.ssr && hasPackageDependency("@sveltejs/kit");
|
|
1701
|
+
return (_command === "build" || viteConfig?.command === "build") && viteConfig?.build?.ssr && require_packageUtils.hasPackageDependency("@sveltejs/kit");
|
|
1851
1702
|
}
|
|
1852
1703
|
function isSvelteKitServerModule(id) {
|
|
1853
|
-
return hasPackageDependency("@sveltejs/kit") && (id.includes(".svelte-kit/generated/") || id.includes("/@sveltejs/kit/src/runtime/server/"));
|
|
1704
|
+
return require_packageUtils.hasPackageDependency("@sveltejs/kit") && (id.includes(".svelte-kit/generated/") || id.includes("/@sveltejs/kit/src/runtime/server/"));
|
|
1854
1705
|
}
|
|
1855
1706
|
function rewriteSvelteKitInlineStart(html, initPath) {
|
|
1856
1707
|
return html.replace(/<script>([\s\S]*?)<\/script>/gi, (scriptTag, body) => {
|
|
@@ -1901,35 +1752,81 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
|
|
|
1901
1752
|
return patched;
|
|
1902
1753
|
}
|
|
1903
1754
|
function getBootstrapSource(initSrc, entrySrc, useSystemImportFallback = false) {
|
|
1904
|
-
const remotePreloads = Object.entries(getUsedRemotesMap()).flatMap(([remoteKey, remotes]) => Array.from(remotes).filter((remote) => remote !== remoteKey)).sort().map((remote) => `runtime.loadRemote(${JSON.stringify(remote)})`).join(",");
|
|
1905
1755
|
const importHelper = useSystemImportFallback ? `const __mfImport = (src) =>
|
|
1906
1756
|
globalThis.System && typeof globalThis.System.import === 'function'
|
|
1907
1757
|
? globalThis.System.import(src)
|
|
1908
1758
|
: import(src);
|
|
1909
1759
|
` : "";
|
|
1910
1760
|
const importExpression = (src) => useSystemImportFallback ? `__mfImport(${JSON.stringify(src)})` : `import(${JSON.stringify(src)})`;
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
const { initHost } = await ${importExpression(initSrc)};
|
|
1761
|
+
const remotePreloads = getNormalizeModuleFederationOptions()?.shareStrategy !== "loaded-first" ? Object.entries(getUsedRemotesMap()).flatMap(([remoteKey, remotes]) => Array.from(remotes).filter((remote) => remote !== remoteKey)).sort().map((remote) => `__mfPreloadRemote(${JSON.stringify(remote)})`).join(",") : "";
|
|
1762
|
+
const preloadBlock = remotePreloads ? `
|
|
1914
1763
|
const runtime = await initHost();
|
|
1764
|
+
const __mfPreloadRemote = (remote) => {
|
|
1765
|
+
const pendingKey = "__mf_pending__" + remote;
|
|
1766
|
+
if (!__mfModuleCache.remote[pendingKey]) {
|
|
1767
|
+
__mfModuleCache.remote[pendingKey] = runtime.loadRemote(remote)
|
|
1768
|
+
.then((mod) => {
|
|
1769
|
+
__mfModuleCache.remote[remote] = mod;
|
|
1770
|
+
delete __mfModuleCache.remote[pendingKey];
|
|
1771
|
+
return mod;
|
|
1772
|
+
})
|
|
1773
|
+
.catch((error) => {
|
|
1774
|
+
delete __mfModuleCache.remote[pendingKey];
|
|
1775
|
+
throw error;
|
|
1776
|
+
});
|
|
1777
|
+
}
|
|
1778
|
+
return __mfModuleCache.remote[pendingKey];
|
|
1779
|
+
};
|
|
1915
1780
|
const __mfRemotePreloads = [${remotePreloads}];
|
|
1916
|
-
await Promise.
|
|
1781
|
+
await Promise.allSettled(__mfRemotePreloads);` : `await initHost();`;
|
|
1782
|
+
const importCode = `
|
|
1783
|
+
(async () => {
|
|
1784
|
+
const { initHost } = await ${importExpression(initSrc)};
|
|
1785
|
+
${preloadBlock}
|
|
1917
1786
|
})().then(() => ${importExpression(entrySrc)});
|
|
1918
1787
|
`;
|
|
1788
|
+
return [
|
|
1789
|
+
getRuntimeModuleCacheBootstrapCode(),
|
|
1790
|
+
importHelper,
|
|
1791
|
+
importCode
|
|
1792
|
+
].join("\n");
|
|
1919
1793
|
}
|
|
1920
1794
|
function getSystemBootstrapSource(initSrc, entrySrc) {
|
|
1921
1795
|
return getBootstrapSource(initSrc, entrySrc, true);
|
|
1922
1796
|
}
|
|
1923
1797
|
function injectHtml() {
|
|
1924
|
-
return inject === "html" && (htmlFilePath || hasPackageDependency("@sveltejs/kit"));
|
|
1798
|
+
return inject === "html" && (htmlFilePath || require_packageUtils.hasPackageDependency("@sveltejs/kit"));
|
|
1925
1799
|
}
|
|
1926
1800
|
function injectEntry() {
|
|
1927
|
-
if (inject === "html" && hasPackageDependency("@sveltejs/kit")) return false;
|
|
1801
|
+
if (inject === "html" && require_packageUtils.hasPackageDependency("@sveltejs/kit")) return false;
|
|
1928
1802
|
return inject === "entry" || !htmlFilePath;
|
|
1929
1803
|
}
|
|
1930
1804
|
function normalizeDevHtmlProxyId(id) {
|
|
1931
1805
|
return id.replace(/^\0/, "").replace(/^\/@id\//, "").replace(/^__x00__/, "");
|
|
1932
1806
|
}
|
|
1807
|
+
function normalizeModuleId(id) {
|
|
1808
|
+
return id.split("?")[0].replace(/\\/g, "/");
|
|
1809
|
+
}
|
|
1810
|
+
function resolveProjectId(id) {
|
|
1811
|
+
if (id.startsWith("\0") || id.startsWith("virtual:")) return normalizeModuleId(id);
|
|
1812
|
+
return normalizeModuleId(pathe.isAbsolute(id) ? id : pathe.resolve(viteConfig.root, id));
|
|
1813
|
+
}
|
|
1814
|
+
function addEntryFile(file) {
|
|
1815
|
+
const normalized = normalizeModuleId(file);
|
|
1816
|
+
if (!entryFiles.includes(normalized)) entryFiles.push(normalized);
|
|
1817
|
+
}
|
|
1818
|
+
function addHtmlScriptEntries(htmlPath) {
|
|
1819
|
+
if (!fs.existsSync(htmlPath)) return;
|
|
1820
|
+
const htmlContent = fs.readFileSync(htmlPath, "utf-8");
|
|
1821
|
+
const scriptRegex = /<script\b(?=[^>]*\btype=["']module["'])(?=[^>]*\bsrc=["']([^"']+)["'])[^>]*>/gi;
|
|
1822
|
+
let match;
|
|
1823
|
+
while ((match = scriptRegex.exec(htmlContent)) !== null) {
|
|
1824
|
+
const scriptSrc = stripQueryAndHash(match[1]);
|
|
1825
|
+
if (/^(?:[a-z]+:)?\/\//i.test(scriptSrc)) continue;
|
|
1826
|
+
addEntryFile(scriptSrc);
|
|
1827
|
+
addEntryFile(scriptSrc.startsWith("/") ? pathe.resolve(viteConfig.root, scriptSrc.slice(1)) : pathe.resolve(pathe.dirname(htmlPath), scriptSrc));
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1933
1830
|
return [{
|
|
1934
1831
|
name: "add-entry",
|
|
1935
1832
|
apply: "serve",
|
|
@@ -1946,6 +1843,7 @@ ${importHelper}(async () => {
|
|
|
1946
1843
|
const relativePath = normalized.startsWith(root + "/") ? normalized.slice(root.length) : "/" + normalized.replace(/^[A-Za-z]:[\\/]/, "");
|
|
1947
1844
|
devEntryPath = config.base + relativePath.replace(/^\//, "");
|
|
1948
1845
|
}
|
|
1846
|
+
skipTransformIds = new Set(skipTransformFor.map(resolveProjectId));
|
|
1949
1847
|
},
|
|
1950
1848
|
configureServer(server) {
|
|
1951
1849
|
server.middlewares.use((req, res, next) => {
|
|
@@ -1973,7 +1871,8 @@ ${importHelper}(async () => {
|
|
|
1973
1871
|
transformIndexHtml: {
|
|
1974
1872
|
order: "pre",
|
|
1975
1873
|
handler(c) {
|
|
1976
|
-
|
|
1874
|
+
const shouldWrapEntryHtml = _command === "serve" && inject === "entry" && waitsForInit;
|
|
1875
|
+
if (!injectHtml() && !shouldWrapEntryHtml) return;
|
|
1977
1876
|
clientInjected = true;
|
|
1978
1877
|
const base = viteConfig.base.replace(/\/$/, "");
|
|
1979
1878
|
const stripBase = (p) => base && p.startsWith(base + "/") ? p.slice(base.length) : p;
|
|
@@ -2005,24 +1904,30 @@ ${importHelper}(async () => {
|
|
|
2005
1904
|
}, {
|
|
2006
1905
|
name: "add-entry",
|
|
2007
1906
|
enforce: "post",
|
|
1907
|
+
applyToEnvironment() {
|
|
1908
|
+
return true;
|
|
1909
|
+
},
|
|
1910
|
+
config(config) {
|
|
1911
|
+
patchHashEntryFileNames(config, entryName, fileName);
|
|
1912
|
+
},
|
|
2008
1913
|
configResolved(config) {
|
|
2009
1914
|
viteConfig = config;
|
|
2010
|
-
|
|
1915
|
+
skipTransformIds = new Set(skipTransformFor.map(resolveProjectId));
|
|
1916
|
+
const ctx = this;
|
|
1917
|
+
const envName = ctx != null && typeof ctx === "object" ? ctx["environment"] : void 0;
|
|
1918
|
+
if (envName?.name && envName.name !== "client") return;
|
|
1919
|
+
const inputOptions = getBuildInput(config);
|
|
2011
1920
|
if (!inputOptions) htmlFilePath = pathe.resolve(config.root, "index.html");
|
|
2012
|
-
else if (typeof inputOptions === "string") entryFiles = [inputOptions];
|
|
2013
|
-
else if (Array.isArray(inputOptions)) entryFiles = inputOptions;
|
|
2014
|
-
else if (typeof inputOptions === "object") entryFiles = Object.values(inputOptions);
|
|
1921
|
+
else if (typeof inputOptions === "string") entryFiles = [normalizeModuleId(inputOptions)];
|
|
1922
|
+
else if (Array.isArray(inputOptions)) entryFiles = inputOptions.map(normalizeModuleId);
|
|
1923
|
+
else if (typeof inputOptions === "object") entryFiles = Object.values(inputOptions).map((input) => normalizeModuleId(String(input)));
|
|
2015
1924
|
if (entryFiles.length > 0) htmlFilePath = getFirstHtmlEntryFile(entryFiles);
|
|
2016
|
-
if (
|
|
2017
|
-
const htmlContent = fs.readFileSync(htmlFilePath, "utf-8");
|
|
2018
|
-
const scriptRegex = /<script\s+[^>]*src=["']([^"']+)["'][^>]*>/gi;
|
|
2019
|
-
let match;
|
|
2020
|
-
while ((match = scriptRegex.exec(htmlContent)) !== null) entryFiles.push(match[1]);
|
|
2021
|
-
}
|
|
1925
|
+
if (htmlFilePath) addHtmlScriptEntries(htmlFilePath);
|
|
2022
1926
|
},
|
|
2023
1927
|
buildStart() {
|
|
2024
1928
|
if (_command === "serve") return;
|
|
2025
1929
|
if (skipSvelteKitSsrBuild()) return;
|
|
1930
|
+
if (this.environment?.name === "ssr") return;
|
|
2026
1931
|
const hasHash = fileName?.includes?.("[hash");
|
|
2027
1932
|
const emitFileOptions = {
|
|
2028
1933
|
name: entryName,
|
|
@@ -2032,16 +1937,14 @@ ${importHelper}(async () => {
|
|
|
2032
1937
|
};
|
|
2033
1938
|
if (!hasHash) emitFileOptions.fileName = fileName;
|
|
2034
1939
|
emitFileId = this.emitFile(emitFileOptions);
|
|
2035
|
-
if (htmlFilePath
|
|
2036
|
-
const htmlContent = fs.readFileSync(htmlFilePath, "utf-8");
|
|
2037
|
-
const scriptRegex = /<script\s+[^>]*src=["']([^"']+)["'][^>]*>/gi;
|
|
2038
|
-
let match;
|
|
2039
|
-
while ((match = scriptRegex.exec(htmlContent)) !== null) entryFiles.push(match[1]);
|
|
2040
|
-
}
|
|
1940
|
+
if (htmlFilePath) addHtmlScriptEntries(htmlFilePath);
|
|
2041
1941
|
},
|
|
2042
1942
|
generateBundle(_options, bundle) {
|
|
2043
1943
|
if (skipSvelteKitSsrBuild()) return;
|
|
2044
1944
|
if (!injectHtml()) return;
|
|
1945
|
+
if (!emitFileId) return;
|
|
1946
|
+
const htmlFileNames = Object.keys(bundle).filter((fileName) => fileName.endsWith(".html"));
|
|
1947
|
+
if (htmlFileNames.length === 0) return;
|
|
2045
1948
|
const file = this.getFileName(emitFileId);
|
|
2046
1949
|
emittedFileName = file;
|
|
2047
1950
|
const resolvePath = (htmlFileName) => {
|
|
@@ -2055,7 +1958,7 @@ ${importHelper}(async () => {
|
|
|
2055
1958
|
if (typeof result === "string") return result;
|
|
2056
1959
|
if (result && typeof result === "object") {
|
|
2057
1960
|
if ("runtime" in result) {
|
|
2058
|
-
mfWarn("renderBuiltUrl returned runtime code for HTML injection. Runtime code cannot be used in <script src=\"\">. Falling back to base path.");
|
|
1961
|
+
require_packageUtils.mfWarn("renderBuiltUrl returned runtime code for HTML injection. Runtime code cannot be used in <script src=\"\">. Falling back to base path.");
|
|
2059
1962
|
return viteConfig.base + file;
|
|
2060
1963
|
}
|
|
2061
1964
|
if (result.relative) return file;
|
|
@@ -2063,7 +1966,7 @@ ${importHelper}(async () => {
|
|
|
2063
1966
|
return viteConfig.base + file;
|
|
2064
1967
|
};
|
|
2065
1968
|
let bootstrapIndex = 0;
|
|
2066
|
-
for (const fileName
|
|
1969
|
+
for (const fileName of htmlFileNames) {
|
|
2067
1970
|
let htmlAsset = bundle[fileName];
|
|
2068
1971
|
if (htmlAsset.type === "chunk") return;
|
|
2069
1972
|
let htmlContent = htmlAsset.source.toString() || "";
|
|
@@ -2072,11 +1975,13 @@ ${importHelper}(async () => {
|
|
|
2072
1975
|
let rewritten = false;
|
|
2073
1976
|
htmlContent = htmlContent.replace(scriptRegex, (scriptTag, entrySrc) => {
|
|
2074
1977
|
rewritten = true;
|
|
2075
|
-
const
|
|
1978
|
+
const bootstrapSource = getSystemBootstrapSource(initPath, entrySrc);
|
|
1979
|
+
const bootstrapHash = (0, node_crypto.createHash)("sha256").update(bootstrapSource).digest("hex").slice(0, 8);
|
|
1980
|
+
const bootstrapFileName = `mf-entry-bootstrap-${bootstrapIndex++}-${bootstrapHash}.js`;
|
|
2076
1981
|
const bootstrapRef = this.emitFile({
|
|
2077
1982
|
type: "asset",
|
|
2078
1983
|
fileName: bootstrapFileName,
|
|
2079
|
-
source:
|
|
1984
|
+
source: bootstrapSource
|
|
2080
1985
|
});
|
|
2081
1986
|
const bootstrapPath = viteConfig.base + this.getFileName(bootstrapRef);
|
|
2082
1987
|
return scriptTag.replace(entrySrc, bootstrapPath);
|
|
@@ -2108,7 +2013,12 @@ ${importHelper}(async () => {
|
|
|
2108
2013
|
if (skipSvelteKitSsrBuild()) return;
|
|
2109
2014
|
if (isSvelteKitServerModule(id)) return;
|
|
2110
2015
|
if (id.includes(ENTRY_BOOTSTRAP_QUERY)) return;
|
|
2111
|
-
|
|
2016
|
+
if (normalizeModuleId(id).endsWith(".html")) return;
|
|
2017
|
+
if (skipTransformIds.has(resolveProjectId(id))) return;
|
|
2018
|
+
const transformCtx = this;
|
|
2019
|
+
const transformEnv = transformCtx != null && typeof transformCtx === "object" ? transformCtx["environment"] : void 0;
|
|
2020
|
+
if (transformEnv?.name && transformEnv.name !== "client") return;
|
|
2021
|
+
const isVinext = require_packageUtils.hasPackageDependency("vinext");
|
|
2112
2022
|
if (isVinext && inject === "html" && id.includes("virtual:vite-rsc/remove-duplicate-server-css")) {
|
|
2113
2023
|
const namespaceReactImport = `import * as React from 'react';`;
|
|
2114
2024
|
if (code.includes(namespaceReactImport)) return;
|
|
@@ -2124,9 +2034,16 @@ ${importHelper}(async () => {
|
|
|
2124
2034
|
clientInjected = true;
|
|
2125
2035
|
return mapCodeToCodeWithSourcemap(injection + code);
|
|
2126
2036
|
}
|
|
2127
|
-
if (
|
|
2037
|
+
if (_command === "serve" && inject === "entry" && waitsForInit && !clientInjected && /(?:^|\/)nuxt\/dist\/app\/entry\.js(?:\?|$)/.test(id) && code.includes("vueApp.mount(vueAppRootContainer);")) {
|
|
2038
|
+
clientInjected = true;
|
|
2039
|
+
const injection = `await import(${JSON.stringify(getEntryPath())}).then(({ initHost }) => initHost());\n `;
|
|
2040
|
+
return mapCodeToCodeWithSourcemap(code.replace("vueApp.mount(vueAppRootContainer);", `${injection}vueApp.mount(vueAppRootContainer);`));
|
|
2041
|
+
}
|
|
2042
|
+
const isHydrationEntryFallback = inject === "entry" && entryFiles.length === 0 && (!htmlFilePath || !fs.existsSync(htmlFilePath)) && !clientInjected && !id.includes("node_modules") && (id.startsWith("\0") || /\.(js|ts|mjs|vue|jsx|tsx)(\?|$)/.test(id)) && /hydrateRoot|createRoot|ReactDOM\.render/.test(code);
|
|
2043
|
+
const isNuxtClientEntryFallback = _command === "serve" && inject === "entry" && entryFiles.length === 0 && (!htmlFilePath || !fs.existsSync(htmlFilePath)) && !clientInjected && !id.includes("node_modules/.vite") && /(?:^|\/)nuxt\/dist\/app\/entry\.async\.js(?:\?|$)/.test(id) && code.includes("entry();");
|
|
2044
|
+
if (injectEntry() && entryFiles.some((file) => resolveProjectId(id) === file) || _command === "serve" && inject === "html" && !isVinext && !clientInjected && !id.startsWith("\0") && !id.includes("node_modules") && /\.(js|ts|mjs|vue|jsx|tsx)(\?|$)/.test(id) || isHydrationEntryFallback || isNuxtClientEntryFallback) {
|
|
2128
2045
|
clientInjected = true;
|
|
2129
|
-
if (!waitsForInit) return mapCodeToCodeWithSourcemap(`import ${JSON.stringify(getEntryPath())};\n` + code);
|
|
2046
|
+
if (!waitsForInit || _command === "serve" && inject === "entry" && isHydrationEntryFallback) return mapCodeToCodeWithSourcemap(`import ${JSON.stringify(getEntryPath())};\n` + code);
|
|
2130
2047
|
const entrySrc = id.includes("?") ? `${id}&${ENTRY_BOOTSTRAP_QUERY.slice(1)}` : `${id}${ENTRY_BOOTSTRAP_QUERY}`;
|
|
2131
2048
|
return mapCodeToCodeWithSourcemap(getBootstrapSource(getEntryPath(), entrySrc));
|
|
2132
2049
|
}
|
|
@@ -2159,7 +2076,7 @@ function checkAliasConflicts(options) {
|
|
|
2159
2076
|
if (!matchesSharedKey(aliasEntry, sharedKey)) continue;
|
|
2160
2077
|
if (replacement === "$1") break;
|
|
2161
2078
|
if (typeof replacement === "string") {
|
|
2162
|
-
if (getPackageNameFromNodeModulePath(replacement) === (sharedKey.endsWith("/") ? sharedKey.slice(0, -1) : sharedKey)) continue;
|
|
2079
|
+
if (require_packageUtils.getPackageNameFromNodeModulePath(replacement) === (sharedKey.endsWith("/") ? sharedKey.slice(0, -1) : sharedKey)) continue;
|
|
2163
2080
|
conflicts.push({
|
|
2164
2081
|
sharedModule: sharedKey,
|
|
2165
2082
|
alias: String(aliasEntry.find),
|
|
@@ -2168,21 +2085,17 @@ function checkAliasConflicts(options) {
|
|
|
2168
2085
|
}
|
|
2169
2086
|
}
|
|
2170
2087
|
if (conflicts.length > 0) {
|
|
2171
|
-
mfWarn("Detected alias conflicts with shared modules:");
|
|
2088
|
+
require_packageUtils.mfWarn("Detected alias conflicts with shared modules:");
|
|
2172
2089
|
conflicts.forEach(({ sharedModule, alias, target }) => {
|
|
2173
|
-
mfWarn(`Shared module "${sharedModule}" is aliased by "${alias}" to "${target}"`);
|
|
2090
|
+
require_packageUtils.mfWarn(`Shared module "${sharedModule}" is aliased by "${alias}" to "${target}"`);
|
|
2174
2091
|
});
|
|
2175
|
-
mfWarn("This may cause runtime errors as the shared module will bypass Module Federation's sharing mechanism.");
|
|
2092
|
+
require_packageUtils.mfWarn("This may cause runtime errors as the shared module will bypass Module Federation's sharing mechanism.");
|
|
2176
2093
|
}
|
|
2177
2094
|
}
|
|
2178
2095
|
};
|
|
2179
2096
|
}
|
|
2180
2097
|
//#endregion
|
|
2181
|
-
//#region src/plugins/
|
|
2182
|
-
const REMOTE_HMR_ENDPOINT = "__mf_hmr";
|
|
2183
|
-
const REMOTE_HMR_EVENT = "mf:remote-update";
|
|
2184
|
-
const REMOTE_HMR_CONNECT_RETRY_DELAY_MS = 1e3;
|
|
2185
|
-
const REMOTE_HMR_CONNECT_MAX_RETRIES = 10;
|
|
2098
|
+
//#region src/plugins/hmr/react.ts
|
|
2186
2099
|
/**
|
|
2187
2100
|
* Proxy module served for `/@react-refresh` on MF remote dev servers.
|
|
2188
2101
|
* Delegates to the host page's RefreshRuntime instance via
|
|
@@ -2202,6 +2115,112 @@ const REACT_REFRESH_PROXY_MODULE = [
|
|
|
2202
2115
|
`export const __hmr_import = __rt.__hmr_import;`,
|
|
2203
2116
|
`export default __rt.default || __rt;`
|
|
2204
2117
|
].join("\n");
|
|
2118
|
+
const reactAdapter = {
|
|
2119
|
+
name: "react",
|
|
2120
|
+
pluginNames: ["vite:react-refresh", "vite:react-swc:refresh"],
|
|
2121
|
+
remote: { configureServer({ server }) {
|
|
2122
|
+
server.middlewares.use((req, res, next) => {
|
|
2123
|
+
if (req.url?.replace(/\?.*$/, "") !== "/@react-refresh") return next();
|
|
2124
|
+
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
2125
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
2126
|
+
res.end(REACT_REFRESH_PROXY_MODULE);
|
|
2127
|
+
});
|
|
2128
|
+
} }
|
|
2129
|
+
};
|
|
2130
|
+
//#endregion
|
|
2131
|
+
//#region src/plugins/hmr/vue.ts
|
|
2132
|
+
/**
|
|
2133
|
+
* In dev mode each Vite dev server serves its own copy of Vue
|
|
2134
|
+
* (`/node_modules/.vite/deps/vue.js`). When a remote module is loaded into the
|
|
2135
|
+
* host page, the remote's Vue copy evaluates and runs:
|
|
2136
|
+
*
|
|
2137
|
+
* globalThis.__VUE_HMR_RUNTIME__ = createHotReloadAPI()
|
|
2138
|
+
*
|
|
2139
|
+
* which silently overwrites the host's runtime. After that, `createRecord` for
|
|
2140
|
+
* host components lives in the orphaned first runtime, but `reload(hmrId, ...)`
|
|
2141
|
+
* goes through the second runtime — the lookup misses and HMR stops working.
|
|
2142
|
+
*
|
|
2143
|
+
* This guard pins `__VUE_HMR_RUNTIME__` to the first writer (the host's Vue)
|
|
2144
|
+
* via a property trap on `globalThis`. Subsequent writes from remote-side Vue
|
|
2145
|
+
* copies are silently dropped. Must execute before any Vue module loads —
|
|
2146
|
+
* injected as a plain (non-module) script at `head-prepend`.
|
|
2147
|
+
*
|
|
2148
|
+
* `singleton: true` in `shared` is not sufficient: in dev mode MF's share-scope
|
|
2149
|
+
* does not actually dedupe Vue across dev servers, so without this guard the
|
|
2150
|
+
* last-loaded copy wins.
|
|
2151
|
+
*/
|
|
2152
|
+
const VUE_HMR_RUNTIME_GUARD_SCRIPT = `
|
|
2153
|
+
(function () {
|
|
2154
|
+
var h = null;
|
|
2155
|
+
Object.defineProperty(globalThis, '__VUE_HMR_RUNTIME__', {
|
|
2156
|
+
get: function () { return h; },
|
|
2157
|
+
set: function (v) { if (h === null) h = v; },
|
|
2158
|
+
configurable: true,
|
|
2159
|
+
enumerable: true,
|
|
2160
|
+
});
|
|
2161
|
+
})();`;
|
|
2162
|
+
/**
|
|
2163
|
+
* `@vitejs/plugin-vue` derives an SFC's `__hmrId` from a hash of the file path
|
|
2164
|
+
* relative to Vite's `root`. With module federation, host and remote are
|
|
2165
|
+
* separate Vite projects with independent roots — so an SFC at `src/App.vue`
|
|
2166
|
+
* in both will hash to the same id. Once both copies of Vue collapse onto the
|
|
2167
|
+
* shared `__VUE_HMR_RUNTIME__` (see the guard above), the host's instance and
|
|
2168
|
+
* the remote's instance both register under that single id. A remote-only
|
|
2169
|
+
* file change then calls `rerender(id, newRender)`, which iterates *every*
|
|
2170
|
+
* instance under that id — including the host one — and applies the remote's
|
|
2171
|
+
* render function to the host instance. The host's `setupState` doesn't have
|
|
2172
|
+
* the remote's bindings, so the render throws and Vue falls back to a full
|
|
2173
|
+
* reload required warning.
|
|
2174
|
+
*
|
|
2175
|
+
* Fix: rewrite the remote's emitted `__hmrId` literal to be prefixed with the
|
|
2176
|
+
* federation `name`, so the remote's instances live under a distinct key. The
|
|
2177
|
+
* accept callback emitted by plugin-vue reads `_sfc_main.__hmrId` /
|
|
2178
|
+
* `updated.__hmrId` at runtime, so rewriting the literal once is enough.
|
|
2179
|
+
*/
|
|
2180
|
+
const SFC_HMR_ID_LITERAL_RE = /(\.__hmrId\s*=\s*["'`])([^"'`]+)(["'`])/g;
|
|
2181
|
+
function rewriteSfcHmrId(code, federationName) {
|
|
2182
|
+
let matched = false;
|
|
2183
|
+
return {
|
|
2184
|
+
code: code.replace(SFC_HMR_ID_LITERAL_RE, (_match, prefix, id, suffix) => {
|
|
2185
|
+
matched = true;
|
|
2186
|
+
if (id.startsWith(`${federationName}-`)) return `${prefix}${id}${suffix}`;
|
|
2187
|
+
return `${prefix}${federationName}-${id}${suffix}`;
|
|
2188
|
+
}),
|
|
2189
|
+
matched
|
|
2190
|
+
};
|
|
2191
|
+
}
|
|
2192
|
+
let pluginVueRegressionWarned = false;
|
|
2193
|
+
function warnPluginVueRegression() {
|
|
2194
|
+
if (pluginVueRegressionWarned) return;
|
|
2195
|
+
pluginVueRegressionWarned = true;
|
|
2196
|
+
require_packageUtils.mfWarn("Detected a Vue SFC module that calls `__VUE_HMR_RUNTIME__.createRecord(` but no `.__hmrId = \"...\"` literal could be rewritten. @vitejs/plugin-vue may have changed its output format — without the rewrite, host and remote SFCs that share a path will collide on the shared HMR runtime. Please report this to @module-federation/vite.");
|
|
2197
|
+
}
|
|
2198
|
+
const vueAdapter = {
|
|
2199
|
+
name: "vue",
|
|
2200
|
+
pluginNames: ["vite:vue", "vite:vue-jsx"],
|
|
2201
|
+
host: { transformIndexHtml() {
|
|
2202
|
+
return [{
|
|
2203
|
+
tag: "script",
|
|
2204
|
+
children: VUE_HMR_RUNTIME_GUARD_SCRIPT,
|
|
2205
|
+
injectTo: "head-prepend"
|
|
2206
|
+
}];
|
|
2207
|
+
} },
|
|
2208
|
+
remote: { transform(code, _id, ctx) {
|
|
2209
|
+
if (!code.includes("__VUE_HMR_RUNTIME__.createRecord(")) return;
|
|
2210
|
+
const { code: rewritten, matched } = rewriteSfcHmrId(code, ctx.options.name);
|
|
2211
|
+
if (!matched) {
|
|
2212
|
+
warnPluginVueRegression();
|
|
2213
|
+
return;
|
|
2214
|
+
}
|
|
2215
|
+
return rewritten === code ? void 0 : rewritten;
|
|
2216
|
+
} }
|
|
2217
|
+
};
|
|
2218
|
+
//#endregion
|
|
2219
|
+
//#region src/plugins/hmr/fullReload.ts
|
|
2220
|
+
const REMOTE_HMR_ENDPOINT = "__mf_hmr";
|
|
2221
|
+
const REMOTE_HMR_EVENT = "mf:remote-update";
|
|
2222
|
+
const REMOTE_HMR_CONNECT_RETRY_DELAY_MS = 1e3;
|
|
2223
|
+
const REMOTE_HMR_CONNECT_MAX_RETRIES = 10;
|
|
2205
2224
|
function getBasePath$1(base) {
|
|
2206
2225
|
if (!base) return "/";
|
|
2207
2226
|
if (base.startsWith("http://") || base.startsWith("https://")) try {
|
|
@@ -2220,9 +2239,6 @@ function getHmrWsPath(base, hmrPath) {
|
|
|
2220
2239
|
if (!normalizedPath || normalizedPath === "/") return normalizedBase;
|
|
2221
2240
|
return `${normalizedBase.endsWith("/") ? normalizedBase.slice(0, -1) : normalizedBase}/${normalizedPath.startsWith("/") ? normalizedPath.slice(1) : normalizedPath}`;
|
|
2222
2241
|
}
|
|
2223
|
-
function shouldIgnoreFile(file, options) {
|
|
2224
|
-
return file.includes("/node_modules/") || file.includes("\\node_modules\\") || file.includes(`/${options.virtualModuleDir}/`) || file.includes(`\\${options.virtualModuleDir}\\`) || file.includes("/.vite/") || file.includes("\\.vite\\") || file.includes("/.mf/") || file.includes("\\.mf\\") || file.includes("/mf-manifest.json") || file.includes("\\mf-manifest.json") || file.includes("/mf-stats.json") || file.includes("\\mf-stats.json");
|
|
2225
|
-
}
|
|
2226
2242
|
function getRemoteHmrWsUrl(server) {
|
|
2227
2243
|
const hmr = server.config.server.hmr;
|
|
2228
2244
|
return `${hmr && typeof hmr === "object" && hmr.protocol ? hmr.protocol : server.config.server.https ? "wss" : "ws"}://${hmr && typeof hmr === "object" && hmr.host ? hmr.host : typeof server.config.server.host === "string" && server.config.server.host !== "0.0.0.0" ? server.config.server.host : "localhost"}:${hmr && typeof hmr === "object" && (hmr.clientPort || hmr.port) ? hmr.clientPort || hmr.port : server.config.server.port}${getHmrWsPath(server.config.base, hmr && typeof hmr === "object" ? hmr.path : "")}?token=${server.config.webSocketToken}`;
|
|
@@ -2261,466 +2277,275 @@ function getStringPreview(value, max = 180) {
|
|
|
2261
2277
|
} catch {}
|
|
2262
2278
|
return rawValue.slice(0, max);
|
|
2263
2279
|
}
|
|
2264
|
-
|
|
2265
|
-
|
|
2280
|
+
/**
|
|
2281
|
+
* Installs the `/__mf_hmr` metadata endpoint on a remote dev server. The host
|
|
2282
|
+
* fetches this to discover the remote's HMR WebSocket URL before opening a
|
|
2283
|
+
* Node-to-Node relay socket. Always installed on remotes when `remoteHmr` is
|
|
2284
|
+
* enabled — under `'native'` strategy the endpoint is unused but harmless;
|
|
2285
|
+
* under `'full-reload'` it's the discovery hop for the host relay.
|
|
2286
|
+
*/
|
|
2287
|
+
function setupRemoteMetadataEndpoint(server, options) {
|
|
2288
|
+
const endpointPath = getRemoteHmrPath(server.config.base);
|
|
2289
|
+
const wsUrl = getRemoteHmrWsUrl(server);
|
|
2290
|
+
server.middlewares.use((req, res, next) => {
|
|
2291
|
+
if (req.url?.replace(/\?.*/, "") !== endpointPath) {
|
|
2292
|
+
next();
|
|
2293
|
+
return;
|
|
2294
|
+
}
|
|
2295
|
+
res.setHeader("Content-Type", "application/json");
|
|
2296
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
2297
|
+
res.end(JSON.stringify({
|
|
2298
|
+
remote: options.name,
|
|
2299
|
+
event: REMOTE_HMR_EVENT,
|
|
2300
|
+
wsUrl
|
|
2301
|
+
}));
|
|
2302
|
+
});
|
|
2266
2303
|
}
|
|
2267
2304
|
/**
|
|
2268
|
-
*
|
|
2269
|
-
*
|
|
2270
|
-
*
|
|
2305
|
+
* Installs file-watcher broadcasts on a remote dev server. Every non-ignored
|
|
2306
|
+
* change/add/unlink emits a `mf:remote-update` custom event on the remote's
|
|
2307
|
+
* own WS channel. The host relay (see `setupHostFullReloadRelay`) listens
|
|
2308
|
+
* for these events and triggers a host-side full reload in response.
|
|
2271
2309
|
*
|
|
2272
|
-
*
|
|
2310
|
+
* Only called under the `'full-reload'` strategy.
|
|
2273
2311
|
*/
|
|
2274
|
-
function
|
|
2275
|
-
const
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
name: "module-federation-dev-remote-hmr",
|
|
2285
|
-
apply: "serve",
|
|
2286
|
-
configureServer(server) {
|
|
2287
|
-
if (!isRemoteHmrEnabled(options.dev)) return;
|
|
2288
|
-
const isRemote = Object.keys(options.exposes).length > 0;
|
|
2289
|
-
const isHost = Object.keys(options.remotes).length > 0;
|
|
2290
|
-
const strategy = resolveHmrStrategy(options.dev, server.config.plugins);
|
|
2291
|
-
if (isRemote) {
|
|
2292
|
-
const endpointPath = getRemoteHmrPath(server.config.base);
|
|
2293
|
-
const wsUrl = getRemoteHmrWsUrl(server);
|
|
2294
|
-
server.middlewares.use((req, res, next) => {
|
|
2295
|
-
if (req.url?.replace(/\?.*$/, "") !== "/@react-refresh") return next();
|
|
2296
|
-
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
2297
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
2298
|
-
res.end(REACT_REFRESH_PROXY_MODULE);
|
|
2299
|
-
});
|
|
2300
|
-
server.middlewares.use((req, res, next) => {
|
|
2301
|
-
if (req.url?.replace(/\?.*/, "") !== endpointPath) {
|
|
2302
|
-
next();
|
|
2303
|
-
return;
|
|
2304
|
-
}
|
|
2305
|
-
res.setHeader("Content-Type", "application/json");
|
|
2306
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
2307
|
-
res.end(JSON.stringify({
|
|
2308
|
-
remote: options.name,
|
|
2309
|
-
event: REMOTE_HMR_EVENT,
|
|
2310
|
-
wsUrl
|
|
2311
|
-
}));
|
|
2312
|
-
});
|
|
2313
|
-
const broadcast = (file) => {
|
|
2314
|
-
if (strategy === "native") return;
|
|
2315
|
-
if (shouldIgnoreFile(file, options)) return;
|
|
2316
|
-
server.ws.send({
|
|
2317
|
-
type: "custom",
|
|
2318
|
-
event: REMOTE_HMR_EVENT,
|
|
2319
|
-
data: {
|
|
2320
|
-
remote: options.name,
|
|
2321
|
-
file,
|
|
2322
|
-
ts: Date.now()
|
|
2323
|
-
}
|
|
2324
|
-
});
|
|
2325
|
-
};
|
|
2326
|
-
server.watcher.on("change", broadcast);
|
|
2327
|
-
server.watcher.on("add", broadcast);
|
|
2328
|
-
server.watcher.on("unlink", broadcast);
|
|
2329
|
-
server.httpServer?.once("close", () => {
|
|
2330
|
-
server.watcher.off("change", broadcast);
|
|
2331
|
-
server.watcher.off("add", broadcast);
|
|
2332
|
-
server.watcher.off("unlink", broadcast);
|
|
2333
|
-
});
|
|
2312
|
+
function setupRemoteBroadcast(server, options) {
|
|
2313
|
+
const broadcast = (file) => {
|
|
2314
|
+
if (shouldIgnoreFile(file, options)) return;
|
|
2315
|
+
server.ws.send({
|
|
2316
|
+
type: "custom",
|
|
2317
|
+
event: REMOTE_HMR_EVENT,
|
|
2318
|
+
data: {
|
|
2319
|
+
remote: options.name,
|
|
2320
|
+
file,
|
|
2321
|
+
ts: Date.now()
|
|
2334
2322
|
}
|
|
2335
|
-
if (isHost) {
|
|
2336
|
-
const connections = [];
|
|
2337
|
-
const reconnectTimers = /* @__PURE__ */ new Map();
|
|
2338
|
-
let isTearingDown = false;
|
|
2339
|
-
const clearReconnectTimer = (remoteName) => {
|
|
2340
|
-
const timer = reconnectTimers.get(remoteName);
|
|
2341
|
-
if (!timer) return;
|
|
2342
|
-
clearTimeout(timer);
|
|
2343
|
-
reconnectTimers.delete(remoteName);
|
|
2344
|
-
};
|
|
2345
|
-
const scheduleReconnect = (remoteName, remote, attempt, reason) => {
|
|
2346
|
-
if (isTearingDown) return;
|
|
2347
|
-
if (attempt >= REMOTE_HMR_CONNECT_MAX_RETRIES) {
|
|
2348
|
-
mfWarn(`Remote "${remoteName}" full HMR reconnect skipped after ${REMOTE_HMR_CONNECT_MAX_RETRIES} attempts: ${reason}`);
|
|
2349
|
-
return;
|
|
2350
|
-
}
|
|
2351
|
-
clearReconnectTimer(remoteName);
|
|
2352
|
-
const timer = setTimeout(() => {
|
|
2353
|
-
reconnectTimers.delete(remoteName);
|
|
2354
|
-
connectRemote(remoteName, remote, attempt + 1);
|
|
2355
|
-
}, REMOTE_HMR_CONNECT_RETRY_DELAY_MS);
|
|
2356
|
-
reconnectTimers.set(remoteName, timer);
|
|
2357
|
-
};
|
|
2358
|
-
const connectRemote = async (remoteName, remote, attempt = 0) => {
|
|
2359
|
-
if (isTearingDown) return;
|
|
2360
|
-
const endpoint = getRemoteHmrEndpoint(remote.entry, server);
|
|
2361
|
-
if (!endpoint) {
|
|
2362
|
-
mfWarn(`Failed to build HMR endpoint URL for remote "${remoteName}"`);
|
|
2363
|
-
return;
|
|
2364
|
-
}
|
|
2365
|
-
try {
|
|
2366
|
-
const metadataResponse = await fetch(endpoint);
|
|
2367
|
-
if (!metadataResponse.ok) {
|
|
2368
|
-
mfWarn(`Failed to fetch remote HMR metadata from "${remoteName}": ${metadataResponse.status}`);
|
|
2369
|
-
scheduleReconnect(remoteName, remote, attempt, `HTTP ${metadataResponse.status}`);
|
|
2370
|
-
return;
|
|
2371
|
-
}
|
|
2372
|
-
const metadata = await metadataResponse.json();
|
|
2373
|
-
if (metadata.event !== REMOTE_HMR_EVENT || !metadata.wsUrl) {
|
|
2374
|
-
mfWarn(`Remote "${remoteName}" returned unexpected HMR metadata shape`);
|
|
2375
|
-
return;
|
|
2376
|
-
}
|
|
2377
|
-
const ws = new WebSocket(metadata.wsUrl, "vite-hmr");
|
|
2378
|
-
ws.onmessage = (rawEvent) => {
|
|
2379
|
-
if (strategy === "native") return;
|
|
2380
|
-
const message = parseRemoteHmrMessage(rawEvent.data);
|
|
2381
|
-
if (!message || message.event !== REMOTE_HMR_EVENT) return;
|
|
2382
|
-
server.ws.send({ type: "full-reload" });
|
|
2383
|
-
};
|
|
2384
|
-
ws.onopen = () => clearReconnectTimer(remoteName);
|
|
2385
|
-
ws.onerror = (error) => mfWarn(`Remote HMR socket error for "${remoteName}":`, error);
|
|
2386
|
-
ws.onclose = () => scheduleReconnect(remoteName, remote, attempt, "socket closed");
|
|
2387
|
-
connections.push(ws);
|
|
2388
|
-
} catch (error) {
|
|
2389
|
-
mfWarn(`Failed to connect remote HMR for "${remoteName}" on attempt ${attempt + 1}: ${getStringPreview(error)}`);
|
|
2390
|
-
scheduleReconnect(remoteName, remote, attempt, getStringPreview(error));
|
|
2391
|
-
}
|
|
2392
|
-
};
|
|
2393
|
-
const teardown = () => {
|
|
2394
|
-
isTearingDown = true;
|
|
2395
|
-
reconnectTimers.forEach((timer) => clearTimeout(timer));
|
|
2396
|
-
reconnectTimers.clear();
|
|
2397
|
-
connections.forEach((connection) => {
|
|
2398
|
-
if (connection.readyState !== connection.CLOSING && connection.readyState !== connection.CLOSED) connection.close();
|
|
2399
|
-
});
|
|
2400
|
-
connections.length = 0;
|
|
2401
|
-
};
|
|
2402
|
-
for (const [remoteName, remote] of Object.entries(options.remotes)) connectRemote(remoteName, remote);
|
|
2403
|
-
const triggerHostReload = (file) => {
|
|
2404
|
-
if (strategy === "native") return;
|
|
2405
|
-
if (shouldIgnoreFile(file, options)) return;
|
|
2406
|
-
server.ws.send({ type: "full-reload" });
|
|
2407
|
-
};
|
|
2408
|
-
server.watcher.on("change", triggerHostReload);
|
|
2409
|
-
server.watcher.on("add", triggerHostReload);
|
|
2410
|
-
server.watcher.on("unlink", triggerHostReload);
|
|
2411
|
-
server.httpServer?.once("close", teardown);
|
|
2412
|
-
}
|
|
2413
|
-
}
|
|
2414
|
-
};
|
|
2415
|
-
}
|
|
2416
|
-
//#endregion
|
|
2417
|
-
//#region src/plugins/pluginDts.ts
|
|
2418
|
-
const DEFAULT_DEV_OPTIONS = {
|
|
2419
|
-
disableLiveReload: true,
|
|
2420
|
-
disableHotTypesReload: false,
|
|
2421
|
-
disableDynamicRemoteTypeHints: false
|
|
2422
|
-
};
|
|
2423
|
-
const DYNAMIC_HINTS_PLUGIN = "@module-federation/dts-plugin/dynamic-remote-type-hints-plugin";
|
|
2424
|
-
const getIPv4 = () => process.env["FEDERATION_IPV4"] || "127.0.0.1";
|
|
2425
|
-
const DEV_TYPES_FOLDER = ".dev-server";
|
|
2426
|
-
const DEFAULT_PUBLIC_TYPES_FOLDER = "@mf-types";
|
|
2427
|
-
const forkDevWorkerPath = require.resolve("@module-federation/dts-plugin/dist/fork-dev-worker.js");
|
|
2428
|
-
var DevWorker = class {
|
|
2429
|
-
worker = _module_federation_dts_plugin_core.rpc.createRpcWorker(forkDevWorkerPath, {}, void 0, false);
|
|
2430
|
-
constructor(options) {
|
|
2431
|
-
this.worker.connect(options);
|
|
2432
|
-
}
|
|
2433
|
-
update() {
|
|
2434
|
-
this.worker.process?.send?.({
|
|
2435
|
-
type: _module_federation_dts_plugin_core.rpc.RpcGMCallTypes.CALL,
|
|
2436
|
-
id: this.worker.id,
|
|
2437
|
-
args: [void 0, "update"]
|
|
2438
2323
|
});
|
|
2439
|
-
}
|
|
2440
|
-
exit() {
|
|
2441
|
-
this.worker.terminate();
|
|
2442
|
-
}
|
|
2443
|
-
};
|
|
2444
|
-
const normalizeDevOptions = (dev) => {
|
|
2445
|
-
if (dev === false) return false;
|
|
2446
|
-
if (dev === true || typeof dev === "undefined") return { ...DEFAULT_DEV_OPTIONS };
|
|
2447
|
-
return {
|
|
2448
|
-
...DEFAULT_DEV_OPTIONS,
|
|
2449
|
-
...dev
|
|
2450
2324
|
};
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
Object.entries(options.remotes).forEach(([key, remote]) => {
|
|
2459
|
-
if (!remote.entry) return;
|
|
2460
|
-
remotes[key] = `${remote.entryGlobalName?.startsWith("http") || remote.entryGlobalName?.includes(".json") ? remote.name || key : remote.entryGlobalName || remote.name || key}@${remote.entry}`;
|
|
2325
|
+
server.watcher.on("change", broadcast);
|
|
2326
|
+
server.watcher.on("add", broadcast);
|
|
2327
|
+
server.watcher.on("unlink", broadcast);
|
|
2328
|
+
server.httpServer?.once("close", () => {
|
|
2329
|
+
server.watcher.off("change", broadcast);
|
|
2330
|
+
server.watcher.off("add", broadcast);
|
|
2331
|
+
server.watcher.off("unlink", broadcast);
|
|
2461
2332
|
});
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
}
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
const
|
|
2480
|
-
|
|
2481
|
-
return
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
const usesVueSfcExposes = (options) => {
|
|
2485
|
-
return getExposeImportPaths(options).some((value) => value.endsWith(".vue"));
|
|
2486
|
-
};
|
|
2487
|
-
const resolveDtsPluginOptions = (dts, options, context) => {
|
|
2488
|
-
if (dts === false) return false;
|
|
2489
|
-
const inferredGenerateTypesDefaults = { generateAPITypes: true };
|
|
2490
|
-
if (usesVueSfcExposes(options) && hasPackageDependency("vue-tsc", context)) inferredGenerateTypesDefaults.compilerInstance = "vue-tsc";
|
|
2491
|
-
if (dts === true || typeof dts === "undefined") return { generateTypes: inferredGenerateTypesDefaults };
|
|
2492
|
-
const generateTypes = dts.generateTypes;
|
|
2493
|
-
return {
|
|
2494
|
-
...dts,
|
|
2495
|
-
generateTypes: generateTypes === false ? false : {
|
|
2496
|
-
...inferredGenerateTypesDefaults,
|
|
2497
|
-
...generateTypes === true || typeof generateTypes === "undefined" ? {} : generateTypes
|
|
2498
|
-
}
|
|
2499
|
-
};
|
|
2500
|
-
};
|
|
2501
|
-
const getBasePath = (base) => {
|
|
2502
|
-
if (base.startsWith("http://") || base.startsWith("https://")) return new URL(base).pathname.replace(/\/$/, "") || "/";
|
|
2503
|
-
return base.replace(/\/$/, "") || "/";
|
|
2504
|
-
};
|
|
2505
|
-
const joinBaseAndAsset = (base, assetFileName) => {
|
|
2506
|
-
const basePath = getBasePath(base);
|
|
2507
|
-
return `${basePath === "/" ? "" : basePath}/${assetFileName}`.replace(/\/{2,}/g, "/");
|
|
2508
|
-
};
|
|
2509
|
-
const getDevDtsAssetPaths = (options) => {
|
|
2510
|
-
const { outputDir, publicTypesFolder, root, base } = options;
|
|
2511
|
-
return {
|
|
2512
|
-
apiFilePath: pathe.resolve(root, outputDir, `${DEV_TYPES_FOLDER}.d.ts`),
|
|
2513
|
-
apiRequestPath: joinBaseAndAsset(base, `${publicTypesFolder}.d.ts`),
|
|
2514
|
-
zipFilePath: pathe.resolve(root, outputDir, `${DEV_TYPES_FOLDER}.zip`),
|
|
2515
|
-
zipRequestPath: joinBaseAndAsset(base, `${publicTypesFolder}.zip`)
|
|
2333
|
+
}
|
|
2334
|
+
/**
|
|
2335
|
+
* Installs the host-side full-reload relay. For each configured remote:
|
|
2336
|
+
* 1. Fetches the remote's `/__mf_hmr` metadata to get its WS URL.
|
|
2337
|
+
* 2. Opens a Node-to-Node WebSocket to that URL.
|
|
2338
|
+
* 3. On any `mf:remote-update` message, broadcasts `{ type: 'full-reload' }`
|
|
2339
|
+
* to the host's own browser-facing WS.
|
|
2340
|
+
*
|
|
2341
|
+
* Also reloads on local host file changes. Retries failed connections up to
|
|
2342
|
+
* `REMOTE_HMR_CONNECT_MAX_RETRIES` times with a fixed delay.
|
|
2343
|
+
*
|
|
2344
|
+
* Only called under the `'full-reload'` strategy.
|
|
2345
|
+
*/
|
|
2346
|
+
function setupHostFullReloadRelay(server, options) {
|
|
2347
|
+
const connections = [];
|
|
2348
|
+
const reconnectTimers = /* @__PURE__ */ new Map();
|
|
2349
|
+
let isTearingDown = false;
|
|
2350
|
+
const clearReconnectTimer = (remoteName) => {
|
|
2351
|
+
const timer = reconnectTimers.get(remoteName);
|
|
2352
|
+
if (!timer) return;
|
|
2353
|
+
clearTimeout(timer);
|
|
2354
|
+
reconnectTimers.delete(remoteName);
|
|
2516
2355
|
};
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
const isZipRequest = requestPath === assetPaths.zipRequestPath;
|
|
2522
|
-
const isApiRequest = requestPath === assetPaths.apiRequestPath;
|
|
2523
|
-
if (!isZipRequest && !isApiRequest) {
|
|
2524
|
-
next();
|
|
2356
|
+
const scheduleReconnect = (remoteName, remote, attempt, reason) => {
|
|
2357
|
+
if (isTearingDown) return;
|
|
2358
|
+
if (attempt >= REMOTE_HMR_CONNECT_MAX_RETRIES) {
|
|
2359
|
+
require_packageUtils.mfWarn(`Remote "${remoteName}" full HMR reconnect skipped after ${REMOTE_HMR_CONNECT_MAX_RETRIES} attempts: ${reason}`);
|
|
2525
2360
|
return;
|
|
2526
2361
|
}
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2362
|
+
clearReconnectTimer(remoteName);
|
|
2363
|
+
const timer = setTimeout(() => {
|
|
2364
|
+
reconnectTimers.delete(remoteName);
|
|
2365
|
+
connectRemote(remoteName, remote, attempt + 1);
|
|
2366
|
+
}, REMOTE_HMR_CONNECT_RETRY_DELAY_MS);
|
|
2367
|
+
reconnectTimers.set(remoteName, timer);
|
|
2368
|
+
};
|
|
2369
|
+
const connectRemote = async (remoteName, remote, attempt = 0) => {
|
|
2370
|
+
if (isTearingDown) return;
|
|
2371
|
+
const endpoint = getRemoteHmrEndpoint(remote.entry, server);
|
|
2372
|
+
if (!endpoint) {
|
|
2373
|
+
require_packageUtils.mfWarn(`Failed to build HMR endpoint URL for remote "${remoteName}"`);
|
|
2531
2374
|
return;
|
|
2532
2375
|
}
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2376
|
+
try {
|
|
2377
|
+
const metadataResponse = await fetch(endpoint);
|
|
2378
|
+
if (!metadataResponse.ok) {
|
|
2379
|
+
require_packageUtils.mfWarn(`Failed to fetch remote HMR metadata from "${remoteName}": ${metadataResponse.status}`);
|
|
2380
|
+
scheduleReconnect(remoteName, remote, attempt, `HTTP ${metadataResponse.status}`);
|
|
2381
|
+
return;
|
|
2382
|
+
}
|
|
2383
|
+
const metadata = await metadataResponse.json();
|
|
2384
|
+
if (metadata.event !== "mf:remote-update" || !metadata.wsUrl) {
|
|
2385
|
+
require_packageUtils.mfWarn(`Remote "${remoteName}" returned unexpected HMR metadata shape`);
|
|
2386
|
+
return;
|
|
2387
|
+
}
|
|
2388
|
+
const ws = new WebSocket(metadata.wsUrl, "vite-hmr");
|
|
2389
|
+
ws.onmessage = (rawEvent) => {
|
|
2390
|
+
const message = parseRemoteHmrMessage(rawEvent.data);
|
|
2391
|
+
if (!message || message.event !== "mf:remote-update") return;
|
|
2392
|
+
server.ws.send({ type: "full-reload" });
|
|
2393
|
+
};
|
|
2394
|
+
ws.onopen = () => clearReconnectTimer(remoteName);
|
|
2395
|
+
ws.onerror = (error) => require_packageUtils.mfWarn(`Remote HMR socket error for "${remoteName}":`, error);
|
|
2396
|
+
ws.onclose = () => scheduleReconnect(remoteName, remote, attempt, "socket closed");
|
|
2397
|
+
connections.push(ws);
|
|
2398
|
+
} catch (error) {
|
|
2399
|
+
require_packageUtils.mfWarn(`Failed to connect remote HMR for "${remoteName}" on attempt ${attempt + 1}: ${getStringPreview(error)}`);
|
|
2400
|
+
scheduleReconnect(remoteName, remote, attempt, getStringPreview(error));
|
|
2538
2401
|
}
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2402
|
+
};
|
|
2403
|
+
const teardown = () => {
|
|
2404
|
+
isTearingDown = true;
|
|
2405
|
+
reconnectTimers.forEach((timer) => clearTimeout(timer));
|
|
2406
|
+
reconnectTimers.clear();
|
|
2407
|
+
connections.forEach((connection) => {
|
|
2408
|
+
if (connection.readyState !== connection.CLOSING && connection.readyState !== connection.CLOSED) connection.close();
|
|
2546
2409
|
});
|
|
2547
|
-
|
|
2410
|
+
connections.length = 0;
|
|
2548
2411
|
};
|
|
2549
|
-
|
|
2550
|
-
const
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2412
|
+
for (const [remoteName, remote] of Object.entries(options.remotes)) connectRemote(remoteName, remote);
|
|
2413
|
+
const triggerHostReload = (file) => {
|
|
2414
|
+
if (shouldIgnoreFile(file, options)) return;
|
|
2415
|
+
server.ws.send({ type: "full-reload" });
|
|
2416
|
+
};
|
|
2417
|
+
server.watcher.on("change", triggerHostReload);
|
|
2418
|
+
server.watcher.on("add", triggerHostReload);
|
|
2419
|
+
server.watcher.on("unlink", triggerHostReload);
|
|
2420
|
+
server.httpServer?.once("close", teardown);
|
|
2421
|
+
}
|
|
2422
|
+
//#endregion
|
|
2423
|
+
//#region src/plugins/pluginDevRemoteHmr.ts
|
|
2424
|
+
/**
|
|
2425
|
+
* Clears the federation runtime's `moduleCache` on every Vite `vite:beforeUpdate`
|
|
2426
|
+
* event. Without this, after a remote SFC change Vite would patch the in-memory
|
|
2427
|
+
* component, but `loadRemote()` would still return the cached stale module on
|
|
2428
|
+
* the next call (e.g. after route navigation), making the patched version
|
|
2429
|
+
* effectively unreachable.
|
|
2430
|
+
*/
|
|
2431
|
+
const FEDERATION_MODULE_CACHE_CLEAR_SCRIPT = `
|
|
2432
|
+
if (import.meta.hot) {
|
|
2433
|
+
import.meta.hot.on('vite:beforeUpdate', function () {
|
|
2434
|
+
try {
|
|
2435
|
+
var f = globalThis.__FEDERATION__ || globalThis.__VMOK__;
|
|
2436
|
+
if (!f || !f.__INSTANCES__) return;
|
|
2437
|
+
for (var i = 0; i < f.__INSTANCES__.length; i++) {
|
|
2438
|
+
if (f.__INSTANCES__[i] && f.__INSTANCES__[i].moduleCache)
|
|
2439
|
+
f.__INSTANCES__[i].moduleCache.clear();
|
|
2440
|
+
}
|
|
2441
|
+
} catch (e) {}
|
|
2442
|
+
});
|
|
2443
|
+
}`;
|
|
2444
|
+
const HMR_ADAPTERS = [reactAdapter, vueAdapter];
|
|
2445
|
+
function resolveAdapters(plugins) {
|
|
2446
|
+
const pluginNames = new Set(plugins.map((p) => p.name));
|
|
2447
|
+
return HMR_ADAPTERS.filter((adapter) => adapter.pluginNames.some((name) => pluginNames.has(name)));
|
|
2448
|
+
}
|
|
2449
|
+
function hasCrossFederationHmr(plugins) {
|
|
2450
|
+
return resolveAdapters(plugins).length > 0;
|
|
2451
|
+
}
|
|
2452
|
+
function isRemoteHmrEnabled(dev) {
|
|
2453
|
+
return typeof dev === "object" && dev !== null && !!dev.remoteHmr;
|
|
2454
|
+
}
|
|
2455
|
+
/**
|
|
2456
|
+
* `'native'` — a matched framework adapter owns HMR through Vite's native
|
|
2457
|
+
* channel (e.g. React Fast Refresh via the `/@react-refresh` proxy, Vue's
|
|
2458
|
+
* patched `__VUE_HMR_RUNTIME__`). The broadcast/relay path stays idle.
|
|
2459
|
+
*
|
|
2460
|
+
* `'full-reload'` — no adapter matched, or the user explicitly opted in with
|
|
2461
|
+
* `remoteHmr: 'full-reload'` to bypass adapters: the plugin's broadcast/relay
|
|
2462
|
+
* machinery triggers a page reload on every remote file change.
|
|
2463
|
+
*/
|
|
2464
|
+
function resolveHmrStrategy(dev, plugins) {
|
|
2465
|
+
if (typeof dev === "object" && dev !== null && dev.remoteHmr === "full-reload") return "full-reload";
|
|
2466
|
+
return hasCrossFederationHmr(plugins) ? "native" : "full-reload";
|
|
2467
|
+
}
|
|
2468
|
+
function shouldIgnoreFile(file, options) {
|
|
2469
|
+
return file.includes("/node_modules/") || file.includes("\\node_modules\\") || file.includes(`/${options.virtualModuleDir}/`) || file.includes(`\\${options.virtualModuleDir}\\`) || file.includes("/.vite/") || file.includes("\\.vite\\") || file.includes("/.mf/") || file.includes("\\.mf\\") || file.includes("/mf-manifest.json") || file.includes("\\mf-manifest.json") || file.includes("/mf-stats.json") || file.includes("\\mf-stats.json");
|
|
2470
|
+
}
|
|
2471
|
+
function collectHostTags(server, options, adapters) {
|
|
2472
|
+
const ctx = {
|
|
2473
|
+
server,
|
|
2474
|
+
options
|
|
2475
|
+
};
|
|
2476
|
+
const tags = [];
|
|
2477
|
+
for (const adapter of adapters) {
|
|
2478
|
+
const adapterTags = adapter.host?.transformIndexHtml?.(ctx);
|
|
2479
|
+
if (adapterTags) tags.push(...adapterTags);
|
|
2480
|
+
}
|
|
2481
|
+
tags.push({
|
|
2482
|
+
tag: "script",
|
|
2483
|
+
attrs: { type: "module" },
|
|
2484
|
+
children: FEDERATION_MODULE_CACHE_CLEAR_SCRIPT,
|
|
2485
|
+
injectTo: "head"
|
|
2569
2486
|
});
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2487
|
+
return tags;
|
|
2488
|
+
}
|
|
2489
|
+
function pluginDevRemoteHmr(options) {
|
|
2490
|
+
const isHost = Object.keys(options.remotes).length > 0;
|
|
2491
|
+
const isRemote = Object.keys(options.exposes).length > 0;
|
|
2492
|
+
let adapters = [];
|
|
2493
|
+
let strategy = "full-reload";
|
|
2494
|
+
return {
|
|
2495
|
+
name: "module-federation-dev-remote-hmr",
|
|
2576
2496
|
apply: "serve",
|
|
2577
|
-
config(config) {
|
|
2578
|
-
normalizedDevOptions = normalizeDevOptions(options.dev);
|
|
2579
|
-
if (!normalizedDevOptions) return;
|
|
2580
|
-
if (normalizedDevOptions.disableDynamicRemoteTypeHints) return;
|
|
2581
|
-
ensureRuntimePlugin(options, DYNAMIC_HINTS_PLUGIN);
|
|
2582
|
-
const define = config.define ? { ...config.define } : {};
|
|
2583
|
-
if (!("FEDERATION_IPV4" in define)) define.FEDERATION_IPV4 = JSON.stringify(getIPv4());
|
|
2584
|
-
config.define = define;
|
|
2585
|
-
},
|
|
2586
2497
|
configResolved(config) {
|
|
2587
|
-
|
|
2498
|
+
adapters = resolveAdapters(config.plugins);
|
|
2499
|
+
strategy = resolveHmrStrategy(options.dev, config.plugins);
|
|
2588
2500
|
},
|
|
2589
2501
|
configureServer(server) {
|
|
2590
|
-
if (!
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
const dtsModuleFederationConfig = getDtsModuleFederationConfig(resolvedConfig.root);
|
|
2596
|
-
const normalizedDtsOptions = normalizeDevDtsOptions(dtsModuleFederationConfig.dts, resolvedConfig.root);
|
|
2597
|
-
if (typeof normalizedDtsOptions !== "object") return;
|
|
2598
|
-
const normalizedGenerateTypes = (0, _module_federation_sdk.normalizeOptions)(Boolean(normalizedDtsOptions), { compileInChildProcess: true }, "mfOptions.dts.generateTypes")(normalizedDtsOptions.generateTypes);
|
|
2599
|
-
const remote = normalizedGenerateTypes === false ? void 0 : {
|
|
2600
|
-
implementation: normalizedDtsOptions.implementation,
|
|
2601
|
-
context: resolvedConfig.root,
|
|
2602
|
-
outputDir,
|
|
2603
|
-
moduleFederationConfig: { ...dtsModuleFederationConfig },
|
|
2604
|
-
hostRemoteTypesFolder: normalizedGenerateTypes.typesFolder || DEFAULT_PUBLIC_TYPES_FOLDER,
|
|
2605
|
-
...normalizedGenerateTypes,
|
|
2606
|
-
typesFolder: DEV_TYPES_FOLDER
|
|
2607
|
-
};
|
|
2608
|
-
if (remote) server.middlewares.use(createDevDtsAssetMiddleware(getDevDtsAssetPaths({
|
|
2609
|
-
outputDir,
|
|
2610
|
-
publicTypesFolder: remote.hostRemoteTypesFolder || DEFAULT_PUBLIC_TYPES_FOLDER,
|
|
2611
|
-
root: resolvedConfig.root,
|
|
2612
|
-
base: resolvedConfig.base
|
|
2613
|
-
})));
|
|
2614
|
-
if (remote && !remote.tsConfigPath && normalizedDtsOptions.tsConfigPath) remote.tsConfigPath = normalizedDtsOptions.tsConfigPath;
|
|
2615
|
-
const normalizedConsumeTypes = (0, _module_federation_sdk.normalizeOptions)(Boolean(normalizedDtsOptions), { consumeAPITypes: true }, "mfOptions.dts.consumeTypes")(normalizedDtsOptions.consumeTypes);
|
|
2616
|
-
const host = normalizedConsumeTypes === false ? void 0 : {
|
|
2617
|
-
implementation: normalizedDtsOptions.implementation,
|
|
2618
|
-
context: resolvedConfig.root,
|
|
2619
|
-
moduleFederationConfig: dtsModuleFederationConfig,
|
|
2620
|
-
typesFolder: normalizedConsumeTypes.typesFolder || "@mf-types",
|
|
2621
|
-
abortOnError: false,
|
|
2622
|
-
...normalizedConsumeTypes
|
|
2623
|
-
};
|
|
2624
|
-
const extraOptions = normalizedDtsOptions.extraOptions || {};
|
|
2625
|
-
if (!remote && !host && devOptions.disableLiveReload) return;
|
|
2626
|
-
const startDevWorker = async () => {
|
|
2627
|
-
let remoteTypeUrls;
|
|
2628
|
-
if (host) remoteTypeUrls = await new Promise((resolve) => {
|
|
2629
|
-
(0, _module_federation_dts_plugin.consumeTypesAPI)({
|
|
2630
|
-
host,
|
|
2631
|
-
extraOptions,
|
|
2632
|
-
displayErrorInTerminal: normalizedDtsOptions.displayErrorInTerminal
|
|
2633
|
-
}, resolve);
|
|
2634
|
-
});
|
|
2635
|
-
devWorker = new DevWorker({
|
|
2636
|
-
name: options.name,
|
|
2637
|
-
remote,
|
|
2638
|
-
host: host ? {
|
|
2639
|
-
...host,
|
|
2640
|
-
remoteTypeUrls
|
|
2641
|
-
} : void 0,
|
|
2642
|
-
extraOptions,
|
|
2643
|
-
disableLiveReload: devOptions.disableLiveReload,
|
|
2644
|
-
disableHotTypesReload: devOptions.disableHotTypesReload
|
|
2645
|
-
});
|
|
2646
|
-
const update = () => devWorker?.update();
|
|
2647
|
-
server.watcher.on("change", update);
|
|
2648
|
-
server.watcher.on("add", update);
|
|
2649
|
-
server.watcher.on("unlink", update);
|
|
2650
|
-
server.httpServer?.once("close", () => {
|
|
2651
|
-
devWorker?.exit();
|
|
2652
|
-
server.watcher.off("change", update);
|
|
2653
|
-
server.watcher.off("add", update);
|
|
2654
|
-
server.watcher.off("unlink", update);
|
|
2502
|
+
if (!isRemoteHmrEnabled(options.dev)) return;
|
|
2503
|
+
if (isRemote) {
|
|
2504
|
+
for (const adapter of adapters) adapter.remote?.configureServer?.({
|
|
2505
|
+
server,
|
|
2506
|
+
options
|
|
2655
2507
|
});
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
logDtsError(error, normalizedDtsOptions);
|
|
2659
|
-
});
|
|
2660
|
-
}
|
|
2661
|
-
}, {
|
|
2662
|
-
name: "module-federation-dts-build",
|
|
2663
|
-
apply: "build",
|
|
2664
|
-
configResolved(config) {
|
|
2665
|
-
resolvedConfig = config;
|
|
2666
|
-
},
|
|
2667
|
-
async generateBundle() {
|
|
2668
|
-
if (hasGeneratedBundle) return;
|
|
2669
|
-
hasGeneratedBundle = true;
|
|
2670
|
-
if (!resolvedConfig) return;
|
|
2671
|
-
let normalizedDtsOptions;
|
|
2672
|
-
try {
|
|
2673
|
-
normalizedDtsOptions = (0, _module_federation_dts_plugin.normalizeDtsOptions)(getDtsModuleFederationConfig(resolvedConfig.root), resolvedConfig.root);
|
|
2674
|
-
} catch (error) {
|
|
2675
|
-
logDtsError(error, options.dts);
|
|
2676
|
-
return;
|
|
2508
|
+
setupRemoteMetadataEndpoint(server, options);
|
|
2509
|
+
if (strategy === "full-reload") setupRemoteBroadcast(server, options);
|
|
2677
2510
|
}
|
|
2678
|
-
if (
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
try {
|
|
2683
|
-
consumeOptions = (0, _module_federation_dts_plugin.normalizeConsumeTypesOptions)({
|
|
2684
|
-
context,
|
|
2685
|
-
dtsOptions: normalizedDtsOptions,
|
|
2686
|
-
pluginOptions: getDtsModuleFederationConfig(resolvedConfig.root)
|
|
2511
|
+
if (isHost) {
|
|
2512
|
+
for (const adapter of adapters) adapter.host?.configureServer?.({
|
|
2513
|
+
server,
|
|
2514
|
+
options
|
|
2687
2515
|
});
|
|
2688
|
-
|
|
2689
|
-
logDtsError(error, normalizedDtsOptions);
|
|
2690
|
-
return;
|
|
2691
|
-
}
|
|
2692
|
-
if (consumeOptions?.host?.typesOnBuild) try {
|
|
2693
|
-
await (0, _module_federation_dts_plugin.consumeTypesAPI)(consumeOptions);
|
|
2694
|
-
} catch (error) {
|
|
2695
|
-
logDtsError(error, normalizedDtsOptions);
|
|
2516
|
+
if (strategy === "full-reload") setupHostFullReloadRelay(server, options);
|
|
2696
2517
|
}
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
}
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2518
|
+
},
|
|
2519
|
+
transform: {
|
|
2520
|
+
order: "post",
|
|
2521
|
+
handler(code, id) {
|
|
2522
|
+
if (!isRemote || !isRemoteHmrEnabled(options.dev)) return;
|
|
2523
|
+
if (!adapters.length) return;
|
|
2524
|
+
let result = code;
|
|
2525
|
+
const adapterCtx = { options };
|
|
2526
|
+
for (const adapter of adapters) {
|
|
2527
|
+
const next = adapter.remote?.transform?.(result, id, adapterCtx);
|
|
2528
|
+
if (typeof next === "string") result = next;
|
|
2529
|
+
}
|
|
2530
|
+
return result === code ? void 0 : result;
|
|
2708
2531
|
}
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2532
|
+
},
|
|
2533
|
+
transformIndexHtml: {
|
|
2534
|
+
order: "pre",
|
|
2535
|
+
handler(_html, ctx) {
|
|
2536
|
+
if (!isRemoteHmrEnabled(options.dev)) return;
|
|
2537
|
+
if (!isHost || !ctx.server) return;
|
|
2538
|
+
return collectHostTags(ctx.server, options, adapters);
|
|
2714
2539
|
}
|
|
2715
2540
|
}
|
|
2716
|
-
}
|
|
2541
|
+
};
|
|
2717
2542
|
}
|
|
2718
2543
|
//#endregion
|
|
2719
2544
|
//#region src/virtualModules/index.ts
|
|
2720
|
-
function initVirtualModules(command, remoteEntryId) {
|
|
2545
|
+
function initVirtualModules(command, remoteEntryId, enableSsrInit = false) {
|
|
2721
2546
|
writeLocalSharedImportMap();
|
|
2722
2547
|
writeHostAutoInit(remoteEntryId, command);
|
|
2723
|
-
writeRuntimeInitStatus(command);
|
|
2548
|
+
writeRuntimeInitStatus(command, enableSsrInit);
|
|
2724
2549
|
}
|
|
2725
2550
|
//#endregion
|
|
2726
2551
|
//#region src/utils/bundleHelpers.ts
|
|
@@ -3070,6 +2895,12 @@ function removeTrailingSlash(value) {
|
|
|
3070
2895
|
function ensureTrailingSlash(value) {
|
|
3071
2896
|
return `${removeTrailingSlash(value)}/`;
|
|
3072
2897
|
}
|
|
2898
|
+
function getBasePath(base) {
|
|
2899
|
+
return removeTrailingSlash(base || "/");
|
|
2900
|
+
}
|
|
2901
|
+
function isNuxtClientBase(base) {
|
|
2902
|
+
return getBasePath(base).endsWith("/_nuxt");
|
|
2903
|
+
}
|
|
3073
2904
|
function normalizeNodeModulePath(source) {
|
|
3074
2905
|
return source.replace(/\\/g, "/").replace(/\?.*$/, "");
|
|
3075
2906
|
}
|
|
@@ -3103,6 +2934,116 @@ function resolvePublicPath(options, viteBase, originalBase) {
|
|
|
3103
2934
|
return "auto";
|
|
3104
2935
|
}
|
|
3105
2936
|
//#endregion
|
|
2937
|
+
//#region src/virtualModules/virtualExposesSSR.ts
|
|
2938
|
+
/**
|
|
2939
|
+
* Virtual module ID for the SSR exposes map.
|
|
2940
|
+
* Separate from the browser exposes: no CSS injection, no document references,
|
|
2941
|
+
* and shared packages are imported as bare specifiers (externals in the SSR build).
|
|
2942
|
+
*/
|
|
2943
|
+
function getVirtualExposesSSRId(options) {
|
|
2944
|
+
return `virtual:mf-exposes-ssr:${`${options.internalName}__${options.filename}`.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
|
|
2945
|
+
}
|
|
2946
|
+
/**
|
|
2947
|
+
* Generates the SSR exposes map module.
|
|
2948
|
+
*
|
|
2949
|
+
* Differences from the browser version (virtualExposes.ts):
|
|
2950
|
+
* - No CSS asset injection (document APIs unavailable on Node)
|
|
2951
|
+
* - Shared packages (react, react-dom, etc.) must be externals in the SSR
|
|
2952
|
+
* build so Node resolves them via its own module cache — this is what
|
|
2953
|
+
* guarantees the React singleton is shared with react-dom/server.
|
|
2954
|
+
*/
|
|
2955
|
+
function generateExposesSSR(options) {
|
|
2956
|
+
return `
|
|
2957
|
+
export default {
|
|
2958
|
+
${Object.keys(options.exposes).map((key) => {
|
|
2959
|
+
return `
|
|
2960
|
+
${JSON.stringify(key)}: async () => {
|
|
2961
|
+
const importModule = await import(${JSON.stringify(options.exposes[key].import)})
|
|
2962
|
+
const exportModule = {}
|
|
2963
|
+
Object.assign(exportModule, importModule)
|
|
2964
|
+
Object.defineProperty(exportModule, "__esModule", {
|
|
2965
|
+
value: true,
|
|
2966
|
+
enumerable: false
|
|
2967
|
+
})
|
|
2968
|
+
return exportModule
|
|
2969
|
+
}
|
|
2970
|
+
`;
|
|
2971
|
+
}).join(",")}
|
|
2972
|
+
}
|
|
2973
|
+
`;
|
|
2974
|
+
}
|
|
2975
|
+
//#endregion
|
|
2976
|
+
//#region src/virtualModules/virtualRemoteEntrySSR.ts
|
|
2977
|
+
const REMOTE_ENTRY_SSR_ID = "virtual:mf-REMOTE_ENTRY_SSR_ID";
|
|
2978
|
+
function getRemoteEntrySSRId(options) {
|
|
2979
|
+
return `${REMOTE_ENTRY_SSR_ID}:${`${options.internalName}__${options.filename}`.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
|
|
2980
|
+
}
|
|
2981
|
+
function getSsrRemoteEntryFileName(browserFilename) {
|
|
2982
|
+
const ext = browserFilename.match(/\.[^.]+$/)?.[0] || ".js";
|
|
2983
|
+
return `${browserFilename.slice(0, browserFilename.length - ext.length)}.ssr${ext}`;
|
|
2984
|
+
}
|
|
2985
|
+
/**
|
|
2986
|
+
* Generates the SSR remote entry module.
|
|
2987
|
+
*
|
|
2988
|
+
* This is intentionally minimal — no HMR shim, no loadShare virtual modules,
|
|
2989
|
+
* no browser globals. Shared packages (react, react-dom, etc.) are imported
|
|
2990
|
+
* as externals by the SSR build, so Node's require cache provides the singleton.
|
|
2991
|
+
*
|
|
2992
|
+
* The container API (init / get) mirrors the browser entry so the MF runtime
|
|
2993
|
+
* can call it the same way on the server.
|
|
2994
|
+
*/
|
|
2995
|
+
function generateRemoteEntrySSR(options) {
|
|
2996
|
+
const virtualExposesSSRId = getVirtualExposesSSRId(options);
|
|
2997
|
+
return `
|
|
2998
|
+
import { init as runtimeInit } from "@module-federation/runtime";
|
|
2999
|
+
|
|
3000
|
+
let exposesMapPromise;
|
|
3001
|
+
|
|
3002
|
+
async function getExposesMap() {
|
|
3003
|
+
exposesMapPromise ??= import(${JSON.stringify(virtualExposesSSRId)}).then((mod) => mod.default ?? mod);
|
|
3004
|
+
return exposesMapPromise;
|
|
3005
|
+
}
|
|
3006
|
+
|
|
3007
|
+
/**
|
|
3008
|
+
* Called by the MF runtime on the host to register this remote's share scope.
|
|
3009
|
+
* On the server the host has already initialised the runtime, so we just need
|
|
3010
|
+
* to set up a minimal runtime instance for the remote container.
|
|
3011
|
+
*/
|
|
3012
|
+
async function init(shared = {}, initScope = []) {
|
|
3013
|
+
const initRes = runtimeInit({
|
|
3014
|
+
name: ${JSON.stringify(options.internalName)},
|
|
3015
|
+
remotes: [],
|
|
3016
|
+
shared: {},
|
|
3017
|
+
});
|
|
3018
|
+
const initToken = { from: ${JSON.stringify(options.internalName)} };
|
|
3019
|
+
if (initScope.indexOf(initToken) >= 0) return;
|
|
3020
|
+
initScope.push(initToken);
|
|
3021
|
+
initRes.initShareScopeMap(${JSON.stringify(options.shareScope)}, shared);
|
|
3022
|
+
try {
|
|
3023
|
+
await Promise.all(
|
|
3024
|
+
await initRes.initializeSharing(${JSON.stringify(options.shareScope)}, {
|
|
3025
|
+
strategy: ${JSON.stringify(options.shareStrategy ?? "version-first")},
|
|
3026
|
+
from: 'build',
|
|
3027
|
+
initScope,
|
|
3028
|
+
})
|
|
3029
|
+
);
|
|
3030
|
+
} catch (e) {
|
|
3031
|
+
console.error('[Module Federation SSR]', e);
|
|
3032
|
+
}
|
|
3033
|
+
return initRes;
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
async function getExposes(moduleName) {
|
|
3037
|
+
const exposesMap = await getExposesMap();
|
|
3038
|
+
if (!(moduleName in exposesMap))
|
|
3039
|
+
throw new Error(\`[Module Federation] Module \${moduleName} does not exist in container.\`);
|
|
3040
|
+
return exposesMap[moduleName]().then((res) => () => res);
|
|
3041
|
+
}
|
|
3042
|
+
|
|
3043
|
+
export { init, getExposes as get };
|
|
3044
|
+
`;
|
|
3045
|
+
}
|
|
3046
|
+
//#endregion
|
|
3106
3047
|
//#region src/plugins/pluginMFManifest.ts
|
|
3107
3048
|
/**
|
|
3108
3049
|
* Resolves the build version for the module federation manifest.
|
|
@@ -3133,6 +3074,7 @@ const Manifest = () => {
|
|
|
3133
3074
|
};
|
|
3134
3075
|
let root;
|
|
3135
3076
|
let remoteEntryFile;
|
|
3077
|
+
let ssrRemoteEntryFile;
|
|
3136
3078
|
let publicPath;
|
|
3137
3079
|
let _command;
|
|
3138
3080
|
let _originalConfigBase;
|
|
@@ -3169,8 +3111,8 @@ const Manifest = () => {
|
|
|
3169
3111
|
type: "module"
|
|
3170
3112
|
},
|
|
3171
3113
|
ssrRemoteEntry: {
|
|
3172
|
-
name: filename,
|
|
3173
|
-
path: "",
|
|
3114
|
+
name: getSsrRemoteEntryFileName(filename),
|
|
3115
|
+
path: "/__mf_ssr__/",
|
|
3174
3116
|
type: "module"
|
|
3175
3117
|
},
|
|
3176
3118
|
varRemoteEntry: varFilename ? {
|
|
@@ -3201,6 +3143,7 @@ const Manifest = () => {
|
|
|
3201
3143
|
_originalConfigBase = config.base;
|
|
3202
3144
|
},
|
|
3203
3145
|
configResolved(config) {
|
|
3146
|
+
viteConfig = config;
|
|
3204
3147
|
root = config.root;
|
|
3205
3148
|
let base = config.base;
|
|
3206
3149
|
if (_command === "serve") base = (config.server.origin || "") + config.base;
|
|
@@ -3210,7 +3153,10 @@ const Manifest = () => {
|
|
|
3210
3153
|
if (!mfManifestName) return;
|
|
3211
3154
|
let filesMap = {};
|
|
3212
3155
|
const foundRemoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
|
|
3156
|
+
const expectedSsrRemoteEntryFile = getSsrRemoteEntryFileName(mfOptions.filename);
|
|
3157
|
+
const foundSsrRemoteEntryFile = Object.values(bundle).find((file) => file.fileName === expectedSsrRemoteEntryFile)?.fileName;
|
|
3213
3158
|
if (foundRemoteEntryFile) remoteEntryFile = foundRemoteEntryFile;
|
|
3159
|
+
ssrRemoteEntryFile = foundSsrRemoteEntryFile || expectedSsrRemoteEntryFile;
|
|
3214
3160
|
const allCssAssets = mfOptions.bundleAllCSS && !disableAssetsAnalyze ? collectCssAssets(bundle) : /* @__PURE__ */ new Set();
|
|
3215
3161
|
if (!disableAssetsAnalyze) {
|
|
3216
3162
|
const exposesModules = Object.keys(mfOptions.exposes).map((item) => mfOptions.exposes[item].import);
|
|
@@ -3252,6 +3198,11 @@ const Manifest = () => {
|
|
|
3252
3198
|
path: "",
|
|
3253
3199
|
type: "module"
|
|
3254
3200
|
};
|
|
3201
|
+
const ssrRemoteEntry = {
|
|
3202
|
+
name: ssrRemoteEntryFile || getSsrRemoteEntryFileName(filename),
|
|
3203
|
+
path: _command === "serve" ? "/__mf_ssr__/" : "",
|
|
3204
|
+
type: "module"
|
|
3205
|
+
};
|
|
3255
3206
|
const varRemoteEntry = varFilename ? {
|
|
3256
3207
|
name: varFilename,
|
|
3257
3208
|
path: "",
|
|
@@ -3315,7 +3266,7 @@ const Manifest = () => {
|
|
|
3315
3266
|
buildName: name
|
|
3316
3267
|
},
|
|
3317
3268
|
remoteEntry,
|
|
3318
|
-
ssrRemoteEntry
|
|
3269
|
+
ssrRemoteEntry,
|
|
3319
3270
|
varRemoteEntry,
|
|
3320
3271
|
types: {
|
|
3321
3272
|
path: "",
|
|
@@ -3382,14 +3333,14 @@ function resetParseState() {
|
|
|
3382
3333
|
}
|
|
3383
3334
|
function setParseTimeout(timeout) {
|
|
3384
3335
|
if (!_parseTimeout) _parseTimeout = setTimeout(() => {
|
|
3385
|
-
mfWarn(`Parse timeout (${timeout}s) - forcing resolve`);
|
|
3336
|
+
require_packageUtils.mfWarn(`Parse timeout (${timeout}s) - forcing resolve`);
|
|
3386
3337
|
_resolve?.(1);
|
|
3387
3338
|
}, timeout * 1e3);
|
|
3388
3339
|
}
|
|
3389
3340
|
function resetIdleTimeout(timeout) {
|
|
3390
3341
|
clearParseTimeout();
|
|
3391
3342
|
_parseTimeout = setTimeout(() => {
|
|
3392
|
-
mfWarn(`moduleParseIdleTimeout: no module activity for ${timeout}s, forcing resolve. Some shared/remote dependencies may be missing. Consider increasing moduleParseIdleTimeout.`);
|
|
3343
|
+
require_packageUtils.mfWarn(`moduleParseIdleTimeout: no module activity for ${timeout}s, forcing resolve. Some shared/remote dependencies may be missing. Consider increasing moduleParseIdleTimeout.`);
|
|
3393
3344
|
_resolve?.(1);
|
|
3394
3345
|
}, timeout * 1e3);
|
|
3395
3346
|
}
|
|
@@ -3554,13 +3505,14 @@ function appendAlias(config, alias) {
|
|
|
3554
3505
|
function pluginProxyRemotes_default(options) {
|
|
3555
3506
|
let command;
|
|
3556
3507
|
let root = process.cwd();
|
|
3508
|
+
let enableSsrInit = false;
|
|
3557
3509
|
const { remotes } = options;
|
|
3558
3510
|
function resolveRemoteId(source, importer, remoteName) {
|
|
3559
3511
|
if (source === remoteName) {
|
|
3560
|
-
const installedPackageEntry = getInstalledPackageEntry(source, { cwd: root });
|
|
3512
|
+
const installedPackageEntry = require_packageUtils.getInstalledPackageEntry(source, { cwd: root });
|
|
3561
3513
|
if (installedPackageEntry && (importer === void 0 || isNodeModulesImporter(importer))) return installedPackageEntry;
|
|
3562
3514
|
}
|
|
3563
|
-
const remoteModule = getRemoteVirtualModule(source, command);
|
|
3515
|
+
const remoteModule = getRemoteVirtualModule(source, command, enableSsrInit);
|
|
3564
3516
|
addUsedRemote(remoteName, source);
|
|
3565
3517
|
refreshHostAutoInit();
|
|
3566
3518
|
return remoteModule.getImportId();
|
|
@@ -3579,6 +3531,9 @@ function pluginProxyRemotes_default(options) {
|
|
|
3579
3531
|
});
|
|
3580
3532
|
});
|
|
3581
3533
|
},
|
|
3534
|
+
configResolved() {
|
|
3535
|
+
enableSsrInit = command === "serve" && parseInt(vite.version, 10) >= 8;
|
|
3536
|
+
},
|
|
3582
3537
|
resolveId(source, importer) {
|
|
3583
3538
|
if (!filterId(source)) return;
|
|
3584
3539
|
for (const remote of Object.values(remotes)) {
|
|
@@ -3626,10 +3581,10 @@ function getPrebuildResolutionSource(pkgName, shareItem) {
|
|
|
3626
3581
|
}
|
|
3627
3582
|
function tryResolveFromProjectRoot(source) {
|
|
3628
3583
|
if (pathe.default.isAbsolute(source) || source.startsWith(".") || source.startsWith("/")) return source;
|
|
3629
|
-
const browserEntry = getInstalledPackageEntry(source, { cwd: getPackageDetectionCwd() });
|
|
3584
|
+
const browserEntry = require_packageUtils.getInstalledPackageEntry(source, { cwd: require_packageUtils.getPackageDetectionCwd() });
|
|
3630
3585
|
if (browserEntry) return browserEntry;
|
|
3631
3586
|
try {
|
|
3632
|
-
return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(getPackageDetectionCwd(), "package.json")}`)).resolve(source);
|
|
3587
|
+
return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(require_packageUtils.getPackageDetectionCwd(), "package.json")}`)).resolve(source);
|
|
3633
3588
|
} catch {
|
|
3634
3589
|
return;
|
|
3635
3590
|
}
|
|
@@ -3655,15 +3610,15 @@ function findSharedKeyForSource(source, shared) {
|
|
|
3655
3610
|
const explicitSubpathKey = getMatchingNodeModuleSubpath(source, Object.keys(shared || {}).filter((sharedKey) => sharedKey.includes("/") && !sharedKey.endsWith("/")));
|
|
3656
3611
|
if (explicitSubpathKey) return explicitSubpathKey;
|
|
3657
3612
|
}
|
|
3658
|
-
const packageName = getPackageNameFromNodeModulePath(source);
|
|
3613
|
+
const packageName = require_packageUtils.getPackageNameFromNodeModulePath(source);
|
|
3659
3614
|
return packageName ? findSharedKey(packageName, shared) : void 0;
|
|
3660
3615
|
}
|
|
3661
3616
|
/**
|
|
3662
3617
|
* Reads the dependencies of an installed package from its package.json.
|
|
3663
3618
|
*/
|
|
3664
3619
|
function getPackageDependencies(pkg) {
|
|
3665
|
-
const packageName = getPackageName(pkg);
|
|
3666
|
-
const installed = getInstalledPackageJson(packageName, { packageName });
|
|
3620
|
+
const packageName = require_packageUtils.getPackageName(pkg);
|
|
3621
|
+
const installed = require_packageUtils.getInstalledPackageJson(packageName, { packageName });
|
|
3667
3622
|
return Object.keys(installed?.packageJson.dependencies || {});
|
|
3668
3623
|
}
|
|
3669
3624
|
/**
|
|
@@ -3682,7 +3637,7 @@ function excludeSharedSubDependencies(shared) {
|
|
|
3682
3637
|
const depKey = sharedKeyByBase.get(dep);
|
|
3683
3638
|
if (depKey && depKey !== parentKey) {
|
|
3684
3639
|
if (shared[depKey]?.shareConfig.singleton === true || shared[depKey]?.shareConfig.import === false) continue;
|
|
3685
|
-
mfWarn(`"${dep}" is a dependency of shared package "${parentKey}" and is also shared separately. This may cause initialization order issues in dev mode. Consider sharing only "${parentKey}".\n Auto-excluding "${dep}" from shared modules for dev mode.`);
|
|
3640
|
+
require_packageUtils.mfWarn(`"${dep}" is a dependency of shared package "${parentKey}" and is also shared separately. This may cause initialization order issues in dev mode. Consider sharing only "${parentKey}".\n Auto-excluding "${dep}" from shared modules for dev mode.`);
|
|
3686
3641
|
delete shared[depKey];
|
|
3687
3642
|
sharedKeys.delete(depKey);
|
|
3688
3643
|
sharedKeyByBase.delete(dep);
|
|
@@ -3724,10 +3679,10 @@ function proxySharedModule(options) {
|
|
|
3724
3679
|
name: "proxyPreBuildShared",
|
|
3725
3680
|
enforce: "post",
|
|
3726
3681
|
config(config, { command }) {
|
|
3727
|
-
setPackageDetectionCwd(config.root || process.cwd());
|
|
3728
|
-
const isVinext = hasPackageDependency("vinext");
|
|
3729
|
-
const isAstro = hasPackageDependency("astro");
|
|
3730
|
-
const isRolldown = getIsRolldown(this);
|
|
3682
|
+
require_packageUtils.setPackageDetectionCwd(config.root || process.cwd());
|
|
3683
|
+
const isVinext = require_packageUtils.hasPackageDependency("vinext");
|
|
3684
|
+
const isAstro = require_packageUtils.hasPackageDependency("astro");
|
|
3685
|
+
const isRolldown = require_packageUtils.getIsRolldown(this);
|
|
3731
3686
|
_command = command;
|
|
3732
3687
|
useRolldown = isRolldown;
|
|
3733
3688
|
useDirectReactImport = isVinext || isAstro;
|
|
@@ -3735,7 +3690,7 @@ function proxySharedModule(options) {
|
|
|
3735
3690
|
},
|
|
3736
3691
|
configResolved(config) {
|
|
3737
3692
|
_config = config;
|
|
3738
|
-
const isRolldown = getIsRolldown(this);
|
|
3693
|
+
const isRolldown = require_packageUtils.getIsRolldown(this);
|
|
3739
3694
|
Object.keys(shared).forEach((key) => {
|
|
3740
3695
|
if (key.endsWith("/")) return;
|
|
3741
3696
|
if (useDirectReactImport && key === "react") {
|
|
@@ -3860,9 +3815,37 @@ function applyRewrites(code, imports, id) {
|
|
|
3860
3815
|
const importParts = [];
|
|
3861
3816
|
if (imp.defaultLocal) importParts.push(`default as ${imp.defaultLocal}`);
|
|
3862
3817
|
importParts.push(`__moduleExports as ${nsId}`);
|
|
3863
|
-
const destructParts = imp.named.map((s) => s.imported === s.local ? s.local : `${s.imported}: ${s.local}`);
|
|
3864
3818
|
let rewrite = `import { ${importParts.join(", ")} } from ${src};`;
|
|
3865
|
-
if (
|
|
3819
|
+
if (imp.named.length > 0) {
|
|
3820
|
+
const isProxyId = `__mf_is_proxy_${counter++}`;
|
|
3821
|
+
const namedProxyHelper = `function __mfCreateNamedRemoteProxy(ns, key) {
|
|
3822
|
+
const target = function (...args) {
|
|
3823
|
+
const value = ns[key];
|
|
3824
|
+
return typeof value === "function" ? value.apply(this, args) : value;
|
|
3825
|
+
};
|
|
3826
|
+
return new Proxy(target, {
|
|
3827
|
+
get(_target, prop) {
|
|
3828
|
+
if (prop === "then") return undefined;
|
|
3829
|
+
const value = ns[key];
|
|
3830
|
+
if (prop === Symbol.toPrimitive) return () => value;
|
|
3831
|
+
const item = value == null ? undefined : value[prop];
|
|
3832
|
+
return typeof item === "function" ? item.bind(value) : item;
|
|
3833
|
+
},
|
|
3834
|
+
apply(target, thisArg, args) {
|
|
3835
|
+
return target.apply(thisArg, args);
|
|
3836
|
+
}
|
|
3837
|
+
});
|
|
3838
|
+
}`;
|
|
3839
|
+
const tempNames = imp.named.map((_s) => `__mf_named_${counter++}`);
|
|
3840
|
+
const destructParts = imp.named.map((s, index) => `${s.imported}: ${tempNames[index]}`);
|
|
3841
|
+
const bindingLines = imp.named.map((s, index) => {
|
|
3842
|
+
const temp = tempNames[index];
|
|
3843
|
+
return `const ${s.local} = ${isProxyId} ? __mfCreateNamedRemoteProxy(${nsId}, ${JSON.stringify(s.imported)}) : ${temp};`;
|
|
3844
|
+
});
|
|
3845
|
+
rewrite += `\n${namedProxyHelper}\nconst ${isProxyId} = ${nsId} && ${nsId}.__mf_is_remote_proxy;`;
|
|
3846
|
+
rewrite += `\nconst { ${destructParts.join(", ")} } = ${isProxyId} ? {} : ${nsId};`;
|
|
3847
|
+
rewrite += `\n${bindingLines.join("\n")}`;
|
|
3848
|
+
}
|
|
3866
3849
|
ms.overwrite(imp.start, imp.end, rewrite);
|
|
3867
3850
|
}
|
|
3868
3851
|
changed = true;
|
|
@@ -4138,6 +4121,205 @@ function pluginRemoteNamedExports(options) {
|
|
|
4138
4121
|
};
|
|
4139
4122
|
}
|
|
4140
4123
|
//#endregion
|
|
4124
|
+
//#region src/plugins/pluginSSRRemoteEntry.ts
|
|
4125
|
+
/**
|
|
4126
|
+
* Emits a Node-compatible SSR remote entry alongside the browser entry.
|
|
4127
|
+
*
|
|
4128
|
+
* Format strategy:
|
|
4129
|
+
* - Emit a dedicated ESM SSR entry alongside the browser entry.
|
|
4130
|
+
* - Keep the SSR entry out of the browser remote graph for Rollup builds by
|
|
4131
|
+
* emitting it as a generated asset.
|
|
4132
|
+
*
|
|
4133
|
+
* In both cases shared packages (react, react-dom, etc.) are marked as external
|
|
4134
|
+
* so Node resolves them through its own module cache, guaranteeing the singleton
|
|
4135
|
+
* is shared with react-dom/server.
|
|
4136
|
+
*/
|
|
4137
|
+
function pluginSSRRemoteEntry(options) {
|
|
4138
|
+
const remoteEntrySSRId = getRemoteEntrySSRId(options);
|
|
4139
|
+
const virtualExposesSSRId = getVirtualExposesSSRId(options);
|
|
4140
|
+
let isRolldown = false;
|
|
4141
|
+
let ssrOutputFilename = "";
|
|
4142
|
+
const ssrOnlyExternals = [
|
|
4143
|
+
"@module-federation/runtime",
|
|
4144
|
+
"@module-federation/runtime-core",
|
|
4145
|
+
"@module-federation/sdk",
|
|
4146
|
+
...options.ssrExternals ?? []
|
|
4147
|
+
];
|
|
4148
|
+
const ssrOnlyExternalPattern = new RegExp(`^(${ssrOnlyExternals.map((e) => e.replace(/[/\\^$*+?.()|[\]{}]/g, "\\$&")).join("|")})(\\/.*)?$`);
|
|
4149
|
+
const ssrModuleIds = new Set([remoteEntrySSRId, virtualExposesSSRId]);
|
|
4150
|
+
const resolvedAbsToPackage = /* @__PURE__ */ new Map();
|
|
4151
|
+
let isServe = false;
|
|
4152
|
+
let viteConfig;
|
|
4153
|
+
let isNuxtProject = false;
|
|
4154
|
+
const findNuxtExposesChunk = (bundle) => {
|
|
4155
|
+
const exposeKeys = Object.keys(options.exposes);
|
|
4156
|
+
if (exposeKeys.length === 0) return;
|
|
4157
|
+
return Object.values(bundle).find((file) => {
|
|
4158
|
+
if (file.type !== "chunk" || !file.fileName.startsWith("_nuxt/") || !file.fileName.endsWith(".js")) return false;
|
|
4159
|
+
const code = file.code || "";
|
|
4160
|
+
return exposeKeys.every((key) => code.includes(JSON.stringify(key)));
|
|
4161
|
+
})?.fileName;
|
|
4162
|
+
};
|
|
4163
|
+
return [{
|
|
4164
|
+
name: "mf:ssr-remote-entry:pre",
|
|
4165
|
+
enforce: "pre",
|
|
4166
|
+
configResolved(config) {
|
|
4167
|
+
isServe = config.command === "serve";
|
|
4168
|
+
for (const pkg of ssrOnlyExternals) {
|
|
4169
|
+
const aliasEntry = (config.resolve?.alias)?.find((a) => a.find === pkg || a.find instanceof RegExp && a.find.test(pkg));
|
|
4170
|
+
if (aliasEntry?.replacement) resolvedAbsToPackage.set(aliasEntry.replacement, pkg);
|
|
4171
|
+
}
|
|
4172
|
+
},
|
|
4173
|
+
resolveId(id, importer) {
|
|
4174
|
+
if (id === remoteEntrySSRId || id.startsWith(remoteEntrySSRId)) return id;
|
|
4175
|
+
if (id === virtualExposesSSRId || id.startsWith(virtualExposesSSRId)) return id;
|
|
4176
|
+
if (!importer || !ssrModuleIds.has(importer)) return;
|
|
4177
|
+
if (ssrOnlyExternalPattern.test(id)) return {
|
|
4178
|
+
id,
|
|
4179
|
+
external: true
|
|
4180
|
+
};
|
|
4181
|
+
const pkg = resolvedAbsToPackage.get(id);
|
|
4182
|
+
if (pkg) return {
|
|
4183
|
+
id: pkg,
|
|
4184
|
+
external: true
|
|
4185
|
+
};
|
|
4186
|
+
if (id.startsWith(".") || id.startsWith("/") || id.startsWith("file:")) return this.resolve(id, importer, { skipSelf: true }).then((resolved) => {
|
|
4187
|
+
if (resolved) ssrModuleIds.add(resolved.id);
|
|
4188
|
+
return resolved;
|
|
4189
|
+
});
|
|
4190
|
+
}
|
|
4191
|
+
}, {
|
|
4192
|
+
name: "mf:ssr-remote-entry",
|
|
4193
|
+
configResolved(config) {
|
|
4194
|
+
viteConfig = config;
|
|
4195
|
+
isNuxtProject = require_packageUtils.isNuxtProjectRoot(config.root);
|
|
4196
|
+
},
|
|
4197
|
+
configureServer(server) {
|
|
4198
|
+
const base = "/__mf_ssr__";
|
|
4199
|
+
const basePath = getBasePath(viteConfig?.base);
|
|
4200
|
+
const ssrEntryFileName = getSsrRemoteEntryFileName(options.filename);
|
|
4201
|
+
if (isNuxtProject || isNuxtClientBase(basePath)) server.middlewares.use((req, _res, next) => {
|
|
4202
|
+
if (req.url?.replace(/\?.*/, "") === `${basePath}/${ssrEntryFileName}`) req.url = `${basePath}/__mf_ssr__/${ssrEntryFileName}`;
|
|
4203
|
+
next();
|
|
4204
|
+
});
|
|
4205
|
+
const ssrEnv = server.environments?.ssr;
|
|
4206
|
+
const clientEnv = server.environments?.client;
|
|
4207
|
+
if (typeof (ssrEnv?.fetchModule ?? clientEnv?.fetchModule) === "function") server.middlewares.use("/__mf_runner__", async (req, res) => {
|
|
4208
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
4209
|
+
if (req.method === "OPTIONS") {
|
|
4210
|
+
res.setHeader("Access-Control-Allow-Methods", "POST");
|
|
4211
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
4212
|
+
res.statusCode = 204;
|
|
4213
|
+
res.end();
|
|
4214
|
+
return;
|
|
4215
|
+
}
|
|
4216
|
+
if (req.method !== "POST") {
|
|
4217
|
+
res.statusCode = 405;
|
|
4218
|
+
res.end("Method not allowed");
|
|
4219
|
+
return;
|
|
4220
|
+
}
|
|
4221
|
+
try {
|
|
4222
|
+
const chunks = [];
|
|
4223
|
+
await new Promise((resolve, reject) => {
|
|
4224
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
4225
|
+
req.on("end", resolve);
|
|
4226
|
+
req.on("error", reject);
|
|
4227
|
+
});
|
|
4228
|
+
const body = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
4229
|
+
if (body.name === "getBuiltins") {
|
|
4230
|
+
const builtins = (clientEnv ?? ssrEnv)?.config?.resolve?.builtins ?? [];
|
|
4231
|
+
res.setHeader("Content-Type", "application/json");
|
|
4232
|
+
res.end(JSON.stringify({ result: builtins }));
|
|
4233
|
+
return;
|
|
4234
|
+
}
|
|
4235
|
+
if (body.name !== "fetchModule") {
|
|
4236
|
+
res.statusCode = 400;
|
|
4237
|
+
res.end(JSON.stringify({ error: { message: `Unsupported invoke: ${body.name}` } }));
|
|
4238
|
+
return;
|
|
4239
|
+
}
|
|
4240
|
+
const [id, importer, opts] = body.data;
|
|
4241
|
+
const fetchEnv = ssrEnv ?? clientEnv;
|
|
4242
|
+
const fetchFn = fetchEnv.fetchModule.bind(fetchEnv);
|
|
4243
|
+
let result;
|
|
4244
|
+
try {
|
|
4245
|
+
result = await fetchFn(id, importer, opts);
|
|
4246
|
+
} catch (fetchErr) {
|
|
4247
|
+
const bareId = id.startsWith("/@id/") ? id.slice(5).replace(/^__x00__/, "\0") : id;
|
|
4248
|
+
try {
|
|
4249
|
+
const { createRequire } = await import("module");
|
|
4250
|
+
const resolved = createRequire(new URL(`file://${server.config.root}/package.json`)).resolve(bareId.replace(/^\0/, ""));
|
|
4251
|
+
const { pathToFileURL } = await import("url");
|
|
4252
|
+
result = {
|
|
4253
|
+
externalize: pathToFileURL(resolved).href,
|
|
4254
|
+
type: "module"
|
|
4255
|
+
};
|
|
4256
|
+
} catch {
|
|
4257
|
+
throw fetchErr;
|
|
4258
|
+
}
|
|
4259
|
+
}
|
|
4260
|
+
res.setHeader("Content-Type", "application/json");
|
|
4261
|
+
res.end(JSON.stringify({ result }));
|
|
4262
|
+
} catch (e) {
|
|
4263
|
+
res.setHeader("Content-Type", "application/json");
|
|
4264
|
+
res.end(JSON.stringify({ error: { message: String(e instanceof Error ? e.message : e) } }));
|
|
4265
|
+
}
|
|
4266
|
+
});
|
|
4267
|
+
const ssrPath = `${base}/${ssrEntryFileName}`;
|
|
4268
|
+
server.middlewares.use(ssrPath, (_req, res) => {
|
|
4269
|
+
const exposesUrl = `${base}/${options.filename.replace(/\.[^.]+$/, "")}.exposes.js`;
|
|
4270
|
+
const code = generateRemoteEntrySSR(options).replace(JSON.stringify(virtualExposesSSRId), JSON.stringify(exposesUrl));
|
|
4271
|
+
res.setHeader("Content-Type", "application/javascript");
|
|
4272
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
4273
|
+
res.end(code);
|
|
4274
|
+
});
|
|
4275
|
+
},
|
|
4276
|
+
resolveId(id) {
|
|
4277
|
+
if (id === remoteEntrySSRId || id.startsWith(remoteEntrySSRId)) return id;
|
|
4278
|
+
if (id === virtualExposesSSRId || id.startsWith(virtualExposesSSRId)) return id;
|
|
4279
|
+
if (id === `/__mf_ssr__/${getSsrRemoteEntryFileName(options.filename)}`) return remoteEntrySSRId;
|
|
4280
|
+
if (id === `/__mf_ssr__/${options.filename.replace(/\.[^.]+$/, "")}.exposes.js`) return virtualExposesSSRId;
|
|
4281
|
+
},
|
|
4282
|
+
load(id) {
|
|
4283
|
+
if (id === remoteEntrySSRId || id.startsWith(remoteEntrySSRId)) return generateRemoteEntrySSR(options);
|
|
4284
|
+
if (id === virtualExposesSSRId || id.startsWith(virtualExposesSSRId)) return generateExposesSSR(options);
|
|
4285
|
+
},
|
|
4286
|
+
buildStart() {
|
|
4287
|
+
if (isServe) return;
|
|
4288
|
+
isRolldown = require_packageUtils.getIsRolldown(this);
|
|
4289
|
+
ssrOutputFilename = getSsrRemoteEntryFileName(options.filename);
|
|
4290
|
+
const environmentName = this.environment?.name;
|
|
4291
|
+
const hasSsrEnvironment = Boolean(viteConfig?.environments?.ssr);
|
|
4292
|
+
const isLegacySsrBuild = Boolean(this.environment?.config?.build?.ssr);
|
|
4293
|
+
if (hasSsrEnvironment) {
|
|
4294
|
+
if (isNuxtProject) {
|
|
4295
|
+
if (environmentName === "ssr") return;
|
|
4296
|
+
} else if (environmentName !== "ssr") return;
|
|
4297
|
+
} else if (isLegacySsrBuild) {} else if (environmentName && environmentName !== "client") return;
|
|
4298
|
+
if (Object.keys(options.exposes).length === 0) return;
|
|
4299
|
+
if (isRolldown) this.emitFile({
|
|
4300
|
+
type: "chunk",
|
|
4301
|
+
id: remoteEntrySSRId,
|
|
4302
|
+
name: "ssrRemoteEntry",
|
|
4303
|
+
fileName: ssrOutputFilename,
|
|
4304
|
+
preserveSignature: "strict"
|
|
4305
|
+
});
|
|
4306
|
+
else this.emitFile({
|
|
4307
|
+
type: "asset",
|
|
4308
|
+
fileName: ssrOutputFilename,
|
|
4309
|
+
source: generateRemoteEntrySSR(options)
|
|
4310
|
+
});
|
|
4311
|
+
},
|
|
4312
|
+
generateBundle(_options, bundle) {
|
|
4313
|
+
const exposesChunk = findNuxtExposesChunk(bundle);
|
|
4314
|
+
const ssrAsset = bundle[ssrOutputFilename];
|
|
4315
|
+
if (exposesChunk && ssrAsset?.type === "asset" && typeof ssrAsset.source === "string") ssrAsset.source = ssrAsset.source.replace(/import\("virtual:mf-exposes-ssr:[^"]+"\)/g, `import("./${exposesChunk}")`);
|
|
4316
|
+
if (!isRolldown) return;
|
|
4317
|
+
const chunk = bundle[ssrOutputFilename];
|
|
4318
|
+
if (!chunk || chunk.type !== "chunk") return;
|
|
4319
|
+
}
|
|
4320
|
+
}];
|
|
4321
|
+
}
|
|
4322
|
+
//#endregion
|
|
4141
4323
|
//#region src/plugins/pluginVarRemoteEntry.ts
|
|
4142
4324
|
const VarRemoteEntry = () => {
|
|
4143
4325
|
const mfOptions = getNormalizeModuleFederationOptions();
|
|
@@ -4173,9 +4355,9 @@ const VarRemoteEntry = () => {
|
|
|
4173
4355
|
},
|
|
4174
4356
|
async generateBundle(_options, bundle) {
|
|
4175
4357
|
if (!varFilename) return;
|
|
4176
|
-
if (!isValidVarName(name)) mfWarn(`Provided remote name "${name}" is not valid for "var" remoteEntry type, thus it's placed in globalThis['${name}'].\nIt may cause problems, so you would better want to use valid var name (see https://www.w3schools.com/js/js_variables.asp).`);
|
|
4358
|
+
if (!isValidVarName(name)) require_packageUtils.mfWarn(`Provided remote name "${name}" is not valid for "var" remoteEntry type, thus it's placed in globalThis['${name}'].\nIt may cause problems, so you would better want to use valid var name (see https://www.w3schools.com/js/js_variables.asp).`);
|
|
4177
4359
|
const remoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
|
|
4178
|
-
if (!remoteEntryFile) throw createModuleFederationError(`Couldn't find a remoteEntry chunk file for ${mfOptions.filename}, can't generate varRemoteEntry file`);
|
|
4360
|
+
if (!remoteEntryFile) throw require_packageUtils.createModuleFederationError(`Couldn't find a remoteEntry chunk file for ${mfOptions.filename}, can't generate varRemoteEntry file`);
|
|
4179
4361
|
this.emitFile({
|
|
4180
4362
|
type: "asset",
|
|
4181
4363
|
fileName: varFilename,
|
|
@@ -4398,10 +4580,15 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
4398
4580
|
config(config, { command: _command }) {
|
|
4399
4581
|
if (_command === "serve") ignoreFederationGeneratedFiles(config, options);
|
|
4400
4582
|
const root = config.root || process.cwd();
|
|
4401
|
-
setPackageDetectionCwd(root);
|
|
4402
|
-
const isVinext = hasPackageDependency("vinext");
|
|
4583
|
+
require_packageUtils.setPackageDetectionCwd(root);
|
|
4584
|
+
const isVinext = require_packageUtils.hasPackageDependency("vinext");
|
|
4585
|
+
setSsrRemotes(Object.entries(options.remotes).map(([key, r]) => ({
|
|
4586
|
+
name: key,
|
|
4587
|
+
entry: r.entry,
|
|
4588
|
+
type: r.type ?? "module"
|
|
4589
|
+
})));
|
|
4403
4590
|
initVirtualModules(_command, getRemoteEntryId(options));
|
|
4404
|
-
const isRolldown = getIsRolldown(this);
|
|
4591
|
+
const isRolldown = require_packageUtils.getIsRolldown(this);
|
|
4405
4592
|
if (remotes && Object.keys(remotes).length > 0) {
|
|
4406
4593
|
for (const key of Object.keys(remotes)) addUsedRemote(key, key);
|
|
4407
4594
|
if (_command === "serve") {
|
|
@@ -4519,15 +4706,52 @@ export default __mfShared.default ?? __mfShared;`
|
|
|
4519
4706
|
}
|
|
4520
4707
|
writeLocalSharedImportMap();
|
|
4521
4708
|
}
|
|
4709
|
+
},
|
|
4710
|
+
configResolved(config) {
|
|
4711
|
+
if (parseInt(vite.version, 10) < 8) return;
|
|
4712
|
+
if (!(Object.keys(options.exposes).length > 0 || Object.keys(options.remotes).length > 0)) return;
|
|
4713
|
+
if (options.runtimePlugins.some((p) => {
|
|
4714
|
+
return (typeof p === "string" ? p : p[0]) === "@module-federation/vite/ssrEntryLoader";
|
|
4715
|
+
})) return;
|
|
4716
|
+
const pluginRequire = (0, module$1.createRequire)(require("url").pathToFileURL(__filename).href);
|
|
4717
|
+
const projectRequire = (0, module$1.createRequire)(new URL(`file://${config.root}/package.json`));
|
|
4718
|
+
const sharedKeys = Object.keys(options.shared ?? {});
|
|
4719
|
+
const commonSharedPkgs = [
|
|
4720
|
+
"react",
|
|
4721
|
+
"react-dom",
|
|
4722
|
+
"react/jsx-runtime",
|
|
4723
|
+
"react/jsx-dev-runtime",
|
|
4724
|
+
"@module-federation/runtime",
|
|
4725
|
+
"@module-federation/runtime-core",
|
|
4726
|
+
"@module-federation/sdk"
|
|
4727
|
+
];
|
|
4728
|
+
const resolvedShared = {};
|
|
4729
|
+
for (const pkg of [...commonSharedPkgs, ...sharedKeys]) try {
|
|
4730
|
+
resolvedShared[pkg] = projectRequire.resolve(pkg);
|
|
4731
|
+
} catch {
|
|
4732
|
+
try {
|
|
4733
|
+
resolvedShared[pkg] = pluginRequire.resolve(pkg);
|
|
4734
|
+
} catch {}
|
|
4735
|
+
}
|
|
4736
|
+
const ssrEntryLoaderSpecifier = "@module-federation/vite/ssrEntryLoader";
|
|
4737
|
+
try {
|
|
4738
|
+
pluginRequire.resolve(ssrEntryLoaderSpecifier);
|
|
4739
|
+
options.runtimePlugins.push([ssrEntryLoaderSpecifier, { resolvedShared }]);
|
|
4740
|
+
} catch {}
|
|
4522
4741
|
}
|
|
4523
4742
|
};
|
|
4524
4743
|
}
|
|
4744
|
+
const SSR_ONLY_PLUGINS = new Set(["@module-federation/vite/ssrEntryLoader"]);
|
|
4745
|
+
function loadPluginDts(options) {
|
|
4746
|
+
if (options.dts === false) return [];
|
|
4747
|
+
return [Promise.resolve().then(() => require("./pluginDts-BEOKyKQ-.cjs")).then(({ default: pluginDts }) => pluginDts(options))];
|
|
4748
|
+
}
|
|
4525
4749
|
function federation(mfUserOptions) {
|
|
4526
4750
|
if (isTestEnv()) return [];
|
|
4527
4751
|
const options = normalizeModuleFederationOptions(mfUserOptions);
|
|
4528
|
-
const isVinext = hasPackageDependency("vinext");
|
|
4752
|
+
const isVinext = require_packageUtils.hasPackageDependency("vinext");
|
|
4529
4753
|
const { name, shared, filename, hostInitInjectLocation } = options;
|
|
4530
|
-
if (!name) throw createModuleFederationError("name is required");
|
|
4754
|
+
if (!name) throw require_packageUtils.createModuleFederationError("name is required");
|
|
4531
4755
|
const remoteEntryId = getRemoteEntryId(options);
|
|
4532
4756
|
const virtualExposesId = getVirtualExposesId(options);
|
|
4533
4757
|
let command;
|
|
@@ -4573,14 +4797,26 @@ function federation(mfUserOptions) {
|
|
|
4573
4797
|
command = env.command;
|
|
4574
4798
|
},
|
|
4575
4799
|
configResolved() {
|
|
4576
|
-
initVirtualModules(command, remoteEntryId);
|
|
4800
|
+
initVirtualModules(command, remoteEntryId, parseInt(vite.version, 10) >= 8);
|
|
4577
4801
|
}
|
|
4578
4802
|
},
|
|
4579
4803
|
aliasToArrayPlugin_default,
|
|
4580
4804
|
checkAliasConflicts({ shared }),
|
|
4581
4805
|
normalizeOptimizeDeps_default,
|
|
4582
|
-
...
|
|
4806
|
+
...loadPluginDts(options),
|
|
4583
4807
|
pluginDevRemoteHmr(options),
|
|
4808
|
+
{
|
|
4809
|
+
name: "mf:normalize-entry-chunks",
|
|
4810
|
+
enforce: "pre",
|
|
4811
|
+
apply: "build",
|
|
4812
|
+
generateBundle(_options, bundle) {
|
|
4813
|
+
for (const chunk of Object.values(bundle)) {
|
|
4814
|
+
if (typeof chunk !== "object" || chunk === null || chunk.type !== "chunk" || !chunk.isEntry) continue;
|
|
4815
|
+
const facadeId = chunk.facadeModuleId ?? "";
|
|
4816
|
+
if (facadeId.includes("__mf__virtual") || facadeId.startsWith("virtual:mf-") || facadeId.startsWith("virtual:mf:") || facadeId.startsWith("\0virtual:mf-") || facadeId.startsWith("\0virtual:mf:")) chunk.isEntry = false;
|
|
4817
|
+
}
|
|
4818
|
+
}
|
|
4819
|
+
},
|
|
4584
4820
|
...addEntry({
|
|
4585
4821
|
entryName: "remoteEntry",
|
|
4586
4822
|
entryPath: remoteEntryId,
|
|
@@ -4590,7 +4826,8 @@ function federation(mfUserOptions) {
|
|
|
4590
4826
|
entryName: "hostInit",
|
|
4591
4827
|
entryPath: () => getHostAutoInitPath(),
|
|
4592
4828
|
inject: hostInitInjectLocation,
|
|
4593
|
-
forceClientInjected: Object.keys(options.exposes).length > 0
|
|
4829
|
+
forceClientInjected: Object.keys(options.exposes).length > 0,
|
|
4830
|
+
skipTransformFor: Object.values(options.exposes).map((expose) => expose.import)
|
|
4594
4831
|
}),
|
|
4595
4832
|
...addEntry({
|
|
4596
4833
|
entryName: "virtualExposes",
|
|
@@ -4640,7 +4877,7 @@ function federation(mfUserOptions) {
|
|
|
4640
4877
|
delete output.codeSplitting;
|
|
4641
4878
|
if (warnedAboutCodeSplitting) return;
|
|
4642
4879
|
warnedAboutCodeSplitting = true;
|
|
4643
|
-
mfWarn("Ignoring `output.codeSplitting = false` because module federation requires chunk splitting.");
|
|
4880
|
+
require_packageUtils.mfWarn("Ignoring `output.codeSplitting = false` because module federation requires chunk splitting.");
|
|
4644
4881
|
return;
|
|
4645
4882
|
}
|
|
4646
4883
|
if (!output?.codeSplitting || typeof output.codeSplitting !== "object") return;
|
|
@@ -4649,7 +4886,7 @@ function federation(mfUserOptions) {
|
|
|
4649
4886
|
if (Object.keys(output.codeSplitting).length === 0) delete output.codeSplitting;
|
|
4650
4887
|
if (warnedAboutCodeSplittingGroups) return;
|
|
4651
4888
|
warnedAboutCodeSplittingGroups = true;
|
|
4652
|
-
mfWarn("Ignoring `output.codeSplitting.groups` because it conflicts with module federation. Grouping shared dependency init wrappers with their dependent modules can break runtime init order and cause standalone remotes to fail before mount.");
|
|
4889
|
+
require_packageUtils.mfWarn("Ignoring `output.codeSplitting.groups` because it conflicts with module federation. Grouping shared dependency init wrappers with their dependent modules can break runtime init order and cause standalone remotes to fail before mount.");
|
|
4653
4890
|
};
|
|
4654
4891
|
let warnedAboutManualChunks = false;
|
|
4655
4892
|
const applyManualChunks = (output) => {
|
|
@@ -4657,7 +4894,7 @@ function federation(mfUserOptions) {
|
|
|
4657
4894
|
const isPatchedByPlugin = typeof output.manualChunks === "function" && patchedManualChunks.has(output.manualChunks);
|
|
4658
4895
|
if (output.manualChunks && !isPatchedByPlugin && !warnedAboutManualChunks) {
|
|
4659
4896
|
warnedAboutManualChunks = true;
|
|
4660
|
-
mfWarn("Ignoring `output.manualChunks` because it conflicts with module federation. Module federation transforms shared dependency imports with async init wrappers, and grouping these transformed modules into a single chunk creates circular async dependencies that cause the application to silently hang.");
|
|
4897
|
+
require_packageUtils.mfWarn("Ignoring `output.manualChunks` because it conflicts with module federation. Module federation transforms shared dependency imports with async init wrappers, and grouping these transformed modules into a single chunk creates circular async dependencies that cause the application to silently hang.");
|
|
4661
4898
|
}
|
|
4662
4899
|
const mfManualChunks = function(id) {
|
|
4663
4900
|
if (id.includes(runtimeInitId)) return "runtimeInit";
|
|
@@ -4735,11 +4972,11 @@ function federation(mfUserOptions) {
|
|
|
4735
4972
|
*
|
|
4736
4973
|
* @see https://rollupjs.org/plugin-development/#synthetic-named-exports
|
|
4737
4974
|
*/
|
|
4738
|
-
if (!/\bexport\s+const\s+__moduleExports\b/.test(code)) {
|
|
4975
|
+
if (!/\bexport\s+const\s+__moduleExports\b/.test(code) && !/\bexport\s*\{[^}]*__moduleExports/.test(code)) {
|
|
4739
4976
|
const nextCode = code.replace("export default exportModule", "export const __moduleExports = exportModule;\nexport default exportModule.__esModule ? exportModule.default : exportModule");
|
|
4740
4977
|
code = nextCode === code ? `${code}\nexport const __moduleExports = exportModule;\n` : nextCode;
|
|
4741
4978
|
}
|
|
4742
|
-
if (getIsRolldown(this)) return { code };
|
|
4979
|
+
if (require_packageUtils.getIsRolldown(this)) return { code };
|
|
4743
4980
|
return {
|
|
4744
4981
|
code,
|
|
4745
4982
|
syntheticNamedExports: "__moduleExports"
|
|
@@ -4793,7 +5030,7 @@ function federation(mfUserOptions) {
|
|
|
4793
5030
|
enforce: "post",
|
|
4794
5031
|
_options: options,
|
|
4795
5032
|
config(config, { command: _command }) {
|
|
4796
|
-
const isRolldown = getIsRolldown(this);
|
|
5033
|
+
const isRolldown = require_packageUtils.getIsRolldown(this);
|
|
4797
5034
|
let implementation = options.implementation;
|
|
4798
5035
|
if (isRolldown) implementation = implementation.replace(/\.cjs(\.js)?$/, ".js");
|
|
4799
5036
|
appendResolveAlias(config, {
|
|
@@ -4808,27 +5045,29 @@ function federation(mfUserOptions) {
|
|
|
4808
5045
|
config.optimizeDeps.include.push("@module-federation/runtime");
|
|
4809
5046
|
options.runtimePlugins.forEach((p) => {
|
|
4810
5047
|
const pluginPath = typeof p === "string" ? p : p[0];
|
|
5048
|
+
if (SSR_ONLY_PLUGINS.has(pluginPath)) return;
|
|
4811
5049
|
if (pluginPath && !pluginPath.startsWith(".") && !pluginPath.startsWith("/") && !pluginPath.startsWith("\0") && !pluginPath.startsWith("virtual:")) config.optimizeDeps.include.push(pluginPath);
|
|
4812
5050
|
});
|
|
4813
5051
|
if (isRolldown) {
|
|
4814
5052
|
config.build ??= {};
|
|
4815
5053
|
config.build.target ??= "esnext";
|
|
4816
5054
|
}
|
|
4817
|
-
const isAstro = hasPackageDependency("astro");
|
|
5055
|
+
const isAstro = require_packageUtils.hasPackageDependency("astro");
|
|
4818
5056
|
const resolvedTarget = options.target ?? (config.build?.ssr ? "node" : "web");
|
|
4819
5057
|
const envTargetDefineValue = !options.target && isAstro ? "undefined" : JSON.stringify(resolvedTarget);
|
|
4820
5058
|
if (!config.define) config.define = {};
|
|
4821
5059
|
if (!("ENV_TARGET" in config.define)) config.define["ENV_TARGET"] = envTargetDefineValue;
|
|
4822
|
-
if (options.target && "ENV_TARGET" in config.define && config.define["ENV_TARGET"] !== JSON.stringify(options.target)) mfWarn(`ENV_TARGET define (${config.define["ENV_TARGET"]}) differs from target option ("${options.target}"). ENV_TARGET will not be overridden.`);
|
|
5060
|
+
if (options.target && "ENV_TARGET" in config.define && config.define["ENV_TARGET"] !== JSON.stringify(options.target)) require_packageUtils.mfWarn(`ENV_TARGET define (${config.define["ENV_TARGET"]}) differs from target option ("${options.target}"). ENV_TARGET will not be overridden.`);
|
|
4823
5061
|
}
|
|
4824
5062
|
},
|
|
4825
5063
|
...Manifest(),
|
|
5064
|
+
...pluginSSRRemoteEntry(options),
|
|
4826
5065
|
...VarRemoteEntry(),
|
|
4827
5066
|
{
|
|
4828
5067
|
name: "module-federation-vinext-fix-rsc-preload-as",
|
|
4829
5068
|
enforce: "post",
|
|
4830
5069
|
configureServer(server) {
|
|
4831
|
-
if (!hasPackageDependency("vinext")) return;
|
|
5070
|
+
if (!require_packageUtils.hasPackageDependency("vinext")) return;
|
|
4832
5071
|
server.middlewares.use((req, res, next) => {
|
|
4833
5072
|
if (!req.headers.accept?.includes("text/html")) {
|
|
4834
5073
|
next();
|
|
@@ -4848,7 +5087,7 @@ function federation(mfUserOptions) {
|
|
|
4848
5087
|
});
|
|
4849
5088
|
},
|
|
4850
5089
|
generateBundle(_, bundle, _isWrite) {
|
|
4851
|
-
if (!hasPackageDependency("vinext")) return;
|
|
5090
|
+
if (!require_packageUtils.hasPackageDependency("vinext")) return;
|
|
4852
5091
|
for (const chunk of Object.values(bundle)) {
|
|
4853
5092
|
if (!isOutputChunk(chunk)) continue;
|
|
4854
5093
|
if (!chunk.code.includes("case\"L\"")) continue;
|
|
@@ -4896,5 +5135,9 @@ function federation(mfUserOptions) {
|
|
|
4896
5135
|
})()
|
|
4897
5136
|
];
|
|
4898
5137
|
}
|
|
5138
|
+
function createModuleFederationConfig(options) {
|
|
5139
|
+
return options;
|
|
5140
|
+
}
|
|
4899
5141
|
//#endregion
|
|
5142
|
+
exports.createModuleFederationConfig = createModuleFederationConfig;
|
|
4900
5143
|
exports.federation = federation;
|