@module-federation/vite 1.22.1 → 1.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -119,6 +119,9 @@ export default defineConfig({
119
119
  // optional: additional "var" remoteEntry file
120
120
  // needed only for legacy hosts with "var" usage (remote.type = 'var')
121
121
  varFilename: "varRemoteEntry.js",
122
+ // optional: exact name of the SSR remote entry
123
+ // default: "<filename base>.ssr.js" (e.g. remoteEntry.ssr.js)
124
+ ssrFilename: "remoteEntry.ssr.js",
122
125
  exposes: {
123
126
  "./remote-app": "./src/App.vue",
124
127
  },
@@ -151,6 +154,18 @@ shared: {
151
154
 
152
155
  `suppressMissingImportWarning` defaults to `false`. Enable it only when the host is guaranteed to provide the dependency and local named-export detection is unnecessary.
153
156
 
157
+ In a production build, a host-only dependency that the exposed modules reach only through a dynamic `import()` is not fetched while the remote initializes. It is loaded from the host's provider when that `import()` runs, before the imported chunk evaluates. A dependency imported statically by an exposed module, or configured with `eager: true`, is still loaded during initialization.
158
+
159
+ ### Shared dependencies installed in several places
160
+
161
+ An absolute import that resolves inside a different `node_modules` directory than the one the share itself resolves to, for example a workspace package with its own nested copy, is not treated as the shared module by default. Set `allowNodeModulesSuffixMatch: true` on the share to match it by the path after `node_modules/`, as webpack and rspack do with the same option:
162
+
163
+ ```ts
164
+ shared: {
165
+ react: { singleton: true, allowNodeModulesSuffixMatch: true },
166
+ },
167
+ ```
168
+
154
169
  ## The Host Application configuration
155
170
 
156
171
  file **host/vite.config.ts**
@@ -263,6 +278,8 @@ federation({
263
278
 
264
279
  The `"vm"` strategy requires Node.js to run with `--experimental-vm-modules`. When unavailable, the loader warns once and falls back to `"temp-file"`. Vite 8 development uses `ModuleRunner`; this option primarily affects build and preview SSR entry loading.
265
280
 
281
+ The SSR remote entry is emitted as `<filename base>.ssr.js` next to the browser entry, or under the exact name given by `ssrFilename`, and is advertised as `metaData.ssrRemoteEntry` in `mf-manifest.json`. It keeps `@module-federation/runtime`, `@module-federation/runtime-core` and `@module-federation/sdk` external by default so Node resolves them from the host. Hosts that cannot resolve those packages, such as a plain `@module-federation/enhanced` host using the SDK's reference Node loader, need a self-contained entry: opt the packages back in with Vite's `ssr.noExternal` (for example `ssr: { noExternal: true }`) on the remote.
282
+
266
283
  ## Runtime capability optimization
267
284
 
268
285
  Runtime features that a build never uses can be removed at build time:
@@ -391,6 +408,8 @@ Do not set `build.rollupOptions.output.codeSplitting` or
391
408
  `build.rolldownOptions.output.codeSplitting` to `false` — it will be **ignored** (with a warning).
392
409
  Module Federation requires chunk splitting so `runtimeInitStatus` and deferred `loadShare` wrappers stay isolated for correct bootstrap order. Eager `loadShare` wrappers are coalesced into one `loadShare-eager` chunk to reduce startup requests, on both Rolldown (Vite 8+) and Rollup (Vite 5–7).
393
410
 
411
+ Non-eager `loadShare` wrappers that reach their local `__prebuild__` fallback only through `import()` are merged into one `__loadShare__shared` chunk per `federation()` instance, with the shared-cache helpers included once. A wrapper that statically imports its local payload keeps its own chunk, since merging it could close a top-level-await cycle. `__prebuild__` fallbacks stay in separate lazily imported chunks, so a consumer never downloads its local copy when a peer already provides the share. The plugin warns at build time if a fallback ends up inside the merged chunk.
412
+
394
413
  ### `codeSplitting.groups` (Vite 8+ / Rolldown)
395
414
 
396
415
  User groups are now **preserved**. The plugin installs its own federation groups at the highest priority and appends your groups below them, so your groups can only claim modules the federation groups didn't.
@@ -1,39 +1,32 @@
1
- import { l as getNodeModulesSuffix } from "./sharedKeyMatcher-BRzBCbuR.js";
2
- import { existsSync, readFileSync, readdirSync } from "fs";
1
+ import { d as getNodeModulesSuffix, r as getSharedRuntimeKey } from "./sharedKeyMatcher-Od_nYxJA.js";
2
+ import { r as mfWarn, t as createModuleFederationError } from "./logger--uKHOVjR.js";
3
+ import { existsSync, readFileSync, readdirSync, realpathSync } from "fs";
3
4
  import { createRequire } from "module";
4
5
  import * as path$1 from "node:path";
5
6
  import { fileURLToPath, pathToFileURL } from "url";
6
7
  import { createHash } from "node:crypto";
7
- //#region src/utils/logger.ts
8
- const MODULE_FEDERATION_LOG_PREFIX = "[Module Federation]";
9
- function formatModuleFederationMessage(message) {
10
- return `${MODULE_FEDERATION_LOG_PREFIX} ${message}`;
11
- }
12
- function createModuleFederationError(message) {
13
- return new Error(formatModuleFederationMessage(message));
14
- }
15
- function toConsoleArgs(message, rest = []) {
16
- if (typeof message === "string") return [formatModuleFederationMessage(message), ...rest];
17
- if (message === void 0) return [MODULE_FEDERATION_LOG_PREFIX, ...rest];
18
- return [
19
- MODULE_FEDERATION_LOG_PREFIX,
20
- message,
21
- ...rest
22
- ];
23
- }
24
- const moduleFederationConsole = {
25
- log(message, ...rest) {
26
- console.log(...toConsoleArgs(message, rest));
27
- },
28
- warn(message, ...rest) {
29
- console.warn(...toConsoleArgs(message, rest));
30
- },
31
- error(message, ...rest) {
32
- console.error(...toConsoleArgs(message, rest));
33
- }
34
- };
35
- const mfWarn = moduleFederationConsole.warn;
36
- const mfError = moduleFederationConsole.error;
8
+ //#region src/utils/reactShares.ts
9
+ /** Property under which React 19 exposes its internals object. */
10
+ const REACT_CLIENT_INTERNALS_KEY = "__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE";
11
+ /**
12
+ * Every property React has used for its internals object, newest first. Two
13
+ * module objects that expose the same internals are the same React instance.
14
+ */
15
+ const REACT_INTERNALS_KEYS = [
16
+ REACT_CLIENT_INTERNALS_KEY,
17
+ "__TEST_INTERNALS",
18
+ "__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED"
19
+ ];
20
+ /**
21
+ * Importing this share's local fallback registers a DOM renderer as a side
22
+ * effect. An entry-injected leaf must not evaluate its own copy while the host
23
+ * renderer already owns the root, so its wrapper waits for the cache or init.
24
+ */
25
+ const REACT_DOM_CLIENT_SHARE = "react-dom/client";
26
+ /** React and its subpath exports must bind synchronously for CJS consumers. */
27
+ function isReactCoreShare(pkg) {
28
+ return pkg === "react" || pkg.startsWith("react/");
29
+ }
37
30
  //#endregion
38
31
  //#region src/utils/packageUtils.ts
39
32
  const dependencyPresenceCache = /* @__PURE__ */ new Map();
@@ -42,6 +35,7 @@ function getDependencyCacheKey(cwd, dependencyName) {
42
35
  return `${cwd}:${dependencyName}`;
43
36
  }
44
37
  const installedPackageJsonCache = /* @__PURE__ */ new Map();
38
+ const dependentsLookupCache = /* @__PURE__ */ new Map();
45
39
  function setPackageDetectionCwd(cwd) {
46
40
  packageDetectionCwd = cwd;
47
41
  }
@@ -213,7 +207,7 @@ function getSharedCacheKeyParts(input) {
213
207
  }
214
208
  function getSharedCacheDescriptor(pkg, shareItem) {
215
209
  const parts = getSharedCacheKeyParts({
216
- pkg,
210
+ pkg: shareItem.shareConfig.request !== void 0 || shareItem.shareConfig.shareKey !== void 0 ? getSharedRuntimeKey(pkg, shareItem) : pkg,
217
211
  singleton: shareItem.shareConfig.singleton,
218
212
  version: shareItem.version,
219
213
  scope: shareItem.scope
@@ -279,7 +273,47 @@ const sharedCacheHelperCode = `const __mfGetSharedCacheDescriptor = (pkg, single
279
273
  };
280
274
  const __mfReadSharedCacheOwner = (cache, descriptor) =>
281
275
  cache[__mfSharedCacheOwnersKey]?.[descriptor.canonical];
276
+ const __mfGetSharedModuleIdentity = (value) => {
277
+ const candidates = [value, value?.default];
278
+ for (const candidate of candidates) {
279
+ if (!candidate || typeof candidate !== "object") continue;
280
+ for (const key of ${JSON.stringify(REACT_INTERNALS_KEYS)}) {
281
+ const internals = candidate[key];
282
+ if (internals && typeof internals === "object") {
283
+ return { internals };
284
+ }
285
+ }
286
+ if (typeof candidate.useState === "function") return { hook: candidate.useState };
287
+ }
288
+ return undefined;
289
+ };
290
+ const __mfIsSameSharedModule = (current, next) => {
291
+ if (current === next) return true;
292
+ const currentIdentity = __mfGetSharedModuleIdentity(current);
293
+ const nextIdentity = __mfGetSharedModuleIdentity(next);
294
+ if (!currentIdentity || !nextIdentity) return false;
295
+ const currentInternals = currentIdentity.internals;
296
+ const nextInternals = nextIdentity.internals;
297
+ // Internals identity is authoritative when either side exposes it.
298
+ // Never treat absent fields as equal (undefined === undefined).
299
+ if (currentInternals !== undefined || nextInternals !== undefined) {
300
+ return (
301
+ currentInternals !== undefined &&
302
+ currentInternals === nextInternals
303
+ );
304
+ }
305
+ // Hook identity is only a fallback when neither side exposes internals.
306
+ return (
307
+ typeof currentIdentity.hook === "function" &&
308
+ currentIdentity.hook === nextIdentity.hook
309
+ );
310
+ };
282
311
  const __mfWriteSharedCache = (cache, descriptor, value, owner) => {
312
+ // Rewriting the same instance is a no-op on purpose: the first
313
+ // provider keeps ownership and subscribers are not re-notified, so
314
+ // an already-bound renderer never sees its React rebound.
315
+ const current = __mfReadSharedCache(cache, descriptor);
316
+ if (current !== undefined && __mfIsSameSharedModule(current, value)) return value;
283
317
  cache[descriptor.canonical] = value;
284
318
  const aliases = descriptor.aliases || [];
285
319
  for (const alias of aliases) {
@@ -378,85 +412,181 @@ function getInstalledPackageJson(pkg, opts) {
378
412
  installedPackageJsonCache.set(cacheKey, result);
379
413
  return result;
380
414
  }
415
+ function tryReadPackageJson(packageJsonPath, expectedName) {
416
+ if (!existsSync(packageJsonPath)) return void 0;
417
+ try {
418
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
419
+ if (expectedName !== void 0 && packageJson.name !== expectedName) return void 0;
420
+ return {
421
+ path: packageJsonPath,
422
+ dir: path$1.dirname(packageJsonPath),
423
+ packageJson
424
+ };
425
+ } catch {
426
+ return;
427
+ }
428
+ }
381
429
  function resolveInstalledPackageJson(pkg, cwd, packageName, opts) {
382
- const tryReadPackageJson = (packageJsonPath) => {
383
- if (!existsSync(packageJsonPath)) return void 0;
384
- try {
385
- return {
386
- path: packageJsonPath,
387
- dir: path$1.dirname(packageJsonPath),
388
- packageJson: JSON.parse(readFileSync(packageJsonPath, "utf-8"))
389
- };
390
- } catch {
391
- return;
392
- }
393
- };
394
430
  const findPackageInPnpmStore = (startDir) => {
395
- let currentDir = startDir;
396
- while (true) {
397
- const pnpmStoreDir = path$1.join(currentDir, "node_modules", ".pnpm");
398
- if (existsSync(pnpmStoreDir)) try {
431
+ for (const dir of ancestorDirs(startDir)) {
432
+ const pnpmStoreDir = path$1.join(dir, "node_modules", ".pnpm");
433
+ if (!existsSync(pnpmStoreDir)) continue;
434
+ try {
399
435
  for (const entry of readdirSync(pnpmStoreDir, { withFileTypes: true })) {
400
436
  if (!entry.isDirectory()) continue;
401
437
  const candidate = tryReadPackageJson(path$1.join(pnpmStoreDir, entry.name, "node_modules", packageName, "package.json"));
402
438
  if (candidate?.packageJson.name === packageName) return candidate;
403
439
  }
404
440
  } catch {}
405
- const parentDir = path$1.dirname(currentDir);
406
- if (parentDir === currentDir) break;
407
- currentDir = parentDir;
408
441
  }
409
442
  };
410
443
  let resolvedPath;
411
444
  try {
412
- const projectRequire = createRequire(pathToFileURL(path$1.join(cwd, "package.json")));
445
+ const rootPackageJson = path$1.join(cwd, "package.json");
413
446
  if (opts?.fromResolvedEntry) resolvedPath = opts.fromResolvedEntry;
414
447
  else try {
415
- resolvedPath = projectRequire.resolve(pkg);
448
+ resolvedPath = resolveModulePath(pkg, rootPackageJson);
416
449
  } catch {
417
- resolvedPath = projectRequire.resolve(packageName);
450
+ resolvedPath = resolveModulePath(packageName, rootPackageJson);
418
451
  }
419
452
  } catch {
420
453
  resolvedPath = void 0;
421
454
  }
422
455
  if (resolvedPath !== void 0 && !path$1.isAbsolute(resolvedPath)) resolvedPath = void 0;
423
- if (resolvedPath !== void 0) try {
424
- let currentDir = path$1.dirname(resolvedPath);
425
- let matchingPackage;
426
- while (true) {
427
- const packageJsonPath = path$1.join(currentDir, "package.json");
428
- if (existsSync(packageJsonPath)) {
429
- const packageJsonContent = readFileSync(packageJsonPath, "utf-8");
430
- try {
431
- const packageJson = JSON.parse(packageJsonContent);
432
- if (packageJson.name === packageName) {
433
- const packageInfo = {
434
- path: packageJsonPath,
435
- dir: currentDir,
436
- packageJson
437
- };
438
- if (currentDir.endsWith(path$1.join("node_modules", packageName))) return packageInfo;
439
- matchingPackage ??= packageInfo;
440
- }
441
- } catch (error) {
442
- if (!(error instanceof SyntaxError)) throw error;
456
+ if (resolvedPath !== void 0) {
457
+ const owner = findOwningPackageJson(path$1.dirname(resolvedPath), packageName);
458
+ if (owner) return owner;
459
+ }
460
+ for (const dir of ancestorDirs(cwd)) {
461
+ const directCandidate = tryReadPackageJson(path$1.join(dir, "node_modules", packageName, "package.json"), packageName);
462
+ if (directCandidate) return directCandidate;
463
+ }
464
+ return findPackageInDependents(packageName, cwd) ?? findPackageInPnpmStore(cwd);
465
+ }
466
+ /**
467
+ * A package installed only under a dependent is invisible to the walks above.
468
+ * Resolving it from each dependent in turn follows the same links that dependent
469
+ * does, so the copy found is the version it is installed against rather than
470
+ * whichever one the pnpm store happens to list first.
471
+ */
472
+ function findPackageInDependents(packageName, cwd) {
473
+ const cacheKey = `${cwd}\0${packageName}`;
474
+ if (!dependentsLookupCache.has(cacheKey)) dependentsLookupCache.set(cacheKey, walkDependents(packageName, cwd));
475
+ return dependentsLookupCache.get(cacheKey);
476
+ }
477
+ function walkDependents(packageName, cwd) {
478
+ const root = tryReadPackageJson(path$1.join(cwd, "package.json"));
479
+ if (!root) return void 0;
480
+ const visited = /* @__PURE__ */ new Set();
481
+ const rootDependencyGroups = [getDependencyNames(root.packageJson), getDependencyNames(root.packageJson, ["devDependencies"])];
482
+ for (const rootDependencies of rootDependencyGroups) {
483
+ let level = rootDependencies.map((name) => ({
484
+ name,
485
+ fromDir: cwd
486
+ }));
487
+ while (level.length) {
488
+ const candidates = [];
489
+ const nextLevel = [];
490
+ for (const { name, fromDir } of level) {
491
+ if (name === packageName) continue;
492
+ const dependent = findPackageFrom(name, fromDir);
493
+ if (!dependent || visited.has(dependent.dir)) continue;
494
+ visited.add(dependent.dir);
495
+ const dependencies = getDependencyNames(dependent.packageJson);
496
+ if (dependencies.includes(packageName)) {
497
+ const copy = findPackageFrom(packageName, dependent.dir);
498
+ if (copy) candidates.push({
499
+ copy,
500
+ via: name
501
+ });
443
502
  }
503
+ for (const dependency of dependencies) nextLevel.push({
504
+ name: dependency,
505
+ fromDir: dependent.dir
506
+ });
444
507
  }
445
- const parentDir = path$1.dirname(currentDir);
446
- if (parentDir === currentDir) break;
447
- currentDir = parentDir;
508
+ if (candidates.length) {
509
+ warnOnAmbiguousDependents(packageName, candidates);
510
+ return candidates[0].copy;
511
+ }
512
+ level = nextLevel;
448
513
  }
449
- return matchingPackage;
450
- } catch {}
451
- let currentDir = cwd;
514
+ }
515
+ }
516
+ function warnOnAmbiguousDependents(packageName, candidates) {
517
+ const viaByVersion = /* @__PURE__ */ new Map();
518
+ for (const { copy, via } of candidates) if (!viaByVersion.has(copy.packageJson.version)) viaByVersion.set(copy.packageJson.version, via);
519
+ if (viaByVersion.size < 2) return;
520
+ const versions = [...viaByVersion].map(([version, via]) => `${version} (via ${via})`);
521
+ mfWarn(`Shared package "${packageName}" is not a dependency of the project, and its closest dependents install different versions: ${versions.join(", ")}. The fallback uses ${versions[0]}. Add "${packageName}" to the project's dependencies or set its shared "import" to choose the version.`);
522
+ }
523
+ /** The package Node's `node_modules` lookup finds from `fromDir`, read at its real path. */
524
+ function findPackageFrom(packageName, fromDir) {
525
+ const entry = findNodeModulesEntry(packageName, fromDir);
526
+ if (!entry) return void 0;
527
+ try {
528
+ return tryReadPackageJson(path$1.join(realpathSync(entry), "package.json"), packageName);
529
+ } catch {
530
+ return;
531
+ }
532
+ }
533
+ /**
534
+ * Walks up from `startDir` to the package.json named `packageName`, preferring the
535
+ * one at `node_modules/<packageName>` so a nested `package.json` (for example a
536
+ * subpath's `type: module` marker) does not shadow the package root.
537
+ */
538
+ function findOwningPackageJson(startDir, packageName) {
539
+ let matchingPackage;
540
+ for (const dir of ancestorDirs(startDir)) {
541
+ const candidate = tryReadPackageJson(path$1.join(dir, "package.json"), packageName);
542
+ if (!candidate) continue;
543
+ if (dir.endsWith(path$1.join("node_modules", packageName))) return candidate;
544
+ matchingPackage ??= candidate;
545
+ }
546
+ return matchingPackage;
547
+ }
548
+ function* ancestorDirs(startDir) {
549
+ let dir = startDir;
452
550
  while (true) {
453
- const directCandidate = tryReadPackageJson(path$1.join(currentDir, "node_modules", packageName, "package.json"));
454
- if (directCandidate?.packageJson.name === packageName) return directCandidate;
455
- const parentDir = path$1.dirname(currentDir);
456
- if (parentDir === currentDir) break;
457
- currentDir = parentDir;
551
+ yield dir;
552
+ const parentDir = path$1.dirname(dir);
553
+ if (parentDir === dir) return;
554
+ dir = parentDir;
458
555
  }
459
- return findPackageInPnpmStore(cwd);
556
+ }
557
+ /** The first `node_modules/<packageName>` that Node's lookup reaches from `fromDir`. */
558
+ function findNodeModulesEntry(packageName, fromDir) {
559
+ for (const dir of ancestorDirs(fromDir)) {
560
+ const entry = path$1.join(dir, "node_modules", packageName);
561
+ if (existsSync(entry)) return entry;
562
+ }
563
+ }
564
+ /**
565
+ * `require.resolve(specifier)` from the file `from`, limited to the `node_modules` lookup
566
+ * bundlers perform. Node also searches NODE_PATH, which pnpm's bin shims point at the
567
+ * store's hoisted `node_modules`, so it can find packages the bundler cannot.
568
+ */
569
+ function resolveModulePath(specifier, from) {
570
+ const resolved = createRequire(pathToFileURL(from)).resolve(specifier);
571
+ if (!path$1.isAbsolute(resolved) || specifier.startsWith(".") || path$1.isAbsolute(specifier) || process.versions.pnp) return resolved;
572
+ if (findNodeModulesEntry(getPackageName(specifier), path$1.dirname(from))) return resolved;
573
+ const error = /* @__PURE__ */ new Error(`Cannot find module '${specifier}' from '${from}'`);
574
+ error.code = "MODULE_NOT_FOUND";
575
+ throw error;
576
+ }
577
+ function getDependencyNames(packageJson, fields = [
578
+ "dependencies",
579
+ "peerDependencies",
580
+ "optionalDependencies"
581
+ ]) {
582
+ if (!packageJson) return [];
583
+ const names = /* @__PURE__ */ new Set();
584
+ for (const field of fields) {
585
+ const deps = packageJson[field];
586
+ if (!deps || typeof deps !== "object") continue;
587
+ for (const dep of Object.keys(deps)) names.add(dep);
588
+ }
589
+ return [...names];
460
590
  }
461
591
  function getInstalledPackageEntry(pkg, opts) {
462
592
  const installed = getInstalledPackageJson(pkg, opts);
@@ -465,7 +595,7 @@ function getInstalledPackageEntry(pkg, opts) {
465
595
  const packageName = opts?.packageName || getPackageName(pkg);
466
596
  const packageJson = installed.packageJson;
467
597
  if (pkg !== packageName && (opts?.resolveSubpathWithRequire !== false || packageJson.exports === void 0)) try {
468
- return createRequire(pathToFileURL(path$1.join(cwd, "package.json"))).resolve(pkg);
598
+ return resolveModulePath(pkg, path$1.join(cwd, "package.json"));
469
599
  } catch {}
470
600
  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";
471
601
  return path$1.join(installed.dir, explicitEntry);
@@ -479,6 +609,18 @@ function getIsRolldown(ctx) {
479
609
  const viteMajor = Number(String(viteVersion ?? "").split(".")[0]);
480
610
  return Number.isFinite(viteMajor) && viteMajor >= 8 || !!ctx?.meta?.rolldownVersion;
481
611
  }
612
+ /**
613
+ * Rolldown 1.2.10 added `codeSplitting.groups[].debugName` and warns when a group's
614
+ * `name` is a function without one. Older versions reject it as an unknown option.
615
+ */
616
+ function supportsCodeSplittingGroupDebugName(ctx) {
617
+ const rolldownVersion = ctx?.meta?.rolldownVersion;
618
+ if (typeof rolldownVersion !== "string") return false;
619
+ const [major = 0, minor = 0, patch = 0] = rolldownVersion.split(/[.+-]/, 3).map((part) => parseInt(part, 10) || 0);
620
+ if (major !== 1) return major > 1;
621
+ if (minor !== 2) return minor > 2;
622
+ return patch >= 10;
623
+ }
482
624
  /** Walk up from Vite `config.root` (Nuxt may point at `.nuxt` cache dirs). */
483
625
  function isNuxtProjectRoot(root) {
484
626
  let dir = root;
@@ -513,4 +655,4 @@ function hasPackageDependency(dependencyName, cwd = packageDetectionCwd || proce
513
655
  //#region src/utils/dtsConstants.ts
514
656
  const DEFAULT_PUBLIC_TYPES_FOLDER = "@mf-types";
515
657
  //#endregion
516
- export { sharedCacheHelperCode as _, getPackageDetectionCwd as a, mfWarn as b, getSharedCacheDescriptor as c, isPackageExportAvailable as d, isPackageInstalled as f, setPackageDetectionCwd as g, resolveImportPath as h, getIsRolldown as i, hasPackageDependency as l, packageNameEncode as m, getInstalledPackageEntry as n, getPackageName as o, packageNameDecode as p, getInstalledPackageJson as r, getPackageNameFromNodeModulePath as s, DEFAULT_PUBLIC_TYPES_FOLDER as t, isNuxtProjectRoot as u, createModuleFederationError as v, mfError as y };
658
+ export { isReactCoreShare as C, REACT_DOM_CLIENT_SHARE as S, resolveModulePath as _, getIsRolldown as a, supportsCodeSplittingGroupDebugName as b, getPackageNameFromNodeModulePath as c, isNuxtProjectRoot as d, isPackageExportAvailable as f, resolveImportPath as g, packageNameEncode as h, getInstalledPackageJson as i, getSharedCacheDescriptor as l, packageNameDecode as m, getDependencyNames as n, getPackageDetectionCwd as o, isPackageInstalled as p, getInstalledPackageEntry as r, getPackageName as s, DEFAULT_PUBLIC_TYPES_FOLDER as t, hasPackageDependency as u, setPackageDetectionCwd as v, REACT_CLIENT_INTERNALS_KEY as x, sharedCacheHelperCode as y };
package/lib/index.d.ts CHANGED
@@ -31,6 +31,12 @@ type ModuleFederationOptions = {
31
31
  import: string;
32
32
  }> | undefined;
33
33
  filename?: string;
34
+ /**
35
+ * Exact file name of the SSR remote entry emitted next to `filename`.
36
+ * Defaults to `<filename base>.ssr<ext>` so it never clobbers the browser
37
+ * entry when both builds share an output directory. `[hash]` is not supported.
38
+ */
39
+ ssrFilename?: string;
34
40
  library?: any;
35
41
  name: string;
36
42
  remotes?: Record<string, string | RemoteObjectConfig> | undefined;
@@ -57,10 +63,13 @@ type ModuleFederationOptions = {
57
63
  name?: string;
58
64
  version?: string;
59
65
  shareScope?: string;
66
+ request?: moduleFederationPlugin.SharedConfig['request'];
67
+ shareKey?: moduleFederationPlugin.SharedConfig['shareKey'];
60
68
  singleton?: boolean;
61
69
  eager?: boolean;
62
70
  requiredVersion?: moduleFederationPlugin.SharedConfig['requiredVersion'];
63
71
  strictVersion?: boolean;
72
+ allowNodeModulesSuffixMatch?: boolean;
64
73
  /** Suppress the missing local dependency warning for `import: false` shares. */
65
74
  suppressMissingImportWarning?: boolean;
66
75
  treeShaking?: TreeShakingConfig;
@@ -122,8 +131,11 @@ type ModuleFederationOptions = {
122
131
  disableSnapshot?: boolean;
123
132
  /**
124
133
  * Additional packages to mark as external in the SSR remote entry build.
125
- * Shared packages and MF runtime packages are always external. Use this to
134
+ * Shared packages and MF runtime packages are external by default. Use this to
126
135
  * add any other Node-only packages that should not be bundled into the SSR entry.
136
+ * To emit a self-contained SSR entry (loadable by hosts that cannot resolve the
137
+ * MF runtime from Node, such as the `@module-federation/sdk` reference loader),
138
+ * opt the MF runtime packages back in through Vite's `ssr.noExternal`.
127
139
  */
128
140
  ssrExternals?: string[];
129
141
  /**
@@ -230,6 +242,7 @@ interface DtsRemoteOptions {
230
242
  extractRemoteTypes?: boolean;
231
243
  abortOnError?: boolean;
232
244
  deleteTsConfig?: boolean;
245
+ afterGenerate?: (options: moduleFederationPlugin.DtsGenerateTypesHookOptions) => Promise<void> | void;
233
246
  }
234
247
  interface DtsHostOptions {
235
248
  typesFolder?: string;