@module-federation/vite 1.15.5 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.cjs CHANGED
@@ -1,34 +1,11 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- //#region \0rolldown/runtime.js
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 _module_federation_sdk = require("@module-federation/sdk");
30
- let _module_federation_dts_plugin = require("@module-federation/dts-plugin");
31
- let _module_federation_dts_plugin_core = require("@module-federation/dts-plugin/core");
7
+ pathe = require_packageUtils.__toESM(pathe);
8
+ let vite = require("vite");
32
9
  let url = require("url");
33
10
  let es_module_lexer = require("es-module-lexer");
34
11
  //#region src/utils/codeRewriter.ts
@@ -192,237 +169,6 @@ function injectEntryScript(html, initSrc) {
192
169
  return html.replace("<head>", `<head><script type="module" src=${JSON.stringify(src)}><\/script>`);
193
170
  }
194
171
  //#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
172
  //#region src/utils/normalizeModuleFederationOptions.ts
427
173
  const INTERNAL_NAME_PREFIX = "__mfe_internal__";
428
174
  function toInternalModuleFederationName(name) {
@@ -430,7 +176,7 @@ function toInternalModuleFederationName(name) {
430
176
  }
431
177
  function warnOnReservedInternalNamePrefix(name, kind) {
432
178
  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.`);
179
+ 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
180
  }
435
181
  function normalizeExposesItem(item) {
436
182
  let importPath = "";
@@ -494,7 +240,7 @@ function normalizeRemoteItem(key, remote) {
494
240
  * @returns {string | undefined}
495
241
  */
496
242
  function searchPackageVersion(sharedName) {
497
- const version = getInstalledPackageJson(sharedName, { packageName: sharedName })?.packageJson.version;
243
+ const version = require_packageUtils.getInstalledPackageJson(sharedName)?.packageJson.version;
498
244
  return typeof version === "string" ? version : void 0;
499
245
  }
500
246
  function inferVersionFromRequiredVersion(requiredVersion) {
@@ -503,7 +249,7 @@ function inferVersionFromRequiredVersion(requiredVersion) {
503
249
  }
504
250
  function getLitExportSubpathShares(sharedName) {
505
251
  if (sharedName !== "lit") return [];
506
- const exportsField = getInstalledPackageJson(sharedName, { packageName: sharedName })?.packageJson.exports;
252
+ const exportsField = require_packageUtils.getInstalledPackageJson(sharedName, { packageName: sharedName })?.packageJson.exports;
507
253
  if (!exportsField || typeof exportsField === "string") return [];
508
254
  return Object.keys(exportsField).filter((key) => key.startsWith("./") && key !== "." && !key.includes("*")).map((key) => `${sharedName}/${key.slice(2)}`);
509
255
  }
@@ -512,18 +258,18 @@ function normalizeShareItem(key, shareItem) {
512
258
  const isImportFalse = typeof shareItem === "object" && shareItem.import === false;
513
259
  try {
514
260
  try {
515
- version = require(pathe.join(getPackageName(key), "package.json")).version;
261
+ version = require(pathe.join(require_packageUtils.getPackageName(key), "package.json")).version;
516
262
  } catch (e1) {
517
263
  try {
518
- const localPath = pathe.join(process.cwd(), "node_modules", getPackageName(key), "package.json");
264
+ const localPath = pathe.join(process.cwd(), "node_modules", require_packageUtils.getPackageName(key), "package.json");
519
265
  version = require(localPath).version;
520
266
  } catch (e2) {
521
267
  version = searchPackageVersion(key);
522
- if (!version && !isImportFalse) mfError(e1);
268
+ if (!version && !isImportFalse) require_packageUtils.mfError(e1);
523
269
  }
524
270
  }
525
271
  } catch (e) {
526
- if (!isImportFalse) mfError(`Unexpected error resolving version for ${key}:`, e);
272
+ if (!isImportFalse) require_packageUtils.mfError(`Unexpected error resolving version for ${key}:`, e);
527
273
  }
528
274
  if (typeof shareItem === "string") return {
529
275
  name: shareItem,
@@ -553,7 +299,7 @@ function normalizeShared(shared) {
553
299
  explicitSharedKeys = /* @__PURE__ */ new Set();
554
300
  if (!shared) {
555
301
  const result = {};
556
- const packageJsonPath = pathe.join(getPackageDetectionCwd(), "package.json");
302
+ const packageJsonPath = pathe.join(require_packageUtils.getPackageDetectionCwd(), "package.json");
557
303
  try {
558
304
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
559
305
  if (packageJson.name === "@module-federation/vite") return result;
@@ -591,7 +337,7 @@ function normalizeShared(shared) {
591
337
  return result;
592
338
  }
593
339
  function shouldAutoShareDependency(key) {
594
- const pkg = getInstalledPackageJson(key)?.packageJson;
340
+ const pkg = require_packageUtils.getInstalledPackageJson(key)?.packageJson;
595
341
  if (!pkg) return false;
596
342
  if (!pkg.browser && !pkg.exports && typeof pkg.module !== "string") return false;
597
343
  if (key === "@module-federation/vite") return false;
@@ -618,6 +364,18 @@ function normalizeManifest(manifest) {
618
364
  }
619
365
  let config;
620
366
  let explicitSharedKeys = /* @__PURE__ */ new Set();
367
+ function resolveRuntimeImplementation() {
368
+ const fallback = require.resolve("@module-federation/runtime");
369
+ try {
370
+ const packageJsonPath = require.resolve("@module-federation/runtime/package.json");
371
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
372
+ const importExport = packageJson.exports?.["."];
373
+ const exportImport = typeof importExport === "object" ? typeof importExport.import === "string" ? importExport.import : importExport.import?.default : void 0;
374
+ const esmEntry = packageJson.module || exportImport;
375
+ if (esmEntry) return pathe.join(pathe.dirname(packageJsonPath), esmEntry);
376
+ } catch {}
377
+ return fallback;
378
+ }
621
379
  function getNormalizeModuleFederationOptions() {
622
380
  return config;
623
381
  }
@@ -626,11 +384,11 @@ function isExplicitSharedKey(key) {
626
384
  }
627
385
  function getNormalizeShareItem(key) {
628
386
  const options = getNormalizeModuleFederationOptions();
629
- return options.shared[key] || options.shared[getPackageName(key)] || options.shared[getPackageName(key) + "/"];
387
+ return options.shared[key] || options.shared[require_packageUtils.getPackageName(key)] || options.shared[require_packageUtils.getPackageName(key) + "/"];
630
388
  }
631
389
  function normalizeModuleFederationOptions(options) {
632
390
  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'.`);
391
+ 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
392
  return config = {
635
393
  exposes: normalizeExposes(options.exposes),
636
394
  filename: options.filename || "remoteEntry-[hash]",
@@ -642,7 +400,7 @@ function normalizeModuleFederationOptions(options) {
642
400
  shareScope: options.shareScope || "default",
643
401
  shared: normalizeShared(options.shared),
644
402
  runtimePlugins: options.runtimePlugins || [],
645
- implementation: options.implementation || require.resolve("@module-federation/runtime"),
403
+ implementation: options.implementation || resolveRuntimeImplementation(),
646
404
  manifest: normalizeManifest(options.manifest),
647
405
  dev: options.dev,
648
406
  dts: options.dts,
@@ -671,7 +429,7 @@ const patternMap = {};
671
429
  const cacheMap = {};
672
430
  function assertModuleFound(tag, str = "") {
673
431
  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.`);
432
+ 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
433
  return module;
676
434
  }
677
435
  var VirtualModule = class {
@@ -681,9 +439,9 @@ var VirtualModule = class {
681
439
  inited = false;
682
440
  code;
683
441
  static findModule(tag, str = "") {
684
- if (!patternMap[tag]) patternMap[tag] = new RegExp(`(.*${packageNameEncode(tag)}(.+?)${packageNameEncode(tag)}.*)`);
442
+ if (!patternMap[tag]) patternMap[tag] = new RegExp(`(.*${require_packageUtils.packageNameEncode(tag)}(.+?)${require_packageUtils.packageNameEncode(tag)}.*)`);
685
443
  const moduleName = (str.match(patternMap[tag]) || [])[2];
686
- if (moduleName) return cacheMap[tag][packageNameDecode(moduleName)];
444
+ if (moduleName) return cacheMap[tag][require_packageUtils.packageNameDecode(moduleName)];
687
445
  }
688
446
  static findById(id) {
689
447
  const normalized = id.replace(/^\0+/, "").replace(/^\/@id\//, "").replace(/^__x00__/, "").replace(/[?#].*$/, "");
@@ -698,7 +456,7 @@ var VirtualModule = class {
698
456
  }
699
457
  getImportId() {
700
458
  const { internalName: mfName } = getNormalizeModuleFederationOptions();
701
- return `virtual:mf:${packageNameEncode(`${mfName}${this.tag}${this.name}${this.tag}`)}${this.suffix}`;
459
+ return `virtual:mf:${require_packageUtils.packageNameEncode(`${mfName}${this.tag}${this.name}${this.tag}`)}${this.suffix}`;
702
460
  }
703
461
  getResolvedId() {
704
462
  return `\0${this.getImportId()}`;
@@ -856,11 +614,24 @@ function getDeferredInitPromiseCode() {
856
614
  initReject = rj;
857
615
  });`;
858
616
  }
859
- function getSsrNoopResolveCode() {
617
+ let _ssrRemotes = [];
618
+ function setSsrRemotes(remotes) {
619
+ _ssrRemotes = remotes;
620
+ }
621
+ function getSsrNoopResolveCode(enableSsrInit) {
622
+ if (!enableSsrInit) return "";
860
623
  return `if (typeof window === 'undefined') {
861
- initResolve({
862
- loadRemote: function() { return Promise.resolve(undefined); },
863
- loadShare: function() { return Promise.resolve(undefined); },
624
+ var _noop = { loadRemote: function() { return Promise.resolve(undefined); }, loadShare: function() { return Promise.resolve(undefined); } };
625
+ import(/* @vite-ignore */ '@module-federation/runtime').then(function(runtimeMod) {
626
+ return import(/* @vite-ignore */ '@module-federation/vite/ssrEntryLoader').then(
627
+ function(loaderMod) { return [runtimeMod, [loaderMod.default()]]; },
628
+ function() { return [runtimeMod, []]; }
629
+ );
630
+ }).then(function(pair) {
631
+ var runtime = pair[0].init({ name: '__mf_ssr_host__', remotes: ${JSON.stringify(_ssrRemotes)}, shared: {}, plugins: pair[1] });
632
+ initResolve(runtime);
633
+ }, function() {
634
+ initResolve(_noop);
864
635
  });
865
636
  }`;
866
637
  }
@@ -875,12 +646,12 @@ if (!${options.stateVar}) {
875
646
  initResolve,
876
647
  initReject,
877
648
  };
878
- ${getSsrNoopResolveCode()}
649
+ ${getSsrNoopResolveCode(options.enableSsrInit)}
879
650
  }
880
651
  const ${options.exposedConst} = ${options.stateVar}.${options.exposedProperty};
881
652
  `;
882
653
  }
883
- function getRuntimeInitBootstrapCode() {
654
+ function getRuntimeInitBootstrapCode(enableSsrInit = false) {
884
655
  return `
885
656
  const globalKey = ${JSON.stringify(getRuntimeInitGlobalKey())};
886
657
  const moduleCacheGlobalKey = ${JSON.stringify(MODULE_CACHE_GLOBAL_KEY)};
@@ -895,7 +666,7 @@ if (!globalThis[globalKey]) {
895
666
  initReject,
896
667
  moduleCache: globalThis[moduleCacheGlobalKey],
897
668
  };
898
- ${getSsrNoopResolveCode()}
669
+ ${getSsrNoopResolveCode(enableSsrInit)}
899
670
  }
900
671
  globalThis[globalKey].moduleCache ||= globalThis[moduleCacheGlobalKey];
901
672
  globalThis[globalKey].moduleCache.share ||= {};
@@ -911,27 +682,29 @@ globalThis[__mfCacheGlobalKey].remote ||= {};
911
682
  const __mfModuleCache = globalThis[__mfCacheGlobalKey];
912
683
  `;
913
684
  }
914
- function getRuntimeInitPromiseBootstrapCode() {
685
+ function getRuntimeInitPromiseBootstrapCode(enableSsrInit = false) {
915
686
  return getRuntimeInitStateBootstrapCode({
916
687
  globalKeyVar: "__mfPromiseGlobalKey",
917
688
  stateVar: "__mfPromiseState",
918
689
  exposedConst: "initPromise",
919
- exposedProperty: "initPromise"
690
+ exposedProperty: "initPromise",
691
+ enableSsrInit
920
692
  });
921
693
  }
922
- function getRuntimeInitResolveBootstrapCode() {
694
+ function getRuntimeInitResolveBootstrapCode(enableSsrInit = false) {
923
695
  return getRuntimeInitStateBootstrapCode({
924
696
  globalKeyVar: "__mfResolveGlobalKey",
925
697
  stateVar: "__mfResolveState",
926
698
  exposedConst: "initResolve",
927
- exposedProperty: "initResolve"
699
+ exposedProperty: "initResolve",
700
+ enableSsrInit
928
701
  });
929
702
  }
930
- function writeRuntimeInitStatus(command) {
703
+ function writeRuntimeInitStatus(command, enableSsrInit = false) {
931
704
  const exportStatement = command === "build" ? `const { initPromise, initResolve, initReject, moduleCache } = globalThis[globalKey];
932
705
  export { initPromise, initResolve, initReject, moduleCache };` : `module.exports = globalThis[globalKey];`;
933
706
  virtualRuntimeInitStatus.writeSync(`
934
- ${getRuntimeInitBootstrapCode()}
707
+ ${getRuntimeInitBootstrapCode(enableSsrInit)}
935
708
  ${exportStatement}
936
709
  `);
937
710
  }
@@ -969,13 +742,13 @@ const JS_IDENTIFIER_PATTERN = `[\$_\\p{ID_Start}][\$_\\u200C\\u200D\\p{ID_Contin
969
742
  const localRequire = (0, module$1.createRequire)(require("url").pathToFileURL(__filename).href);
970
743
  function resolvePackageEntryFromProjectRoot(pkg) {
971
744
  try {
972
- return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
745
+ return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(require_packageUtils.getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
973
746
  } catch {
974
747
  return;
975
748
  }
976
749
  }
977
750
  function getPackageEsmEntryPath(pkg) {
978
- return getInstalledPackageEntry(pkg, {
751
+ return require_packageUtils.getInstalledPackageEntry(pkg, {
979
752
  conditions: [
980
753
  "browser",
981
754
  "import",
@@ -1067,7 +840,7 @@ function getNamedExportsViaRegex(source, filePath, visited) {
1067
840
  }
1068
841
  function getPackageNamedExports(pkg) {
1069
842
  try {
1070
- const mod = (0, module$1.createRequire)(new URL(`file://${pathe.default.join(getPackageDetectionCwd(), "package.json")}`))(pkg);
843
+ const mod = (0, module$1.createRequire)(new URL(`file://${pathe.default.join(require_packageUtils.getPackageDetectionCwd(), "package.json")}`))(pkg);
1071
844
  return Object.keys(mod).filter((k) => isValidEsmExportName(k));
1072
845
  } catch {
1073
846
  return getEsmNamedExports(pkg);
@@ -1075,10 +848,10 @@ function getPackageNamedExports(pkg) {
1075
848
  }
1076
849
  function getLocalProviderImportPath(pkg) {
1077
850
  try {
1078
- const resolved = (0, module$1.createRequire)(new URL(`file://${pathe.default.join(getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
851
+ const resolved = (0, module$1.createRequire)(new URL(`file://${pathe.default.join(require_packageUtils.getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
1079
852
  return isWorkspaceFilePath(resolved) ? resolved : void 0;
1080
853
  } catch {
1081
- const resolved = getInstalledPackageEntry(pkg, {
854
+ const resolved = require_packageUtils.getInstalledPackageEntry(pkg, {
1082
855
  conditions: [
1083
856
  "browser",
1084
857
  "import",
@@ -1091,12 +864,12 @@ function getLocalProviderImportPath(pkg) {
1091
864
  }
1092
865
  }
1093
866
  function getProjectResolvedImportPath(pkg) {
1094
- if (pkg === getPackageName(pkg)) {
867
+ if (pkg === require_packageUtils.getPackageName(pkg)) {
1095
868
  const esmEntry = getPackageEsmEntryPath(pkg);
1096
869
  if (esmEntry) return esmEntry;
1097
870
  }
1098
871
  try {
1099
- return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
872
+ return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(require_packageUtils.getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
1100
873
  } catch {
1101
874
  return;
1102
875
  }
@@ -1111,8 +884,8 @@ function isWorkspaceFilePath(resolved) {
1111
884
  }
1112
885
  function isWorkspacePackageEntry(pkg, resolved) {
1113
886
  if (!resolved || !pathe.default.isAbsolute(resolved) || !isWorkspaceFilePath(resolved)) return false;
1114
- return !!getInstalledPackageJson(pkg, {
1115
- packageName: getPackageName(pkg),
887
+ return !!require_packageUtils.getInstalledPackageJson(pkg, {
888
+ packageName: require_packageUtils.getPackageName(pkg),
1116
889
  fromResolvedEntry: resolved
1117
890
  });
1118
891
  }
@@ -1126,7 +899,7 @@ function tryResolveImportFromPackageRoot(pkg, root) {
1126
899
  function getConcreteSharedImportSource(pkg, shareItem) {
1127
900
  const configuredImport = shareItem?.shareConfig.import;
1128
901
  if (typeof configuredImport === "string") return configuredImport;
1129
- const projectRoot = getPackageDetectionCwd();
902
+ const projectRoot = require_packageUtils.getPackageDetectionCwd();
1130
903
  if (tryResolveImportFromPackageRoot(pkg, projectRoot)) return;
1131
904
  let currentDir = pathe.default.dirname(projectRoot);
1132
905
  while (currentDir !== pathe.default.dirname(currentDir)) {
@@ -1254,7 +1027,7 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown) {
1254
1027
  let exportLine;
1255
1028
  if (namedExports.length > 0) exportLine = generateDeferredHostProvidedExports(namedExports, pkg);
1256
1029
  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.`);
1030
+ 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
1031
  exportLine = generateDeferredHostProvidedExports([], pkg);
1259
1032
  }
1260
1033
  loadShareCacheMap[pkg].writeSync(`
@@ -1317,7 +1090,7 @@ function addUsedShares(pkg) {
1317
1090
  const LOCAL_SHARED_IMPORT_MAP_ID = "virtual:mf-localSharedImportMap";
1318
1091
  function getLocalSharedImportMapPath() {
1319
1092
  const { internalName, name } = getNormalizeModuleFederationOptions();
1320
- return `${LOCAL_SHARED_IMPORT_MAP_ID}:${packageNameEncode(internalName || name)}`;
1093
+ return `${LOCAL_SHARED_IMPORT_MAP_ID}:${require_packageUtils.packageNameEncode(internalName || name)}`;
1321
1094
  }
1322
1095
  function getResolvedLocalSharedImportMapId() {
1323
1096
  return `\0${getLocalSharedImportMapPath()}`;
@@ -1335,8 +1108,8 @@ function writeLocalSharedImportMap() {
1335
1108
  }
1336
1109
  }
1337
1110
  function shouldUseDirectReactImport() {
1338
- const isVinext = hasPackageDependency("vinext");
1339
- const isAstro = hasPackageDependency("astro");
1111
+ const isVinext = require_packageUtils.hasPackageDependency("vinext");
1112
+ const isAstro = require_packageUtils.hasPackageDependency("astro");
1340
1113
  return isVinext || isAstro;
1341
1114
  }
1342
1115
  function getLocalSharedPackagePath(pkg, shareItem) {
@@ -1471,7 +1244,7 @@ const normalizeRuntimeShareCode = `const __mfNormalizeRuntimeShare = (mod) => {
1471
1244
  let current = mod;
1472
1245
  for (let i = 0; i < 5; i++) {
1473
1246
  const defaultExport = current?.default;
1474
- if (!defaultExport || typeof defaultExport !== "object") break;
1247
+ if (!defaultExport || typeof defaultExport !== "object" || Object.keys(defaultExport).length === 0) break;
1475
1248
  const namedValues = Object.keys(current).filter((key) => key !== "default").map((key) => current[key]);
1476
1249
  if (namedValues.length > 0 && namedValues.some((value) => value !== undefined)) break;
1477
1250
  current = defaultExport;
@@ -1511,6 +1284,9 @@ const REMOTE_ENTRY_ID = "virtual:mf-REMOTE_ENTRY_ID";
1511
1284
  function getRemoteEntryId(options) {
1512
1285
  return `${REMOTE_ENTRY_ID}:${`${options.internalName}__${options.filename}`.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
1513
1286
  }
1287
+ const SSR_ONLY_PLUGIN_SPECIFIERS = new Set(["@module-federation/vite/ssrEntryLoader"]);
1288
+ const isSsrOnlyPlugin = (importStatement) => [...SSR_ONLY_PLUGIN_SPECIFIERS].some((s) => importStatement.includes(s));
1289
+ const getSsrOnlyPluginSpecifier = (importStatement) => [...SSR_ONLY_PLUGIN_SPECIFIERS].find((s) => importStatement.includes(s));
1514
1290
  function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(options), command = "build") {
1515
1291
  const pluginImportNames = options.runtimePlugins.map((p, i) => {
1516
1292
  if (typeof p === "string") return [
@@ -1534,7 +1310,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1534
1310
  globalThis.__VUE_HMR_RUNTIME__ = { createRecord() {}, rerender() {}, reload() {} };
1535
1311
  }
1536
1312
  import {init as runtimeInit, loadRemote} from "@module-federation/runtime";
1537
- ${pluginImportNames.map((item) => item[1]).join("\n")}
1313
+ ${pluginImportNames.filter((item) => !isSsrOnlyPlugin(item[1])).map((item) => item[1]).join("\n")}
1538
1314
  ${command === "build" ? getRuntimeInitResolveBootstrapCode() : getRuntimeInitBootstrapCode() + "\n const { initResolve } = globalThis[globalKey];"}
1539
1315
  ${getRuntimeModuleCacheBootstrapCode()}
1540
1316
  const initTokens = {}
@@ -1582,11 +1358,19 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1582
1358
  async function init(shared = {}, initScope = []) {
1583
1359
  const {usedShared, usedRemotes} = await getLocalSharedImportMap()
1584
1360
  ${generateDirectSharedCacheSeedCode(command)}
1361
+ const __browserPlugins = [${pluginImportNames.filter((item) => !isSsrOnlyPlugin(item[1])).map((item) => `${item[0]}(${item[2]})`).join(", ")}];
1362
+ const __ssrPlugins = typeof globalThis.window === 'undefined'
1363
+ ? await Promise.all([${pluginImportNames.filter((item) => isSsrOnlyPlugin(item[1])).map((item) => {
1364
+ const specifier = getSsrOnlyPluginSpecifier(item[1]);
1365
+ const opts = item[2];
1366
+ return `import(${JSON.stringify(specifier)}).then(m => (m.default ?? m)(${opts}))`;
1367
+ }).join(", ")}])
1368
+ : [];
1585
1369
  const initRes = runtimeInit({
1586
1370
  name: mfName,
1587
- remotes: usedRemotes,
1371
+ remotes: ${options.shareStrategy === "loaded-first" ? "[]" : "usedRemotes"},
1588
1372
  shared: usedShared,
1589
- plugins: [${pluginImportNames.map((item) => `${item[0]}(${item[2]})`).join(", ")}],
1373
+ plugins: [...__browserPlugins, ...__ssrPlugins],
1590
1374
  ${options.shareStrategy ? `shareStrategy: '${options.shareStrategy}'` : ""}
1591
1375
  });
1592
1376
  // handling circular init calls
@@ -1637,6 +1421,7 @@ const hostAutoInitModule = new VirtualModule("hostAutoInit", "__H_A_I__");
1637
1421
  let currentHostAutoInitRemoteEntryId = REMOTE_ENTRY_ID;
1638
1422
  let currentHostAutoInitCommand = "build";
1639
1423
  function generateHostAutoInitCode(remoteEntryImport, _command = "build") {
1424
+ const shouldPreloadShares = getNormalizeModuleFederationOptions().shareStrategy !== "loaded-first";
1640
1425
  return `
1641
1426
  ${getRuntimeModuleCacheBootstrapCode()}
1642
1427
  let hostInitPromise;
@@ -1648,6 +1433,7 @@ function generateHostAutoInitCode(remoteEntryImport, _command = "build") {
1648
1433
  const runtime = await remoteEntry.init();
1649
1434
  const usedShared = ${generateUsedSharedPreloadConfig()};
1650
1435
  ${normalizeRuntimeShareCode}
1436
+ ${shouldPreloadShares ? `
1651
1437
  for (const [pkg, share] of Object.entries(usedShared)) {
1652
1438
  if (__mfModuleCache.share[pkg] !== undefined) {
1653
1439
  continue;
@@ -1661,6 +1447,7 @@ function generateHostAutoInitCode(remoteEntryImport, _command = "build") {
1661
1447
  });
1662
1448
  });
1663
1449
  }
1450
+ ` : ""}
1664
1451
  const __mfRemotePreloads = [];
1665
1452
  await Promise.all(__mfRemotePreloads);
1666
1453
  return runtime;
@@ -1692,12 +1479,13 @@ function getHostAutoInitPath() {
1692
1479
  //#region src/virtualModules/virtualRemotes.ts
1693
1480
  const cacheRemoteMap = {};
1694
1481
  const LOAD_REMOTE_TAG = "__loadRemote__";
1695
- function getRemoteVirtualModule(remote, command) {
1696
- if (!cacheRemoteMap[remote]) {
1697
- cacheRemoteMap[remote] = new VirtualModule(remote, LOAD_REMOTE_TAG, ".mjs");
1698
- cacheRemoteMap[remote].writeSync(generateRemotes(remote, command));
1482
+ function getRemoteVirtualModule(remote, command, enableSsrInit = false) {
1483
+ const cacheKey = `${remote}__${command}__${enableSsrInit ? "ssr" : "no-ssr"}`;
1484
+ if (!cacheRemoteMap[cacheKey]) {
1485
+ cacheRemoteMap[cacheKey] = new VirtualModule(remote, LOAD_REMOTE_TAG, ".mjs");
1486
+ cacheRemoteMap[cacheKey].writeSync(generateRemotes(remote, command, enableSsrInit));
1699
1487
  }
1700
- return cacheRemoteMap[remote];
1488
+ return cacheRemoteMap[cacheKey];
1701
1489
  }
1702
1490
  const usedRemotesMap = {};
1703
1491
  function addUsedRemote(remoteKey, remoteModule) {
@@ -1707,40 +1495,93 @@ function addUsedRemote(remoteKey, remoteModule) {
1707
1495
  function getUsedRemotesMap() {
1708
1496
  return usedRemotesMap;
1709
1497
  }
1710
- function generateRemotes(id, command) {
1711
- const useReactProxy = command === "serve" && hasPackageDependency("react");
1498
+ function getRemoteFromId(id, remotes) {
1499
+ const remoteName = Object.keys(remotes).filter((name) => id === name || id.startsWith(name + "/")).sort((a, b) => b.length - a.length)[0];
1500
+ return remoteName ? remotes[remoteName] : void 0;
1501
+ }
1502
+ function generateRemotes(id, command, enableSsrInit = false) {
1503
+ const useReactProxy = require_packageUtils.hasPackageDependency("react");
1504
+ const options = getNormalizeModuleFederationOptions();
1505
+ const isLoadedFirst = options.shareStrategy === "loaded-first";
1506
+ const remote = getRemoteFromId(id, options.remotes);
1507
+ const registerRemoteCode = isLoadedFirst && remote ? `runtime.registerRemotes([${JSON.stringify({
1508
+ entryGlobalName: remote.entryGlobalName,
1509
+ name: remote.name,
1510
+ type: remote.type,
1511
+ entry: remote.entry,
1512
+ shareScope: remote.shareScope ?? "default"
1513
+ })}]);` : "";
1712
1514
  const reactImportLine = useReactProxy ? `import __mfReactDefault from "react";
1713
1515
  import * as __mfReactNamespace from "react";
1714
1516
  const __mfReact = __mfReactDefault ?? __mfReactNamespace.default ?? __mfReactNamespace;` : "";
1715
1517
  const importLine = command === "build" ? `${getRuntimeModuleCacheBootstrapCode()}
1716
- import { hostInitPromise as __mfHostInitPromise } from ${JSON.stringify(getHostAutoInitPath())};` : `${getRuntimeInitBootstrapCode()}
1717
- const { initPromise, moduleCache: __mfModuleCache } = globalThis[globalKey];`;
1518
+ import { hostInitPromise as __mfHostInitPromise } from ${JSON.stringify(getHostAutoInitPath())};` : `${getRuntimeInitBootstrapCode(enableSsrInit)}
1519
+ const { initPromise, initResolve, initReject, moduleCache: __mfModuleCache } = globalThis[globalKey];
1520
+ if (typeof window !== "undefined") {
1521
+ import(${JSON.stringify(getHostAutoInitPath())})
1522
+ .then((mod) => mod.hostInitPromise)
1523
+ .then(initResolve, initReject);
1524
+ }`;
1718
1525
  const exportLine = command === "serve" ? `if (__mfRemotePending) {
1719
- const mod = await __mfRemotePending;
1720
- if (mod !== undefined) exportModule = mod;
1526
+ __mfRemotePending = __mfRemotePending.then((mod) => {
1527
+ if (mod !== undefined) exportModule = mod;
1528
+ return exportModule;
1529
+ });
1721
1530
  }
1722
- export const __moduleExports = exportModule;
1723
- export const __mf_remote_pending = Promise.resolve(exportModule);
1531
+ export { exportModule as __moduleExports };
1532
+ export const __mf_remote_pending = __mfRemotePending || Promise.resolve(exportModule);
1724
1533
  export default exportModule?.__mf_is_remote_proxy ? exportModule : exportModule?.__esModule ? exportModule.default : exportModule.default ?? exportModule` : command === "build" ? `if (__mfRemotePending) {
1725
- const mod = await __mfRemotePending;
1726
- if (mod !== undefined) exportModule = mod;
1534
+ __mfRemotePending = __mfRemotePending.then((mod) => {
1535
+ if (mod !== undefined) exportModule = mod;
1536
+ return exportModule;
1537
+ });
1727
1538
  }
1728
- export const __moduleExports = exportModule;
1729
- export const __mf_remote_pending = Promise.resolve(exportModule);
1539
+ export { exportModule as __moduleExports };
1540
+ export const __mf_remote_pending = __mfRemotePending || Promise.resolve(exportModule);
1730
1541
  export default exportModule?.__mf_is_remote_proxy ? exportModule : exportModule?.__esModule ? exportModule.default : exportModule.default ?? exportModule` : "export default exportModule";
1542
+ const remoteLoadRuntimePromise = command === "build" ? "__mfHostInitPromise" : "initPromise";
1543
+ const remoteLoadFailureHandler = command === "build" ? `.catch((error) => {
1544
+ delete __mfModuleCache.remote[pendingKey];
1545
+ throw error;
1546
+ })` : `.catch(() => {
1547
+ delete __mfModuleCache.remote[pendingKey];
1548
+ })`;
1731
1549
  return `
1732
1550
  ${reactImportLine}
1733
1551
  ${importLine}
1734
- ${command !== "build" ? `
1552
+ ${`
1553
+ function __mfStartRemoteLoad() {
1554
+ ${`
1555
+ const pendingKey = ${JSON.stringify(`__mf_pending__${id}`)};
1556
+ if (!__mfModuleCache.remote[pendingKey]) {
1557
+ __mfModuleCache.remote[pendingKey] = ${remoteLoadRuntimePromise}
1558
+ .then((runtime) => {
1559
+ ${registerRemoteCode}
1560
+ return runtime.loadRemote(${JSON.stringify(id)});
1561
+ })
1562
+ .then((mod) => {
1563
+ __mfModuleCache.remote[${JSON.stringify(id)}] = mod;
1564
+ delete __mfModuleCache.remote[pendingKey];
1565
+ return mod;
1566
+ })
1567
+ ${remoteLoadFailureHandler};
1568
+ }
1569
+ return __mfModuleCache.remote[pendingKey];`}
1570
+ }
1735
1571
  function __mfCreateRemoteProxy(pendingPromise) {
1736
1572
  const listeners = new Set();
1737
- pendingPromise?.finally(() => {
1738
- for (const listener of listeners) listener();
1739
- });
1573
+ const ensurePending = () => {
1574
+ pendingPromise ||= __mfStartRemoteLoad();
1575
+ pendingPromise?.finally(() => {
1576
+ for (const listener of listeners) listener();
1577
+ });
1578
+ return pendingPromise;
1579
+ };
1740
1580
  const getModule = () => __mfModuleCache.remote[${JSON.stringify(id)}];
1741
1581
  const proxyTarget = function (...args) {
1742
1582
  ${useReactProxy ? `const [, setVersion] = __mfReact.useState(0);
1743
1583
  __mfReact.useEffect(() => {
1584
+ ensurePending();
1744
1585
  const listener = () => setVersion((value) => value + 1);
1745
1586
  listeners.add(listener);
1746
1587
  if (getModule()) listener();
@@ -1751,18 +1592,33 @@ export default exportModule?.__mf_is_remote_proxy ? exportModule : exportModule?
1751
1592
  if (fn !== undefined && fn !== null) {
1752
1593
  ${useReactProxy ? `return __mfReact.createElement(fn, args[0]);` : `return fn.apply(this, args);`}
1753
1594
  }
1754
- ${useReactProxy ? `return null;` : `throw pendingPromise;`}
1595
+ ${useReactProxy ? `return null;` : `throw ensurePending();`}
1755
1596
  };
1756
1597
  return new Proxy(proxyTarget, {
1757
1598
  get(_target, prop) {
1758
1599
  if (prop === "__mf_is_remote_proxy") return true;
1759
1600
  if (prop === "__esModule") return true;
1760
1601
  if (prop === "then") return undefined;
1602
+ // Allow React's dev-mode console.warn to stringify the proxy without
1603
+ // throwing "Cannot convert object to primitive value".
1604
+ if (prop === Symbol.toPrimitive || prop === "toString")
1605
+ return () => "[MF remote proxy: pending]";
1761
1606
  const mod = getModule();
1762
1607
  if (mod) {
1763
1608
  return prop in mod ? mod[prop] : mod.default?.[prop];
1764
1609
  }
1765
- ${useReactProxy ? `return undefined;` : `throw pendingPromise;`}
1610
+ // When the module is pending and React.lazy() checks for "default",
1611
+ // return the proxy function itself so React renders it (returns null)
1612
+ // rather than crashing on undefined.
1613
+ ${useReactProxy ? `if (prop === "default") return proxyTarget;
1614
+ return undefined;` : `throw ensurePending();`}
1615
+ },
1616
+ has(_target, prop) {
1617
+ const mod = getModule();
1618
+ if (mod) return prop in mod;
1619
+ // Tell React that "default" exists when module is pending so it
1620
+ // doesn't warn "lazy: Expected the result of a dynamic import()".
1621
+ ${useReactProxy ? `return prop === "default" || prop === "__esModule" || prop === "__mf_is_remote_proxy";` : `return false;`}
1766
1622
  },
1767
1623
  ownKeys() {
1768
1624
  const mod = getModule();
@@ -1790,40 +1646,12 @@ export default exportModule?.__mf_is_remote_proxy ? exportModule : exportModule?
1790
1646
  return target.apply(thisArg, args);
1791
1647
  }
1792
1648
  });
1793
- }` : ""}
1649
+ }`}
1794
1650
  let __mfRemotePending;
1795
1651
  let exportModule = __mfModuleCache.remote[${JSON.stringify(id)}]
1796
1652
  if (exportModule === undefined) {
1797
- ${command !== "build" ? `const pendingKey = ${JSON.stringify(`__mf_pending__${id}`)};
1798
- if (!__mfModuleCache.remote[pendingKey]) {
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 = {};`}
1653
+ __mfRemotePending = __mfStartRemoteLoad();
1654
+ exportModule = __mfCreateRemoteProxy(__mfRemotePending);
1827
1655
  }
1828
1656
  ${exportLine}
1829
1657
  `;
@@ -1833,7 +1661,38 @@ export default exportModule?.__mf_is_remote_proxy ? exportModule : exportModule?
1833
1661
  function getFirstHtmlEntryFile(entryFiles) {
1834
1662
  return entryFiles.find((file) => file.endsWith(".html"));
1835
1663
  }
1836
- const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClientInjected }) => {
1664
+ function stripQueryAndHash(file) {
1665
+ return file.split(/[?#]/)[0];
1666
+ }
1667
+ function getBuildInput(config) {
1668
+ return config.build?.rollupOptions?.input ?? config.build?.rolldownOptions?.input;
1669
+ }
1670
+ function patchHashEntryFileName(output, entryName, fileName) {
1671
+ const originalEntryFileNames = output.entryFileNames;
1672
+ output.entryFileNames = (chunkInfo, ...args) => {
1673
+ if (chunkInfo?.name === entryName) return fileName;
1674
+ if (typeof originalEntryFileNames === "function") return originalEntryFileNames(chunkInfo, ...args);
1675
+ return originalEntryFileNames || "assets/[name]-[hash].js";
1676
+ };
1677
+ }
1678
+ function patchHashEntryFileNames(config, entryName, fileName) {
1679
+ if (!fileName?.includes?.("[hash")) return;
1680
+ config.build ??= {};
1681
+ config.build.rollupOptions ??= {};
1682
+ config.build.rolldownOptions ??= {};
1683
+ const patchOutput = (output) => patchHashEntryFileName(output, entryName, fileName);
1684
+ const patchBundlerOutput = (bundlerOptions) => {
1685
+ const output = bundlerOptions.output;
1686
+ if (Array.isArray(output)) {
1687
+ output.forEach(patchOutput);
1688
+ return;
1689
+ }
1690
+ patchOutput(bundlerOptions.output ??= {});
1691
+ };
1692
+ patchBundlerOutput(config.build.rollupOptions);
1693
+ patchBundlerOutput(config.build.rolldownOptions);
1694
+ }
1695
+ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClientInjected, skipTransformFor = [] }) => {
1837
1696
  const DEV_HTML_PROXY_PREFIX = "virtual:mf-html-entry-proxy?";
1838
1697
  const ENTRY_BOOTSTRAP_QUERY = "?mf-entry-bootstrap";
1839
1698
  const waitsForInit = entryName === "hostInit";
@@ -1846,11 +1705,12 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
1846
1705
  let viteConfig;
1847
1706
  let clientInjected = forceClientInjected ?? false;
1848
1707
  let emittedFileName;
1708
+ let skipTransformIds = /* @__PURE__ */ new Set();
1849
1709
  function skipSvelteKitSsrBuild() {
1850
- return (_command === "build" || viteConfig?.command === "build") && viteConfig?.build?.ssr && hasPackageDependency("@sveltejs/kit");
1710
+ return (_command === "build" || viteConfig?.command === "build") && viteConfig?.build?.ssr && require_packageUtils.hasPackageDependency("@sveltejs/kit");
1851
1711
  }
1852
1712
  function isSvelteKitServerModule(id) {
1853
- return hasPackageDependency("@sveltejs/kit") && (id.includes(".svelte-kit/generated/") || id.includes("/@sveltejs/kit/src/runtime/server/"));
1713
+ return require_packageUtils.hasPackageDependency("@sveltejs/kit") && (id.includes(".svelte-kit/generated/") || id.includes("/@sveltejs/kit/src/runtime/server/"));
1854
1714
  }
1855
1715
  function rewriteSvelteKitInlineStart(html, initPath) {
1856
1716
  return html.replace(/<script>([\s\S]*?)<\/script>/gi, (scriptTag, body) => {
@@ -1901,35 +1761,81 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
1901
1761
  return patched;
1902
1762
  }
1903
1763
  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
1764
  const importHelper = useSystemImportFallback ? `const __mfImport = (src) =>
1906
1765
  globalThis.System && typeof globalThis.System.import === 'function'
1907
1766
  ? globalThis.System.import(src)
1908
1767
  : import(src);
1909
1768
  ` : "";
1910
1769
  const importExpression = (src) => useSystemImportFallback ? `__mfImport(${JSON.stringify(src)})` : `import(${JSON.stringify(src)})`;
1911
- return `${getRuntimeModuleCacheBootstrapCode()}
1912
- ${importHelper}(async () => {
1913
- const { initHost } = await ${importExpression(initSrc)};
1770
+ 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(",") : "";
1771
+ const preloadBlock = remotePreloads ? `
1914
1772
  const runtime = await initHost();
1773
+ const __mfPreloadRemote = (remote) => {
1774
+ const pendingKey = "__mf_pending__" + remote;
1775
+ if (!__mfModuleCache.remote[pendingKey]) {
1776
+ __mfModuleCache.remote[pendingKey] = runtime.loadRemote(remote)
1777
+ .then((mod) => {
1778
+ __mfModuleCache.remote[remote] = mod;
1779
+ delete __mfModuleCache.remote[pendingKey];
1780
+ return mod;
1781
+ })
1782
+ .catch((error) => {
1783
+ delete __mfModuleCache.remote[pendingKey];
1784
+ throw error;
1785
+ });
1786
+ }
1787
+ return __mfModuleCache.remote[pendingKey];
1788
+ };
1915
1789
  const __mfRemotePreloads = [${remotePreloads}];
1916
- await Promise.all(__mfRemotePreloads);
1790
+ await Promise.allSettled(__mfRemotePreloads);` : `await initHost();`;
1791
+ const importCode = `
1792
+ (async () => {
1793
+ const { initHost } = await ${importExpression(initSrc)};
1794
+ ${preloadBlock}
1917
1795
  })().then(() => ${importExpression(entrySrc)});
1918
1796
  `;
1797
+ return [
1798
+ getRuntimeModuleCacheBootstrapCode(),
1799
+ importHelper,
1800
+ importCode
1801
+ ].join("\n");
1919
1802
  }
1920
1803
  function getSystemBootstrapSource(initSrc, entrySrc) {
1921
1804
  return getBootstrapSource(initSrc, entrySrc, true);
1922
1805
  }
1923
1806
  function injectHtml() {
1924
- return inject === "html" && (htmlFilePath || hasPackageDependency("@sveltejs/kit"));
1807
+ return inject === "html" && (htmlFilePath || require_packageUtils.hasPackageDependency("@sveltejs/kit"));
1925
1808
  }
1926
1809
  function injectEntry() {
1927
- if (inject === "html" && hasPackageDependency("@sveltejs/kit")) return false;
1810
+ if (inject === "html" && require_packageUtils.hasPackageDependency("@sveltejs/kit")) return false;
1928
1811
  return inject === "entry" || !htmlFilePath;
1929
1812
  }
1930
1813
  function normalizeDevHtmlProxyId(id) {
1931
1814
  return id.replace(/^\0/, "").replace(/^\/@id\//, "").replace(/^__x00__/, "");
1932
1815
  }
1816
+ function normalizeModuleId(id) {
1817
+ return id.split("?")[0].replace(/\\/g, "/");
1818
+ }
1819
+ function resolveProjectId(id) {
1820
+ if (id.startsWith("\0") || id.startsWith("virtual:")) return normalizeModuleId(id);
1821
+ return normalizeModuleId(pathe.isAbsolute(id) ? id : pathe.resolve(viteConfig.root, id));
1822
+ }
1823
+ function addEntryFile(file) {
1824
+ const normalized = normalizeModuleId(file);
1825
+ if (!entryFiles.includes(normalized)) entryFiles.push(normalized);
1826
+ }
1827
+ function addHtmlScriptEntries(htmlPath) {
1828
+ if (!fs.existsSync(htmlPath)) return;
1829
+ const htmlContent = fs.readFileSync(htmlPath, "utf-8");
1830
+ const scriptRegex = /<script\b(?=[^>]*\btype=["']module["'])(?=[^>]*\bsrc=["']([^"']+)["'])[^>]*>/gi;
1831
+ let match;
1832
+ while ((match = scriptRegex.exec(htmlContent)) !== null) {
1833
+ const scriptSrc = stripQueryAndHash(match[1]);
1834
+ if (/^(?:[a-z]+:)?\/\//i.test(scriptSrc)) continue;
1835
+ addEntryFile(scriptSrc);
1836
+ addEntryFile(scriptSrc.startsWith("/") ? pathe.resolve(viteConfig.root, scriptSrc.slice(1)) : pathe.resolve(pathe.dirname(htmlPath), scriptSrc));
1837
+ }
1838
+ }
1933
1839
  return [{
1934
1840
  name: "add-entry",
1935
1841
  apply: "serve",
@@ -1946,6 +1852,7 @@ ${importHelper}(async () => {
1946
1852
  const relativePath = normalized.startsWith(root + "/") ? normalized.slice(root.length) : "/" + normalized.replace(/^[A-Za-z]:[\\/]/, "");
1947
1853
  devEntryPath = config.base + relativePath.replace(/^\//, "");
1948
1854
  }
1855
+ skipTransformIds = new Set(skipTransformFor.map(resolveProjectId));
1949
1856
  },
1950
1857
  configureServer(server) {
1951
1858
  server.middlewares.use((req, res, next) => {
@@ -1973,7 +1880,8 @@ ${importHelper}(async () => {
1973
1880
  transformIndexHtml: {
1974
1881
  order: "pre",
1975
1882
  handler(c) {
1976
- if (!injectHtml()) return;
1883
+ const shouldWrapEntryHtml = _command === "serve" && inject === "entry" && waitsForInit;
1884
+ if (!injectHtml() && !shouldWrapEntryHtml) return;
1977
1885
  clientInjected = true;
1978
1886
  const base = viteConfig.base.replace(/\/$/, "");
1979
1887
  const stripBase = (p) => base && p.startsWith(base + "/") ? p.slice(base.length) : p;
@@ -2005,24 +1913,30 @@ ${importHelper}(async () => {
2005
1913
  }, {
2006
1914
  name: "add-entry",
2007
1915
  enforce: "post",
1916
+ applyToEnvironment() {
1917
+ return true;
1918
+ },
1919
+ config(config) {
1920
+ patchHashEntryFileNames(config, entryName, fileName);
1921
+ },
2008
1922
  configResolved(config) {
2009
1923
  viteConfig = config;
2010
- const inputOptions = config.build.rollupOptions.input;
1924
+ skipTransformIds = new Set(skipTransformFor.map(resolveProjectId));
1925
+ const ctx = this;
1926
+ const envName = ctx != null && typeof ctx === "object" ? ctx["environment"] : void 0;
1927
+ if (envName?.name && envName.name !== "client") return;
1928
+ const inputOptions = getBuildInput(config);
2011
1929
  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);
1930
+ else if (typeof inputOptions === "string") entryFiles = [normalizeModuleId(inputOptions)];
1931
+ else if (Array.isArray(inputOptions)) entryFiles = inputOptions.map(normalizeModuleId);
1932
+ else if (typeof inputOptions === "object") entryFiles = Object.values(inputOptions).map((input) => normalizeModuleId(String(input)));
2015
1933
  if (entryFiles.length > 0) htmlFilePath = getFirstHtmlEntryFile(entryFiles);
2016
- if (_command === "serve" && htmlFilePath && fs.existsSync(htmlFilePath)) {
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
- }
1934
+ if (htmlFilePath) addHtmlScriptEntries(htmlFilePath);
2022
1935
  },
2023
1936
  buildStart() {
2024
1937
  if (_command === "serve") return;
2025
1938
  if (skipSvelteKitSsrBuild()) return;
1939
+ if (this.environment?.name === "ssr") return;
2026
1940
  const hasHash = fileName?.includes?.("[hash");
2027
1941
  const emitFileOptions = {
2028
1942
  name: entryName,
@@ -2032,16 +1946,14 @@ ${importHelper}(async () => {
2032
1946
  };
2033
1947
  if (!hasHash) emitFileOptions.fileName = fileName;
2034
1948
  emitFileId = this.emitFile(emitFileOptions);
2035
- if (htmlFilePath && fs.existsSync(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
- }
1949
+ if (htmlFilePath) addHtmlScriptEntries(htmlFilePath);
2041
1950
  },
2042
1951
  generateBundle(_options, bundle) {
2043
1952
  if (skipSvelteKitSsrBuild()) return;
2044
1953
  if (!injectHtml()) return;
1954
+ if (!emitFileId) return;
1955
+ const htmlFileNames = Object.keys(bundle).filter((fileName) => fileName.endsWith(".html"));
1956
+ if (htmlFileNames.length === 0) return;
2045
1957
  const file = this.getFileName(emitFileId);
2046
1958
  emittedFileName = file;
2047
1959
  const resolvePath = (htmlFileName) => {
@@ -2055,7 +1967,7 @@ ${importHelper}(async () => {
2055
1967
  if (typeof result === "string") return result;
2056
1968
  if (result && typeof result === "object") {
2057
1969
  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.");
1970
+ require_packageUtils.mfWarn("renderBuiltUrl returned runtime code for HTML injection. Runtime code cannot be used in <script src=\"\">. Falling back to base path.");
2059
1971
  return viteConfig.base + file;
2060
1972
  }
2061
1973
  if (result.relative) return file;
@@ -2063,7 +1975,7 @@ ${importHelper}(async () => {
2063
1975
  return viteConfig.base + file;
2064
1976
  };
2065
1977
  let bootstrapIndex = 0;
2066
- for (const fileName in bundle) if (fileName.endsWith(".html")) {
1978
+ for (const fileName of htmlFileNames) {
2067
1979
  let htmlAsset = bundle[fileName];
2068
1980
  if (htmlAsset.type === "chunk") return;
2069
1981
  let htmlContent = htmlAsset.source.toString() || "";
@@ -2108,7 +2020,12 @@ ${importHelper}(async () => {
2108
2020
  if (skipSvelteKitSsrBuild()) return;
2109
2021
  if (isSvelteKitServerModule(id)) return;
2110
2022
  if (id.includes(ENTRY_BOOTSTRAP_QUERY)) return;
2111
- const isVinext = hasPackageDependency("vinext");
2023
+ if (normalizeModuleId(id).endsWith(".html")) return;
2024
+ if (skipTransformIds.has(resolveProjectId(id))) return;
2025
+ const transformCtx = this;
2026
+ const transformEnv = transformCtx != null && typeof transformCtx === "object" ? transformCtx["environment"] : void 0;
2027
+ if (transformEnv?.name && transformEnv.name !== "client") return;
2028
+ const isVinext = require_packageUtils.hasPackageDependency("vinext");
2112
2029
  if (isVinext && inject === "html" && id.includes("virtual:vite-rsc/remove-duplicate-server-css")) {
2113
2030
  const namespaceReactImport = `import * as React from 'react';`;
2114
2031
  if (code.includes(namespaceReactImport)) return;
@@ -2124,9 +2041,16 @@ ${importHelper}(async () => {
2124
2041
  clientInjected = true;
2125
2042
  return mapCodeToCodeWithSourcemap(injection + code);
2126
2043
  }
2127
- if (injectEntry() && entryFiles.some((file) => id.endsWith(file)) || _command === "serve" && inject === "html" && !isVinext && !clientInjected && !id.startsWith("\0") && !id.includes("node_modules") && /\.(js|ts|mjs|vue|jsx|tsx)(\?|$)/.test(id)) {
2044
+ if (_command === "serve" && inject === "entry" && waitsForInit && !clientInjected && /(?:^|\/)nuxt\/dist\/app\/entry\.js(?:\?|$)/.test(id) && code.includes("vueApp.mount(vueAppRootContainer);")) {
2128
2045
  clientInjected = true;
2129
- if (!waitsForInit) return mapCodeToCodeWithSourcemap(`import ${JSON.stringify(getEntryPath())};\n` + code);
2046
+ const injection = `await import(${JSON.stringify(getEntryPath())}).then(({ initHost }) => initHost());\n `;
2047
+ return mapCodeToCodeWithSourcemap(code.replace("vueApp.mount(vueAppRootContainer);", `${injection}vueApp.mount(vueAppRootContainer);`));
2048
+ }
2049
+ 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);
2050
+ 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();");
2051
+ 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) {
2052
+ clientInjected = true;
2053
+ if (!waitsForInit || _command === "serve" && inject === "entry" && isHydrationEntryFallback) return mapCodeToCodeWithSourcemap(`import ${JSON.stringify(getEntryPath())};\n` + code);
2130
2054
  const entrySrc = id.includes("?") ? `${id}&${ENTRY_BOOTSTRAP_QUERY.slice(1)}` : `${id}${ENTRY_BOOTSTRAP_QUERY}`;
2131
2055
  return mapCodeToCodeWithSourcemap(getBootstrapSource(getEntryPath(), entrySrc));
2132
2056
  }
@@ -2159,7 +2083,7 @@ function checkAliasConflicts(options) {
2159
2083
  if (!matchesSharedKey(aliasEntry, sharedKey)) continue;
2160
2084
  if (replacement === "$1") break;
2161
2085
  if (typeof replacement === "string") {
2162
- if (getPackageNameFromNodeModulePath(replacement) === (sharedKey.endsWith("/") ? sharedKey.slice(0, -1) : sharedKey)) continue;
2086
+ if (require_packageUtils.getPackageNameFromNodeModulePath(replacement) === (sharedKey.endsWith("/") ? sharedKey.slice(0, -1) : sharedKey)) continue;
2163
2087
  conflicts.push({
2164
2088
  sharedModule: sharedKey,
2165
2089
  alias: String(aliasEntry.find),
@@ -2168,21 +2092,17 @@ function checkAliasConflicts(options) {
2168
2092
  }
2169
2093
  }
2170
2094
  if (conflicts.length > 0) {
2171
- mfWarn("Detected alias conflicts with shared modules:");
2095
+ require_packageUtils.mfWarn("Detected alias conflicts with shared modules:");
2172
2096
  conflicts.forEach(({ sharedModule, alias, target }) => {
2173
- mfWarn(`Shared module "${sharedModule}" is aliased by "${alias}" to "${target}"`);
2097
+ require_packageUtils.mfWarn(`Shared module "${sharedModule}" is aliased by "${alias}" to "${target}"`);
2174
2098
  });
2175
- mfWarn("This may cause runtime errors as the shared module will bypass Module Federation's sharing mechanism.");
2099
+ require_packageUtils.mfWarn("This may cause runtime errors as the shared module will bypass Module Federation's sharing mechanism.");
2176
2100
  }
2177
2101
  }
2178
2102
  };
2179
2103
  }
2180
2104
  //#endregion
2181
- //#region src/plugins/pluginDevRemoteHmr.ts
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;
2105
+ //#region src/plugins/hmr/react.ts
2186
2106
  /**
2187
2107
  * Proxy module served for `/@react-refresh` on MF remote dev servers.
2188
2108
  * Delegates to the host page's RefreshRuntime instance via
@@ -2202,6 +2122,112 @@ const REACT_REFRESH_PROXY_MODULE = [
2202
2122
  `export const __hmr_import = __rt.__hmr_import;`,
2203
2123
  `export default __rt.default || __rt;`
2204
2124
  ].join("\n");
2125
+ const reactAdapter = {
2126
+ name: "react",
2127
+ pluginNames: ["vite:react-refresh", "vite:react-swc:refresh"],
2128
+ remote: { configureServer({ server }) {
2129
+ server.middlewares.use((req, res, next) => {
2130
+ if (req.url?.replace(/\?.*$/, "") !== "/@react-refresh") return next();
2131
+ res.setHeader("Content-Type", "application/javascript; charset=utf-8");
2132
+ res.setHeader("Access-Control-Allow-Origin", "*");
2133
+ res.end(REACT_REFRESH_PROXY_MODULE);
2134
+ });
2135
+ } }
2136
+ };
2137
+ //#endregion
2138
+ //#region src/plugins/hmr/vue.ts
2139
+ /**
2140
+ * In dev mode each Vite dev server serves its own copy of Vue
2141
+ * (`/node_modules/.vite/deps/vue.js`). When a remote module is loaded into the
2142
+ * host page, the remote's Vue copy evaluates and runs:
2143
+ *
2144
+ * globalThis.__VUE_HMR_RUNTIME__ = createHotReloadAPI()
2145
+ *
2146
+ * which silently overwrites the host's runtime. After that, `createRecord` for
2147
+ * host components lives in the orphaned first runtime, but `reload(hmrId, ...)`
2148
+ * goes through the second runtime — the lookup misses and HMR stops working.
2149
+ *
2150
+ * This guard pins `__VUE_HMR_RUNTIME__` to the first writer (the host's Vue)
2151
+ * via a property trap on `globalThis`. Subsequent writes from remote-side Vue
2152
+ * copies are silently dropped. Must execute before any Vue module loads —
2153
+ * injected as a plain (non-module) script at `head-prepend`.
2154
+ *
2155
+ * `singleton: true` in `shared` is not sufficient: in dev mode MF's share-scope
2156
+ * does not actually dedupe Vue across dev servers, so without this guard the
2157
+ * last-loaded copy wins.
2158
+ */
2159
+ const VUE_HMR_RUNTIME_GUARD_SCRIPT = `
2160
+ (function () {
2161
+ var h = null;
2162
+ Object.defineProperty(globalThis, '__VUE_HMR_RUNTIME__', {
2163
+ get: function () { return h; },
2164
+ set: function (v) { if (h === null) h = v; },
2165
+ configurable: true,
2166
+ enumerable: true,
2167
+ });
2168
+ })();`;
2169
+ /**
2170
+ * `@vitejs/plugin-vue` derives an SFC's `__hmrId` from a hash of the file path
2171
+ * relative to Vite's `root`. With module federation, host and remote are
2172
+ * separate Vite projects with independent roots — so an SFC at `src/App.vue`
2173
+ * in both will hash to the same id. Once both copies of Vue collapse onto the
2174
+ * shared `__VUE_HMR_RUNTIME__` (see the guard above), the host's instance and
2175
+ * the remote's instance both register under that single id. A remote-only
2176
+ * file change then calls `rerender(id, newRender)`, which iterates *every*
2177
+ * instance under that id — including the host one — and applies the remote's
2178
+ * render function to the host instance. The host's `setupState` doesn't have
2179
+ * the remote's bindings, so the render throws and Vue falls back to a full
2180
+ * reload required warning.
2181
+ *
2182
+ * Fix: rewrite the remote's emitted `__hmrId` literal to be prefixed with the
2183
+ * federation `name`, so the remote's instances live under a distinct key. The
2184
+ * accept callback emitted by plugin-vue reads `_sfc_main.__hmrId` /
2185
+ * `updated.__hmrId` at runtime, so rewriting the literal once is enough.
2186
+ */
2187
+ const SFC_HMR_ID_LITERAL_RE = /(\.__hmrId\s*=\s*["'`])([^"'`]+)(["'`])/g;
2188
+ function rewriteSfcHmrId(code, federationName) {
2189
+ let matched = false;
2190
+ return {
2191
+ code: code.replace(SFC_HMR_ID_LITERAL_RE, (_match, prefix, id, suffix) => {
2192
+ matched = true;
2193
+ if (id.startsWith(`${federationName}-`)) return `${prefix}${id}${suffix}`;
2194
+ return `${prefix}${federationName}-${id}${suffix}`;
2195
+ }),
2196
+ matched
2197
+ };
2198
+ }
2199
+ let pluginVueRegressionWarned = false;
2200
+ function warnPluginVueRegression() {
2201
+ if (pluginVueRegressionWarned) return;
2202
+ pluginVueRegressionWarned = true;
2203
+ 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.");
2204
+ }
2205
+ const vueAdapter = {
2206
+ name: "vue",
2207
+ pluginNames: ["vite:vue", "vite:vue-jsx"],
2208
+ host: { transformIndexHtml() {
2209
+ return [{
2210
+ tag: "script",
2211
+ children: VUE_HMR_RUNTIME_GUARD_SCRIPT,
2212
+ injectTo: "head-prepend"
2213
+ }];
2214
+ } },
2215
+ remote: { transform(code, _id, ctx) {
2216
+ if (!code.includes("__VUE_HMR_RUNTIME__.createRecord(")) return;
2217
+ const { code: rewritten, matched } = rewriteSfcHmrId(code, ctx.options.name);
2218
+ if (!matched) {
2219
+ warnPluginVueRegression();
2220
+ return;
2221
+ }
2222
+ return rewritten === code ? void 0 : rewritten;
2223
+ } }
2224
+ };
2225
+ //#endregion
2226
+ //#region src/plugins/hmr/fullReload.ts
2227
+ const REMOTE_HMR_ENDPOINT = "__mf_hmr";
2228
+ const REMOTE_HMR_EVENT = "mf:remote-update";
2229
+ const REMOTE_HMR_CONNECT_RETRY_DELAY_MS = 1e3;
2230
+ const REMOTE_HMR_CONNECT_MAX_RETRIES = 10;
2205
2231
  function getBasePath$1(base) {
2206
2232
  if (!base) return "/";
2207
2233
  if (base.startsWith("http://") || base.startsWith("https://")) try {
@@ -2220,9 +2246,6 @@ function getHmrWsPath(base, hmrPath) {
2220
2246
  if (!normalizedPath || normalizedPath === "/") return normalizedBase;
2221
2247
  return `${normalizedBase.endsWith("/") ? normalizedBase.slice(0, -1) : normalizedBase}/${normalizedPath.startsWith("/") ? normalizedPath.slice(1) : normalizedPath}`;
2222
2248
  }
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
2249
  function getRemoteHmrWsUrl(server) {
2227
2250
  const hmr = server.config.server.hmr;
2228
2251
  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 +2284,275 @@ function getStringPreview(value, max = 180) {
2261
2284
  } catch {}
2262
2285
  return rawValue.slice(0, max);
2263
2286
  }
2264
- function isRemoteHmrEnabled(dev) {
2265
- return typeof dev === "object" && dev !== null && !!dev.remoteHmr;
2287
+ /**
2288
+ * Installs the `/__mf_hmr` metadata endpoint on a remote dev server. The host
2289
+ * fetches this to discover the remote's HMR WebSocket URL before opening a
2290
+ * Node-to-Node relay socket. Always installed on remotes when `remoteHmr` is
2291
+ * enabled — under `'native'` strategy the endpoint is unused but harmless;
2292
+ * under `'full-reload'` it's the discovery hop for the host relay.
2293
+ */
2294
+ function setupRemoteMetadataEndpoint(server, options) {
2295
+ const endpointPath = getRemoteHmrPath(server.config.base);
2296
+ const wsUrl = getRemoteHmrWsUrl(server);
2297
+ server.middlewares.use((req, res, next) => {
2298
+ if (req.url?.replace(/\?.*/, "") !== endpointPath) {
2299
+ next();
2300
+ return;
2301
+ }
2302
+ res.setHeader("Content-Type", "application/json");
2303
+ res.setHeader("Access-Control-Allow-Origin", "*");
2304
+ res.end(JSON.stringify({
2305
+ remote: options.name,
2306
+ event: REMOTE_HMR_EVENT,
2307
+ wsUrl
2308
+ }));
2309
+ });
2266
2310
  }
2267
2311
  /**
2268
- * Detects whether the Vite plugin pipeline includes a framework with
2269
- * cross-federation HMR support (a shared runtime proxy that works
2270
- * across module federation boundaries).
2312
+ * Installs file-watcher broadcasts on a remote dev server. Every non-ignored
2313
+ * change/add/unlink emits a `mf:remote-update` custom event on the remote's
2314
+ * own WS channel. The host relay (see `setupHostFullReloadRelay`) listens
2315
+ * for these events and triggers a host-side full reload in response.
2271
2316
  *
2272
- * Currently only React is supported via the shared /@react-refresh proxy.
2317
+ * Only called under the `'full-reload'` strategy.
2273
2318
  */
2274
- function hasCrossFederationHmr(plugins) {
2275
- const supportedPlugins = ["vite:react-refresh", "vite:react-swc:refresh"];
2276
- return plugins.some((p) => supportedPlugins.includes(p.name));
2277
- }
2278
- function resolveHmrStrategy(dev, plugins) {
2279
- if (typeof dev === "object" && dev !== null && dev.remoteHmr === "full-reload") return "full-reload";
2280
- return hasCrossFederationHmr(plugins) ? "native" : "full-reload";
2281
- }
2282
- function pluginDevRemoteHmr(options) {
2283
- return {
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
- });
2334
- }
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);
2319
+ function setupRemoteBroadcast(server, options) {
2320
+ const broadcast = (file) => {
2321
+ if (shouldIgnoreFile(file, options)) return;
2322
+ server.ws.send({
2323
+ type: "custom",
2324
+ event: REMOTE_HMR_EVENT,
2325
+ data: {
2326
+ remote: options.name,
2327
+ file,
2328
+ ts: Date.now()
2412
2329
  }
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
2330
  });
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
2331
  };
2451
- };
2452
- const buildDtsModuleFederationConfig = (options) => {
2453
- const exposes = {};
2454
- Object.entries(options.exposes).forEach(([key, value]) => {
2455
- if (value.import) exposes[key] = value.import;
2456
- });
2457
- const remotes = {};
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}`;
2332
+ server.watcher.on("change", broadcast);
2333
+ server.watcher.on("add", broadcast);
2334
+ server.watcher.on("unlink", broadcast);
2335
+ server.httpServer?.once("close", () => {
2336
+ server.watcher.off("change", broadcast);
2337
+ server.watcher.off("add", broadcast);
2338
+ server.watcher.off("unlink", broadcast);
2461
2339
  });
2462
- return {
2463
- ...options,
2464
- exposes,
2465
- remotes
2466
- };
2467
- };
2468
- const resolveOutputDir = (config) => {
2469
- const { outDir } = config.build;
2470
- if (pathe.isAbsolute(outDir)) return pathe.relative(config.root, outDir);
2471
- return outDir;
2472
- };
2473
- const ensureRuntimePlugin = (options, pluginId) => {
2474
- if (!options.runtimePlugins.some((plugin) => {
2475
- if (typeof plugin === "string") return plugin === pluginId;
2476
- return plugin[0] === pluginId;
2477
- })) options.runtimePlugins.push(pluginId);
2478
- };
2479
- const getExposeImportPaths = (options) => {
2480
- return Object.values(options.exposes).map((value) => {
2481
- return value.import;
2482
- }).filter((value) => Boolean(value));
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`)
2340
+ }
2341
+ /**
2342
+ * Installs the host-side full-reload relay. For each configured remote:
2343
+ * 1. Fetches the remote's `/__mf_hmr` metadata to get its WS URL.
2344
+ * 2. Opens a Node-to-Node WebSocket to that URL.
2345
+ * 3. On any `mf:remote-update` message, broadcasts `{ type: 'full-reload' }`
2346
+ * to the host's own browser-facing WS.
2347
+ *
2348
+ * Also reloads on local host file changes. Retries failed connections up to
2349
+ * `REMOTE_HMR_CONNECT_MAX_RETRIES` times with a fixed delay.
2350
+ *
2351
+ * Only called under the `'full-reload'` strategy.
2352
+ */
2353
+ function setupHostFullReloadRelay(server, options) {
2354
+ const connections = [];
2355
+ const reconnectTimers = /* @__PURE__ */ new Map();
2356
+ let isTearingDown = false;
2357
+ const clearReconnectTimer = (remoteName) => {
2358
+ const timer = reconnectTimers.get(remoteName);
2359
+ if (!timer) return;
2360
+ clearTimeout(timer);
2361
+ reconnectTimers.delete(remoteName);
2516
2362
  };
2517
- };
2518
- const createDevDtsAssetMiddleware = (assetPaths) => {
2519
- return (req, res, next) => {
2520
- const requestPath = req.url?.split("?")[0];
2521
- const isZipRequest = requestPath === assetPaths.zipRequestPath;
2522
- const isApiRequest = requestPath === assetPaths.apiRequestPath;
2523
- if (!isZipRequest && !isApiRequest) {
2524
- next();
2363
+ const scheduleReconnect = (remoteName, remote, attempt, reason) => {
2364
+ if (isTearingDown) return;
2365
+ if (attempt >= REMOTE_HMR_CONNECT_MAX_RETRIES) {
2366
+ require_packageUtils.mfWarn(`Remote "${remoteName}" full HMR reconnect skipped after ${REMOTE_HMR_CONNECT_MAX_RETRIES} attempts: ${reason}`);
2525
2367
  return;
2526
2368
  }
2527
- const filePath = isZipRequest ? assetPaths.zipFilePath : assetPaths.apiFilePath;
2528
- if (!fs.default.existsSync(filePath)) {
2529
- res.statusCode = 404;
2530
- res.end();
2369
+ clearReconnectTimer(remoteName);
2370
+ const timer = setTimeout(() => {
2371
+ reconnectTimers.delete(remoteName);
2372
+ connectRemote(remoteName, remote, attempt + 1);
2373
+ }, REMOTE_HMR_CONNECT_RETRY_DELAY_MS);
2374
+ reconnectTimers.set(remoteName, timer);
2375
+ };
2376
+ const connectRemote = async (remoteName, remote, attempt = 0) => {
2377
+ if (isTearingDown) return;
2378
+ const endpoint = getRemoteHmrEndpoint(remote.entry, server);
2379
+ if (!endpoint) {
2380
+ require_packageUtils.mfWarn(`Failed to build HMR endpoint URL for remote "${remoteName}"`);
2531
2381
  return;
2532
2382
  }
2533
- res.statusCode = 200;
2534
- res.setHeader("Content-Type", isZipRequest ? "application/x-gzip" : "application/typescript");
2535
- if (req.method === "HEAD") {
2536
- res.end();
2537
- return;
2383
+ try {
2384
+ const metadataResponse = await fetch(endpoint);
2385
+ if (!metadataResponse.ok) {
2386
+ require_packageUtils.mfWarn(`Failed to fetch remote HMR metadata from "${remoteName}": ${metadataResponse.status}`);
2387
+ scheduleReconnect(remoteName, remote, attempt, `HTTP ${metadataResponse.status}`);
2388
+ return;
2389
+ }
2390
+ const metadata = await metadataResponse.json();
2391
+ if (metadata.event !== "mf:remote-update" || !metadata.wsUrl) {
2392
+ require_packageUtils.mfWarn(`Remote "${remoteName}" returned unexpected HMR metadata shape`);
2393
+ return;
2394
+ }
2395
+ const ws = new WebSocket(metadata.wsUrl, "vite-hmr");
2396
+ ws.onmessage = (rawEvent) => {
2397
+ const message = parseRemoteHmrMessage(rawEvent.data);
2398
+ if (!message || message.event !== "mf:remote-update") return;
2399
+ server.ws.send({ type: "full-reload" });
2400
+ };
2401
+ ws.onopen = () => clearReconnectTimer(remoteName);
2402
+ ws.onerror = (error) => require_packageUtils.mfWarn(`Remote HMR socket error for "${remoteName}":`, error);
2403
+ ws.onclose = () => scheduleReconnect(remoteName, remote, attempt, "socket closed");
2404
+ connections.push(ws);
2405
+ } catch (error) {
2406
+ require_packageUtils.mfWarn(`Failed to connect remote HMR for "${remoteName}" on attempt ${attempt + 1}: ${getStringPreview(error)}`);
2407
+ scheduleReconnect(remoteName, remote, attempt, getStringPreview(error));
2538
2408
  }
2539
- const stream = fs.default.createReadStream(filePath);
2540
- stream.on("error", () => {
2541
- if (!res.headersSent) res.statusCode = 500;
2542
- res.end();
2543
- });
2544
- res.on("close", () => {
2545
- stream.destroy();
2409
+ };
2410
+ const teardown = () => {
2411
+ isTearingDown = true;
2412
+ reconnectTimers.forEach((timer) => clearTimeout(timer));
2413
+ reconnectTimers.clear();
2414
+ connections.forEach((connection) => {
2415
+ if (connection.readyState !== connection.CLOSING && connection.readyState !== connection.CLOSED) connection.close();
2546
2416
  });
2547
- stream.pipe(res);
2417
+ connections.length = 0;
2548
2418
  };
2549
- };
2550
- const normalizeDevDtsOptions = (dts, context) => {
2551
- return (0, _module_federation_sdk.normalizeOptions)((0, _module_federation_dts_plugin.isTSProject)(dts, context), {
2552
- generateTypes: { compileInChildProcess: true },
2553
- consumeTypes: { consumeAPITypes: true },
2554
- extraOptions: {},
2555
- displayErrorInTerminal: typeof dts === "object" && dts ? dts.displayErrorInTerminal : void 0
2556
- }, "mfOptions.dts")(dts);
2557
- };
2558
- const logDtsError = (error, dtsOptions) => {
2559
- if (dtsOptions === false) return;
2560
- if (typeof dtsOptions === "object" && dtsOptions && dtsOptions.displayErrorInTerminal === false) return;
2561
- mfError(error);
2562
- };
2563
- function pluginDts(options) {
2564
- if (options.dts === false) return [];
2565
- const baseDtsModuleFederationConfig = buildDtsModuleFederationConfig(options);
2566
- const getDtsModuleFederationConfig = (context) => ({
2567
- ...baseDtsModuleFederationConfig,
2568
- dts: resolveDtsPluginOptions(options.dts, options, context)
2419
+ for (const [remoteName, remote] of Object.entries(options.remotes)) connectRemote(remoteName, remote);
2420
+ const triggerHostReload = (file) => {
2421
+ if (shouldIgnoreFile(file, options)) return;
2422
+ server.ws.send({ type: "full-reload" });
2423
+ };
2424
+ server.watcher.on("change", triggerHostReload);
2425
+ server.watcher.on("add", triggerHostReload);
2426
+ server.watcher.on("unlink", triggerHostReload);
2427
+ server.httpServer?.once("close", teardown);
2428
+ }
2429
+ //#endregion
2430
+ //#region src/plugins/pluginDevRemoteHmr.ts
2431
+ /**
2432
+ * Clears the federation runtime's `moduleCache` on every Vite `vite:beforeUpdate`
2433
+ * event. Without this, after a remote SFC change Vite would patch the in-memory
2434
+ * component, but `loadRemote()` would still return the cached stale module on
2435
+ * the next call (e.g. after route navigation), making the patched version
2436
+ * effectively unreachable.
2437
+ */
2438
+ const FEDERATION_MODULE_CACHE_CLEAR_SCRIPT = `
2439
+ if (import.meta.hot) {
2440
+ import.meta.hot.on('vite:beforeUpdate', function () {
2441
+ try {
2442
+ var f = globalThis.__FEDERATION__ || globalThis.__VMOK__;
2443
+ if (!f || !f.__INSTANCES__) return;
2444
+ for (var i = 0; i < f.__INSTANCES__.length; i++) {
2445
+ if (f.__INSTANCES__[i] && f.__INSTANCES__[i].moduleCache)
2446
+ f.__INSTANCES__[i].moduleCache.clear();
2447
+ }
2448
+ } catch (e) {}
2449
+ });
2450
+ }`;
2451
+ const HMR_ADAPTERS = [reactAdapter, vueAdapter];
2452
+ function resolveAdapters(plugins) {
2453
+ const pluginNames = new Set(plugins.map((p) => p.name));
2454
+ return HMR_ADAPTERS.filter((adapter) => adapter.pluginNames.some((name) => pluginNames.has(name)));
2455
+ }
2456
+ function hasCrossFederationHmr(plugins) {
2457
+ return resolveAdapters(plugins).length > 0;
2458
+ }
2459
+ function isRemoteHmrEnabled(dev) {
2460
+ return typeof dev === "object" && dev !== null && !!dev.remoteHmr;
2461
+ }
2462
+ /**
2463
+ * `'native'` — a matched framework adapter owns HMR through Vite's native
2464
+ * channel (e.g. React Fast Refresh via the `/@react-refresh` proxy, Vue's
2465
+ * patched `__VUE_HMR_RUNTIME__`). The broadcast/relay path stays idle.
2466
+ *
2467
+ * `'full-reload'` — no adapter matched, or the user explicitly opted in with
2468
+ * `remoteHmr: 'full-reload'` to bypass adapters: the plugin's broadcast/relay
2469
+ * machinery triggers a page reload on every remote file change.
2470
+ */
2471
+ function resolveHmrStrategy(dev, plugins) {
2472
+ if (typeof dev === "object" && dev !== null && dev.remoteHmr === "full-reload") return "full-reload";
2473
+ return hasCrossFederationHmr(plugins) ? "native" : "full-reload";
2474
+ }
2475
+ function shouldIgnoreFile(file, options) {
2476
+ 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");
2477
+ }
2478
+ function collectHostTags(server, options, adapters) {
2479
+ const ctx = {
2480
+ server,
2481
+ options
2482
+ };
2483
+ const tags = [];
2484
+ for (const adapter of adapters) {
2485
+ const adapterTags = adapter.host?.transformIndexHtml?.(ctx);
2486
+ if (adapterTags) tags.push(...adapterTags);
2487
+ }
2488
+ tags.push({
2489
+ tag: "script",
2490
+ attrs: { type: "module" },
2491
+ children: FEDERATION_MODULE_CACHE_CLEAR_SCRIPT,
2492
+ injectTo: "head"
2569
2493
  });
2570
- let resolvedConfig;
2571
- let devWorker;
2572
- let normalizedDevOptions;
2573
- let hasGeneratedBundle = false;
2574
- return [{
2575
- name: "module-federation-dts-dev",
2494
+ return tags;
2495
+ }
2496
+ function pluginDevRemoteHmr(options) {
2497
+ const isHost = Object.keys(options.remotes).length > 0;
2498
+ const isRemote = Object.keys(options.exposes).length > 0;
2499
+ let adapters = [];
2500
+ let strategy = "full-reload";
2501
+ return {
2502
+ name: "module-federation-dev-remote-hmr",
2576
2503
  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
2504
  configResolved(config) {
2587
- resolvedConfig = config;
2505
+ adapters = resolveAdapters(config.plugins);
2506
+ strategy = resolveHmrStrategy(options.dev, config.plugins);
2588
2507
  },
2589
2508
  configureServer(server) {
2590
- if (!normalizedDevOptions || !resolvedConfig) return;
2591
- const devOptions = normalizedDevOptions;
2592
- if (devOptions.disableDynamicRemoteTypeHints && devOptions.disableHotTypesReload && devOptions.disableLiveReload) return;
2593
- if (!options.name) throw createModuleFederationError("name is required if you want to enable dev server!");
2594
- const outputDir = resolveOutputDir(resolvedConfig);
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);
2509
+ if (!isRemoteHmrEnabled(options.dev)) return;
2510
+ if (isRemote) {
2511
+ for (const adapter of adapters) adapter.remote?.configureServer?.({
2512
+ server,
2513
+ options
2655
2514
  });
2656
- };
2657
- startDevWorker().catch((error) => {
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;
2515
+ setupRemoteMetadataEndpoint(server, options);
2516
+ if (strategy === "full-reload") setupRemoteBroadcast(server, options);
2677
2517
  }
2678
- if (typeof normalizedDtsOptions !== "object") return;
2679
- const context = resolvedConfig.root;
2680
- const outputDir = resolveOutputDir(resolvedConfig);
2681
- let consumeOptions;
2682
- try {
2683
- consumeOptions = (0, _module_federation_dts_plugin.normalizeConsumeTypesOptions)({
2684
- context,
2685
- dtsOptions: normalizedDtsOptions,
2686
- pluginOptions: getDtsModuleFederationConfig(resolvedConfig.root)
2518
+ if (isHost) {
2519
+ for (const adapter of adapters) adapter.host?.configureServer?.({
2520
+ server,
2521
+ options
2687
2522
  });
2688
- } catch (error) {
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);
2523
+ if (strategy === "full-reload") setupHostFullReloadRelay(server, options);
2696
2524
  }
2697
- let generateOptions;
2698
- try {
2699
- generateOptions = (0, _module_federation_dts_plugin.normalizeGenerateTypesOptions)({
2700
- context,
2701
- outputDir,
2702
- dtsOptions: normalizedDtsOptions,
2703
- pluginOptions: getDtsModuleFederationConfig(resolvedConfig.root)
2704
- });
2705
- } catch (error) {
2706
- logDtsError(error, normalizedDtsOptions);
2707
- return;
2525
+ },
2526
+ transform: {
2527
+ order: "post",
2528
+ handler(code, id) {
2529
+ if (!isRemote || !isRemoteHmrEnabled(options.dev)) return;
2530
+ if (!adapters.length) return;
2531
+ let result = code;
2532
+ const adapterCtx = { options };
2533
+ for (const adapter of adapters) {
2534
+ const next = adapter.remote?.transform?.(result, id, adapterCtx);
2535
+ if (typeof next === "string") result = next;
2536
+ }
2537
+ return result === code ? void 0 : result;
2708
2538
  }
2709
- if (!generateOptions) return;
2710
- try {
2711
- await (0, _module_federation_dts_plugin.generateTypesAPI)({ dtsManagerOptions: generateOptions });
2712
- } catch (error) {
2713
- logDtsError(error, normalizedDtsOptions);
2539
+ },
2540
+ transformIndexHtml: {
2541
+ order: "pre",
2542
+ handler(_html, ctx) {
2543
+ if (!isRemoteHmrEnabled(options.dev)) return;
2544
+ if (!isHost || !ctx.server) return;
2545
+ return collectHostTags(ctx.server, options, adapters);
2714
2546
  }
2715
2547
  }
2716
- }];
2548
+ };
2717
2549
  }
2718
2550
  //#endregion
2719
2551
  //#region src/virtualModules/index.ts
2720
- function initVirtualModules(command, remoteEntryId) {
2552
+ function initVirtualModules(command, remoteEntryId, enableSsrInit = false) {
2721
2553
  writeLocalSharedImportMap();
2722
2554
  writeHostAutoInit(remoteEntryId, command);
2723
- writeRuntimeInitStatus(command);
2555
+ writeRuntimeInitStatus(command, enableSsrInit);
2724
2556
  }
2725
2557
  //#endregion
2726
2558
  //#region src/utils/bundleHelpers.ts
@@ -3070,6 +2902,12 @@ function removeTrailingSlash(value) {
3070
2902
  function ensureTrailingSlash(value) {
3071
2903
  return `${removeTrailingSlash(value)}/`;
3072
2904
  }
2905
+ function getBasePath(base) {
2906
+ return removeTrailingSlash(base || "/");
2907
+ }
2908
+ function isNuxtClientBase(base) {
2909
+ return getBasePath(base).endsWith("/_nuxt");
2910
+ }
3073
2911
  function normalizeNodeModulePath(source) {
3074
2912
  return source.replace(/\\/g, "/").replace(/\?.*$/, "");
3075
2913
  }
@@ -3103,6 +2941,116 @@ function resolvePublicPath(options, viteBase, originalBase) {
3103
2941
  return "auto";
3104
2942
  }
3105
2943
  //#endregion
2944
+ //#region src/virtualModules/virtualExposesSSR.ts
2945
+ /**
2946
+ * Virtual module ID for the SSR exposes map.
2947
+ * Separate from the browser exposes: no CSS injection, no document references,
2948
+ * and shared packages are imported as bare specifiers (externals in the SSR build).
2949
+ */
2950
+ function getVirtualExposesSSRId(options) {
2951
+ return `virtual:mf-exposes-ssr:${`${options.internalName}__${options.filename}`.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
2952
+ }
2953
+ /**
2954
+ * Generates the SSR exposes map module.
2955
+ *
2956
+ * Differences from the browser version (virtualExposes.ts):
2957
+ * - No CSS asset injection (document APIs unavailable on Node)
2958
+ * - Shared packages (react, react-dom, etc.) must be externals in the SSR
2959
+ * build so Node resolves them via its own module cache — this is what
2960
+ * guarantees the React singleton is shared with react-dom/server.
2961
+ */
2962
+ function generateExposesSSR(options) {
2963
+ return `
2964
+ export default {
2965
+ ${Object.keys(options.exposes).map((key) => {
2966
+ return `
2967
+ ${JSON.stringify(key)}: async () => {
2968
+ const importModule = await import(${JSON.stringify(options.exposes[key].import)})
2969
+ const exportModule = {}
2970
+ Object.assign(exportModule, importModule)
2971
+ Object.defineProperty(exportModule, "__esModule", {
2972
+ value: true,
2973
+ enumerable: false
2974
+ })
2975
+ return exportModule
2976
+ }
2977
+ `;
2978
+ }).join(",")}
2979
+ }
2980
+ `;
2981
+ }
2982
+ //#endregion
2983
+ //#region src/virtualModules/virtualRemoteEntrySSR.ts
2984
+ const REMOTE_ENTRY_SSR_ID = "virtual:mf-REMOTE_ENTRY_SSR_ID";
2985
+ function getRemoteEntrySSRId(options) {
2986
+ return `${REMOTE_ENTRY_SSR_ID}:${`${options.internalName}__${options.filename}`.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
2987
+ }
2988
+ function getSsrRemoteEntryFileName(browserFilename) {
2989
+ const ext = browserFilename.match(/\.[^.]+$/)?.[0] || ".js";
2990
+ return `${browserFilename.slice(0, browserFilename.length - ext.length)}.ssr${ext}`;
2991
+ }
2992
+ /**
2993
+ * Generates the SSR remote entry module.
2994
+ *
2995
+ * This is intentionally minimal — no HMR shim, no loadShare virtual modules,
2996
+ * no browser globals. Shared packages (react, react-dom, etc.) are imported
2997
+ * as externals by the SSR build, so Node's require cache provides the singleton.
2998
+ *
2999
+ * The container API (init / get) mirrors the browser entry so the MF runtime
3000
+ * can call it the same way on the server.
3001
+ */
3002
+ function generateRemoteEntrySSR(options) {
3003
+ const virtualExposesSSRId = getVirtualExposesSSRId(options);
3004
+ return `
3005
+ import { init as runtimeInit } from "@module-federation/runtime";
3006
+
3007
+ let exposesMapPromise;
3008
+
3009
+ async function getExposesMap() {
3010
+ exposesMapPromise ??= import(${JSON.stringify(virtualExposesSSRId)}).then((mod) => mod.default ?? mod);
3011
+ return exposesMapPromise;
3012
+ }
3013
+
3014
+ /**
3015
+ * Called by the MF runtime on the host to register this remote's share scope.
3016
+ * On the server the host has already initialised the runtime, so we just need
3017
+ * to set up a minimal runtime instance for the remote container.
3018
+ */
3019
+ async function init(shared = {}, initScope = []) {
3020
+ const initRes = runtimeInit({
3021
+ name: ${JSON.stringify(options.internalName)},
3022
+ remotes: [],
3023
+ shared: {},
3024
+ });
3025
+ const initToken = { from: ${JSON.stringify(options.internalName)} };
3026
+ if (initScope.indexOf(initToken) >= 0) return;
3027
+ initScope.push(initToken);
3028
+ initRes.initShareScopeMap(${JSON.stringify(options.shareScope)}, shared);
3029
+ try {
3030
+ await Promise.all(
3031
+ await initRes.initializeSharing(${JSON.stringify(options.shareScope)}, {
3032
+ strategy: ${JSON.stringify(options.shareStrategy ?? "version-first")},
3033
+ from: 'build',
3034
+ initScope,
3035
+ })
3036
+ );
3037
+ } catch (e) {
3038
+ console.error('[Module Federation SSR]', e);
3039
+ }
3040
+ return initRes;
3041
+ }
3042
+
3043
+ async function getExposes(moduleName) {
3044
+ const exposesMap = await getExposesMap();
3045
+ if (!(moduleName in exposesMap))
3046
+ throw new Error(\`[Module Federation] Module \${moduleName} does not exist in container.\`);
3047
+ return exposesMap[moduleName]().then((res) => () => res);
3048
+ }
3049
+
3050
+ export { init, getExposes as get };
3051
+ `;
3052
+ }
3053
+ //#endregion
3106
3054
  //#region src/plugins/pluginMFManifest.ts
3107
3055
  /**
3108
3056
  * Resolves the build version for the module federation manifest.
@@ -3133,6 +3081,7 @@ const Manifest = () => {
3133
3081
  };
3134
3082
  let root;
3135
3083
  let remoteEntryFile;
3084
+ let ssrRemoteEntryFile;
3136
3085
  let publicPath;
3137
3086
  let _command;
3138
3087
  let _originalConfigBase;
@@ -3169,8 +3118,8 @@ const Manifest = () => {
3169
3118
  type: "module"
3170
3119
  },
3171
3120
  ssrRemoteEntry: {
3172
- name: filename,
3173
- path: "",
3121
+ name: getSsrRemoteEntryFileName(filename),
3122
+ path: "/__mf_ssr__/",
3174
3123
  type: "module"
3175
3124
  },
3176
3125
  varRemoteEntry: varFilename ? {
@@ -3201,6 +3150,7 @@ const Manifest = () => {
3201
3150
  _originalConfigBase = config.base;
3202
3151
  },
3203
3152
  configResolved(config) {
3153
+ viteConfig = config;
3204
3154
  root = config.root;
3205
3155
  let base = config.base;
3206
3156
  if (_command === "serve") base = (config.server.origin || "") + config.base;
@@ -3210,7 +3160,10 @@ const Manifest = () => {
3210
3160
  if (!mfManifestName) return;
3211
3161
  let filesMap = {};
3212
3162
  const foundRemoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
3163
+ const expectedSsrRemoteEntryFile = getSsrRemoteEntryFileName(mfOptions.filename);
3164
+ const foundSsrRemoteEntryFile = Object.values(bundle).find((file) => file.fileName === expectedSsrRemoteEntryFile)?.fileName;
3213
3165
  if (foundRemoteEntryFile) remoteEntryFile = foundRemoteEntryFile;
3166
+ ssrRemoteEntryFile = foundSsrRemoteEntryFile || expectedSsrRemoteEntryFile;
3214
3167
  const allCssAssets = mfOptions.bundleAllCSS && !disableAssetsAnalyze ? collectCssAssets(bundle) : /* @__PURE__ */ new Set();
3215
3168
  if (!disableAssetsAnalyze) {
3216
3169
  const exposesModules = Object.keys(mfOptions.exposes).map((item) => mfOptions.exposes[item].import);
@@ -3252,6 +3205,11 @@ const Manifest = () => {
3252
3205
  path: "",
3253
3206
  type: "module"
3254
3207
  };
3208
+ const ssrRemoteEntry = {
3209
+ name: ssrRemoteEntryFile || getSsrRemoteEntryFileName(filename),
3210
+ path: _command === "serve" ? "/__mf_ssr__/" : "",
3211
+ type: "module"
3212
+ };
3255
3213
  const varRemoteEntry = varFilename ? {
3256
3214
  name: varFilename,
3257
3215
  path: "",
@@ -3315,7 +3273,7 @@ const Manifest = () => {
3315
3273
  buildName: name
3316
3274
  },
3317
3275
  remoteEntry,
3318
- ssrRemoteEntry: remoteEntry,
3276
+ ssrRemoteEntry,
3319
3277
  varRemoteEntry,
3320
3278
  types: {
3321
3279
  path: "",
@@ -3382,14 +3340,14 @@ function resetParseState() {
3382
3340
  }
3383
3341
  function setParseTimeout(timeout) {
3384
3342
  if (!_parseTimeout) _parseTimeout = setTimeout(() => {
3385
- mfWarn(`Parse timeout (${timeout}s) - forcing resolve`);
3343
+ require_packageUtils.mfWarn(`Parse timeout (${timeout}s) - forcing resolve`);
3386
3344
  _resolve?.(1);
3387
3345
  }, timeout * 1e3);
3388
3346
  }
3389
3347
  function resetIdleTimeout(timeout) {
3390
3348
  clearParseTimeout();
3391
3349
  _parseTimeout = setTimeout(() => {
3392
- mfWarn(`moduleParseIdleTimeout: no module activity for ${timeout}s, forcing resolve. Some shared/remote dependencies may be missing. Consider increasing moduleParseIdleTimeout.`);
3350
+ require_packageUtils.mfWarn(`moduleParseIdleTimeout: no module activity for ${timeout}s, forcing resolve. Some shared/remote dependencies may be missing. Consider increasing moduleParseIdleTimeout.`);
3393
3351
  _resolve?.(1);
3394
3352
  }, timeout * 1e3);
3395
3353
  }
@@ -3554,13 +3512,14 @@ function appendAlias(config, alias) {
3554
3512
  function pluginProxyRemotes_default(options) {
3555
3513
  let command;
3556
3514
  let root = process.cwd();
3515
+ let enableSsrInit = false;
3557
3516
  const { remotes } = options;
3558
3517
  function resolveRemoteId(source, importer, remoteName) {
3559
3518
  if (source === remoteName) {
3560
- const installedPackageEntry = getInstalledPackageEntry(source, { cwd: root });
3519
+ const installedPackageEntry = require_packageUtils.getInstalledPackageEntry(source, { cwd: root });
3561
3520
  if (installedPackageEntry && (importer === void 0 || isNodeModulesImporter(importer))) return installedPackageEntry;
3562
3521
  }
3563
- const remoteModule = getRemoteVirtualModule(source, command);
3522
+ const remoteModule = getRemoteVirtualModule(source, command, enableSsrInit);
3564
3523
  addUsedRemote(remoteName, source);
3565
3524
  refreshHostAutoInit();
3566
3525
  return remoteModule.getImportId();
@@ -3579,6 +3538,9 @@ function pluginProxyRemotes_default(options) {
3579
3538
  });
3580
3539
  });
3581
3540
  },
3541
+ configResolved() {
3542
+ enableSsrInit = command === "serve" && parseInt(vite.version, 10) >= 8;
3543
+ },
3582
3544
  resolveId(source, importer) {
3583
3545
  if (!filterId(source)) return;
3584
3546
  for (const remote of Object.values(remotes)) {
@@ -3626,10 +3588,10 @@ function getPrebuildResolutionSource(pkgName, shareItem) {
3626
3588
  }
3627
3589
  function tryResolveFromProjectRoot(source) {
3628
3590
  if (pathe.default.isAbsolute(source) || source.startsWith(".") || source.startsWith("/")) return source;
3629
- const browserEntry = getInstalledPackageEntry(source, { cwd: getPackageDetectionCwd() });
3591
+ const browserEntry = require_packageUtils.getInstalledPackageEntry(source, { cwd: require_packageUtils.getPackageDetectionCwd() });
3630
3592
  if (browserEntry) return browserEntry;
3631
3593
  try {
3632
- return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(getPackageDetectionCwd(), "package.json")}`)).resolve(source);
3594
+ return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(require_packageUtils.getPackageDetectionCwd(), "package.json")}`)).resolve(source);
3633
3595
  } catch {
3634
3596
  return;
3635
3597
  }
@@ -3655,15 +3617,15 @@ function findSharedKeyForSource(source, shared) {
3655
3617
  const explicitSubpathKey = getMatchingNodeModuleSubpath(source, Object.keys(shared || {}).filter((sharedKey) => sharedKey.includes("/") && !sharedKey.endsWith("/")));
3656
3618
  if (explicitSubpathKey) return explicitSubpathKey;
3657
3619
  }
3658
- const packageName = getPackageNameFromNodeModulePath(source);
3620
+ const packageName = require_packageUtils.getPackageNameFromNodeModulePath(source);
3659
3621
  return packageName ? findSharedKey(packageName, shared) : void 0;
3660
3622
  }
3661
3623
  /**
3662
3624
  * Reads the dependencies of an installed package from its package.json.
3663
3625
  */
3664
3626
  function getPackageDependencies(pkg) {
3665
- const packageName = getPackageName(pkg);
3666
- const installed = getInstalledPackageJson(packageName, { packageName });
3627
+ const packageName = require_packageUtils.getPackageName(pkg);
3628
+ const installed = require_packageUtils.getInstalledPackageJson(packageName, { packageName });
3667
3629
  return Object.keys(installed?.packageJson.dependencies || {});
3668
3630
  }
3669
3631
  /**
@@ -3682,7 +3644,7 @@ function excludeSharedSubDependencies(shared) {
3682
3644
  const depKey = sharedKeyByBase.get(dep);
3683
3645
  if (depKey && depKey !== parentKey) {
3684
3646
  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.`);
3647
+ 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
3648
  delete shared[depKey];
3687
3649
  sharedKeys.delete(depKey);
3688
3650
  sharedKeyByBase.delete(dep);
@@ -3724,10 +3686,10 @@ function proxySharedModule(options) {
3724
3686
  name: "proxyPreBuildShared",
3725
3687
  enforce: "post",
3726
3688
  config(config, { command }) {
3727
- setPackageDetectionCwd(config.root || process.cwd());
3728
- const isVinext = hasPackageDependency("vinext");
3729
- const isAstro = hasPackageDependency("astro");
3730
- const isRolldown = getIsRolldown(this);
3689
+ require_packageUtils.setPackageDetectionCwd(config.root || process.cwd());
3690
+ const isVinext = require_packageUtils.hasPackageDependency("vinext");
3691
+ const isAstro = require_packageUtils.hasPackageDependency("astro");
3692
+ const isRolldown = require_packageUtils.getIsRolldown(this);
3731
3693
  _command = command;
3732
3694
  useRolldown = isRolldown;
3733
3695
  useDirectReactImport = isVinext || isAstro;
@@ -3735,7 +3697,7 @@ function proxySharedModule(options) {
3735
3697
  },
3736
3698
  configResolved(config) {
3737
3699
  _config = config;
3738
- const isRolldown = getIsRolldown(this);
3700
+ const isRolldown = require_packageUtils.getIsRolldown(this);
3739
3701
  Object.keys(shared).forEach((key) => {
3740
3702
  if (key.endsWith("/")) return;
3741
3703
  if (useDirectReactImport && key === "react") {
@@ -3860,9 +3822,37 @@ function applyRewrites(code, imports, id) {
3860
3822
  const importParts = [];
3861
3823
  if (imp.defaultLocal) importParts.push(`default as ${imp.defaultLocal}`);
3862
3824
  importParts.push(`__moduleExports as ${nsId}`);
3863
- const destructParts = imp.named.map((s) => s.imported === s.local ? s.local : `${s.imported}: ${s.local}`);
3864
3825
  let rewrite = `import { ${importParts.join(", ")} } from ${src};`;
3865
- if (destructParts.length > 0) rewrite += `\nconst { ${destructParts.join(", ")} } = ${nsId};`;
3826
+ if (imp.named.length > 0) {
3827
+ const isProxyId = `__mf_is_proxy_${counter++}`;
3828
+ const namedProxyHelper = `function __mfCreateNamedRemoteProxy(ns, key) {
3829
+ const target = function (...args) {
3830
+ const value = ns[key];
3831
+ return typeof value === "function" ? value.apply(this, args) : value;
3832
+ };
3833
+ return new Proxy(target, {
3834
+ get(_target, prop) {
3835
+ if (prop === "then") return undefined;
3836
+ const value = ns[key];
3837
+ if (prop === Symbol.toPrimitive) return () => value;
3838
+ const item = value == null ? undefined : value[prop];
3839
+ return typeof item === "function" ? item.bind(value) : item;
3840
+ },
3841
+ apply(target, thisArg, args) {
3842
+ return target.apply(thisArg, args);
3843
+ }
3844
+ });
3845
+ }`;
3846
+ const tempNames = imp.named.map((_s) => `__mf_named_${counter++}`);
3847
+ const destructParts = imp.named.map((s, index) => `${s.imported}: ${tempNames[index]}`);
3848
+ const bindingLines = imp.named.map((s, index) => {
3849
+ const temp = tempNames[index];
3850
+ return `const ${s.local} = ${isProxyId} ? __mfCreateNamedRemoteProxy(${nsId}, ${JSON.stringify(s.imported)}) : ${temp};`;
3851
+ });
3852
+ rewrite += `\n${namedProxyHelper}\nconst ${isProxyId} = ${nsId} && ${nsId}.__mf_is_remote_proxy;`;
3853
+ rewrite += `\nconst { ${destructParts.join(", ")} } = ${isProxyId} ? {} : ${nsId};`;
3854
+ rewrite += `\n${bindingLines.join("\n")}`;
3855
+ }
3866
3856
  ms.overwrite(imp.start, imp.end, rewrite);
3867
3857
  }
3868
3858
  changed = true;
@@ -4138,6 +4128,205 @@ function pluginRemoteNamedExports(options) {
4138
4128
  };
4139
4129
  }
4140
4130
  //#endregion
4131
+ //#region src/plugins/pluginSSRRemoteEntry.ts
4132
+ /**
4133
+ * Emits a Node-compatible SSR remote entry alongside the browser entry.
4134
+ *
4135
+ * Format strategy:
4136
+ * - Emit a dedicated ESM SSR entry alongside the browser entry.
4137
+ * - Keep the SSR entry out of the browser remote graph for Rollup builds by
4138
+ * emitting it as a generated asset.
4139
+ *
4140
+ * In both cases shared packages (react, react-dom, etc.) are marked as external
4141
+ * so Node resolves them through its own module cache, guaranteeing the singleton
4142
+ * is shared with react-dom/server.
4143
+ */
4144
+ function pluginSSRRemoteEntry(options) {
4145
+ const remoteEntrySSRId = getRemoteEntrySSRId(options);
4146
+ const virtualExposesSSRId = getVirtualExposesSSRId(options);
4147
+ let isRolldown = false;
4148
+ let ssrOutputFilename = "";
4149
+ const ssrOnlyExternals = [
4150
+ "@module-federation/runtime",
4151
+ "@module-federation/runtime-core",
4152
+ "@module-federation/sdk",
4153
+ ...options.ssrExternals ?? []
4154
+ ];
4155
+ const ssrOnlyExternalPattern = new RegExp(`^(${ssrOnlyExternals.map((e) => e.replace(/[/\\^$*+?.()|[\]{}]/g, "\\$&")).join("|")})(\\/.*)?$`);
4156
+ const ssrModuleIds = new Set([remoteEntrySSRId, virtualExposesSSRId]);
4157
+ const resolvedAbsToPackage = /* @__PURE__ */ new Map();
4158
+ let isServe = false;
4159
+ let viteConfig;
4160
+ let isNuxtProject = false;
4161
+ const findNuxtExposesChunk = (bundle) => {
4162
+ const exposeKeys = Object.keys(options.exposes);
4163
+ if (exposeKeys.length === 0) return;
4164
+ return Object.values(bundle).find((file) => {
4165
+ if (file.type !== "chunk" || !file.fileName.startsWith("_nuxt/") || !file.fileName.endsWith(".js")) return false;
4166
+ const code = file.code || "";
4167
+ return exposeKeys.every((key) => code.includes(JSON.stringify(key)));
4168
+ })?.fileName;
4169
+ };
4170
+ return [{
4171
+ name: "mf:ssr-remote-entry:pre",
4172
+ enforce: "pre",
4173
+ configResolved(config) {
4174
+ isServe = config.command === "serve";
4175
+ for (const pkg of ssrOnlyExternals) {
4176
+ const aliasEntry = (config.resolve?.alias)?.find((a) => a.find === pkg || a.find instanceof RegExp && a.find.test(pkg));
4177
+ if (aliasEntry?.replacement) resolvedAbsToPackage.set(aliasEntry.replacement, pkg);
4178
+ }
4179
+ },
4180
+ resolveId(id, importer) {
4181
+ if (id === remoteEntrySSRId || id.startsWith(remoteEntrySSRId)) return id;
4182
+ if (id === virtualExposesSSRId || id.startsWith(virtualExposesSSRId)) return id;
4183
+ if (!importer || !ssrModuleIds.has(importer)) return;
4184
+ if (ssrOnlyExternalPattern.test(id)) return {
4185
+ id,
4186
+ external: true
4187
+ };
4188
+ const pkg = resolvedAbsToPackage.get(id);
4189
+ if (pkg) return {
4190
+ id: pkg,
4191
+ external: true
4192
+ };
4193
+ if (id.startsWith(".") || id.startsWith("/") || id.startsWith("file:")) return this.resolve(id, importer, { skipSelf: true }).then((resolved) => {
4194
+ if (resolved) ssrModuleIds.add(resolved.id);
4195
+ return resolved;
4196
+ });
4197
+ }
4198
+ }, {
4199
+ name: "mf:ssr-remote-entry",
4200
+ configResolved(config) {
4201
+ viteConfig = config;
4202
+ isNuxtProject = require_packageUtils.isNuxtProjectRoot(config.root);
4203
+ },
4204
+ configureServer(server) {
4205
+ const base = "/__mf_ssr__";
4206
+ const basePath = getBasePath(viteConfig?.base);
4207
+ const ssrEntryFileName = getSsrRemoteEntryFileName(options.filename);
4208
+ if (isNuxtProject || isNuxtClientBase(basePath)) server.middlewares.use((req, _res, next) => {
4209
+ if (req.url?.replace(/\?.*/, "") === `${basePath}/${ssrEntryFileName}`) req.url = `${basePath}/__mf_ssr__/${ssrEntryFileName}`;
4210
+ next();
4211
+ });
4212
+ const ssrEnv = server.environments?.ssr;
4213
+ const clientEnv = server.environments?.client;
4214
+ if (typeof (ssrEnv?.fetchModule ?? clientEnv?.fetchModule) === "function") server.middlewares.use("/__mf_runner__", async (req, res) => {
4215
+ res.setHeader("Access-Control-Allow-Origin", "*");
4216
+ if (req.method === "OPTIONS") {
4217
+ res.setHeader("Access-Control-Allow-Methods", "POST");
4218
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
4219
+ res.statusCode = 204;
4220
+ res.end();
4221
+ return;
4222
+ }
4223
+ if (req.method !== "POST") {
4224
+ res.statusCode = 405;
4225
+ res.end("Method not allowed");
4226
+ return;
4227
+ }
4228
+ try {
4229
+ const chunks = [];
4230
+ await new Promise((resolve, reject) => {
4231
+ req.on("data", (chunk) => chunks.push(chunk));
4232
+ req.on("end", resolve);
4233
+ req.on("error", reject);
4234
+ });
4235
+ const body = JSON.parse(Buffer.concat(chunks).toString("utf8"));
4236
+ if (body.name === "getBuiltins") {
4237
+ const builtins = (clientEnv ?? ssrEnv)?.config?.resolve?.builtins ?? [];
4238
+ res.setHeader("Content-Type", "application/json");
4239
+ res.end(JSON.stringify({ result: builtins }));
4240
+ return;
4241
+ }
4242
+ if (body.name !== "fetchModule") {
4243
+ res.statusCode = 400;
4244
+ res.end(JSON.stringify({ error: { message: `Unsupported invoke: ${body.name}` } }));
4245
+ return;
4246
+ }
4247
+ const [id, importer, opts] = body.data;
4248
+ const fetchEnv = ssrEnv ?? clientEnv;
4249
+ const fetchFn = fetchEnv.fetchModule.bind(fetchEnv);
4250
+ let result;
4251
+ try {
4252
+ result = await fetchFn(id, importer, opts);
4253
+ } catch (fetchErr) {
4254
+ const bareId = id.startsWith("/@id/") ? id.slice(5).replace(/^__x00__/, "\0") : id;
4255
+ try {
4256
+ const { createRequire } = await import("module");
4257
+ const resolved = createRequire(new URL(`file://${server.config.root}/package.json`)).resolve(bareId.replace(/^\0/, ""));
4258
+ const { pathToFileURL } = await import("url");
4259
+ result = {
4260
+ externalize: pathToFileURL(resolved).href,
4261
+ type: "module"
4262
+ };
4263
+ } catch {
4264
+ throw fetchErr;
4265
+ }
4266
+ }
4267
+ res.setHeader("Content-Type", "application/json");
4268
+ res.end(JSON.stringify({ result }));
4269
+ } catch (e) {
4270
+ res.setHeader("Content-Type", "application/json");
4271
+ res.end(JSON.stringify({ error: { message: String(e instanceof Error ? e.message : e) } }));
4272
+ }
4273
+ });
4274
+ const ssrPath = `${base}/${ssrEntryFileName}`;
4275
+ server.middlewares.use(ssrPath, (_req, res) => {
4276
+ const exposesUrl = `${base}/${options.filename.replace(/\.[^.]+$/, "")}.exposes.js`;
4277
+ const code = generateRemoteEntrySSR(options).replace(JSON.stringify(virtualExposesSSRId), JSON.stringify(exposesUrl));
4278
+ res.setHeader("Content-Type", "application/javascript");
4279
+ res.setHeader("Access-Control-Allow-Origin", "*");
4280
+ res.end(code);
4281
+ });
4282
+ },
4283
+ resolveId(id) {
4284
+ if (id === remoteEntrySSRId || id.startsWith(remoteEntrySSRId)) return id;
4285
+ if (id === virtualExposesSSRId || id.startsWith(virtualExposesSSRId)) return id;
4286
+ if (id === `/__mf_ssr__/${getSsrRemoteEntryFileName(options.filename)}`) return remoteEntrySSRId;
4287
+ if (id === `/__mf_ssr__/${options.filename.replace(/\.[^.]+$/, "")}.exposes.js`) return virtualExposesSSRId;
4288
+ },
4289
+ load(id) {
4290
+ if (id === remoteEntrySSRId || id.startsWith(remoteEntrySSRId)) return generateRemoteEntrySSR(options);
4291
+ if (id === virtualExposesSSRId || id.startsWith(virtualExposesSSRId)) return generateExposesSSR(options);
4292
+ },
4293
+ buildStart() {
4294
+ if (isServe) return;
4295
+ isRolldown = require_packageUtils.getIsRolldown(this);
4296
+ ssrOutputFilename = getSsrRemoteEntryFileName(options.filename);
4297
+ const environmentName = this.environment?.name;
4298
+ const hasSsrEnvironment = Boolean(viteConfig?.environments?.ssr);
4299
+ const isLegacySsrBuild = Boolean(this.environment?.config?.build?.ssr);
4300
+ if (hasSsrEnvironment) {
4301
+ if (isNuxtProject) {
4302
+ if (environmentName === "ssr") return;
4303
+ } else if (environmentName !== "ssr") return;
4304
+ } else if (isLegacySsrBuild) {} else if (environmentName && environmentName !== "client") return;
4305
+ if (Object.keys(options.exposes).length === 0) return;
4306
+ if (isRolldown) this.emitFile({
4307
+ type: "chunk",
4308
+ id: remoteEntrySSRId,
4309
+ name: "ssrRemoteEntry",
4310
+ fileName: ssrOutputFilename,
4311
+ preserveSignature: "strict"
4312
+ });
4313
+ else this.emitFile({
4314
+ type: "asset",
4315
+ fileName: ssrOutputFilename,
4316
+ source: generateRemoteEntrySSR(options)
4317
+ });
4318
+ },
4319
+ generateBundle(_options, bundle) {
4320
+ const exposesChunk = findNuxtExposesChunk(bundle);
4321
+ const ssrAsset = bundle[ssrOutputFilename];
4322
+ if (exposesChunk && ssrAsset?.type === "asset" && typeof ssrAsset.source === "string") ssrAsset.source = ssrAsset.source.replace(/import\("virtual:mf-exposes-ssr:[^"]+"\)/g, `import("./${exposesChunk}")`);
4323
+ if (!isRolldown) return;
4324
+ const chunk = bundle[ssrOutputFilename];
4325
+ if (!chunk || chunk.type !== "chunk") return;
4326
+ }
4327
+ }];
4328
+ }
4329
+ //#endregion
4141
4330
  //#region src/plugins/pluginVarRemoteEntry.ts
4142
4331
  const VarRemoteEntry = () => {
4143
4332
  const mfOptions = getNormalizeModuleFederationOptions();
@@ -4173,9 +4362,9 @@ const VarRemoteEntry = () => {
4173
4362
  },
4174
4363
  async generateBundle(_options, bundle) {
4175
4364
  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).`);
4365
+ 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
4366
  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`);
4367
+ if (!remoteEntryFile) throw require_packageUtils.createModuleFederationError(`Couldn't find a remoteEntry chunk file for ${mfOptions.filename}, can't generate varRemoteEntry file`);
4179
4368
  this.emitFile({
4180
4369
  type: "asset",
4181
4370
  fileName: varFilename,
@@ -4398,10 +4587,15 @@ function createEarlyVirtualModulesPlugin(options) {
4398
4587
  config(config, { command: _command }) {
4399
4588
  if (_command === "serve") ignoreFederationGeneratedFiles(config, options);
4400
4589
  const root = config.root || process.cwd();
4401
- setPackageDetectionCwd(root);
4402
- const isVinext = hasPackageDependency("vinext");
4590
+ require_packageUtils.setPackageDetectionCwd(root);
4591
+ const isVinext = require_packageUtils.hasPackageDependency("vinext");
4592
+ setSsrRemotes(Object.entries(options.remotes).map(([key, r]) => ({
4593
+ name: key,
4594
+ entry: r.entry,
4595
+ type: r.type ?? "module"
4596
+ })));
4403
4597
  initVirtualModules(_command, getRemoteEntryId(options));
4404
- const isRolldown = getIsRolldown(this);
4598
+ const isRolldown = require_packageUtils.getIsRolldown(this);
4405
4599
  if (remotes && Object.keys(remotes).length > 0) {
4406
4600
  for (const key of Object.keys(remotes)) addUsedRemote(key, key);
4407
4601
  if (_command === "serve") {
@@ -4519,15 +4713,52 @@ export default __mfShared.default ?? __mfShared;`
4519
4713
  }
4520
4714
  writeLocalSharedImportMap();
4521
4715
  }
4716
+ },
4717
+ configResolved(config) {
4718
+ if (parseInt(vite.version, 10) < 8) return;
4719
+ if (!(Object.keys(options.exposes).length > 0 || Object.keys(options.remotes).length > 0)) return;
4720
+ if (options.runtimePlugins.some((p) => {
4721
+ return (typeof p === "string" ? p : p[0]) === "@module-federation/vite/ssrEntryLoader";
4722
+ })) return;
4723
+ const pluginRequire = (0, module$1.createRequire)(require("url").pathToFileURL(__filename).href);
4724
+ const projectRequire = (0, module$1.createRequire)(new URL(`file://${config.root}/package.json`));
4725
+ const sharedKeys = Object.keys(options.shared ?? {});
4726
+ const commonSharedPkgs = [
4727
+ "react",
4728
+ "react-dom",
4729
+ "react/jsx-runtime",
4730
+ "react/jsx-dev-runtime",
4731
+ "@module-federation/runtime",
4732
+ "@module-federation/runtime-core",
4733
+ "@module-federation/sdk"
4734
+ ];
4735
+ const resolvedShared = {};
4736
+ for (const pkg of [...commonSharedPkgs, ...sharedKeys]) try {
4737
+ resolvedShared[pkg] = projectRequire.resolve(pkg);
4738
+ } catch {
4739
+ try {
4740
+ resolvedShared[pkg] = pluginRequire.resolve(pkg);
4741
+ } catch {}
4742
+ }
4743
+ const ssrEntryLoaderSpecifier = "@module-federation/vite/ssrEntryLoader";
4744
+ try {
4745
+ pluginRequire.resolve(ssrEntryLoaderSpecifier);
4746
+ options.runtimePlugins.push([ssrEntryLoaderSpecifier, { resolvedShared }]);
4747
+ } catch {}
4522
4748
  }
4523
4749
  };
4524
4750
  }
4751
+ const SSR_ONLY_PLUGINS = new Set(["@module-federation/vite/ssrEntryLoader"]);
4752
+ function loadPluginDts(options) {
4753
+ if (options.dts === false) return [];
4754
+ return [Promise.resolve().then(() => require("./pluginDts-BEOKyKQ-.cjs")).then(({ default: pluginDts }) => pluginDts(options))];
4755
+ }
4525
4756
  function federation(mfUserOptions) {
4526
4757
  if (isTestEnv()) return [];
4527
4758
  const options = normalizeModuleFederationOptions(mfUserOptions);
4528
- const isVinext = hasPackageDependency("vinext");
4759
+ const isVinext = require_packageUtils.hasPackageDependency("vinext");
4529
4760
  const { name, shared, filename, hostInitInjectLocation } = options;
4530
- if (!name) throw createModuleFederationError("name is required");
4761
+ if (!name) throw require_packageUtils.createModuleFederationError("name is required");
4531
4762
  const remoteEntryId = getRemoteEntryId(options);
4532
4763
  const virtualExposesId = getVirtualExposesId(options);
4533
4764
  let command;
@@ -4573,14 +4804,26 @@ function federation(mfUserOptions) {
4573
4804
  command = env.command;
4574
4805
  },
4575
4806
  configResolved() {
4576
- initVirtualModules(command, remoteEntryId);
4807
+ initVirtualModules(command, remoteEntryId, parseInt(vite.version, 10) >= 8);
4577
4808
  }
4578
4809
  },
4579
4810
  aliasToArrayPlugin_default,
4580
4811
  checkAliasConflicts({ shared }),
4581
4812
  normalizeOptimizeDeps_default,
4582
- ...pluginDts(options),
4813
+ ...loadPluginDts(options),
4583
4814
  pluginDevRemoteHmr(options),
4815
+ {
4816
+ name: "mf:normalize-entry-chunks",
4817
+ enforce: "pre",
4818
+ apply: "build",
4819
+ generateBundle(_options, bundle) {
4820
+ for (const chunk of Object.values(bundle)) {
4821
+ if (typeof chunk !== "object" || chunk === null || chunk.type !== "chunk" || !chunk.isEntry) continue;
4822
+ const facadeId = chunk.facadeModuleId ?? "";
4823
+ if (facadeId.includes("__mf__virtual") || facadeId.startsWith("virtual:mf-") || facadeId.startsWith("virtual:mf:") || facadeId.startsWith("\0virtual:mf-") || facadeId.startsWith("\0virtual:mf:")) chunk.isEntry = false;
4824
+ }
4825
+ }
4826
+ },
4584
4827
  ...addEntry({
4585
4828
  entryName: "remoteEntry",
4586
4829
  entryPath: remoteEntryId,
@@ -4590,7 +4833,8 @@ function federation(mfUserOptions) {
4590
4833
  entryName: "hostInit",
4591
4834
  entryPath: () => getHostAutoInitPath(),
4592
4835
  inject: hostInitInjectLocation,
4593
- forceClientInjected: Object.keys(options.exposes).length > 0
4836
+ forceClientInjected: Object.keys(options.exposes).length > 0,
4837
+ skipTransformFor: Object.values(options.exposes).map((expose) => expose.import)
4594
4838
  }),
4595
4839
  ...addEntry({
4596
4840
  entryName: "virtualExposes",
@@ -4640,7 +4884,7 @@ function federation(mfUserOptions) {
4640
4884
  delete output.codeSplitting;
4641
4885
  if (warnedAboutCodeSplitting) return;
4642
4886
  warnedAboutCodeSplitting = true;
4643
- mfWarn("Ignoring `output.codeSplitting = false` because module federation requires chunk splitting.");
4887
+ require_packageUtils.mfWarn("Ignoring `output.codeSplitting = false` because module federation requires chunk splitting.");
4644
4888
  return;
4645
4889
  }
4646
4890
  if (!output?.codeSplitting || typeof output.codeSplitting !== "object") return;
@@ -4649,7 +4893,7 @@ function federation(mfUserOptions) {
4649
4893
  if (Object.keys(output.codeSplitting).length === 0) delete output.codeSplitting;
4650
4894
  if (warnedAboutCodeSplittingGroups) return;
4651
4895
  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.");
4896
+ 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
4897
  };
4654
4898
  let warnedAboutManualChunks = false;
4655
4899
  const applyManualChunks = (output) => {
@@ -4657,7 +4901,7 @@ function federation(mfUserOptions) {
4657
4901
  const isPatchedByPlugin = typeof output.manualChunks === "function" && patchedManualChunks.has(output.manualChunks);
4658
4902
  if (output.manualChunks && !isPatchedByPlugin && !warnedAboutManualChunks) {
4659
4903
  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.");
4904
+ 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
4905
  }
4662
4906
  const mfManualChunks = function(id) {
4663
4907
  if (id.includes(runtimeInitId)) return "runtimeInit";
@@ -4735,11 +4979,11 @@ function federation(mfUserOptions) {
4735
4979
  *
4736
4980
  * @see https://rollupjs.org/plugin-development/#synthetic-named-exports
4737
4981
  */
4738
- if (!/\bexport\s+const\s+__moduleExports\b/.test(code)) {
4982
+ if (!/\bexport\s+const\s+__moduleExports\b/.test(code) && !/\bexport\s*\{[^}]*__moduleExports/.test(code)) {
4739
4983
  const nextCode = code.replace("export default exportModule", "export const __moduleExports = exportModule;\nexport default exportModule.__esModule ? exportModule.default : exportModule");
4740
4984
  code = nextCode === code ? `${code}\nexport const __moduleExports = exportModule;\n` : nextCode;
4741
4985
  }
4742
- if (getIsRolldown(this)) return { code };
4986
+ if (require_packageUtils.getIsRolldown(this)) return { code };
4743
4987
  return {
4744
4988
  code,
4745
4989
  syntheticNamedExports: "__moduleExports"
@@ -4793,7 +5037,7 @@ function federation(mfUserOptions) {
4793
5037
  enforce: "post",
4794
5038
  _options: options,
4795
5039
  config(config, { command: _command }) {
4796
- const isRolldown = getIsRolldown(this);
5040
+ const isRolldown = require_packageUtils.getIsRolldown(this);
4797
5041
  let implementation = options.implementation;
4798
5042
  if (isRolldown) implementation = implementation.replace(/\.cjs(\.js)?$/, ".js");
4799
5043
  appendResolveAlias(config, {
@@ -4808,27 +5052,29 @@ function federation(mfUserOptions) {
4808
5052
  config.optimizeDeps.include.push("@module-federation/runtime");
4809
5053
  options.runtimePlugins.forEach((p) => {
4810
5054
  const pluginPath = typeof p === "string" ? p : p[0];
5055
+ if (SSR_ONLY_PLUGINS.has(pluginPath)) return;
4811
5056
  if (pluginPath && !pluginPath.startsWith(".") && !pluginPath.startsWith("/") && !pluginPath.startsWith("\0") && !pluginPath.startsWith("virtual:")) config.optimizeDeps.include.push(pluginPath);
4812
5057
  });
4813
5058
  if (isRolldown) {
4814
5059
  config.build ??= {};
4815
5060
  config.build.target ??= "esnext";
4816
5061
  }
4817
- const isAstro = hasPackageDependency("astro");
5062
+ const isAstro = require_packageUtils.hasPackageDependency("astro");
4818
5063
  const resolvedTarget = options.target ?? (config.build?.ssr ? "node" : "web");
4819
5064
  const envTargetDefineValue = !options.target && isAstro ? "undefined" : JSON.stringify(resolvedTarget);
4820
5065
  if (!config.define) config.define = {};
4821
5066
  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.`);
5067
+ 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
5068
  }
4824
5069
  },
4825
5070
  ...Manifest(),
5071
+ ...pluginSSRRemoteEntry(options),
4826
5072
  ...VarRemoteEntry(),
4827
5073
  {
4828
5074
  name: "module-federation-vinext-fix-rsc-preload-as",
4829
5075
  enforce: "post",
4830
5076
  configureServer(server) {
4831
- if (!hasPackageDependency("vinext")) return;
5077
+ if (!require_packageUtils.hasPackageDependency("vinext")) return;
4832
5078
  server.middlewares.use((req, res, next) => {
4833
5079
  if (!req.headers.accept?.includes("text/html")) {
4834
5080
  next();
@@ -4848,7 +5094,7 @@ function federation(mfUserOptions) {
4848
5094
  });
4849
5095
  },
4850
5096
  generateBundle(_, bundle, _isWrite) {
4851
- if (!hasPackageDependency("vinext")) return;
5097
+ if (!require_packageUtils.hasPackageDependency("vinext")) return;
4852
5098
  for (const chunk of Object.values(bundle)) {
4853
5099
  if (!isOutputChunk(chunk)) continue;
4854
5100
  if (!chunk.code.includes("case\"L\"")) continue;
@@ -4896,5 +5142,9 @@ function federation(mfUserOptions) {
4896
5142
  })()
4897
5143
  ];
4898
5144
  }
5145
+ function createModuleFederationConfig(options) {
5146
+ return options;
5147
+ }
4899
5148
  //#endregion
5149
+ exports.createModuleFederationConfig = createModuleFederationConfig;
4900
5150
  exports.federation = federation;