@module-federation/vite 1.13.4 → 1.13.6
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 +42 -11
- package/lib/index.cjs +501 -82
- package/lib/index.d.cts +3 -3
- package/lib/index.d.mts +3 -3
- package/lib/index.mjs +501 -82
- package/package.json +10 -7
package/lib/index.mjs
CHANGED
|
@@ -11,6 +11,7 @@ import { normalizeOptions } from "@module-federation/sdk";
|
|
|
11
11
|
import { consumeTypesAPI, generateTypesAPI, isTSProject, normalizeConsumeTypesOptions, normalizeDtsOptions, normalizeGenerateTypesOptions } from "@module-federation/dts-plugin";
|
|
12
12
|
import { rpc } from "@module-federation/dts-plugin/core";
|
|
13
13
|
import { fileURLToPath } from "url";
|
|
14
|
+
import { init, parse as parse$1 } from "es-module-lexer";
|
|
14
15
|
//#region \0rolldown/runtime.js
|
|
15
16
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
16
17
|
//#endregion
|
|
@@ -129,11 +130,13 @@ function removePathFromNpmPackage(packageString) {
|
|
|
129
130
|
return match ? match[0] : packageString;
|
|
130
131
|
}
|
|
131
132
|
/**
|
|
132
|
-
* Detect whether the current
|
|
133
|
-
*
|
|
133
|
+
* Detect whether the current runtime is Vite 8+ by checking for a Vite version flag
|
|
134
|
+
* on the plugin hook context, with Rolldown metadata kept as a compatibility fallback.
|
|
134
135
|
*/
|
|
135
136
|
function getIsRolldown(ctx) {
|
|
136
|
-
|
|
137
|
+
const viteVersion = ctx?.meta?.viteVersion;
|
|
138
|
+
const viteMajor = Number(String(viteVersion ?? "").split(".")[0]);
|
|
139
|
+
return Number.isFinite(viteMajor) && viteMajor >= 8 || !!ctx?.meta?.rolldownVersion;
|
|
137
140
|
}
|
|
138
141
|
function hasPackageDependency(dependencyName, cwd = packageDetectionCwd || process.cwd()) {
|
|
139
142
|
const cacheKey = getDependencyCacheKey(cwd, dependencyName);
|
|
@@ -358,15 +361,17 @@ function checkAliasConflicts(options) {
|
|
|
358
361
|
};
|
|
359
362
|
}
|
|
360
363
|
//#endregion
|
|
361
|
-
//#region src/
|
|
362
|
-
/**
|
|
363
|
-
* Solve the problem that dev mode dependency prebunding does not support top-level await syntax
|
|
364
|
-
*/
|
|
364
|
+
//#region src/utils/loadWalk.ts
|
|
365
365
|
let walkPromise = null;
|
|
366
366
|
function loadWalk() {
|
|
367
367
|
walkPromise ||= import("estree-walker").then(({ walk }) => walk);
|
|
368
368
|
return walkPromise;
|
|
369
369
|
}
|
|
370
|
+
//#endregion
|
|
371
|
+
//#region src/plugins/pluginDevProxyModuleTopLevelAwait.ts
|
|
372
|
+
/**
|
|
373
|
+
* Solve the problem that dev mode dependency prebunding does not support top-level await syntax
|
|
374
|
+
*/
|
|
370
375
|
function PluginDevProxyModuleTopLevelAwait() {
|
|
371
376
|
const filterFunction = createFilter();
|
|
372
377
|
const processedFlag = "/* already-processed-by-dev-proxy-module-top-level-await */";
|
|
@@ -780,13 +785,13 @@ function normalizeLibrary(library) {
|
|
|
780
785
|
if (!library) return void 0;
|
|
781
786
|
return library;
|
|
782
787
|
}
|
|
783
|
-
function normalizeManifest(manifest
|
|
788
|
+
function normalizeManifest(manifest) {
|
|
789
|
+
if (manifest === void 0) return;
|
|
784
790
|
if (typeof manifest === "boolean") return manifest;
|
|
785
|
-
return
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
}, manifest);
|
|
791
|
+
return {
|
|
792
|
+
...manifest,
|
|
793
|
+
fileName: manifest.fileName || "mf-manifest.json"
|
|
794
|
+
};
|
|
790
795
|
}
|
|
791
796
|
let config;
|
|
792
797
|
function getNormalizeModuleFederationOptions() {
|
|
@@ -1174,7 +1179,7 @@ function generateRemotes(id, command, isRolldown) {
|
|
|
1174
1179
|
const importLine = command === "build" ? getRuntimeInitPromiseBootstrapCode() : useESM ? `${getRuntimeInitBootstrapCode()}
|
|
1175
1180
|
const { initPromise } = globalThis[globalKey];` : `const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")`;
|
|
1176
1181
|
const awaitOrPlaceholder = useESM ? "await " : "/*mf top-level-await placeholder replacement mf*/";
|
|
1177
|
-
const exportLine = command === "serve" && useESM ? "export default exportModule.default ?? exportModule" : useESM ? "export default exportModule" : "module.exports = exportModule";
|
|
1182
|
+
const exportLine = command === "serve" && useESM ? "export const __moduleExports = exportModule;\nexport default exportModule.default ?? exportModule" : useESM ? "export default exportModule" : "module.exports = exportModule";
|
|
1178
1183
|
return `
|
|
1179
1184
|
${importLine}
|
|
1180
1185
|
const res = initPromise.then(runtime => runtime.loadRemote(${JSON.stringify(id)}))
|
|
@@ -1205,6 +1210,9 @@ function escapeGeneratedStringLiteral(value) {
|
|
|
1205
1210
|
}
|
|
1206
1211
|
});
|
|
1207
1212
|
}
|
|
1213
|
+
function isValidJsIdentifier(name) {
|
|
1214
|
+
return /^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*$/u.test(name);
|
|
1215
|
+
}
|
|
1208
1216
|
const localRequire = createRequire$1(import.meta.url);
|
|
1209
1217
|
function resolvePackageEntryFromProjectRoot(pkg) {
|
|
1210
1218
|
try {
|
|
@@ -1288,7 +1296,7 @@ function getEsmNamedExports(pkg) {
|
|
|
1288
1296
|
const { initSync, parse } = localRequire("es-module-lexer");
|
|
1289
1297
|
initSync();
|
|
1290
1298
|
const [, exports] = parse(readFileSync(entryPath, "utf-8"), entryPath);
|
|
1291
|
-
return exports.map((item) => item.n).filter((name) => !!name && name !== "default" && name !== "__esModule" &&
|
|
1299
|
+
return exports.map((item) => item.n).filter((name) => !!name && name !== "default" && name !== "__esModule" && isValidJsIdentifier(name));
|
|
1292
1300
|
} catch {
|
|
1293
1301
|
return [];
|
|
1294
1302
|
}
|
|
@@ -1296,7 +1304,7 @@ function getEsmNamedExports(pkg) {
|
|
|
1296
1304
|
function getPackageNamedExports(pkg) {
|
|
1297
1305
|
try {
|
|
1298
1306
|
const mod = createRequire$1(new URL(`file://${path.join(getPackageDetectionCwd(), "package.json")}`))(pkg);
|
|
1299
|
-
return Object.keys(mod).filter((k) => k !== "default" && k !== "__esModule" &&
|
|
1307
|
+
return Object.keys(mod).filter((k) => k !== "default" && k !== "__esModule" && isValidJsIdentifier(k));
|
|
1300
1308
|
} catch {
|
|
1301
1309
|
return getEsmNamedExports(pkg);
|
|
1302
1310
|
}
|
|
@@ -1385,7 +1393,9 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
|
1385
1393
|
`, true);
|
|
1386
1394
|
return;
|
|
1387
1395
|
}
|
|
1388
|
-
const
|
|
1396
|
+
const isVinext = hasPackageDependency("vinext");
|
|
1397
|
+
const isAstro = hasPackageDependency("astro");
|
|
1398
|
+
const useSsrProviderFallback = (isVinext || isAstro) && command === "build" && pkg === "react";
|
|
1389
1399
|
const concreteSharedImportSource = getConcreteSharedImportSource(pkg, shareItem);
|
|
1390
1400
|
const sharedImportSource = concreteSharedImportSource || getPreBuildLibImportId(pkg);
|
|
1391
1401
|
const devImportSource = concreteSharedImportSource || pkg;
|
|
@@ -1440,6 +1450,8 @@ function writeLocalSharedImportMap() {
|
|
|
1440
1450
|
}
|
|
1441
1451
|
function generateLocalSharedImportMap() {
|
|
1442
1452
|
const isVinext = hasPackageDependency("vinext");
|
|
1453
|
+
const isAstro = hasPackageDependency("astro");
|
|
1454
|
+
const useDirectReactImport = isVinext || isAstro;
|
|
1443
1455
|
const options = getNormalizeModuleFederationOptions();
|
|
1444
1456
|
return `
|
|
1445
1457
|
import {loadShare} from "@module-federation/runtime";
|
|
@@ -1448,7 +1460,7 @@ function generateLocalSharedImportMap() {
|
|
|
1448
1460
|
const shareItem = getNormalizeShareItem(pkg);
|
|
1449
1461
|
return `
|
|
1450
1462
|
${JSON.stringify(pkg)}: async () => {
|
|
1451
|
-
${shareItem?.shareConfig.import === false ? `throw new Error(\`[Module Federation] Shared module '\${${JSON.stringify(pkg)}}' must be provided by host\`);` :
|
|
1463
|
+
${shareItem?.shareConfig.import === false ? `throw new Error(\`[Module Federation] Shared module '\${${JSON.stringify(pkg)}}' must be provided by host\`);` : useDirectReactImport && pkg === "react" ? `let pkg = await import("react");
|
|
1452
1464
|
return pkg;` : `let pkg = await import(${JSON.stringify(getSharedImportSource(pkg, shareItem))});
|
|
1453
1465
|
return pkg;`}
|
|
1454
1466
|
}
|
|
@@ -1473,7 +1485,7 @@ function generateLocalSharedImportMap() {
|
|
|
1473
1485
|
usedShared[${JSON.stringify(key)}].loaded = true
|
|
1474
1486
|
const {${JSON.stringify(key)}: pkgDynamicImport} = importMap
|
|
1475
1487
|
const res = await pkgDynamicImport()
|
|
1476
|
-
const exportModule = ${JSON.stringify(
|
|
1488
|
+
const exportModule = ${JSON.stringify(useDirectReactImport)} && ${JSON.stringify(key)} === "react"
|
|
1477
1489
|
? (res?.default ?? res)
|
|
1478
1490
|
: {...res}
|
|
1479
1491
|
// All npm packages pre-built by vite will be converted to esm
|
|
@@ -1788,7 +1800,7 @@ const buildFileToShareKeyMap = async (shareKeys, resolveFn) => {
|
|
|
1788
1800
|
* @returns The resolved public path
|
|
1789
1801
|
*/
|
|
1790
1802
|
function resolvePublicPath(options, viteBase, originalBase) {
|
|
1791
|
-
if (options.publicPath) return options.publicPath;
|
|
1803
|
+
if (options.publicPath && options.publicPath !== "auto") return options.publicPath;
|
|
1792
1804
|
if (originalBase === "") return "auto";
|
|
1793
1805
|
if (viteBase) return viteBase.replace(/\/?$/, "/");
|
|
1794
1806
|
return "auto";
|
|
@@ -1798,9 +1810,17 @@ function resolvePublicPath(options, viteBase, originalBase) {
|
|
|
1798
1810
|
const Manifest = () => {
|
|
1799
1811
|
const mfOptions = getNormalizeModuleFederationOptions();
|
|
1800
1812
|
const { name, filename, getPublicPath, manifest: manifestOptions, varFilename } = mfOptions;
|
|
1801
|
-
let mfManifestName = "";
|
|
1802
|
-
|
|
1803
|
-
|
|
1813
|
+
let mfManifestName = manifestOptions === true ? "mf-manifest.json" : typeof manifestOptions === "object" ? path$1.join(manifestOptions?.filePath || "", manifestOptions?.fileName || "mf-manifest.json") : void 0;
|
|
1814
|
+
let mfManifestStatsName = mfManifestName ? getStatsFileName(mfManifestName) : void 0;
|
|
1815
|
+
const isConsumerProject = Object.keys(mfOptions.exposes).length === 0;
|
|
1816
|
+
let disableAssetsAnalyze = false;
|
|
1817
|
+
const getDefaultDisableAssetsAnalyze = (command) => command === "serve" && isConsumerProject && (typeof manifestOptions !== "object" || !Object.prototype.hasOwnProperty.call(manifestOptions, "disableAssetsAnalyze"));
|
|
1818
|
+
const getConfiguredDisableAssetsAnalyze = (command) => {
|
|
1819
|
+
if (typeof manifestOptions === "object" && manifestOptions !== null) {
|
|
1820
|
+
if (Object.prototype.hasOwnProperty.call(manifestOptions, "disableAssetsAnalyze")) return manifestOptions.disableAssetsAnalyze === true;
|
|
1821
|
+
}
|
|
1822
|
+
return getDefaultDisableAssetsAnalyze(command);
|
|
1823
|
+
};
|
|
1804
1824
|
let root;
|
|
1805
1825
|
let remoteEntryFile;
|
|
1806
1826
|
let publicPath;
|
|
@@ -1835,7 +1855,7 @@ const Manifest = () => {
|
|
|
1835
1855
|
res.setHeader("Content-Type", "application/json");
|
|
1836
1856
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
1837
1857
|
res.end(JSON.stringify({
|
|
1838
|
-
...generateMFManifest({}),
|
|
1858
|
+
...generateMFManifest({}, disableAssetsAnalyze),
|
|
1839
1859
|
id: name,
|
|
1840
1860
|
name,
|
|
1841
1861
|
metaData: {
|
|
@@ -1876,9 +1896,10 @@ const Manifest = () => {
|
|
|
1876
1896
|
name: "module-federation-manifest",
|
|
1877
1897
|
enforce: "post",
|
|
1878
1898
|
config(config, { command }) {
|
|
1879
|
-
if (!config.build) config.build = {};
|
|
1880
|
-
if (!config.build.manifest) config.build.manifest = config.build.manifest || !!manifestOptions;
|
|
1881
1899
|
_command = command;
|
|
1900
|
+
if (!config.build) config.build = {};
|
|
1901
|
+
if (!config.build.manifest) config.build.manifest = config.build.manifest || !!mfManifestName;
|
|
1902
|
+
disableAssetsAnalyze = getConfiguredDisableAssetsAnalyze(command);
|
|
1882
1903
|
_originalConfigBase = config.base;
|
|
1883
1904
|
},
|
|
1884
1905
|
configResolved(config) {
|
|
@@ -1892,28 +1913,35 @@ const Manifest = () => {
|
|
|
1892
1913
|
let filesMap = {};
|
|
1893
1914
|
const foundRemoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
|
|
1894
1915
|
if (foundRemoteEntryFile) remoteEntryFile = foundRemoteEntryFile;
|
|
1895
|
-
const allCssAssets = mfOptions.bundleAllCSS ? collectCssAssets(bundle) : /* @__PURE__ */ new Set();
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
const
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1916
|
+
const allCssAssets = mfOptions.bundleAllCSS && !disableAssetsAnalyze ? collectCssAssets(bundle) : /* @__PURE__ */ new Set();
|
|
1917
|
+
if (!disableAssetsAnalyze) {
|
|
1918
|
+
const exposesModules = Object.keys(mfOptions.exposes).map((item) => mfOptions.exposes[item].import);
|
|
1919
|
+
processModuleAssets(bundle, filesMap, (modulePath) => {
|
|
1920
|
+
const absoluteModulePath = path$1.resolve(root, modulePath);
|
|
1921
|
+
return exposesModules.find((exposeModule) => {
|
|
1922
|
+
const exposePath = path$1.resolve(root, exposeModule);
|
|
1923
|
+
if (absoluteModulePath === exposePath) return true;
|
|
1924
|
+
const getPathWithoutKnownExt = (filePath) => {
|
|
1925
|
+
const ext = path$1.extname(filePath);
|
|
1926
|
+
return JS_EXTENSIONS.includes(ext) ? path$1.join(path$1.dirname(filePath), path$1.basename(filePath, ext)) : filePath;
|
|
1927
|
+
};
|
|
1928
|
+
return getPathWithoutKnownExt(absoluteModulePath) === getPathWithoutKnownExt(exposePath);
|
|
1929
|
+
});
|
|
1907
1930
|
});
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1931
|
+
const fileToShareKey = await buildFileToShareKeyMap(getUsedShares(), this.resolve.bind(this));
|
|
1932
|
+
processModuleAssets(bundle, filesMap, (modulePath) => fileToShareKey.get(modulePath));
|
|
1933
|
+
if (mfOptions.bundleAllCSS) addCssAssetsToAllExports(filesMap, allCssAssets);
|
|
1934
|
+
filesMap = deduplicateAssets(filesMap);
|
|
1935
|
+
}
|
|
1913
1936
|
this.emitFile({
|
|
1914
1937
|
type: "asset",
|
|
1915
1938
|
fileName: mfManifestName,
|
|
1916
|
-
source: JSON.stringify(generateMFManifest(filesMap))
|
|
1939
|
+
source: JSON.stringify(generateMFManifest(filesMap, disableAssetsAnalyze))
|
|
1940
|
+
});
|
|
1941
|
+
if (mfManifestStatsName) this.emitFile({
|
|
1942
|
+
type: "asset",
|
|
1943
|
+
fileName: mfManifestStatsName,
|
|
1944
|
+
source: JSON.stringify(generateMFStats(filesMap, bundle, disableAssetsAnalyze))
|
|
1917
1945
|
});
|
|
1918
1946
|
}
|
|
1919
1947
|
}];
|
|
@@ -1922,7 +1950,7 @@ const Manifest = () => {
|
|
|
1922
1950
|
* @param preloadMap - Map of module assets to include
|
|
1923
1951
|
* @returns Complete manifest object
|
|
1924
1952
|
*/
|
|
1925
|
-
function generateMFManifest(preloadMap) {
|
|
1953
|
+
function generateMFManifest(preloadMap, disableAssetsAnalyze = false) {
|
|
1926
1954
|
const options = getNormalizeModuleFederationOptions();
|
|
1927
1955
|
const { name, varFilename } = options;
|
|
1928
1956
|
const remoteEntry = {
|
|
@@ -1948,6 +1976,7 @@ const Manifest = () => {
|
|
|
1948
1976
|
id: `${name}:${shareKey}`,
|
|
1949
1977
|
name: shareKey,
|
|
1950
1978
|
version: shareItem.version,
|
|
1979
|
+
singleton: shareItem.shareConfig.singleton,
|
|
1951
1980
|
requiredVersion: shareItem.shareConfig.requiredVersion,
|
|
1952
1981
|
assets: {
|
|
1953
1982
|
js: {
|
|
@@ -2001,12 +2030,33 @@ const Manifest = () => {
|
|
|
2001
2030
|
pluginVersion: "0.2.5",
|
|
2002
2031
|
...!!getPublicPath ? { getPublicPath } : { publicPath }
|
|
2003
2032
|
},
|
|
2004
|
-
shared,
|
|
2033
|
+
...disableAssetsAnalyze ? {} : { shared },
|
|
2005
2034
|
remotes,
|
|
2006
|
-
exposes
|
|
2035
|
+
...disableAssetsAnalyze ? {} : { exposes }
|
|
2036
|
+
};
|
|
2037
|
+
}
|
|
2038
|
+
function generateMFStats(preloadMap, bundle, disableAssetsAnalyze = false) {
|
|
2039
|
+
const baseManifest = generateMFManifest(preloadMap, disableAssetsAnalyze);
|
|
2040
|
+
const bundleSummary = Object.entries(bundle).map(([fileName, chunkOrAsset]) => ({
|
|
2041
|
+
fileName,
|
|
2042
|
+
type: chunkOrAsset.type,
|
|
2043
|
+
isEntry: chunkOrAsset.isEntry || false,
|
|
2044
|
+
size: typeof chunkOrAsset.code === "string" ? chunkOrAsset.code.length : chunkOrAsset.source?.length || chunkOrAsset.source?.byteLength || void 0
|
|
2045
|
+
}));
|
|
2046
|
+
return {
|
|
2047
|
+
...baseManifest,
|
|
2048
|
+
buildOutput: bundleSummary,
|
|
2049
|
+
...disableAssetsAnalyze ? {} : { assetAnalysis: preloadMap }
|
|
2007
2050
|
};
|
|
2008
2051
|
}
|
|
2009
2052
|
};
|
|
2053
|
+
function getStatsFileName(manifestFileName) {
|
|
2054
|
+
const parsed = path$1.parse(manifestFileName);
|
|
2055
|
+
const fileExt = parsed.ext || ".json";
|
|
2056
|
+
const baseName = parsed.ext ? parsed.name : parsed.base;
|
|
2057
|
+
const fileName = `${baseName === "mf-manifest" ? "mf" : baseName}-stats${fileExt}`;
|
|
2058
|
+
return parsed.dir ? path$1.join(parsed.dir, fileName) : fileName;
|
|
2059
|
+
}
|
|
2010
2060
|
//#endregion
|
|
2011
2061
|
//#region src/plugins/pluginModuleParseEnd.ts
|
|
2012
2062
|
let _resolve, _parseTimeout;
|
|
@@ -2251,7 +2301,7 @@ function proxySharedModule(options) {
|
|
|
2251
2301
|
const { shared = {} } = options;
|
|
2252
2302
|
let _config;
|
|
2253
2303
|
let _command = "serve";
|
|
2254
|
-
let
|
|
2304
|
+
let useDirectReactImport = false;
|
|
2255
2305
|
const savePrebuild = new PromiseStore();
|
|
2256
2306
|
return [{
|
|
2257
2307
|
name: "generateLocalSharedImportMap",
|
|
@@ -2267,10 +2317,12 @@ function proxySharedModule(options) {
|
|
|
2267
2317
|
enforce: "post",
|
|
2268
2318
|
config(config, { command }) {
|
|
2269
2319
|
setPackageDetectionCwd(config.root || process.cwd());
|
|
2270
|
-
isVinext = hasPackageDependency("vinext");
|
|
2320
|
+
const isVinext = hasPackageDependency("vinext");
|
|
2321
|
+
const isAstro = hasPackageDependency("astro");
|
|
2271
2322
|
const isRolldown = getIsRolldown(this);
|
|
2272
2323
|
_command = command;
|
|
2273
|
-
|
|
2324
|
+
useDirectReactImport = isVinext || isAstro;
|
|
2325
|
+
config.resolve.alias.push(...Object.keys(shared).filter((key) => !(useDirectReactImport && key === "react")).map((key) => {
|
|
2274
2326
|
const keyBase = key.endsWith("/") ? key.slice(0, -1) : key;
|
|
2275
2327
|
const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2276
2328
|
const escapedKeyBase = escapeRegex(keyBase);
|
|
@@ -2280,7 +2332,7 @@ function proxySharedModule(options) {
|
|
|
2280
2332
|
replacement: "$1",
|
|
2281
2333
|
customResolver(source, importer) {
|
|
2282
2334
|
if (/\.css$/.test(source)) return;
|
|
2283
|
-
if (
|
|
2335
|
+
if (useDirectReactImport && source === "react") return;
|
|
2284
2336
|
if (importer && importer.includes("localSharedImportMap")) return;
|
|
2285
2337
|
if (key.endsWith("/") && source !== key.slice(0, -1)) return;
|
|
2286
2338
|
const loadSharePath = getLoadShareModulePath(source, isRolldown, command);
|
|
@@ -2292,7 +2344,7 @@ function proxySharedModule(options) {
|
|
|
2292
2344
|
}
|
|
2293
2345
|
};
|
|
2294
2346
|
}));
|
|
2295
|
-
config.resolve.alias.push(...Object.keys(shared).filter((key) => !(
|
|
2347
|
+
config.resolve.alias.push(...Object.keys(shared).filter((key) => !(useDirectReactImport && key === "react")).map((key) => {
|
|
2296
2348
|
return command === "build" ? {
|
|
2297
2349
|
find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
|
|
2298
2350
|
replacement: function($1) {
|
|
@@ -2316,10 +2368,10 @@ function proxySharedModule(options) {
|
|
|
2316
2368
|
},
|
|
2317
2369
|
configResolved(config) {
|
|
2318
2370
|
_config = config;
|
|
2319
|
-
const isRolldown =
|
|
2371
|
+
const isRolldown = getIsRolldown(this);
|
|
2320
2372
|
Object.keys(shared).forEach((key) => {
|
|
2321
2373
|
if (key.endsWith("/")) return;
|
|
2322
|
-
if (
|
|
2374
|
+
if (useDirectReactImport && key === "react") {
|
|
2323
2375
|
addUsedShares(key);
|
|
2324
2376
|
return;
|
|
2325
2377
|
}
|
|
@@ -2332,6 +2384,345 @@ function proxySharedModule(options) {
|
|
|
2332
2384
|
}];
|
|
2333
2385
|
}
|
|
2334
2386
|
//#endregion
|
|
2387
|
+
//#region src/plugins/pluginRemoteNamedExports.ts
|
|
2388
|
+
/**
|
|
2389
|
+
* Transforms consumer-side imports of remote modules so that named exports
|
|
2390
|
+
* are accessible even when the bundler does not support syntheticNamedExports
|
|
2391
|
+
* (Rolldown / Vite 8+).
|
|
2392
|
+
*
|
|
2393
|
+
* The remote proxy module exports:
|
|
2394
|
+
* export const __moduleExports = exportModule; // full namespace
|
|
2395
|
+
* export default exportModule.default ?? exportModule; // unwrapped default
|
|
2396
|
+
*
|
|
2397
|
+
* This plugin rewrites consumer code:
|
|
2398
|
+
* import { foo } from "remote/xxx"
|
|
2399
|
+
* → import { __moduleExports as __mf_ns_0 } from "remote/xxx"; const { foo } = __mf_ns_0;
|
|
2400
|
+
*
|
|
2401
|
+
* import("remote/xxx")
|
|
2402
|
+
* → import("remote/xxx").then(…) // spreads __moduleExports into namespace
|
|
2403
|
+
*
|
|
2404
|
+
* NOTE: `export * from "remote/xxx"` is not supported — Rolldown cannot
|
|
2405
|
+
* statically resolve the set of exported names from a federated remote at
|
|
2406
|
+
* build time. Use explicit named re-exports instead.
|
|
2407
|
+
*/
|
|
2408
|
+
const JS_EXTENSIONS_RE = /\.(?:[mc]?[jt]sx?|vue|svelte)(?:\?|$)/;
|
|
2409
|
+
const REGEX_FALLBACK_EXTENSIONS_RE = /\.(?:[mc]?[jt]sx?)(?:\?|$)/;
|
|
2410
|
+
function wrapDynamicImport(original) {
|
|
2411
|
+
return `${original}.then(function(__mf_m__) {\n if (!__mf_m__ || !__mf_m__.__moduleExports) return __mf_m__;\n var __mf_ns__ = Object.create(null);\n Object.defineProperty(__mf_ns__, Symbol.toStringTag, { value: "Module" });\n var __mf_e__ = __mf_m__.__moduleExports;\n Object.keys(__mf_e__).forEach(function(k) { if (k !== "__esModule") __mf_ns__[k] = __mf_e__[k] });\n if ("default" in __mf_m__) __mf_ns__.default = __mf_m__.default;\n return __mf_ns__;\n})`;
|
|
2412
|
+
}
|
|
2413
|
+
function applyRewrites(code, imports, id) {
|
|
2414
|
+
if (imports.length === 0) return;
|
|
2415
|
+
const ms = new MagicString(code);
|
|
2416
|
+
let changed = false;
|
|
2417
|
+
let counter = 0;
|
|
2418
|
+
for (const imp of imports) switch (imp.kind) {
|
|
2419
|
+
case "static": {
|
|
2420
|
+
const src = JSON.stringify(imp.source);
|
|
2421
|
+
if (imp.namespaceLocal && !imp.defaultLocal && imp.named.length === 0) ms.overwrite(imp.start, imp.end, `import { __moduleExports as ${imp.namespaceLocal} } from ${src};`);
|
|
2422
|
+
else {
|
|
2423
|
+
const nsId = `__mf_ns_${counter++}`;
|
|
2424
|
+
const importParts = [];
|
|
2425
|
+
if (imp.defaultLocal) importParts.push(`default as ${imp.defaultLocal}`);
|
|
2426
|
+
importParts.push(`__moduleExports as ${nsId}`);
|
|
2427
|
+
const destructParts = imp.named.map((s) => s.imported === s.local ? s.local : `${s.imported}: ${s.local}`);
|
|
2428
|
+
let rewrite = `import { ${importParts.join(", ")} } from ${src};`;
|
|
2429
|
+
if (destructParts.length > 0) rewrite += `\nconst { ${destructParts.join(", ")} } = ${nsId};`;
|
|
2430
|
+
ms.overwrite(imp.start, imp.end, rewrite);
|
|
2431
|
+
}
|
|
2432
|
+
changed = true;
|
|
2433
|
+
break;
|
|
2434
|
+
}
|
|
2435
|
+
case "reexport": {
|
|
2436
|
+
const src = JSON.stringify(imp.source);
|
|
2437
|
+
const nsId = `__mf_ns_${counter++}`;
|
|
2438
|
+
const vars = imp.specifiers.map((s) => {
|
|
2439
|
+
const tmp = `__mf_re_${counter++}`;
|
|
2440
|
+
return {
|
|
2441
|
+
...s,
|
|
2442
|
+
tmp
|
|
2443
|
+
};
|
|
2444
|
+
});
|
|
2445
|
+
const importLine = `import { __moduleExports as ${nsId} } from ${src};`;
|
|
2446
|
+
const varLines = vars.map((v) => `const ${v.tmp} = ${nsId}[${JSON.stringify(v.local)}];`).join("\n");
|
|
2447
|
+
const exportLine = `export { ${vars.map((v) => `${v.tmp} as ${v.exported}`).join(", ")} };`;
|
|
2448
|
+
ms.overwrite(imp.start, imp.end, `${importLine}\n${varLines}\n${exportLine}`);
|
|
2449
|
+
changed = true;
|
|
2450
|
+
break;
|
|
2451
|
+
}
|
|
2452
|
+
case "export-all":
|
|
2453
|
+
console.warn(`[module-federation] "export * from '${imp.source}'" is not supported with Rolldown — use explicit named re-exports instead. (${id})`);
|
|
2454
|
+
break;
|
|
2455
|
+
case "dynamic":
|
|
2456
|
+
ms.overwrite(imp.start, imp.end, wrapDynamicImport(imp.originalText));
|
|
2457
|
+
changed = true;
|
|
2458
|
+
break;
|
|
2459
|
+
}
|
|
2460
|
+
if (!changed) return;
|
|
2461
|
+
return {
|
|
2462
|
+
code: ms.toString(),
|
|
2463
|
+
map: ms.generateMap({ hires: true })
|
|
2464
|
+
};
|
|
2465
|
+
}
|
|
2466
|
+
async function collectFromAST(ast, code, isRemoteImport) {
|
|
2467
|
+
const walk = await loadWalk();
|
|
2468
|
+
const result = [];
|
|
2469
|
+
walk(ast, { enter(node) {
|
|
2470
|
+
if (node.type === "ImportDeclaration" && node.source?.value) {
|
|
2471
|
+
if (!isRemoteImport(node.source.value)) return;
|
|
2472
|
+
const specifiers = node.specifiers || [];
|
|
2473
|
+
const named = specifiers.filter((s) => s.type === "ImportSpecifier" && s.importKind !== "type").map((s) => ({
|
|
2474
|
+
imported: s.imported.name ?? s.imported.value,
|
|
2475
|
+
local: s.local.name
|
|
2476
|
+
}));
|
|
2477
|
+
const defaultSpec = specifiers.find((s) => s.type === "ImportDefaultSpecifier");
|
|
2478
|
+
const nsSpec = specifiers.find((s) => s.type === "ImportNamespaceSpecifier");
|
|
2479
|
+
if (named.length === 0 && !nsSpec) return;
|
|
2480
|
+
result.push({
|
|
2481
|
+
kind: "static",
|
|
2482
|
+
source: node.source.value,
|
|
2483
|
+
start: node.start,
|
|
2484
|
+
end: node.end,
|
|
2485
|
+
named,
|
|
2486
|
+
defaultLocal: defaultSpec?.local.name,
|
|
2487
|
+
namespaceLocal: nsSpec?.local.name
|
|
2488
|
+
});
|
|
2489
|
+
}
|
|
2490
|
+
if (node.type === "ExportNamedDeclaration" && node.source?.value && isRemoteImport(node.source.value)) {
|
|
2491
|
+
const specifiers = (node.specifiers || []).filter((s) => s.exportKind !== "type").map((s) => ({
|
|
2492
|
+
local: s.local.name ?? s.local.value,
|
|
2493
|
+
exported: s.exported.name ?? s.exported.value
|
|
2494
|
+
}));
|
|
2495
|
+
if (specifiers.length === 0) return;
|
|
2496
|
+
result.push({
|
|
2497
|
+
kind: "reexport",
|
|
2498
|
+
source: node.source.value,
|
|
2499
|
+
start: node.start,
|
|
2500
|
+
end: node.end,
|
|
2501
|
+
specifiers
|
|
2502
|
+
});
|
|
2503
|
+
}
|
|
2504
|
+
if (node.type === "ExportAllDeclaration" && node.source?.value && isRemoteImport(node.source.value)) {
|
|
2505
|
+
this.skip();
|
|
2506
|
+
result.push({
|
|
2507
|
+
kind: "export-all",
|
|
2508
|
+
source: node.source.value,
|
|
2509
|
+
start: node.start,
|
|
2510
|
+
end: node.end
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2513
|
+
if (node.type === "ImportExpression") {
|
|
2514
|
+
const source = node.source;
|
|
2515
|
+
if (source.type !== "Literal" && source.type !== "StringLiteral" && source.type !== "TemplateLiteral") return;
|
|
2516
|
+
const value = source.type === "TemplateLiteral" ? source.quasis?.length === 1 ? source.quasis[0].value?.cooked : void 0 : source.value;
|
|
2517
|
+
if (!value || !isRemoteImport(value)) return;
|
|
2518
|
+
result.push({
|
|
2519
|
+
kind: "dynamic",
|
|
2520
|
+
start: node.start,
|
|
2521
|
+
end: node.end,
|
|
2522
|
+
originalText: code.slice(node.start, node.end)
|
|
2523
|
+
});
|
|
2524
|
+
}
|
|
2525
|
+
} });
|
|
2526
|
+
return result;
|
|
2527
|
+
}
|
|
2528
|
+
async function collectFromEsLexer(code, isRemoteImport) {
|
|
2529
|
+
await init;
|
|
2530
|
+
let imports;
|
|
2531
|
+
try {
|
|
2532
|
+
[imports] = parse$1(code);
|
|
2533
|
+
} catch {
|
|
2534
|
+
return;
|
|
2535
|
+
}
|
|
2536
|
+
const result = [];
|
|
2537
|
+
for (const imp of imports) {
|
|
2538
|
+
if (imp.d === -2) continue;
|
|
2539
|
+
if (!imp.n || !isRemoteImport(imp.n)) continue;
|
|
2540
|
+
const stmtText = code.slice(imp.ss, imp.se);
|
|
2541
|
+
if (imp.d >= 0) {
|
|
2542
|
+
result.push({
|
|
2543
|
+
kind: "dynamic",
|
|
2544
|
+
start: imp.ss,
|
|
2545
|
+
end: imp.se,
|
|
2546
|
+
originalText: stmtText
|
|
2547
|
+
});
|
|
2548
|
+
continue;
|
|
2549
|
+
}
|
|
2550
|
+
if (/^\s*export\s*\*\s/.test(stmtText)) {
|
|
2551
|
+
result.push({
|
|
2552
|
+
kind: "export-all",
|
|
2553
|
+
source: imp.n,
|
|
2554
|
+
start: imp.ss,
|
|
2555
|
+
end: imp.se
|
|
2556
|
+
});
|
|
2557
|
+
continue;
|
|
2558
|
+
}
|
|
2559
|
+
if (/^\s*export\s/.test(stmtText)) {
|
|
2560
|
+
const braceMatch = stmtText.match(/\{([^}]*)\}/);
|
|
2561
|
+
if (!braceMatch) continue;
|
|
2562
|
+
const specs = braceMatch[1].split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
2563
|
+
if (specs.length === 0) continue;
|
|
2564
|
+
const specifiers = specs.map((s) => {
|
|
2565
|
+
const asMatch = s.match(/^(\w+)\s+as\s+(\w+)$/);
|
|
2566
|
+
return {
|
|
2567
|
+
local: asMatch ? asMatch[1] : s,
|
|
2568
|
+
exported: asMatch ? asMatch[2] : s
|
|
2569
|
+
};
|
|
2570
|
+
});
|
|
2571
|
+
result.push({
|
|
2572
|
+
kind: "reexport",
|
|
2573
|
+
source: imp.n,
|
|
2574
|
+
start: imp.ss,
|
|
2575
|
+
end: imp.se,
|
|
2576
|
+
specifiers
|
|
2577
|
+
});
|
|
2578
|
+
continue;
|
|
2579
|
+
}
|
|
2580
|
+
const importMatch = stmtText.match(/^import\s+([\s\S]*?)\s+from\s/);
|
|
2581
|
+
if (!importMatch) continue;
|
|
2582
|
+
const specifiersPart = importMatch[1].trim();
|
|
2583
|
+
if (/^type\s/.test(specifiersPart)) continue;
|
|
2584
|
+
const nsMatch = specifiersPart.match(/^\*\s+as\s+(\w+)$/);
|
|
2585
|
+
if (nsMatch) {
|
|
2586
|
+
result.push({
|
|
2587
|
+
kind: "static",
|
|
2588
|
+
source: imp.n,
|
|
2589
|
+
start: imp.ss,
|
|
2590
|
+
end: imp.se,
|
|
2591
|
+
named: [],
|
|
2592
|
+
namespaceLocal: nsMatch[1]
|
|
2593
|
+
});
|
|
2594
|
+
continue;
|
|
2595
|
+
}
|
|
2596
|
+
const braceMatch = specifiersPart.match(/\{([^}]*)\}/);
|
|
2597
|
+
if (!braceMatch) continue;
|
|
2598
|
+
const namedSpecifiers = braceMatch[1].split(",").map((s) => s.trim()).filter((s) => s.length > 0 && !s.startsWith("type "));
|
|
2599
|
+
if (namedSpecifiers.length === 0) continue;
|
|
2600
|
+
const defaultMatch = specifiersPart.match(/^(\w+)\s*,/);
|
|
2601
|
+
const named = namedSpecifiers.map((s) => {
|
|
2602
|
+
const asMatch = s.match(/^(\w+)\s+as\s+(\w+)$/);
|
|
2603
|
+
return {
|
|
2604
|
+
imported: asMatch ? asMatch[1] : s,
|
|
2605
|
+
local: asMatch ? asMatch[2] : s
|
|
2606
|
+
};
|
|
2607
|
+
});
|
|
2608
|
+
result.push({
|
|
2609
|
+
kind: "static",
|
|
2610
|
+
source: imp.n,
|
|
2611
|
+
start: imp.ss,
|
|
2612
|
+
end: imp.se,
|
|
2613
|
+
named,
|
|
2614
|
+
defaultLocal: defaultMatch?.[1]
|
|
2615
|
+
});
|
|
2616
|
+
}
|
|
2617
|
+
return result;
|
|
2618
|
+
}
|
|
2619
|
+
function collectFromRegex(code, isRemoteImport) {
|
|
2620
|
+
const result = [];
|
|
2621
|
+
for (const match of code.matchAll(/^\s*import\s+([\s\S]*?)\s+from\s+(['"])([^'"]+)\2\s*;?/gm)) {
|
|
2622
|
+
const [full, specifiersPartRaw, , source] = match;
|
|
2623
|
+
if (!isRemoteImport(source)) continue;
|
|
2624
|
+
const specifiersPart = specifiersPartRaw.trim();
|
|
2625
|
+
if (/^type\s/.test(specifiersPart)) continue;
|
|
2626
|
+
const nsMatch = specifiersPart.match(/^\*\s+as\s+(\w+)$/);
|
|
2627
|
+
if (nsMatch) {
|
|
2628
|
+
result.push({
|
|
2629
|
+
kind: "static",
|
|
2630
|
+
source,
|
|
2631
|
+
start: match.index,
|
|
2632
|
+
end: match.index + full.length,
|
|
2633
|
+
named: [],
|
|
2634
|
+
namespaceLocal: nsMatch[1]
|
|
2635
|
+
});
|
|
2636
|
+
continue;
|
|
2637
|
+
}
|
|
2638
|
+
const braceMatch = specifiersPart.match(/\{([^}]*)\}/);
|
|
2639
|
+
if (!braceMatch) continue;
|
|
2640
|
+
const namedSpecifiers = braceMatch[1].split(",").map((s) => s.trim()).filter((s) => s.length > 0 && !s.startsWith("type "));
|
|
2641
|
+
if (namedSpecifiers.length === 0) continue;
|
|
2642
|
+
const defaultMatch = specifiersPart.match(/^(\w+)\s*,/);
|
|
2643
|
+
const named = namedSpecifiers.map((s) => {
|
|
2644
|
+
const asMatch = s.match(/^(\w+)\s+as\s+(\w+)$/);
|
|
2645
|
+
return {
|
|
2646
|
+
imported: asMatch ? asMatch[1] : s,
|
|
2647
|
+
local: asMatch ? asMatch[2] : s
|
|
2648
|
+
};
|
|
2649
|
+
});
|
|
2650
|
+
result.push({
|
|
2651
|
+
kind: "static",
|
|
2652
|
+
source,
|
|
2653
|
+
start: match.index,
|
|
2654
|
+
end: match.index + full.length,
|
|
2655
|
+
named,
|
|
2656
|
+
defaultLocal: defaultMatch?.[1]
|
|
2657
|
+
});
|
|
2658
|
+
}
|
|
2659
|
+
for (const match of code.matchAll(/^\s*export\s+\{([\s\S]*?)\}\s+from\s+(['"])([^'"]+)\2\s*;?/gm)) {
|
|
2660
|
+
const [full, specifiersRaw, , source] = match;
|
|
2661
|
+
if (!isRemoteImport(source)) continue;
|
|
2662
|
+
const specs = specifiersRaw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
2663
|
+
if (specs.length === 0) continue;
|
|
2664
|
+
result.push({
|
|
2665
|
+
kind: "reexport",
|
|
2666
|
+
source,
|
|
2667
|
+
start: match.index,
|
|
2668
|
+
end: match.index + full.length,
|
|
2669
|
+
specifiers: specs.map((s) => {
|
|
2670
|
+
const asMatch = s.match(/^(\w+)\s+as\s+(\w+)$/);
|
|
2671
|
+
return {
|
|
2672
|
+
local: asMatch ? asMatch[1] : s,
|
|
2673
|
+
exported: asMatch ? asMatch[2] : s
|
|
2674
|
+
};
|
|
2675
|
+
})
|
|
2676
|
+
});
|
|
2677
|
+
}
|
|
2678
|
+
for (const match of code.matchAll(/^\s*export\s+\*\s+from\s+(['"])([^'"]+)\1\s*;?/gm)) {
|
|
2679
|
+
const [full, , source] = match;
|
|
2680
|
+
if (!isRemoteImport(source)) continue;
|
|
2681
|
+
result.push({
|
|
2682
|
+
kind: "export-all",
|
|
2683
|
+
source,
|
|
2684
|
+
start: match.index,
|
|
2685
|
+
end: match.index + full.length
|
|
2686
|
+
});
|
|
2687
|
+
}
|
|
2688
|
+
for (const match of code.matchAll(/import\(\s*(['"])([^'"]+)\1\s*\)/g)) {
|
|
2689
|
+
const [full, , source] = match;
|
|
2690
|
+
if (!isRemoteImport(source)) continue;
|
|
2691
|
+
result.push({
|
|
2692
|
+
kind: "dynamic",
|
|
2693
|
+
start: match.index,
|
|
2694
|
+
end: match.index + full.length,
|
|
2695
|
+
originalText: full
|
|
2696
|
+
});
|
|
2697
|
+
}
|
|
2698
|
+
return result.length > 0 ? result : void 0;
|
|
2699
|
+
}
|
|
2700
|
+
function pluginRemoteNamedExports(options) {
|
|
2701
|
+
const remoteNames = Object.keys(options.remotes);
|
|
2702
|
+
function isRemoteImport(source) {
|
|
2703
|
+
return remoteNames.some((name) => source === name || source.startsWith(name + "/")) || source.includes("__loadRemote__");
|
|
2704
|
+
}
|
|
2705
|
+
return {
|
|
2706
|
+
name: "module-federation-remote-named-exports",
|
|
2707
|
+
enforce: "post",
|
|
2708
|
+
async transform(code, id) {
|
|
2709
|
+
if (remoteNames.length === 0) return;
|
|
2710
|
+
if (id.includes("__loadRemote__") || id.includes("__loadShare__")) return;
|
|
2711
|
+
if (!JS_EXTENSIONS_RE.test(id)) return;
|
|
2712
|
+
if (!remoteNames.some((name) => code.includes(name))) return;
|
|
2713
|
+
let imports;
|
|
2714
|
+
try {
|
|
2715
|
+
imports = await collectFromAST(this.parse(code), code, isRemoteImport);
|
|
2716
|
+
} catch {
|
|
2717
|
+
imports = await collectFromEsLexer(code, isRemoteImport);
|
|
2718
|
+
}
|
|
2719
|
+
if ((!imports || imports.length === 0) && REGEX_FALLBACK_EXTENSIONS_RE.test(id)) imports = collectFromRegex(code, isRemoteImport);
|
|
2720
|
+
if (!imports) return;
|
|
2721
|
+
return applyRewrites(code, imports, id);
|
|
2722
|
+
}
|
|
2723
|
+
};
|
|
2724
|
+
}
|
|
2725
|
+
//#endregion
|
|
2335
2726
|
//#region src/plugins/pluginVarRemoteEntry.ts
|
|
2336
2727
|
const VarRemoteEntry = () => {
|
|
2337
2728
|
const mfOptions = getNormalizeModuleFederationOptions();
|
|
@@ -2498,6 +2889,7 @@ var normalizeOptimizeDeps_default = {
|
|
|
2498
2889
|
};
|
|
2499
2890
|
//#endregion
|
|
2500
2891
|
//#region src/index.ts
|
|
2892
|
+
const patchedManualChunks = /* @__PURE__ */ new WeakSet();
|
|
2501
2893
|
const UNSAFE_JS_SOURCE_CHAR_MAP = {
|
|
2502
2894
|
"<": "\\u003C",
|
|
2503
2895
|
">": "\\u003E",
|
|
@@ -2542,6 +2934,10 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
2542
2934
|
config.optimizeDeps = config.optimizeDeps || {};
|
|
2543
2935
|
config.optimizeDeps.include = config.optimizeDeps.include || [];
|
|
2544
2936
|
config.optimizeDeps.include.push(virtualRuntimeInitStatus.getImportId());
|
|
2937
|
+
if (isRolldown) {
|
|
2938
|
+
config.optimizeDeps.exclude = config.optimizeDeps.exclude || [];
|
|
2939
|
+
config.optimizeDeps.exclude.push(...Object.keys(remotes || {}));
|
|
2940
|
+
}
|
|
2545
2941
|
}
|
|
2546
2942
|
for (const key of Object.keys(shared)) {
|
|
2547
2943
|
if (key.endsWith("/")) continue;
|
|
@@ -2627,6 +3023,7 @@ function federation(mfUserOptions) {
|
|
|
2627
3023
|
virtualExposesId
|
|
2628
3024
|
}),
|
|
2629
3025
|
pluginProxyRemotes_default(options),
|
|
3026
|
+
pluginRemoteNamedExports(options),
|
|
2630
3027
|
...pluginModuleParseEnd_default((id) => {
|
|
2631
3028
|
return id.includes(getHostAutoInitImportId()) || id.includes(remoteEntryId) || id.includes(virtualExposesId) || id.includes(getLocalSharedImportMapPath());
|
|
2632
3029
|
}, {
|
|
@@ -2662,20 +3059,23 @@ function federation(mfUserOptions) {
|
|
|
2662
3059
|
warnedAboutCodeSplitting = true;
|
|
2663
3060
|
mfWarn("Ignoring `build.rolldownOptions.output.codeSplitting = false` because module federation requires chunk splitting.");
|
|
2664
3061
|
};
|
|
3062
|
+
let warnedAboutManualChunks = false;
|
|
2665
3063
|
const applyManualChunks = (output) => {
|
|
2666
3064
|
ensureCodeSplitting(output);
|
|
2667
|
-
const
|
|
2668
|
-
output.manualChunks
|
|
3065
|
+
const isPatchedByPlugin = !!(output.manualChunks && patchedManualChunks.has(output.manualChunks));
|
|
3066
|
+
if (output.manualChunks && !isPatchedByPlugin && !warnedAboutManualChunks) {
|
|
3067
|
+
warnedAboutManualChunks = true;
|
|
3068
|
+
mfWarn("Ignoring `build.rollupOptions.output.manualChunks` because it conflicts with module federation. Module federation transforms shared dependency imports with top-level await, and grouping these transformed modules into a single chunk creates circular async dependencies that cause the application to silently hang.");
|
|
3069
|
+
}
|
|
3070
|
+
const mfManualChunks = function(id) {
|
|
2669
3071
|
if (id.includes(runtimeInitId)) return "runtimeInit";
|
|
2670
3072
|
if (id.includes("__loadShare__")) {
|
|
2671
3073
|
const match = id.match(/([^/\\]+__loadShare__[^/\\]+)/);
|
|
2672
3074
|
return match ? match[1] : "loadShare";
|
|
2673
3075
|
}
|
|
2674
|
-
if (typeof existingManualChunks === "function") return existingManualChunks.apply(this, arguments);
|
|
2675
|
-
if (existingManualChunks && typeof existingManualChunks === "object") {
|
|
2676
|
-
for (const [key, ids] of Object.entries(existingManualChunks)) if (Array.isArray(ids) && ids.some((v) => id.includes(v))) return key;
|
|
2677
|
-
}
|
|
2678
3076
|
};
|
|
3077
|
+
patchedManualChunks.add(mfManualChunks);
|
|
3078
|
+
output.manualChunks = mfManualChunks;
|
|
2679
3079
|
};
|
|
2680
3080
|
config.build.rollupOptions = config.build.rollupOptions || {};
|
|
2681
3081
|
if (!Array.isArray(config.build.rollupOptions.output)) applyManualChunks(config.build.rollupOptions.output ||= {});
|
|
@@ -2706,6 +3106,7 @@ function federation(mfUserOptions) {
|
|
|
2706
3106
|
* @see https://rollupjs.org/plugin-development/#synthetic-named-exports
|
|
2707
3107
|
*/
|
|
2708
3108
|
code = code.replace("export default exportModule", "export const __moduleExports = exportModule;\nexport default exportModule.__esModule ? exportModule.default : exportModule");
|
|
3109
|
+
if (getIsRolldown(this)) return { code };
|
|
2709
3110
|
return {
|
|
2710
3111
|
code,
|
|
2711
3112
|
syntheticNamedExports: "__moduleExports"
|
|
@@ -2911,37 +3312,55 @@ function federation(mfUserOptions) {
|
|
|
2911
3312
|
config.optimizeDeps.needsInterop.push(virtualDir);
|
|
2912
3313
|
config.optimizeDeps.needsInterop.push(getLocalSharedImportMapPath());
|
|
2913
3314
|
}
|
|
3315
|
+
const isAstro = hasPackageDependency("astro");
|
|
2914
3316
|
const resolvedTarget = options.target ?? (config.build?.ssr ? "node" : "web");
|
|
3317
|
+
const envTargetDefineValue = !options.target && isAstro ? "undefined" : JSON.stringify(resolvedTarget);
|
|
2915
3318
|
if (!config.define) config.define = {};
|
|
2916
|
-
if (!("ENV_TARGET" in config.define)) config.define["ENV_TARGET"] =
|
|
3319
|
+
if (!("ENV_TARGET" in config.define)) config.define["ENV_TARGET"] = envTargetDefineValue;
|
|
2917
3320
|
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.`);
|
|
2918
3321
|
}
|
|
2919
3322
|
},
|
|
2920
3323
|
...Manifest(),
|
|
2921
3324
|
...VarRemoteEntry(),
|
|
2922
|
-
...
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
const
|
|
2931
|
-
const
|
|
2932
|
-
const
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
3325
|
+
...(function() {
|
|
3326
|
+
let disablePreload = false;
|
|
3327
|
+
return Object.keys(options.exposes).length > 0 ? [{
|
|
3328
|
+
name: "module-federation-fix-preload",
|
|
3329
|
+
enforce: "post",
|
|
3330
|
+
apply: "build",
|
|
3331
|
+
config(_config, { command }) {
|
|
3332
|
+
const manifest = options.manifest;
|
|
3333
|
+
const isConsumerProject = Object.keys(options.exposes).length === 0;
|
|
3334
|
+
const getDefaultDisableAssetsAnalyze = (cfgCommand) => cfgCommand === "serve" && isConsumerProject && (typeof manifest !== "object" || !Object.prototype.hasOwnProperty.call(manifest, "disableAssetsAnalyze"));
|
|
3335
|
+
const getConfiguredDisableAssetsAnalyze = (cfgCommand) => {
|
|
3336
|
+
if (typeof manifest === "object" && manifest !== null) {
|
|
3337
|
+
if (Object.prototype.hasOwnProperty.call(manifest, "disableAssetsAnalyze")) return manifest.disableAssetsAnalyze === true;
|
|
3338
|
+
}
|
|
3339
|
+
return getDefaultDisableAssetsAnalyze(cfgCommand);
|
|
3340
|
+
};
|
|
3341
|
+
disablePreload = getConfiguredDisableAssetsAnalyze(command);
|
|
3342
|
+
},
|
|
3343
|
+
generateBundle(_, bundle) {
|
|
3344
|
+
if (disablePreload) return;
|
|
3345
|
+
for (const chunk of Object.values(bundle)) {
|
|
3346
|
+
if (chunk.type !== "chunk") continue;
|
|
3347
|
+
if (!chunk.code.includes("modulepreload")) continue;
|
|
3348
|
+
const chunkDir = path.dirname(chunk.fileName);
|
|
3349
|
+
const prefixToRoot = chunkDir === "." ? "" : `${path.relative(chunkDir, ".")}/`;
|
|
3350
|
+
const replacementExpr = prefixToRoot ? `${escapeUnsafeJsSourceChars(JSON.stringify(prefixToRoot))}+$1` : "$1";
|
|
3351
|
+
const replacement = `=function($1){return new URL(${replacementExpr},import.meta.url).href}`;
|
|
3352
|
+
const replaced = chunk.code.replace(/=\(?(\w+)(?:,\w+)?\)?\s*=>\s*["'`][^"'`]*["'`]\s*\+\s*\1/, replacement);
|
|
3353
|
+
if (replaced !== chunk.code) {
|
|
3354
|
+
chunk.code = replaced;
|
|
3355
|
+
continue;
|
|
3356
|
+
}
|
|
3357
|
+
chunk.code = chunk.code.replace(/=function\((\w+)(?:,\w+)?\)\{return\s*["'`][^"'`]*["'`]\s*\+\s*\1\s*\}/, replacement);
|
|
3358
|
+
chunk.code = chunk.code.replace(/=function\((\w+)(?:,\w+)?\)\{return new URL\("\.\.\/"\+\1,import\.meta\.url\)\.href\}/, replacement);
|
|
3359
|
+
chunk.code = chunk.code.replace(/new URL\("\.\.\/"\+(\w+),import\.meta\.url\)\.href/g, `new URL(${replacementExpr},import.meta.url).href`);
|
|
2938
3360
|
}
|
|
2939
|
-
chunk.code = chunk.code.replace(/=function\((\w+)(?:,\w+)?\)\{return\s*["'`][^"'`]*["'`]\s*\+\s*\1\s*\}/, replacement);
|
|
2940
|
-
chunk.code = chunk.code.replace(/=function\((\w+)(?:,\w+)?\)\{return new URL\("\.\.\/"\+\1,import\.meta\.url\)\.href\}/, replacement);
|
|
2941
|
-
chunk.code = chunk.code.replace(/new URL\("\.\.\/"\+(\w+),import\.meta\.url\)\.href/g, `new URL(${replacementExpr},import.meta.url).href`);
|
|
2942
3361
|
}
|
|
2943
|
-
}
|
|
2944
|
-
}
|
|
3362
|
+
}] : [];
|
|
3363
|
+
})()
|
|
2945
3364
|
];
|
|
2946
3365
|
}
|
|
2947
3366
|
//#endregion
|