@module-federation/vite 1.15.5 → 1.16.1

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