@module-federation/vite 1.17.1 → 1.18.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 +1 -0
- package/lib/index.d.ts +2 -2
- package/lib/index.js +231 -64
- package/lib/{ssrEntryLoader-D_sUES94.js → ssrEntryLoader-DgsCQOqq.js} +60 -21
- package/lib/{ssrVmStrategy-By_N71Dl.js → ssrVmStrategy-ChF8MB7l.js} +26 -4
- package/lib/utils/ssrEntryLoader.d.ts +3 -1
- package/lib/utils/ssrEntryLoader.js +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -31,6 +31,7 @@ Examples live in [`gioboa/module-federation-vite-examples`](https://github.com/g
|
|
|
31
31
|
| ---------------------------------------------------------------------------------------- | --------------- | ----------------- | --------------------------- |
|
|
32
32
|
| [Alpine](https://github.com/gioboa/module-federation-vite-examples/tree/main/alpine) | `alpine-host` | `alpine-remote` | Alpine.js |
|
|
33
33
|
| [Angular](https://github.com/gioboa/module-federation-vite-examples/tree/main/angular) | `angular-host` | `angular-remote` | Angular |
|
|
34
|
+
| [Ember](https://github.com/gioboa/module-federation-vite-examples/tree/main/ember) | `ember-host` | `ember-remote` | Ember 7 |
|
|
34
35
|
| [Lit](https://github.com/gioboa/module-federation-vite-examples/tree/main/lit) | `lit-host` | `lit-remote` | Lit |
|
|
35
36
|
| [Nuxt](https://github.com/gioboa/module-federation-vite-examples/tree/main/nuxt) | `nuxt-host` | `nuxt-remote` | Nuxt 4 |
|
|
36
37
|
| [Nx](https://github.com/gioboa/react-nx-microfrontend-demo) | `host` | `remote` | React + Nx |
|
package/lib/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ interface RemoteObjectConfig {
|
|
|
8
8
|
internalName?: string;
|
|
9
9
|
entry: string;
|
|
10
10
|
entryGlobalName?: string;
|
|
11
|
-
shareScope?: string;
|
|
11
|
+
shareScope?: string | string[];
|
|
12
12
|
}
|
|
13
13
|
interface TreeShakingConfig {
|
|
14
14
|
mode: 'server-calc' | 'runtime-infer';
|
|
@@ -36,7 +36,7 @@ type ModuleFederationOptions = {
|
|
|
36
36
|
name: string;
|
|
37
37
|
remotes?: Record<string, string | RemoteObjectConfig> | undefined;
|
|
38
38
|
runtime?: any;
|
|
39
|
-
shareScope?: string;
|
|
39
|
+
shareScope?: string | string[];
|
|
40
40
|
/**
|
|
41
41
|
* Override the public path used for remote entries
|
|
42
42
|
* Defaults to Vite's base config or "auto" if base is empty
|
package/lib/index.js
CHANGED
|
@@ -639,7 +639,7 @@ var VirtualModule = class VirtualModule {
|
|
|
639
639
|
//#endregion
|
|
640
640
|
//#region src/utils/ssrCapabilities.ts
|
|
641
641
|
/** A browser-safe generated expression that is true only in Node.js. */
|
|
642
|
-
const SERVER_ENV_GUARD = "
|
|
642
|
+
const SERVER_ENV_GUARD = "import.meta.env.SSR";
|
|
643
643
|
/**
|
|
644
644
|
* Single source of truth for SSR-related feature gates.
|
|
645
645
|
*
|
|
@@ -1854,6 +1854,7 @@ function getDependencyNames(packageJson) {
|
|
|
1854
1854
|
}
|
|
1855
1855
|
function isSharedSingletonConsumedByPeer(pkg) {
|
|
1856
1856
|
const shared = getNormalizeModuleFederationOptions()?.shared || {};
|
|
1857
|
+
if (Object.entries(shared).some(([key, item]) => key !== pkg && key.startsWith(`${pkg}/`) && item.shareConfig.singleton === true)) return true;
|
|
1857
1858
|
const sharedKeyByPackageName = /* @__PURE__ */ new Map();
|
|
1858
1859
|
Object.entries(shared).filter(([, item]) => item.shareConfig.singleton === true).forEach(([key]) => {
|
|
1859
1860
|
const packageName = getPackageName(key);
|
|
@@ -2144,13 +2145,14 @@ function generateEagerWorkspaceSingletonExports(namedExports, importSource, cach
|
|
|
2144
2145
|
__mfApplyEagerShareExports(exportModule);
|
|
2145
2146
|
export { __mf_default as default };${namedExportLine}`;
|
|
2146
2147
|
}
|
|
2147
|
-
function generateLazyWorkspaceSingletonExports(namedExports, importSource, cacheDescriptor, cacheOwner, treeShakingConsumer) {
|
|
2148
|
+
function generateLazyWorkspaceSingletonExports(namedExports, importSource, cacheDescriptor, cacheOwner, treeShakingConsumer, serveLocalFallback = false) {
|
|
2148
2149
|
const namedExportVars = namedExports.map((_name, i) => `__mf_${i}`);
|
|
2149
2150
|
const declarations = namedExports.length > 0 ? ["let __mf_default;", ...namedExportVars.map((name) => `let ${name};`)].join("\n ") : "let __mf_default;";
|
|
2150
2151
|
const assignments = namedExports.length > 0 ? [...namedExports.map((name, i) => `${namedExportVars[i]} = mod[${escapeGeneratedStringLiteral(name)}];`), "__mf_default = mod.default ?? mod;"].join("\n ") : "__mf_default = mod.default ?? mod;";
|
|
2151
2152
|
const namedExportLine = namedExports.length > 0 ? `\n export { ${namedExports.map((name, i) => `${namedExportVars[i]} as ${name}`).join(", ")} };` : "";
|
|
2152
2153
|
const applyLocalFallback = `exportModule = __mfNormalizeShareModule(__mfLocalShare);
|
|
2153
|
-
__mfWriteSharedCache(__mfModuleCache.share, ${cacheDescriptor}, exportModule, ${cacheOwner})
|
|
2154
|
+
__mfWriteSharedCache(__mfModuleCache.share, ${cacheDescriptor}, exportModule, ${cacheOwner});
|
|
2155
|
+
__mfApplyLazyShareExports(exportModule);`;
|
|
2154
2156
|
return `${declarations}
|
|
2155
2157
|
const __mfApplyLazyShareExports = (mod) => {
|
|
2156
2158
|
${assignments}
|
|
@@ -2158,7 +2160,7 @@ function generateLazyWorkspaceSingletonExports(namedExports, importSource, cache
|
|
|
2158
2160
|
__mfSubscribeSharedCache(__mfModuleCache.share, ${cacheDescriptor}, __mfApplyLazyShareExports);
|
|
2159
2161
|
let exportModule = ${getSharedCacheReadExpression(cacheDescriptor, treeShakingConsumer)};
|
|
2160
2162
|
if (exportModule === undefined) {
|
|
2161
|
-
if (import.meta.env.SSR) {
|
|
2163
|
+
if (import.meta.env.SSR${serveLocalFallback ? " || (import.meta.env.DEV && typeof __mfLocalShare !== 'undefined')" : ""}) {
|
|
2162
2164
|
${applyLocalFallback}
|
|
2163
2165
|
} else {
|
|
2164
2166
|
(__mfModuleCache.pendingShareLoads ||= []).push(initPromise.then(() => {
|
|
@@ -2182,8 +2184,15 @@ const WORKSPACE_SINGLETON_SSR_LOCAL_SHARE = "__mfNormalizeShareModule(__mfLocalS
|
|
|
2182
2184
|
function prependWorkspaceSingletonSsrImport(code) {
|
|
2183
2185
|
if (!code.includes("if (import.meta.env.SSR)")) return code;
|
|
2184
2186
|
if (!code.includes(WORKSPACE_SINGLETON_SSR_LOCAL_SHARE)) return code;
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
+
const localShareImport = /^[ \t]*import\s+\*\s+as\s+__mfLocalShare\s+from\s+(['"])(.+?)\1\s*;?[ \t]*\r?\n?/gm;
|
|
2188
|
+
let hasLocalShareImport = false;
|
|
2189
|
+
code = code.replace(localShareImport, (statement) => {
|
|
2190
|
+
if (hasLocalShareImport) return "";
|
|
2191
|
+
hasLocalShareImport = true;
|
|
2192
|
+
return statement;
|
|
2193
|
+
});
|
|
2194
|
+
if (hasLocalShareImport) return code;
|
|
2195
|
+
const importMatch = code.match(/initPromise\.then\(\(\)\s*=>\s*\{[\s\S]*?\breturn import\((["'])(.+?)\1\)\.then\(\(mod\)\s*=>\s*\{[\s\S]*?__mfApplyLazyShareExports/) ?? code.match(/initPromise\.then\(\(\)\s*=>\s*\n\s*import\((["'])(.+?)\1\)\.then\(\(mod\)\s*=>\s*\{[\s\S]*?__mfApplyLazyShareExports/) ?? code.match(/import\((["'])(.+?)\1\)/);
|
|
2187
2196
|
if (!importMatch) return code;
|
|
2188
2197
|
const quote = importMatch[1];
|
|
2189
2198
|
return `import * as __mfLocalShare from ${quote}${importMatch[2]}${quote};\n${code}`;
|
|
@@ -2223,10 +2232,15 @@ function generateShareModuleUnwrapCode({ source, preserveNamedExports, stopWithR
|
|
|
2223
2232
|
return current;`;
|
|
2224
2233
|
}
|
|
2225
2234
|
const normalizeLocalShareModuleCode = `const __mfNormalizeShareModule = (mod) => {
|
|
2226
|
-
|
|
2235
|
+
const normalized = (() => {
|
|
2236
|
+
${generateShareModuleUnwrapCode({
|
|
2227
2237
|
source: "mod",
|
|
2228
2238
|
preserveNamedExports: true
|
|
2229
2239
|
})}
|
|
2240
|
+
})();
|
|
2241
|
+
return normalized && Object.getPrototypeOf(normalized) === null
|
|
2242
|
+
? Object.assign({}, normalized)
|
|
2243
|
+
: normalized;
|
|
2230
2244
|
};`;
|
|
2231
2245
|
function writeLoadShareModule(pkg, shareItem, command, _isRolldown) {
|
|
2232
2246
|
if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, ".js");
|
|
@@ -2265,6 +2279,7 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown) {
|
|
|
2265
2279
|
const isWorkspaceSingleton = isWorkspacePackage && shareItem.shareConfig.singleton === true;
|
|
2266
2280
|
const isDefaultShareScope = shareItem.scope === void 0 || shareItem.scope === "default" || Array.isArray(shareItem.scope) && shareItem.scope[0] === "default";
|
|
2267
2281
|
const usesDeferredSingletonFallback = hasCompleteExportCoverage && (isWorkspaceSingleton || command !== "build" && isRemoteOnlyContainer() && shareItem.shareConfig.singleton === true || command === "build" && isRemoteOnlyContainer() && shareItem.shareConfig.singleton === true && !isDefaultShareScope);
|
|
2282
|
+
const servesRemoteSingletonFallback = command !== "build" && isRemoteOnlyContainer() && shareItem.shareConfig.singleton === true;
|
|
2268
2283
|
const isConsumedByPeerSingleton = isSharedSingletonConsumedByPeer(pkg);
|
|
2269
2284
|
const usesEntryInjectedRemoteFallback = hasCompleteExportCoverage && command !== "build" && !isWorkspaceSingleton && isRemoteOnlyContainer() && shareItem.shareConfig.singleton === true && getNormalizeModuleFederationOptions().hostInitInjectLocation === "entry" && isConsumedByPeerSingleton;
|
|
2270
2285
|
const usesEagerWorkspaceFallback = hasCompleteExportCoverage && isWorkspaceSingleton && isConsumedByPeerSingleton;
|
|
@@ -2273,11 +2288,11 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown) {
|
|
|
2273
2288
|
let initBlock = "";
|
|
2274
2289
|
if (usesDeferredTreeShakingFallback) {
|
|
2275
2290
|
importLine = `${getRuntimeInitPromiseBootstrapCode()}\n ${importLine}`;
|
|
2276
|
-
exportLine = generateLazyWorkspaceSingletonExports(namedExports, lazyLocalFallbackSource, cacheDescriptor, cacheOwner, treeShakingConsumer);
|
|
2291
|
+
exportLine = generateLazyWorkspaceSingletonExports(namedExports, lazyLocalFallbackSource, cacheDescriptor, cacheOwner, treeShakingConsumer, command !== "build" && (isWorkspaceSingleton || isWorkspacePackage || servesRemoteSingletonFallback));
|
|
2277
2292
|
} else if (usesEagerWorkspaceFallback || usesEntryInjectedRemoteFallback) exportLine = generateEagerWorkspaceSingletonExports(namedExports, lazyLocalFallbackSource, cacheDescriptor, cacheOwner, treeShakingConsumer);
|
|
2278
2293
|
else if (usesDeferredSingletonFallback) {
|
|
2279
2294
|
importLine = `${getRuntimeInitPromiseBootstrapCode()}\n ${importLine}`;
|
|
2280
|
-
exportLine = generateLazyWorkspaceSingletonExports(namedExports, lazyLocalFallbackSource, cacheDescriptor, cacheOwner, treeShakingConsumer);
|
|
2295
|
+
exportLine = generateLazyWorkspaceSingletonExports(namedExports, lazyLocalFallbackSource, cacheDescriptor, cacheOwner, treeShakingConsumer, command !== "build" && (isWorkspaceSingleton || isWorkspacePackage || servesRemoteSingletonFallback));
|
|
2281
2296
|
} else if (detectedNamedExports === void 0) {
|
|
2282
2297
|
exportLine = `const __mfDefaultExport = (() => {
|
|
2283
2298
|
${generateShareModuleUnwrapCode({
|
|
@@ -2339,7 +2354,7 @@ function writeLoadShareModule(pkg, shareItem, command, _isRolldown) {
|
|
|
2339
2354
|
initBlock = `exportModule = __mfNormalizeShareModule(__mfLocalShare);
|
|
2340
2355
|
__mfWriteSharedCache(__mfModuleCache.share, ${cacheDescriptor}, exportModule, ${cacheOwner});`;
|
|
2341
2356
|
}
|
|
2342
|
-
const prebuildImportLine = usesDeferredSingletonFallback || usesDeferredTreeShakingFallback ? "" : `import * as __mfLocalShare from ${escapeGeneratedStringLiteral(detectedNamedExports === void 0 ? coherentLocalSource : skipServePrebuildWarmup ? devImportSource : sharedImportSource)};`;
|
|
2357
|
+
const prebuildImportLine = usesEagerWorkspaceFallback || usesEntryInjectedRemoteFallback ? "" : usesDeferredSingletonFallback || usesDeferredTreeShakingFallback ? servesRemoteSingletonFallback || usesDeferredSingletonFallback && command !== "build" && (isWorkspaceSingleton || isWorkspacePackage) ? `import * as __mfLocalShare from ${escapeGeneratedStringLiteral(lazyLocalFallbackSource)};` : "" : `import * as __mfLocalShare from ${escapeGeneratedStringLiteral(detectedNamedExports === void 0 ? coherentLocalSource : skipServePrebuildWarmup ? devImportSource : sharedImportSource)};`;
|
|
2343
2358
|
const devDynamicImportLine = isWorkspacePackage ? "" : usesDeferredSingletonFallback || usesDeferredTreeShakingFallback ? "" : command !== "build" && !skipServePrebuildWarmup ? `;() => import(${escapeGeneratedStringLiteral(devImportSource)}).catch(() => {});` : "";
|
|
2344
2359
|
const moduleBody = usesDeferredSingletonFallback || usesDeferredTreeShakingFallback ? `
|
|
2345
2360
|
${prebuildImportLine}
|
|
@@ -2454,10 +2469,12 @@ function generateLocalSharedImportMap() {
|
|
|
2454
2469
|
? (res?.default ?? res)
|
|
2455
2470
|
: {...res}
|
|
2456
2471
|
// All npm packages pre-built by vite will be converted to esm
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2472
|
+
if (exportModule.__esModule !== true) {
|
|
2473
|
+
Object.defineProperty(exportModule, "__esModule", {
|
|
2474
|
+
value: true,
|
|
2475
|
+
enumerable: false
|
|
2476
|
+
})
|
|
2477
|
+
}
|
|
2461
2478
|
return function () {
|
|
2462
2479
|
return exportModule
|
|
2463
2480
|
}
|
|
@@ -2550,7 +2567,17 @@ function orderSharedDependenciesFirst(sharedPackages) {
|
|
|
2550
2567
|
const sharedDependency = sharedKeyByPackageName.get(dependency);
|
|
2551
2568
|
if (sharedDependency) visit(sharedDependency);
|
|
2552
2569
|
});
|
|
2553
|
-
if (pkg === packageName)
|
|
2570
|
+
if (pkg === packageName) {
|
|
2571
|
+
const subpaths = subpathKeysByPackageName.get(packageName) || [];
|
|
2572
|
+
if (packageName === "react" || packageName === "react-dom") {
|
|
2573
|
+
visiting.delete(pkg);
|
|
2574
|
+
visited.add(pkg);
|
|
2575
|
+
ordered.push(pkg);
|
|
2576
|
+
subpaths.forEach(visit);
|
|
2577
|
+
return;
|
|
2578
|
+
}
|
|
2579
|
+
subpaths.forEach(visit);
|
|
2580
|
+
}
|
|
2554
2581
|
visiting.delete(pkg);
|
|
2555
2582
|
visited.add(pkg);
|
|
2556
2583
|
ordered.push(pkg);
|
|
@@ -2572,7 +2599,7 @@ function generateSharedCacheSeedItem(pkg, shareItem, importPath) {
|
|
|
2572
2599
|
${normalizeRuntimeShareCode}
|
|
2573
2600
|
const normalizedModule = __mfNormalizeRuntimeShare(mod);
|
|
2574
2601
|
const exportModule = normalizedModule === mod ? {...mod} : normalizedModule;
|
|
2575
|
-
Object.defineProperty(exportModule, "__esModule", {
|
|
2602
|
+
if (exportModule.__esModule !== true) Object.defineProperty(exportModule, "__esModule", {
|
|
2576
2603
|
value: true,
|
|
2577
2604
|
enumerable: false
|
|
2578
2605
|
});
|
|
@@ -2789,7 +2816,7 @@ function generateRuntimeSharedCacheSeedCode(shareStrategy) {
|
|
|
2789
2816
|
${normalizeRuntimeShareCode}
|
|
2790
2817
|
const normalizedModule = __mfNormalizeRuntimeShare(resolved);
|
|
2791
2818
|
const exportModule = normalizedModule === resolved ? {...resolved} : normalizedModule;
|
|
2792
|
-
Object.defineProperty(exportModule, "__esModule", {
|
|
2819
|
+
if (exportModule.__esModule !== true) Object.defineProperty(exportModule, "__esModule", {
|
|
2793
2820
|
value: true,
|
|
2794
2821
|
enumerable: false
|
|
2795
2822
|
});
|
|
@@ -3047,6 +3074,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
3047
3074
|
const needsSharedProviderSelectionHelper = Object.keys(options.shared ?? {}).length > 0;
|
|
3048
3075
|
const hasTreeShakingShared = Object.values(options.shared ?? {}).some((share) => !!share?.shareConfig.treeShaking);
|
|
3049
3076
|
const hasEagerShared = Object.values(options.shared ?? {}).some((share) => share?.shareConfig.eager === true && share.shareConfig.import !== false);
|
|
3077
|
+
const hasMultipleShareScopes = Array.isArray(options.shareScope);
|
|
3050
3078
|
const runtimeImports = [
|
|
3051
3079
|
"init as runtimeInit",
|
|
3052
3080
|
"loadRemote",
|
|
@@ -3065,7 +3093,19 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
3065
3093
|
serializeRuntimeOptions(p[1])
|
|
3066
3094
|
];
|
|
3067
3095
|
});
|
|
3068
|
-
const initializeSharingCode = `
|
|
3096
|
+
const initializeSharingCode = hasMultipleShareScopes ? `for (const shareScopeName of shareScopeNamesToInitialize) {
|
|
3097
|
+
try {
|
|
3098
|
+
await retrySharedInit(async () => {
|
|
3099
|
+
await Promise.all(await initRes.initializeSharing(shareScopeName, {
|
|
3100
|
+
strategy: '${options.shareStrategy}',
|
|
3101
|
+
from: "build",
|
|
3102
|
+
initScope
|
|
3103
|
+
}));
|
|
3104
|
+
});
|
|
3105
|
+
} catch (e) {
|
|
3106
|
+
console.error('[Module Federation]', e)
|
|
3107
|
+
}
|
|
3108
|
+
}` : `try {
|
|
3069
3109
|
await retrySharedInit(async () => {
|
|
3070
3110
|
await Promise.all(await initRes.initializeSharing('${options.shareScope}', {
|
|
3071
3111
|
strategy: '${options.shareStrategy}',
|
|
@@ -3092,7 +3132,8 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
3092
3132
|
${command === "build" ? getRuntimeInitResolveBootstrapCode() : getRuntimeInitBootstrapCode() + "\n const { initResolve } = globalThis[globalKey];"}
|
|
3093
3133
|
${getRuntimeModuleCacheBootstrapCode()}
|
|
3094
3134
|
const initTokens = {}
|
|
3095
|
-
const
|
|
3135
|
+
const shareScopeNames = Array.isArray(${JSON.stringify(options.shareScope)}) ? ${JSON.stringify(options.shareScope)} : [${JSON.stringify(options.shareScope)}]
|
|
3136
|
+
const shareScopeName = ${JSON.stringify(hasMultipleShareScopes ? options.shareScope[0] : options.shareScope)}
|
|
3096
3137
|
const mfName = ${JSON.stringify(options.name)}
|
|
3097
3138
|
let localSharedImportMapPromise
|
|
3098
3139
|
let exposesMapPromise
|
|
@@ -3139,31 +3180,66 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
3139
3180
|
|
|
3140
3181
|
async function init(shared = {}, initScope = []) {
|
|
3141
3182
|
${sharedCacheHelperCode}
|
|
3183
|
+
const getShareScope = (scopeName) => ${hasMultipleShareScopes} ? (shared?.[scopeName] || {}) : shared;
|
|
3184
|
+
const getShareScopeNames = (share) => {
|
|
3185
|
+
const configuredScopes = Array.isArray(share?.scope) ? share.scope : [share?.scope || shareScopeName];
|
|
3186
|
+
if (!${hasMultipleShareScopes}) return configuredScopes;
|
|
3187
|
+
return [...new Set([...configuredScopes, ...shareScopeNames])];
|
|
3188
|
+
};
|
|
3189
|
+
const getShareScopeName = (pkg, share) => {
|
|
3190
|
+
for (const scopeName of getShareScopeNames(share)) {
|
|
3191
|
+
if (getShareScope(scopeName)?.[pkg]) return scopeName;
|
|
3192
|
+
}
|
|
3193
|
+
return shareScopeName;
|
|
3194
|
+
};
|
|
3195
|
+
const getShareVersions = (pkg, share) => {
|
|
3196
|
+
for (const scopeName of getShareScopeNames(share)) {
|
|
3197
|
+
const versions = getShareScope(scopeName)?.[pkg];
|
|
3198
|
+
if (versions) return versions;
|
|
3199
|
+
}
|
|
3200
|
+
return getShareScope(shareScopeName)?.[pkg];
|
|
3201
|
+
};
|
|
3142
3202
|
const federationInstances = globalThis.__FEDERATION__?.__INSTANCES__ || [];
|
|
3143
3203
|
const initRootName = initScope.find((token) => token?.from)?.from;
|
|
3144
3204
|
const scopeRoot = federationInstances.find((instance) =>
|
|
3145
3205
|
instance?.options?.name === initRootName &&
|
|
3146
|
-
instance?.shareScopeMap?.['${options.shareScope}'] === shared
|
|
3206
|
+
${hasMultipleShareScopes ? "shareScopeNames.some((scopeName) => instance?.shareScopeMap?.[scopeName] === getShareScope(scopeName))" : `instance?.shareScopeMap?.['${options.shareScope}'] === shared`}
|
|
3147
3207
|
) || federationInstances.find((instance) =>
|
|
3148
3208
|
instance?.options?.name !== mfName &&
|
|
3149
|
-
instance?.shareScopeMap?.['${options.shareScope}'] === shared
|
|
3209
|
+
${hasMultipleShareScopes ? "shareScopeNames.some((scopeName) => instance?.shareScopeMap?.[scopeName] === getShareScope(scopeName))" : `instance?.shareScopeMap?.['${options.shareScope}'] === shared`}
|
|
3150
3210
|
);
|
|
3151
3211
|
const initialShared = Object.create(null);
|
|
3152
|
-
for (const
|
|
3212
|
+
${hasMultipleShareScopes ? `for (const scopeName of shareScopeNames) {
|
|
3213
|
+
for (const [pkg, versions] of Object.entries(getShareScope(scopeName))) {
|
|
3214
|
+
if (initialShared[pkg]) continue;
|
|
3215
|
+
const initialVersions = initialShared[pkg] = Object.create(null);
|
|
3216
|
+
for (const [version, provider] of Object.entries(versions)) {
|
|
3217
|
+
initialVersions[version] = Object.assign({}, provider);
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
}` : `for (const [pkg, versions] of Object.entries(shared)) {
|
|
3153
3221
|
const initialVersions = initialShared[pkg] = Object.create(null);
|
|
3154
3222
|
for (const [version, provider] of Object.entries(versions)) {
|
|
3155
3223
|
// Runtime registration mutates provider records in-place, notably their origin.
|
|
3156
3224
|
// Preserve the parent-visible provider and its original provenance.
|
|
3157
3225
|
initialVersions[version] = Object.assign({}, provider);
|
|
3158
3226
|
}
|
|
3159
|
-
}
|
|
3227
|
+
}`}
|
|
3160
3228
|
const {usedShared, usedRemotes} = await getLocalSharedImportMap()
|
|
3161
3229
|
// handling circular init calls before an external provider can re-enter this container
|
|
3162
|
-
|
|
3230
|
+
${hasMultipleShareScopes ? `const shareScopeNamesToInitialize = [];
|
|
3231
|
+
for (const shareScopeName of shareScopeNames) {
|
|
3232
|
+
let initToken = initTokens[shareScopeName];
|
|
3233
|
+
if (!initToken) initToken = initTokens[shareScopeName] = { from: mfName };
|
|
3234
|
+
if (initScope.indexOf(initToken) >= 0) continue;
|
|
3235
|
+
initScope.push(initToken);
|
|
3236
|
+
shareScopeNamesToInitialize.push(shareScopeName);
|
|
3237
|
+
}
|
|
3238
|
+
if (shareScopeNamesToInitialize.length === 0) return;` : `var initToken = initTokens[shareScopeName];
|
|
3163
3239
|
if (!initToken)
|
|
3164
3240
|
initToken = initTokens[shareScopeName] = { from: mfName };
|
|
3165
3241
|
if (initScope.indexOf(initToken) >= 0) return;
|
|
3166
|
-
initScope.push(initToken)
|
|
3242
|
+
initScope.push(initToken);`}
|
|
3167
3243
|
${normalizeRuntimeShareCode}
|
|
3168
3244
|
const __browserPlugins = [${pluginImportNames.filter((item) => !isSsrOnlyPlugin(item[1])).map((item) => `${item[0]}(${item[2]})`).join(", ")}];
|
|
3169
3245
|
const __ssrPlugins = typeof globalThis.window === 'undefined'
|
|
@@ -3184,7 +3260,10 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
3184
3260
|
plugins: [__mfSharePinLifecyclePlugin(), ${hasTreeShakingShared ? "__mfTreeShakingSnapshotPlugin()," : ""} ...__browserPlugins, ...__ssrPlugins],
|
|
3185
3261
|
${options.shareStrategy ? `shareStrategy: '${options.shareStrategy}'` : ""}
|
|
3186
3262
|
});
|
|
3187
|
-
|
|
3263
|
+
${hasMultipleShareScopes ? `for (const shareScopeName of shareScopeNamesToInitialize) {
|
|
3264
|
+
const scopeShare = getShareScope(shareScopeName);
|
|
3265
|
+
initRes.initShareScopeMap(shareScopeName, scopeShare);
|
|
3266
|
+
}` : `initRes.initShareScopeMap('${options.shareScope}', shared);`}
|
|
3188
3267
|
function __mfSharePinLifecyclePlugin() {
|
|
3189
3268
|
return {
|
|
3190
3269
|
name: "vite-share-pin-lifecycle-plugin",
|
|
@@ -3232,7 +3311,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
3232
3311
|
if (!versionMap || versionMap[version] !== currentProvider) return undefined;
|
|
3233
3312
|
const pinnedProvider = Object.assign({}, provider, {
|
|
3234
3313
|
version: provider.version ?? version,
|
|
3235
|
-
scope: provider.scope ?? currentProvider?.scope ??
|
|
3314
|
+
scope: provider.scope ?? currentProvider?.scope ?? ${JSON.stringify(hasMultipleShareScopes ? options.shareScope : [options.shareScope])},
|
|
3236
3315
|
strategy: 'loaded-first'
|
|
3237
3316
|
});
|
|
3238
3317
|
const providerFrom = provider.from;
|
|
@@ -3440,7 +3519,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
3440
3519
|
usedShare.scope
|
|
3441
3520
|
);
|
|
3442
3521
|
if (__mfReadSharedCache(__mfModuleCache.share, usedCacheDescriptor) !== undefined) return;
|
|
3443
|
-
const liveVersionMap = shared[pkg];
|
|
3522
|
+
const liveVersionMap = ${hasMultipleShareScopes ? "getShareVersions(pkg, usedShare)" : "shared[pkg]"};
|
|
3444
3523
|
const liveProvider = liveVersionMap?.[version];
|
|
3445
3524
|
if (providerEntry.registered && !__mfMatchesSharedProvider(liveProvider, provider)) return;
|
|
3446
3525
|
let loadedShare;
|
|
@@ -3526,8 +3605,8 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
3526
3605
|
const resolvedExternalProvider = __mfResolveExternalSharedProvider(
|
|
3527
3606
|
federationInstances,
|
|
3528
3607
|
scopeRoot,
|
|
3529
|
-
shared,
|
|
3530
|
-
'${options.shareScope}',
|
|
3608
|
+
${hasMultipleShareScopes ? "getShareScope(getShareScopeName(pkg, usedShare))" : "shared"},
|
|
3609
|
+
${hasMultipleShareScopes ? "getShareScopeName(pkg, usedShare)" : `'${options.shareScope}'`},
|
|
3531
3610
|
pkg,
|
|
3532
3611
|
providerEntry,
|
|
3533
3612
|
selectedExternalProvider,
|
|
@@ -3549,7 +3628,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
3549
3628
|
if (cachedShare !== undefined && cachedShareOwner !== mfName) return;
|
|
3550
3629
|
// Registration can replace an unloaded same-version root provider in-place.
|
|
3551
3630
|
// Pin the chosen provider while loadShare() runs its implicit registration.
|
|
3552
|
-
const liveVersionMap = shared[pkg];
|
|
3631
|
+
const liveVersionMap = ${hasMultipleShareScopes ? "getShareVersions(pkg, usedShare)" : "shared[pkg]"};
|
|
3553
3632
|
const liveProvider = liveVersionMap?.[version];
|
|
3554
3633
|
if (
|
|
3555
3634
|
providerEntry.registered &&
|
|
@@ -3631,7 +3710,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
3631
3710
|
await __mfBridgeExternalSharedProvider(
|
|
3632
3711
|
pkg,
|
|
3633
3712
|
usedShare,
|
|
3634
|
-
shared[pkg],
|
|
3713
|
+
${hasMultipleShareScopes ? "getShareVersions(pkg, usedShare)" : "shared[pkg]"},
|
|
3635
3714
|
initialShared[pkg],
|
|
3636
3715
|
undefined
|
|
3637
3716
|
);
|
|
@@ -3641,9 +3720,10 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
3641
3720
|
const globalVersionsByPackage = Object.create(null);
|
|
3642
3721
|
if (allInstances) {
|
|
3643
3722
|
for (const [, scopes] of Object.entries(allInstances)) {
|
|
3644
|
-
const
|
|
3645
|
-
|
|
3646
|
-
|
|
3723
|
+
for (const scopeName of shareScopeNames) {
|
|
3724
|
+
const scopeShare = scopes?.[scopeName];
|
|
3725
|
+
if (!scopeShare) continue;
|
|
3726
|
+
for (const [pkg, versionMap] of Object.entries(scopeShare)) {
|
|
3647
3727
|
const usedShare = usedShared?.[pkg];
|
|
3648
3728
|
const passedVersions = initialShared[pkg];
|
|
3649
3729
|
const bridgeSelection = bridgeSelections.get(pkg);
|
|
@@ -3664,6 +3744,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
3664
3744
|
if (provider === usedShare || (usedShare.from && provider.from === usedShare.from)) continue;
|
|
3665
3745
|
if (globalVersions[version] === undefined) globalVersions[version] = provider;
|
|
3666
3746
|
}
|
|
3747
|
+
}
|
|
3667
3748
|
}
|
|
3668
3749
|
}
|
|
3669
3750
|
}
|
|
@@ -3687,7 +3768,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
3687
3768
|
: __mfReadSharedCache(__mfModuleCache.share, cacheDescriptor);
|
|
3688
3769
|
if (share.shareConfig?.import !== false || cachedShare !== undefined) return;
|
|
3689
3770
|
${normalizeRuntimeShareCode}
|
|
3690
|
-
const versionMap = shared?.[pkg];
|
|
3771
|
+
const versionMap = ${hasMultipleShareScopes ? "getShareVersions(pkg, share)" : "shared?.[pkg]"};
|
|
3691
3772
|
const provider = __mfSelectSharedProvider(
|
|
3692
3773
|
versionMap,
|
|
3693
3774
|
pkg,
|
|
@@ -3861,7 +3942,7 @@ function getRemoteVirtualModule(remote, command, enableSsrInit = false, consumer
|
|
|
3861
3942
|
const { shareStrategy } = getNormalizeModuleFederationOptions();
|
|
3862
3943
|
const cacheKey = `${remote}__${command}__${shareStrategy}__${consumer}__${enableSsrInit ? "ssr-init" : "no-ssr-init"}`;
|
|
3863
3944
|
if (!cacheRemoteMap[cacheKey]) {
|
|
3864
|
-
cacheRemoteMap[cacheKey] = new VirtualModule(remote
|
|
3945
|
+
cacheRemoteMap[cacheKey] = new VirtualModule(consumer === "unified" ? remote : `${remote}__mf_consumer__${consumer}`, LOAD_REMOTE_TAG, ".js");
|
|
3865
3946
|
cacheRemoteMap[cacheKey].writeSync(generateRemotes(remote, command, enableSsrInit, consumer));
|
|
3866
3947
|
}
|
|
3867
3948
|
return cacheRemoteMap[cacheKey];
|
|
@@ -3904,9 +3985,24 @@ function shouldIncludeDeferredProxy(initMode, consumer, eagerLoadClientRemote, d
|
|
|
3904
3985
|
function getRemoteModuleRuntimeHelpers() {
|
|
3905
3986
|
return `
|
|
3906
3987
|
function __mfUnwrapRemoteDefault(mod) {
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3988
|
+
let value = mod;
|
|
3989
|
+
// A federated expose can pass through more than one ESM/CJS namespace
|
|
3990
|
+
// wrapper (notably with React/Preact lazy imports). Keep unwrapping
|
|
3991
|
+
// explicit default namespaces until the actual component is reached.
|
|
3992
|
+
const seen = new Set();
|
|
3993
|
+
while (value != null && typeof value === "object" && !seen.has(value)) {
|
|
3994
|
+
seen.add(value);
|
|
3995
|
+
if (value.__esModule && value.default != null) {
|
|
3996
|
+
value = value.default;
|
|
3997
|
+
continue;
|
|
3998
|
+
}
|
|
3999
|
+
if (!value.__esModule && value.default != null) {
|
|
4000
|
+
value = value.default;
|
|
4001
|
+
continue;
|
|
4002
|
+
}
|
|
4003
|
+
break;
|
|
4004
|
+
}
|
|
4005
|
+
return value;
|
|
3910
4006
|
}
|
|
3911
4007
|
let __mfDefaultExport;
|
|
3912
4008
|
function __mfSyncDefaultExport() {
|
|
@@ -4210,9 +4306,10 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
|
|
|
4210
4306
|
const blockEnd = body.lastIndexOf("}");
|
|
4211
4307
|
if (blockStart === -1 || blockEnd <= blockStart) return scriptTag;
|
|
4212
4308
|
return `<script>${body.slice(0, blockStart + 1) + `
|
|
4309
|
+
const __mfCurrentScript = document.currentScript;
|
|
4213
4310
|
(async () => {
|
|
4214
4311
|
await import(${JSON.stringify(initPath)}).then(({ initHost }) => initHost());
|
|
4215
|
-
` + body.slice(blockStart + 1, blockEnd) + `
|
|
4312
|
+
` + body.slice(blockStart + 1, blockEnd).replaceAll("document.currentScript", "__mfCurrentScript") + `
|
|
4216
4313
|
})();
|
|
4217
4314
|
` + body.slice(blockEnd)}<\/script>`;
|
|
4218
4315
|
});
|
|
@@ -5521,15 +5618,25 @@ function generateRemoteEntrySSR(options) {
|
|
|
5521
5618
|
const initToken = { from: ${JSON.stringify(options.name)} };
|
|
5522
5619
|
if (initScope.indexOf(initToken) >= 0) return;
|
|
5523
5620
|
initScope.push(initToken);
|
|
5524
|
-
|
|
5621
|
+
const shareScopeNames = Array.isArray(${JSON.stringify(options.shareScope)})
|
|
5622
|
+
? ${JSON.stringify(options.shareScope)}
|
|
5623
|
+
: [${JSON.stringify(options.shareScope)}];
|
|
5525
5624
|
try {
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5625
|
+
for (const scopeName of shareScopeNames) {
|
|
5626
|
+
try {
|
|
5627
|
+
const scopeShare = Array.isArray(${JSON.stringify(options.shareScope)}) ? (shared?.[scopeName] || {}) : shared;
|
|
5628
|
+
initRes.initShareScopeMap(scopeName, scopeShare);
|
|
5629
|
+
await Promise.all(
|
|
5630
|
+
await initRes.initializeSharing(scopeName, {
|
|
5631
|
+
strategy: ${JSON.stringify(options.shareStrategy ?? "version-first")},
|
|
5632
|
+
from: 'build',
|
|
5633
|
+
initScope,
|
|
5634
|
+
})
|
|
5635
|
+
);
|
|
5636
|
+
} catch (e) {
|
|
5637
|
+
console.error('[Module Federation SSR]', e);
|
|
5638
|
+
}
|
|
5639
|
+
}
|
|
5533
5640
|
} catch (e) {
|
|
5534
5641
|
console.error('[Module Federation SSR]', e);
|
|
5535
5642
|
}
|
|
@@ -6114,7 +6221,7 @@ function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposes
|
|
|
6114
6221
|
},
|
|
6115
6222
|
async buildStart() {
|
|
6116
6223
|
await refreshExposeRemoteDependencies(this);
|
|
6117
|
-
if (_command !== "build") return;
|
|
6224
|
+
if (_command !== "build" || hasPackageDependency("@tanstack/react-start", root)) return;
|
|
6118
6225
|
for (const expose of Object.values(options.exposes)) {
|
|
6119
6226
|
const resolved = await this.resolve(expose.import);
|
|
6120
6227
|
if (resolved) this.emitFile({
|
|
@@ -6925,11 +7032,27 @@ function pluginRemoteNamedExports(options) {
|
|
|
6925
7032
|
//#endregion
|
|
6926
7033
|
//#region src/plugins/pluginSSRRemoteEntry.ts
|
|
6927
7034
|
const MAX_RUNNER_BODY_BYTES = 1024 * 1024;
|
|
7035
|
+
const MAX_RUNNER_START_OFFSET = 1024 * 1024;
|
|
6928
7036
|
const ALLOWED_RUNNER_INVOKE_NAMES = new Set(["fetchModule", "getBuiltins"]);
|
|
6929
7037
|
const VITE_FS_PREFIX = "/@fs/";
|
|
6930
7038
|
function isPlainObject(value) {
|
|
6931
7039
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
6932
7040
|
}
|
|
7041
|
+
function isSafeRunnerFetchModuleOptions(value) {
|
|
7042
|
+
if (!isPlainObject(value)) return false;
|
|
7043
|
+
const allowedKeys = new Set([
|
|
7044
|
+
"cached",
|
|
7045
|
+
"startOffset",
|
|
7046
|
+
"inlineSourceMap"
|
|
7047
|
+
]);
|
|
7048
|
+
for (const [key, option] of Object.entries(value)) {
|
|
7049
|
+
if (!allowedKeys.has(key)) return false;
|
|
7050
|
+
if (key === "startOffset") {
|
|
7051
|
+
if (typeof option !== "number" || !Number.isSafeInteger(option) || option < 0 || option > MAX_RUNNER_START_OFFSET) return false;
|
|
7052
|
+
} else if (typeof option !== "boolean") return false;
|
|
7053
|
+
}
|
|
7054
|
+
return true;
|
|
7055
|
+
}
|
|
6933
7056
|
function stripQueryAndHash(id) {
|
|
6934
7057
|
const queryIndex = id.indexOf("?");
|
|
6935
7058
|
const hashIndex = id.indexOf("#");
|
|
@@ -6966,15 +7089,21 @@ function isPathWithinAllowedDirectories(filePath, allowedDirectories) {
|
|
|
6966
7089
|
return allowedDirectories.some((directory) => isPathWithinDirectory(filePath, directory));
|
|
6967
7090
|
}
|
|
6968
7091
|
function isSafeRunnerFetchModuleId(id, config) {
|
|
6969
|
-
if (typeof id !== "string" || !id
|
|
7092
|
+
if (typeof id !== "string" || !id) return false;
|
|
6970
7093
|
const decoded = decodeViteId(id).replace(/^\0+/, "");
|
|
6971
7094
|
if (!decoded || decoded.startsWith("virtual:")) return !!decoded;
|
|
6972
|
-
if (
|
|
7095
|
+
if (decoded.startsWith("file://")) try {
|
|
7096
|
+
const filePath = decodeURIComponent(new URL(decoded).pathname);
|
|
7097
|
+
return path$1.isAbsolute(filePath) && isPathWithinAllowedDirectories(filePath, getRunnerAllowedDirectories(config));
|
|
7098
|
+
} catch {
|
|
7099
|
+
return false;
|
|
7100
|
+
}
|
|
7101
|
+
if (/^(?:https?|data|blob|javascript):/i.test(decoded) || decoded.startsWith("//")) return false;
|
|
6973
7102
|
const cleanId = decodeRunnerFilePath(stripQueryAndHash(decoded));
|
|
6974
7103
|
if (!cleanId || hasRelativeTraversal(cleanId)) return false;
|
|
6975
7104
|
const allowedDirectories = getRunnerAllowedDirectories(config);
|
|
6976
7105
|
if (cleanId.startsWith(VITE_FS_PREFIX)) {
|
|
6977
|
-
const fsPath = cleanId.slice(5)
|
|
7106
|
+
const fsPath = `/${cleanId.slice(5)}`;
|
|
6978
7107
|
return path$1.isAbsolute(fsPath) && isPathWithinAllowedDirectories(fsPath, allowedDirectories);
|
|
6979
7108
|
}
|
|
6980
7109
|
if (path$1.isAbsolute(cleanId)) {
|
|
@@ -6994,7 +7123,7 @@ function isRunnerInvokePayload(payload, config) {
|
|
|
6994
7123
|
if (name === "getBuiltins") return args.length === 0;
|
|
6995
7124
|
if (args.length < 1 || args.length > 3) return false;
|
|
6996
7125
|
const [id, importer, opts] = args;
|
|
6997
|
-
return isSafeRunnerFetchModuleId(id, config) && (importer === void 0 || importer === null || isSafeRunnerFetchModuleId(importer, config)) && (opts === void 0 ||
|
|
7126
|
+
return isSafeRunnerFetchModuleId(id, config) && (importer === void 0 || importer === null || isSafeRunnerFetchModuleId(importer, config)) && (opts === void 0 || isSafeRunnerFetchModuleOptions(opts));
|
|
6998
7127
|
}
|
|
6999
7128
|
function readBoundedRunnerBody(req, res) {
|
|
7000
7129
|
return new Promise((resolve) => {
|
|
@@ -7110,14 +7239,6 @@ function pluginSSRRemoteEntry(options) {
|
|
|
7110
7239
|
const clientEnv = server.environments?.client;
|
|
7111
7240
|
const runnerEnv = typeof ssrEnv?.hot?.handleInvoke === "function" ? ssrEnv : typeof clientEnv?.hot?.handleInvoke === "function" ? clientEnv : void 0;
|
|
7112
7241
|
if (typeof (ssrEnv?.fetchModule ?? clientEnv?.fetchModule) === "function" && runnerEnv) server.middlewares.use("/__mf_runner__", async (req, res) => {
|
|
7113
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
7114
|
-
if (req.method === "OPTIONS") {
|
|
7115
|
-
res.setHeader("Access-Control-Allow-Methods", "POST");
|
|
7116
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
7117
|
-
res.statusCode = 204;
|
|
7118
|
-
res.end();
|
|
7119
|
-
return;
|
|
7120
|
-
}
|
|
7121
7242
|
if (req.method !== "POST") {
|
|
7122
7243
|
res.statusCode = 405;
|
|
7123
7244
|
res.end("Method not allowed");
|
|
@@ -7548,6 +7669,43 @@ function canResolveSharedSubpath(subpath, projectRoot) {
|
|
|
7548
7669
|
}
|
|
7549
7670
|
}
|
|
7550
7671
|
/**
|
|
7672
|
+
* Vite's dependency scanner cannot see through the virtual loadShare modules
|
|
7673
|
+
* generated for shared packages. As a result, dependencies of a linked/shared
|
|
7674
|
+
* package may be discovered one request at a time and each discovery starts a
|
|
7675
|
+
* new optimizer pass. Seed the optimizer with the complete dependency graph
|
|
7676
|
+
* before the first request instead.
|
|
7677
|
+
*
|
|
7678
|
+
* Vite then resolves the package's own dependency graph using its normal
|
|
7679
|
+
* scanner, preserving package and peer-dependency resolution semantics.
|
|
7680
|
+
*/
|
|
7681
|
+
function includeLinkedSharedEntries(optimizeDeps, shared, projectRoot, exposes, outDir) {
|
|
7682
|
+
const additions = /* @__PURE__ */ new Set();
|
|
7683
|
+
const entries = new Set(Array.isArray(optimizeDeps.entries) ? optimizeDeps.entries : optimizeDeps.entries ? [optimizeDeps.entries] : [
|
|
7684
|
+
"**/*.html",
|
|
7685
|
+
"!**/node_modules/**",
|
|
7686
|
+
`!**/${outDir.replace(/\\/g, "/")}/**`,
|
|
7687
|
+
"!**/__tests__/**",
|
|
7688
|
+
"!**/coverage/**"
|
|
7689
|
+
]);
|
|
7690
|
+
for (const [packageName, share] of Object.entries(shared ?? {})) {
|
|
7691
|
+
if (share?.shareConfig?.import === false) continue;
|
|
7692
|
+
const installed = getInstalledPackageJson(packageName, { cwd: projectRoot });
|
|
7693
|
+
if (!installed || installed.dir.replaceAll("\\", "/").includes("/node_modules/")) continue;
|
|
7694
|
+
const entry = getInstalledPackageEntry(packageName, { cwd: projectRoot });
|
|
7695
|
+
if (entry && existsSync(entry)) additions.add(entry);
|
|
7696
|
+
}
|
|
7697
|
+
for (const expose of Object.values(exposes ?? {})) {
|
|
7698
|
+
const source = expose.import;
|
|
7699
|
+
if (source.startsWith(".") || path$1.isAbsolute(source)) {
|
|
7700
|
+
const entry = path$1.resolve(projectRoot, source);
|
|
7701
|
+
if (existsSync(entry)) additions.add(entry);
|
|
7702
|
+
}
|
|
7703
|
+
}
|
|
7704
|
+
if (additions.size === 0) return;
|
|
7705
|
+
for (const entry of additions) entries.add(entry);
|
|
7706
|
+
optimizeDeps.entries = [...entries];
|
|
7707
|
+
}
|
|
7708
|
+
/**
|
|
7551
7709
|
* Plugin that runs FIRST to register generated virtual modules in the config hook.
|
|
7552
7710
|
* This prevents 504 "Outdated Optimize Dep" errors by ensuring ids are known
|
|
7553
7711
|
* before Vite's optimization phase.
|
|
@@ -7591,8 +7749,8 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
7591
7749
|
name: "module-federation:optimize-shared-resolver",
|
|
7592
7750
|
load(id) {
|
|
7593
7751
|
if (id !== "module-federation:optimized-require-react") return;
|
|
7594
|
-
const
|
|
7595
|
-
const source = JSON.stringify(
|
|
7752
|
+
const loadSharePath = getLoadShareModulePath("react", isRolldown);
|
|
7753
|
+
const source = JSON.stringify(loadSharePath);
|
|
7596
7754
|
return "import * as __mfShared from " + source + ";\nexport * from " + source + ";\nexport default __mfShared.default ?? __mfShared;";
|
|
7597
7755
|
},
|
|
7598
7756
|
resolveId(source, importer, options) {
|
|
@@ -7711,6 +7869,10 @@ export default __mfShared.default ?? __mfShared;`
|
|
|
7711
7869
|
}
|
|
7712
7870
|
writeLocalSharedImportMap();
|
|
7713
7871
|
}
|
|
7872
|
+
if (_command === "serve") {
|
|
7873
|
+
config.optimizeDeps ??= {};
|
|
7874
|
+
includeLinkedSharedEntries(config.optimizeDeps, shared, root, options.exposes, config.build?.outDir ?? "dist");
|
|
7875
|
+
}
|
|
7714
7876
|
},
|
|
7715
7877
|
configResolved(config) {
|
|
7716
7878
|
const viteMajor = parseInt(version, 10);
|
|
@@ -8105,6 +8267,11 @@ function federation(mfUserOptions) {
|
|
|
8105
8267
|
if (resolvedTarget === "node" && !("FEDERATION_OPTIMIZE_NO_SNAPSHOT_PLUGIN" in config.define)) config.define["FEDERATION_OPTIMIZE_NO_SNAPSHOT_PLUGIN"] = "true";
|
|
8106
8268
|
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.`);
|
|
8107
8269
|
},
|
|
8270
|
+
configResolved(config) {
|
|
8271
|
+
if (!hasPackageDependency("nitro")) return;
|
|
8272
|
+
const prematureExit = config.plugins.find((plugin) => plugin.name === "tanstack-build-exit");
|
|
8273
|
+
if (prematureExit) prematureExit.closeBundle = void 0;
|
|
8274
|
+
},
|
|
8108
8275
|
configEnvironment(name, config) {
|
|
8109
8276
|
if (!(config.consumer === "server" || name === "ssr" || name === "server" || config.build?.ssr === true)) return;
|
|
8110
8277
|
const isAstro = hasPackageDependency("astro");
|
|
@@ -1,14 +1,38 @@
|
|
|
1
1
|
//#region src/utils/fetchWithTimeout.ts
|
|
2
2
|
const DEFAULT_SSR_FETCH_TIMEOUT_MS = 1e4;
|
|
3
|
+
function getFetchUrl(input) {
|
|
4
|
+
const raw = typeof input === "string" || input instanceof URL ? String(input) : input.url;
|
|
5
|
+
return new URL(raw);
|
|
6
|
+
}
|
|
7
|
+
function getSecureFetchUrl(input) {
|
|
8
|
+
const url = getFetchUrl(input);
|
|
9
|
+
const isLoopback = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]";
|
|
10
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && isLoopback)) throw new TypeError(`Refusing to fetch SSR resource over an insecure connection: ${url}`);
|
|
11
|
+
return url;
|
|
12
|
+
}
|
|
3
13
|
/** Fetch with a bounded wait. Set timeoutMs to 0 to disable the timeout. */
|
|
4
|
-
function fetchWithTimeout(input, init = {}, timeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS) {
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
async function fetchWithTimeout(input, init = {}, timeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS) {
|
|
15
|
+
const inputUrl = getSecureFetchUrl(input);
|
|
16
|
+
const request = (target) => {
|
|
17
|
+
const requestInit = {
|
|
18
|
+
...init,
|
|
19
|
+
redirect: "error"
|
|
20
|
+
};
|
|
21
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) return fetch(target.href, requestInit);
|
|
22
|
+
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
23
|
+
const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
|
|
24
|
+
return fetch(target.href, {
|
|
25
|
+
...requestInit,
|
|
26
|
+
signal
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
try {
|
|
30
|
+
return await request(inputUrl);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
if (inputUrl.hostname !== "localhost") throw error;
|
|
33
|
+
inputUrl.hostname = "[::1]";
|
|
34
|
+
return request(inputUrl);
|
|
35
|
+
}
|
|
12
36
|
}
|
|
13
37
|
//#endregion
|
|
14
38
|
//#region src/utils/ssrEntryLoader.ts
|
|
@@ -347,6 +371,9 @@ function revalidate(remoteEntryUrl) {
|
|
|
347
371
|
}
|
|
348
372
|
const tempFileCache = /* @__PURE__ */ new Map();
|
|
349
373
|
const tempFilePathCache = /* @__PURE__ */ new Map();
|
|
374
|
+
function getSsrTransformContextKey(resolvedShared, shareScopeName) {
|
|
375
|
+
return JSON.stringify([shareScopeName, Object.entries(resolvedShared).sort(([left], [right]) => left.localeCompare(right))]);
|
|
376
|
+
}
|
|
350
377
|
let ssrCacheDirPromise;
|
|
351
378
|
async function getSSRCacheDir() {
|
|
352
379
|
if (!ssrCacheDirPromise) ssrCacheDirPromise = (async () => {
|
|
@@ -402,11 +429,12 @@ function isVitePreloadHelperSpecifier(specifier) {
|
|
|
402
429
|
* a remote redeploy (new manifest → new key) produces new files and bypasses
|
|
403
430
|
* Node's ESM module cache instead of serving the stale build.
|
|
404
431
|
*/
|
|
405
|
-
async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, versionKey = UNVERSIONED, fetchTimeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS) {
|
|
432
|
+
async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, versionKey = UNVERSIONED, fetchTimeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS, contextKey = "default") {
|
|
406
433
|
const cacheKey = JSON.stringify([
|
|
407
434
|
fetchTimeoutMs,
|
|
408
435
|
versionKey,
|
|
409
|
-
url
|
|
436
|
+
url,
|
|
437
|
+
contextKey
|
|
410
438
|
]);
|
|
411
439
|
if (visited.has(url)) return visited.get(url);
|
|
412
440
|
const cached = tempFileCache.get(cacheKey);
|
|
@@ -435,7 +463,7 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
|
|
|
435
463
|
while ((m = relRegex.exec(code)) !== null) if ((m[1].startsWith("./") || m[1].startsWith("../")) && !isVitePreloadHelperSpecifier(m[1])) relImports.push(new URL(m[1], base).href);
|
|
436
464
|
const subMap = /* @__PURE__ */ new Map();
|
|
437
465
|
await Promise.all([...new Set(relImports)].filter((u) => u.startsWith("http://") || u.startsWith("https://")).map(async (u) => {
|
|
438
|
-
const tmpPath = await fetchEsmToTempFile(u, tmpDir, visited, pending, sharedPkgMap, versionKey, fetchTimeoutMs);
|
|
466
|
+
const tmpPath = await fetchEsmToTempFile(u, tmpDir, visited, pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey);
|
|
439
467
|
subMap.set(u, `file://${tmpPath}`);
|
|
440
468
|
}));
|
|
441
469
|
code = transformSsrCode(code, base, sharedPkgMap);
|
|
@@ -452,18 +480,21 @@ async function fetchEsmToTempFile(url, tmpDir, visited, pending, sharedPkgMap, v
|
|
|
452
480
|
});
|
|
453
481
|
return promise;
|
|
454
482
|
}
|
|
455
|
-
async function fetchEsmGraphToTempFile(url, tmpDir, sharedPkgMap, versionKey = UNVERSIONED, fetchTimeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS) {
|
|
483
|
+
async function fetchEsmGraphToTempFile(url, tmpDir, sharedPkgMap, versionKey = UNVERSIONED, fetchTimeoutMs = DEFAULT_SSR_FETCH_TIMEOUT_MS, contextKey = "default") {
|
|
456
484
|
const pending = /* @__PURE__ */ new Set();
|
|
457
|
-
const rootFile = await fetchEsmToTempFile(url, tmpDir, /* @__PURE__ */ new Map(), pending, sharedPkgMap, versionKey, fetchTimeoutMs);
|
|
485
|
+
const rootFile = await fetchEsmToTempFile(url, tmpDir, /* @__PURE__ */ new Map(), pending, sharedPkgMap, versionKey, fetchTimeoutMs, contextKey);
|
|
458
486
|
await Promise.all(pending);
|
|
459
487
|
return rootFile;
|
|
460
488
|
}
|
|
461
489
|
async function importTempModule(filePath, versionKey) {
|
|
462
|
-
return await import(
|
|
490
|
+
return await import(
|
|
491
|
+
/* @vite-ignore */
|
|
492
|
+
`${filePath}?v=${encodeURIComponent(versionKey)}`
|
|
493
|
+
);
|
|
463
494
|
}
|
|
464
495
|
let warnedVmUnavailable = false;
|
|
465
496
|
async function tryVmStrategy(ssrEntry, options) {
|
|
466
|
-
const { loadViaVmStrategy, isVmStrategyAvailable } = await import("./ssrVmStrategy-
|
|
497
|
+
const { loadViaVmStrategy, isVmStrategyAvailable } = await import("./ssrVmStrategy-ChF8MB7l.js");
|
|
467
498
|
if (!await isVmStrategyAvailable()) {
|
|
468
499
|
if (!warnedVmUnavailable) {
|
|
469
500
|
warnedVmUnavailable = true;
|
|
@@ -475,7 +506,9 @@ async function tryVmStrategy(ssrEntry, options) {
|
|
|
475
506
|
resolvedShared: options.resolvedShared,
|
|
476
507
|
shareScopeName: options.shareScopeName,
|
|
477
508
|
versionKey: ssrEntry.versionKey,
|
|
478
|
-
fetchTimeoutMs: options.fetchTimeoutMs
|
|
509
|
+
fetchTimeoutMs: options.fetchTimeoutMs,
|
|
510
|
+
cacheContext: options.cacheContext,
|
|
511
|
+
federationInstance: options.federationInstance
|
|
479
512
|
});
|
|
480
513
|
}
|
|
481
514
|
async function loadSSRRemoteEntry(ssrEntry, options) {
|
|
@@ -514,7 +547,7 @@ async function loadSSRRemoteEntry(ssrEntry, options) {
|
|
|
514
547
|
mkdirSync(cacheDir, { recursive: true });
|
|
515
548
|
const sharedPkgMap = new Map(Object.entries(resolvedShared));
|
|
516
549
|
try {
|
|
517
|
-
return await importTempModule(await fetchEsmGraphToTempFile(url, cacheDir, sharedPkgMap, versionKey, options.fetchTimeoutMs), versionKey);
|
|
550
|
+
return await importTempModule(await fetchEsmGraphToTempFile(url, cacheDir, sharedPkgMap, versionKey, options.fetchTimeoutMs, getSsrTransformContextKey(resolvedShared, options.shareScopeName)), versionKey);
|
|
518
551
|
} catch (error) {
|
|
519
552
|
if (isSsrEntryHttpError(error)) throw error;
|
|
520
553
|
return null;
|
|
@@ -535,15 +568,21 @@ function ssrEntryLoaderPlugin(options = {}) {
|
|
|
535
568
|
strategy: options.strategy ?? "temp-file",
|
|
536
569
|
shareScopeName: options.shareScopeName ?? "default",
|
|
537
570
|
maxAgeMs: options.maxAgeMs,
|
|
538
|
-
fetchTimeoutMs: options.fetchTimeoutMs ?? 1e4
|
|
571
|
+
fetchTimeoutMs: options.fetchTimeoutMs ?? 1e4,
|
|
572
|
+
cacheContext: {}
|
|
539
573
|
};
|
|
540
574
|
return {
|
|
541
575
|
name: "mf-vite:ssr-entry-loader",
|
|
542
|
-
async loadEntry({ remoteInfo }) {
|
|
576
|
+
async loadEntry({ remoteInfo, origin }) {
|
|
543
577
|
if (!isNodeServer()) return;
|
|
544
|
-
const
|
|
578
|
+
const loadOptions = origin ? {
|
|
579
|
+
...resolved,
|
|
580
|
+
cacheContext: origin,
|
|
581
|
+
federationInstance: origin
|
|
582
|
+
} : resolved;
|
|
583
|
+
const ssrEntry = await getSSREntry(remoteInfo.entry, loadOptions.maxAgeMs, loadOptions.fetchTimeoutMs);
|
|
545
584
|
if (!ssrEntry) return;
|
|
546
|
-
const mod = await loadSSRRemoteEntry(ssrEntry,
|
|
585
|
+
const mod = await loadSSRRemoteEntry(ssrEntry, loadOptions);
|
|
547
586
|
if (!mod) return;
|
|
548
587
|
return mod;
|
|
549
588
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as neutralizeBrowserPreloadHelpers, o as fetchWithTimeout, t as SsrEntryHttpError } from "./ssrEntryLoader-
|
|
1
|
+
import { n as neutralizeBrowserPreloadHelpers, o as fetchWithTimeout, t as SsrEntryHttpError } from "./ssrEntryLoader-DgsCQOqq.js";
|
|
2
2
|
//#region src/utils/ssrVmStrategy.ts
|
|
3
3
|
/**
|
|
4
4
|
* vm.SourceTextModule strategy for loading remote SSR entries.
|
|
@@ -47,9 +47,13 @@ function getFederationInstances() {
|
|
|
47
47
|
* build-time resolvedShared file map, then plain host import.
|
|
48
48
|
*/
|
|
49
49
|
async function loadBareModule(specifier, options) {
|
|
50
|
-
|
|
50
|
+
const owner = options.federationInstance;
|
|
51
|
+
const instances = owner ? [owner] : getFederationInstances();
|
|
52
|
+
for (const instance of instances) {
|
|
51
53
|
if (typeof instance?.loadShare !== "function") continue;
|
|
52
|
-
|
|
54
|
+
const shared = instance.options?.shared?.[specifier];
|
|
55
|
+
if (!shared) continue;
|
|
56
|
+
if (!(Array.isArray(shared.scope) ? shared.scope : [shared.scope ?? "default"]).includes(options.shareScopeName)) continue;
|
|
53
57
|
try {
|
|
54
58
|
const factory = await instance.loadShare(specifier);
|
|
55
59
|
if (typeof factory === "function") {
|
|
@@ -80,6 +84,23 @@ function createSyntheticModule(vm, specifier, namespace) {
|
|
|
80
84
|
}
|
|
81
85
|
const httpModuleCache = /* @__PURE__ */ new Map();
|
|
82
86
|
const namespaceCache = /* @__PURE__ */ new Map();
|
|
87
|
+
const contextIds = /* @__PURE__ */ new WeakMap();
|
|
88
|
+
let nextContextId = 1;
|
|
89
|
+
function getContextId(context) {
|
|
90
|
+
let id = contextIds.get(context);
|
|
91
|
+
if (id === void 0) {
|
|
92
|
+
id = nextContextId++;
|
|
93
|
+
contextIds.set(context, id);
|
|
94
|
+
}
|
|
95
|
+
return id;
|
|
96
|
+
}
|
|
97
|
+
function getVmCacheContextKey(options) {
|
|
98
|
+
return JSON.stringify([
|
|
99
|
+
getContextId(options.cacheContext),
|
|
100
|
+
options.shareScopeName,
|
|
101
|
+
Object.entries(options.resolvedShared).sort(([left], [right]) => left.localeCompare(right))
|
|
102
|
+
]);
|
|
103
|
+
}
|
|
83
104
|
function getBodyPreview(body) {
|
|
84
105
|
return body.slice(0, 240).replace(/\s+/g, " ").trim();
|
|
85
106
|
}
|
|
@@ -100,6 +121,7 @@ function resolveSpecifierUrl(specifier, referencerUrl) {
|
|
|
100
121
|
}
|
|
101
122
|
function getHttpModule(vm, url, options) {
|
|
102
123
|
const cacheKey = JSON.stringify([
|
|
124
|
+
getVmCacheContextKey(options),
|
|
103
125
|
options.fetchTimeoutMs ?? 1e4,
|
|
104
126
|
options.versionKey,
|
|
105
127
|
url
|
|
@@ -139,7 +161,7 @@ async function importDynamically(vm, specifier, referencingModule, options) {
|
|
|
139
161
|
async function loadViaVmStrategy(entryUrl, options) {
|
|
140
162
|
const vm = await getVmApi();
|
|
141
163
|
if (!vm) return null;
|
|
142
|
-
const cacheKey = `${options.versionKey}::${entryUrl}`;
|
|
164
|
+
const cacheKey = `${getVmCacheContextKey(options)}::${options.versionKey}::${entryUrl}`;
|
|
143
165
|
if (!namespaceCache.has(cacheKey)) namespaceCache.set(cacheKey, (async () => {
|
|
144
166
|
const entryModule = await getHttpModule(vm, entryUrl, options);
|
|
145
167
|
const linker = (specifier, referencingModule) => linkModule(vm, specifier, referencingModule, options);
|
|
@@ -109,9 +109,11 @@ interface SsrEntryLoaderOptions {
|
|
|
109
109
|
declare function ssrEntryLoaderPlugin(options?: SsrEntryLoaderOptions): {
|
|
110
110
|
name: string;
|
|
111
111
|
loadEntry({
|
|
112
|
-
remoteInfo
|
|
112
|
+
remoteInfo,
|
|
113
|
+
origin
|
|
113
114
|
}: {
|
|
114
115
|
remoteInfo: RemoteInfo;
|
|
116
|
+
origin?: object;
|
|
115
117
|
}): Promise<{
|
|
116
118
|
init: unknown;
|
|
117
119
|
get: unknown;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as ssrEntryLoaderPlugin, n as neutralizeBrowserPreloadHelpers, r as revalidate, t as SsrEntryHttpError } from "../ssrEntryLoader-
|
|
1
|
+
import { i as ssrEntryLoaderPlugin, n as neutralizeBrowserPreloadHelpers, r as revalidate, t as SsrEntryHttpError } from "../ssrEntryLoader-DgsCQOqq.js";
|
|
2
2
|
export { SsrEntryHttpError, ssrEntryLoaderPlugin as default, neutralizeBrowserPreloadHelpers, revalidate };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@module-federation/vite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.1",
|
|
4
4
|
"description": "Vite plugin for Module Federation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -70,9 +70,9 @@
|
|
|
70
70
|
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
|
-
"@module-federation/dts-plugin": "2.
|
|
74
|
-
"@module-federation/runtime": "2.
|
|
75
|
-
"@module-federation/sdk": "2.
|
|
73
|
+
"@module-federation/dts-plugin": "2.8.0",
|
|
74
|
+
"@module-federation/runtime": "2.8.0",
|
|
75
|
+
"@module-federation/sdk": "2.8.0"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@playwright/test": "1.58.2",
|