@module-federation/vite 1.22.0 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -1
- package/lib/{dtsConstants-BEGrtvcw.js → dtsConstants-DEMpRfBz.js} +248 -62
- package/lib/index.d.ts +14 -1
- package/lib/index.js +1689 -721
- package/lib/{pluginDts-D7Faa4NJ.js → pluginDts-VSLhAx6d.js} +1 -1
- package/lib/{sharedKeyMatcher-DiUzRVH1.js → sharedKeyMatcher-Od_nYxJA.js} +57 -34
- package/lib/{ssrEntryLoader-CMVCDSsG.js → ssrEntryLoader-BvAkpCyi.js} +1 -1
- package/lib/{ssrVmStrategy-Cx9WlTsx.js → ssrVmStrategy-CDbcwMnf.js} +2 -2
- package/lib/utils/ssrEntryLoader.js +1 -1
- package/package.json +4 -4
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:
|
|
@@ -389,7 +406,9 @@ The `externalRuntime` rewrite applies to the browser remote graph; SSR remote en
|
|
|
389
406
|
|
|
390
407
|
Do not set `build.rollupOptions.output.codeSplitting` or
|
|
391
408
|
`build.rolldownOptions.output.codeSplitting` to `false` — it will be **ignored** (with a warning).
|
|
392
|
-
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 on Vite 8+
|
|
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).
|
|
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.
|
|
393
412
|
|
|
394
413
|
### `codeSplitting.groups` (Vite 8+ / Rolldown)
|
|
395
414
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as getNodeModulesSuffix, r as getSharedRuntimeKey } from "./sharedKeyMatcher-Od_nYxJA.js";
|
|
2
|
+
import { existsSync, readFileSync, readdirSync, realpathSync } from "fs";
|
|
2
3
|
import { createRequire } from "module";
|
|
3
4
|
import * as path$1 from "node:path";
|
|
4
5
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
@@ -34,6 +35,29 @@ const moduleFederationConsole = {
|
|
|
34
35
|
const mfWarn = moduleFederationConsole.warn;
|
|
35
36
|
const mfError = moduleFederationConsole.error;
|
|
36
37
|
//#endregion
|
|
38
|
+
//#region src/utils/reactShares.ts
|
|
39
|
+
/** Property under which React 19 exposes its internals object. */
|
|
40
|
+
const REACT_CLIENT_INTERNALS_KEY = "__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE";
|
|
41
|
+
/**
|
|
42
|
+
* Every property React has used for its internals object, newest first. Two
|
|
43
|
+
* module objects that expose the same internals are the same React instance.
|
|
44
|
+
*/
|
|
45
|
+
const REACT_INTERNALS_KEYS = [
|
|
46
|
+
REACT_CLIENT_INTERNALS_KEY,
|
|
47
|
+
"__TEST_INTERNALS",
|
|
48
|
+
"__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED"
|
|
49
|
+
];
|
|
50
|
+
/**
|
|
51
|
+
* Importing this share's local fallback registers a DOM renderer as a side
|
|
52
|
+
* effect. An entry-injected leaf must not evaluate its own copy while the host
|
|
53
|
+
* renderer already owns the root, so its wrapper waits for the cache or init.
|
|
54
|
+
*/
|
|
55
|
+
const REACT_DOM_CLIENT_SHARE = "react-dom/client";
|
|
56
|
+
/** React and its subpath exports must bind synchronously for CJS consumers. */
|
|
57
|
+
function isReactCoreShare(pkg) {
|
|
58
|
+
return pkg === "react" || pkg.startsWith("react/");
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
37
61
|
//#region src/utils/packageUtils.ts
|
|
38
62
|
const dependencyPresenceCache = /* @__PURE__ */ new Map();
|
|
39
63
|
let packageDetectionCwd;
|
|
@@ -41,6 +65,7 @@ function getDependencyCacheKey(cwd, dependencyName) {
|
|
|
41
65
|
return `${cwd}:${dependencyName}`;
|
|
42
66
|
}
|
|
43
67
|
const installedPackageJsonCache = /* @__PURE__ */ new Map();
|
|
68
|
+
const dependentsLookupCache = /* @__PURE__ */ new Map();
|
|
44
69
|
function setPackageDetectionCwd(cwd) {
|
|
45
70
|
packageDetectionCwd = cwd;
|
|
46
71
|
}
|
|
@@ -129,6 +154,20 @@ function getPackageExportsTarget(pkg, packageName, exportsField) {
|
|
|
129
154
|
if (subpath !== ".") return matchExportsSubpath(record, subpath);
|
|
130
155
|
return record["."] ?? (!Object.keys(record).some((key) => key.startsWith(".")) ? record : void 0);
|
|
131
156
|
}
|
|
157
|
+
/** Whether `pkg` can be located from `opts.cwd` (or the detection cwd). Aliased or non-hoisted packages may still resolve through Vite. */
|
|
158
|
+
function isPackageInstalled(pkg, opts = {}) {
|
|
159
|
+
return getInstalledPackageJson(getPackageName(pkg), opts) !== void 0;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Whether the installed package's `exports` field permits `pkg`. Lenient when the package cannot
|
|
163
|
+
* be found or has no `exports`: callers that need a hard "is installed" gate use `isPackageInstalled`.
|
|
164
|
+
*/
|
|
165
|
+
function isPackageExportAvailable(pkg, opts = {}) {
|
|
166
|
+
const packageName = getPackageName(pkg);
|
|
167
|
+
const installed = getInstalledPackageJson(packageName, opts);
|
|
168
|
+
if (installed?.packageJson.exports == null) return true;
|
|
169
|
+
return resolveExportsEntry(getPackageExportsTarget(pkg, packageName, installed.packageJson.exports), opts.conditions) !== void 0;
|
|
170
|
+
}
|
|
132
171
|
/**
|
|
133
172
|
* Escaping rules:
|
|
134
173
|
* Convert using the format __${mapping}__, where _ and $ are not allowed in npm package names but can be used in variable names.
|
|
@@ -180,10 +219,9 @@ function getPackageName(packageString) {
|
|
|
180
219
|
return match ? match[0] : packageString;
|
|
181
220
|
}
|
|
182
221
|
function getPackageNameFromNodeModulePath(source) {
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const parts = normalized.slice(nodeModulesIndex + 14).split("/");
|
|
222
|
+
const suffix = getNodeModulesSuffix(source);
|
|
223
|
+
if (!suffix) return;
|
|
224
|
+
const parts = suffix.split("/");
|
|
187
225
|
if (!parts[0]) return;
|
|
188
226
|
if (parts[0].startsWith("@")) return parts[1] ? `${parts[0]}/${parts[1]}` : void 0;
|
|
189
227
|
return parts[0];
|
|
@@ -199,7 +237,7 @@ function getSharedCacheKeyParts(input) {
|
|
|
199
237
|
}
|
|
200
238
|
function getSharedCacheDescriptor(pkg, shareItem) {
|
|
201
239
|
const parts = getSharedCacheKeyParts({
|
|
202
|
-
pkg,
|
|
240
|
+
pkg: shareItem.shareConfig.request !== void 0 || shareItem.shareConfig.shareKey !== void 0 ? getSharedRuntimeKey(pkg, shareItem) : pkg,
|
|
203
241
|
singleton: shareItem.shareConfig.singleton,
|
|
204
242
|
version: shareItem.version,
|
|
205
243
|
scope: shareItem.scope
|
|
@@ -265,7 +303,47 @@ const sharedCacheHelperCode = `const __mfGetSharedCacheDescriptor = (pkg, single
|
|
|
265
303
|
};
|
|
266
304
|
const __mfReadSharedCacheOwner = (cache, descriptor) =>
|
|
267
305
|
cache[__mfSharedCacheOwnersKey]?.[descriptor.canonical];
|
|
306
|
+
const __mfGetSharedModuleIdentity = (value) => {
|
|
307
|
+
const candidates = [value, value?.default];
|
|
308
|
+
for (const candidate of candidates) {
|
|
309
|
+
if (!candidate || typeof candidate !== "object") continue;
|
|
310
|
+
for (const key of ${JSON.stringify(REACT_INTERNALS_KEYS)}) {
|
|
311
|
+
const internals = candidate[key];
|
|
312
|
+
if (internals && typeof internals === "object") {
|
|
313
|
+
return { internals };
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (typeof candidate.useState === "function") return { hook: candidate.useState };
|
|
317
|
+
}
|
|
318
|
+
return undefined;
|
|
319
|
+
};
|
|
320
|
+
const __mfIsSameSharedModule = (current, next) => {
|
|
321
|
+
if (current === next) return true;
|
|
322
|
+
const currentIdentity = __mfGetSharedModuleIdentity(current);
|
|
323
|
+
const nextIdentity = __mfGetSharedModuleIdentity(next);
|
|
324
|
+
if (!currentIdentity || !nextIdentity) return false;
|
|
325
|
+
const currentInternals = currentIdentity.internals;
|
|
326
|
+
const nextInternals = nextIdentity.internals;
|
|
327
|
+
// Internals identity is authoritative when either side exposes it.
|
|
328
|
+
// Never treat absent fields as equal (undefined === undefined).
|
|
329
|
+
if (currentInternals !== undefined || nextInternals !== undefined) {
|
|
330
|
+
return (
|
|
331
|
+
currentInternals !== undefined &&
|
|
332
|
+
currentInternals === nextInternals
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
// Hook identity is only a fallback when neither side exposes internals.
|
|
336
|
+
return (
|
|
337
|
+
typeof currentIdentity.hook === "function" &&
|
|
338
|
+
currentIdentity.hook === nextIdentity.hook
|
|
339
|
+
);
|
|
340
|
+
};
|
|
268
341
|
const __mfWriteSharedCache = (cache, descriptor, value, owner) => {
|
|
342
|
+
// Rewriting the same instance is a no-op on purpose: the first
|
|
343
|
+
// provider keeps ownership and subscribers are not re-notified, so
|
|
344
|
+
// an already-bound renderer never sees its React rebound.
|
|
345
|
+
const current = __mfReadSharedCache(cache, descriptor);
|
|
346
|
+
if (current !== undefined && __mfIsSameSharedModule(current, value)) return value;
|
|
269
347
|
cache[descriptor.canonical] = value;
|
|
270
348
|
const aliases = descriptor.aliases || [];
|
|
271
349
|
for (const alias of aliases) {
|
|
@@ -364,85 +442,181 @@ function getInstalledPackageJson(pkg, opts) {
|
|
|
364
442
|
installedPackageJsonCache.set(cacheKey, result);
|
|
365
443
|
return result;
|
|
366
444
|
}
|
|
445
|
+
function tryReadPackageJson(packageJsonPath, expectedName) {
|
|
446
|
+
if (!existsSync(packageJsonPath)) return void 0;
|
|
447
|
+
try {
|
|
448
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
449
|
+
if (expectedName !== void 0 && packageJson.name !== expectedName) return void 0;
|
|
450
|
+
return {
|
|
451
|
+
path: packageJsonPath,
|
|
452
|
+
dir: path$1.dirname(packageJsonPath),
|
|
453
|
+
packageJson
|
|
454
|
+
};
|
|
455
|
+
} catch {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
367
459
|
function resolveInstalledPackageJson(pkg, cwd, packageName, opts) {
|
|
368
|
-
const tryReadPackageJson = (packageJsonPath) => {
|
|
369
|
-
if (!existsSync(packageJsonPath)) return void 0;
|
|
370
|
-
try {
|
|
371
|
-
return {
|
|
372
|
-
path: packageJsonPath,
|
|
373
|
-
dir: path$1.dirname(packageJsonPath),
|
|
374
|
-
packageJson: JSON.parse(readFileSync(packageJsonPath, "utf-8"))
|
|
375
|
-
};
|
|
376
|
-
} catch {
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
460
|
const findPackageInPnpmStore = (startDir) => {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
461
|
+
for (const dir of ancestorDirs(startDir)) {
|
|
462
|
+
const pnpmStoreDir = path$1.join(dir, "node_modules", ".pnpm");
|
|
463
|
+
if (!existsSync(pnpmStoreDir)) continue;
|
|
464
|
+
try {
|
|
385
465
|
for (const entry of readdirSync(pnpmStoreDir, { withFileTypes: true })) {
|
|
386
466
|
if (!entry.isDirectory()) continue;
|
|
387
467
|
const candidate = tryReadPackageJson(path$1.join(pnpmStoreDir, entry.name, "node_modules", packageName, "package.json"));
|
|
388
468
|
if (candidate?.packageJson.name === packageName) return candidate;
|
|
389
469
|
}
|
|
390
470
|
} catch {}
|
|
391
|
-
const parentDir = path$1.dirname(currentDir);
|
|
392
|
-
if (parentDir === currentDir) break;
|
|
393
|
-
currentDir = parentDir;
|
|
394
471
|
}
|
|
395
472
|
};
|
|
396
473
|
let resolvedPath;
|
|
397
474
|
try {
|
|
398
|
-
const
|
|
475
|
+
const rootPackageJson = path$1.join(cwd, "package.json");
|
|
399
476
|
if (opts?.fromResolvedEntry) resolvedPath = opts.fromResolvedEntry;
|
|
400
477
|
else try {
|
|
401
|
-
resolvedPath =
|
|
478
|
+
resolvedPath = resolveModulePath(pkg, rootPackageJson);
|
|
402
479
|
} catch {
|
|
403
|
-
resolvedPath =
|
|
480
|
+
resolvedPath = resolveModulePath(packageName, rootPackageJson);
|
|
404
481
|
}
|
|
405
482
|
} catch {
|
|
406
483
|
resolvedPath = void 0;
|
|
407
484
|
}
|
|
408
485
|
if (resolvedPath !== void 0 && !path$1.isAbsolute(resolvedPath)) resolvedPath = void 0;
|
|
409
|
-
if (resolvedPath !== void 0)
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
486
|
+
if (resolvedPath !== void 0) {
|
|
487
|
+
const owner = findOwningPackageJson(path$1.dirname(resolvedPath), packageName);
|
|
488
|
+
if (owner) return owner;
|
|
489
|
+
}
|
|
490
|
+
for (const dir of ancestorDirs(cwd)) {
|
|
491
|
+
const directCandidate = tryReadPackageJson(path$1.join(dir, "node_modules", packageName, "package.json"), packageName);
|
|
492
|
+
if (directCandidate) return directCandidate;
|
|
493
|
+
}
|
|
494
|
+
return findPackageInDependents(packageName, cwd) ?? findPackageInPnpmStore(cwd);
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* A package installed only under a dependent is invisible to the walks above.
|
|
498
|
+
* Resolving it from each dependent in turn follows the same links that dependent
|
|
499
|
+
* does, so the copy found is the version it is installed against rather than
|
|
500
|
+
* whichever one the pnpm store happens to list first.
|
|
501
|
+
*/
|
|
502
|
+
function findPackageInDependents(packageName, cwd) {
|
|
503
|
+
const cacheKey = `${cwd}\0${packageName}`;
|
|
504
|
+
if (!dependentsLookupCache.has(cacheKey)) dependentsLookupCache.set(cacheKey, walkDependents(packageName, cwd));
|
|
505
|
+
return dependentsLookupCache.get(cacheKey);
|
|
506
|
+
}
|
|
507
|
+
function walkDependents(packageName, cwd) {
|
|
508
|
+
const root = tryReadPackageJson(path$1.join(cwd, "package.json"));
|
|
509
|
+
if (!root) return void 0;
|
|
510
|
+
const visited = /* @__PURE__ */ new Set();
|
|
511
|
+
const rootDependencyGroups = [getDependencyNames(root.packageJson), getDependencyNames(root.packageJson, ["devDependencies"])];
|
|
512
|
+
for (const rootDependencies of rootDependencyGroups) {
|
|
513
|
+
let level = rootDependencies.map((name) => ({
|
|
514
|
+
name,
|
|
515
|
+
fromDir: cwd
|
|
516
|
+
}));
|
|
517
|
+
while (level.length) {
|
|
518
|
+
const candidates = [];
|
|
519
|
+
const nextLevel = [];
|
|
520
|
+
for (const { name, fromDir } of level) {
|
|
521
|
+
if (name === packageName) continue;
|
|
522
|
+
const dependent = findPackageFrom(name, fromDir);
|
|
523
|
+
if (!dependent || visited.has(dependent.dir)) continue;
|
|
524
|
+
visited.add(dependent.dir);
|
|
525
|
+
const dependencies = getDependencyNames(dependent.packageJson);
|
|
526
|
+
if (dependencies.includes(packageName)) {
|
|
527
|
+
const copy = findPackageFrom(packageName, dependent.dir);
|
|
528
|
+
if (copy) candidates.push({
|
|
529
|
+
copy,
|
|
530
|
+
via: name
|
|
531
|
+
});
|
|
429
532
|
}
|
|
533
|
+
for (const dependency of dependencies) nextLevel.push({
|
|
534
|
+
name: dependency,
|
|
535
|
+
fromDir: dependent.dir
|
|
536
|
+
});
|
|
430
537
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
538
|
+
if (candidates.length) {
|
|
539
|
+
warnOnAmbiguousDependents(packageName, candidates);
|
|
540
|
+
return candidates[0].copy;
|
|
541
|
+
}
|
|
542
|
+
level = nextLevel;
|
|
434
543
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
function warnOnAmbiguousDependents(packageName, candidates) {
|
|
547
|
+
const viaByVersion = /* @__PURE__ */ new Map();
|
|
548
|
+
for (const { copy, via } of candidates) if (!viaByVersion.has(copy.packageJson.version)) viaByVersion.set(copy.packageJson.version, via);
|
|
549
|
+
if (viaByVersion.size < 2) return;
|
|
550
|
+
const versions = [...viaByVersion].map(([version, via]) => `${version} (via ${via})`);
|
|
551
|
+
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.`);
|
|
552
|
+
}
|
|
553
|
+
/** The package Node's `node_modules` lookup finds from `fromDir`, read at its real path. */
|
|
554
|
+
function findPackageFrom(packageName, fromDir) {
|
|
555
|
+
const entry = findNodeModulesEntry(packageName, fromDir);
|
|
556
|
+
if (!entry) return void 0;
|
|
557
|
+
try {
|
|
558
|
+
return tryReadPackageJson(path$1.join(realpathSync(entry), "package.json"), packageName);
|
|
559
|
+
} catch {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Walks up from `startDir` to the package.json named `packageName`, preferring the
|
|
565
|
+
* one at `node_modules/<packageName>` so a nested `package.json` (for example a
|
|
566
|
+
* subpath's `type: module` marker) does not shadow the package root.
|
|
567
|
+
*/
|
|
568
|
+
function findOwningPackageJson(startDir, packageName) {
|
|
569
|
+
let matchingPackage;
|
|
570
|
+
for (const dir of ancestorDirs(startDir)) {
|
|
571
|
+
const candidate = tryReadPackageJson(path$1.join(dir, "package.json"), packageName);
|
|
572
|
+
if (!candidate) continue;
|
|
573
|
+
if (dir.endsWith(path$1.join("node_modules", packageName))) return candidate;
|
|
574
|
+
matchingPackage ??= candidate;
|
|
575
|
+
}
|
|
576
|
+
return matchingPackage;
|
|
577
|
+
}
|
|
578
|
+
function* ancestorDirs(startDir) {
|
|
579
|
+
let dir = startDir;
|
|
438
580
|
while (true) {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
581
|
+
yield dir;
|
|
582
|
+
const parentDir = path$1.dirname(dir);
|
|
583
|
+
if (parentDir === dir) return;
|
|
584
|
+
dir = parentDir;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
/** The first `node_modules/<packageName>` that Node's lookup reaches from `fromDir`. */
|
|
588
|
+
function findNodeModulesEntry(packageName, fromDir) {
|
|
589
|
+
for (const dir of ancestorDirs(fromDir)) {
|
|
590
|
+
const entry = path$1.join(dir, "node_modules", packageName);
|
|
591
|
+
if (existsSync(entry)) return entry;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* `require.resolve(specifier)` from the file `from`, limited to the `node_modules` lookup
|
|
596
|
+
* bundlers perform. Node also searches NODE_PATH, which pnpm's bin shims point at the
|
|
597
|
+
* store's hoisted `node_modules`, so it can find packages the bundler cannot.
|
|
598
|
+
*/
|
|
599
|
+
function resolveModulePath(specifier, from) {
|
|
600
|
+
const resolved = createRequire(pathToFileURL(from)).resolve(specifier);
|
|
601
|
+
if (!path$1.isAbsolute(resolved) || specifier.startsWith(".") || path$1.isAbsolute(specifier) || process.versions.pnp) return resolved;
|
|
602
|
+
if (findNodeModulesEntry(getPackageName(specifier), path$1.dirname(from))) return resolved;
|
|
603
|
+
const error = /* @__PURE__ */ new Error(`Cannot find module '${specifier}' from '${from}'`);
|
|
604
|
+
error.code = "MODULE_NOT_FOUND";
|
|
605
|
+
throw error;
|
|
606
|
+
}
|
|
607
|
+
function getDependencyNames(packageJson, fields = [
|
|
608
|
+
"dependencies",
|
|
609
|
+
"peerDependencies",
|
|
610
|
+
"optionalDependencies"
|
|
611
|
+
]) {
|
|
612
|
+
if (!packageJson) return [];
|
|
613
|
+
const names = /* @__PURE__ */ new Set();
|
|
614
|
+
for (const field of fields) {
|
|
615
|
+
const deps = packageJson[field];
|
|
616
|
+
if (!deps || typeof deps !== "object") continue;
|
|
617
|
+
for (const dep of Object.keys(deps)) names.add(dep);
|
|
444
618
|
}
|
|
445
|
-
return
|
|
619
|
+
return [...names];
|
|
446
620
|
}
|
|
447
621
|
function getInstalledPackageEntry(pkg, opts) {
|
|
448
622
|
const installed = getInstalledPackageJson(pkg, opts);
|
|
@@ -451,7 +625,7 @@ function getInstalledPackageEntry(pkg, opts) {
|
|
|
451
625
|
const packageName = opts?.packageName || getPackageName(pkg);
|
|
452
626
|
const packageJson = installed.packageJson;
|
|
453
627
|
if (pkg !== packageName && (opts?.resolveSubpathWithRequire !== false || packageJson.exports === void 0)) try {
|
|
454
|
-
return
|
|
628
|
+
return resolveModulePath(pkg, path$1.join(cwd, "package.json"));
|
|
455
629
|
} catch {}
|
|
456
630
|
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";
|
|
457
631
|
return path$1.join(installed.dir, explicitEntry);
|
|
@@ -465,6 +639,18 @@ function getIsRolldown(ctx) {
|
|
|
465
639
|
const viteMajor = Number(String(viteVersion ?? "").split(".")[0]);
|
|
466
640
|
return Number.isFinite(viteMajor) && viteMajor >= 8 || !!ctx?.meta?.rolldownVersion;
|
|
467
641
|
}
|
|
642
|
+
/**
|
|
643
|
+
* Rolldown 1.2.10 added `codeSplitting.groups[].debugName` and warns when a group's
|
|
644
|
+
* `name` is a function without one. Older versions reject it as an unknown option.
|
|
645
|
+
*/
|
|
646
|
+
function supportsCodeSplittingGroupDebugName(ctx) {
|
|
647
|
+
const rolldownVersion = ctx?.meta?.rolldownVersion;
|
|
648
|
+
if (typeof rolldownVersion !== "string") return false;
|
|
649
|
+
const [major = 0, minor = 0, patch = 0] = rolldownVersion.split(/[.+-]/, 3).map((part) => parseInt(part, 10) || 0);
|
|
650
|
+
if (major !== 1) return major > 1;
|
|
651
|
+
if (minor !== 2) return minor > 2;
|
|
652
|
+
return patch >= 10;
|
|
653
|
+
}
|
|
468
654
|
/** Walk up from Vite `config.root` (Nuxt may point at `.nuxt` cache dirs). */
|
|
469
655
|
function isNuxtProjectRoot(root) {
|
|
470
656
|
let dir = root;
|
|
@@ -499,4 +685,4 @@ function hasPackageDependency(dependencyName, cwd = packageDetectionCwd || proce
|
|
|
499
685
|
//#region src/utils/dtsConstants.ts
|
|
500
686
|
const DEFAULT_PUBLIC_TYPES_FOLDER = "@mf-types";
|
|
501
687
|
//#endregion
|
|
502
|
-
export { mfError as _,
|
|
688
|
+
export { isReactCoreShare as C, mfWarn as E, REACT_DOM_CLIENT_SHARE as S, mfError as T, 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, createModuleFederationError as w, 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
|
|
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;
|