@module-federation/vite 1.23.6 → 1.23.8
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 +6 -0
- package/lib/{dtsConstants-CDuC8Bb7.js → dtsConstants-286VtFnC.js} +19 -33
- package/lib/index.js +749 -566
- package/lib/{pluginDts-rZMRTCTz.js → pluginDts-DvTJxjaE.js} +1 -1
- package/lib/{ssrEntryLoader-Bh2Tq1cZ.js → ssrEntryLoader-DKpOrW8D.js} +69 -5
- package/lib/{ssrVmStrategy-BCaiSEbA.js → ssrVmStrategy-D1cSKUV-.js} +4 -7
- package/lib/utils/ssrEntryLoader.d.ts +7 -1
- package/lib/utils/ssrEntryLoader.js +2 -2
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as CodeRewriter, c as isAbsoluteUrl, d as rebaseImport, f as resolveHashPlaceholderFileName, i as createCodePositionMap, l as isHttpUrl, o as createSourceMap, r as mfWarn, t as createModuleFederationError, u as normalizePathForImport } from "./logger-D67aJYOe.js";
|
|
2
2
|
import { _ as removeTrailingSlash, a as matchesSharedSource, b as stripViteFsPrefix, c as filterId, d as getNodeModulesSuffix, f as isAssetLikeImport, g as normalizeNodeModulePath, h as isViteOptimizableEntry, i as invalidateSharedKeyMatcher, l as getBasePath$1, m as isNuxtClientBase, n as getSharedRequest, p as isNodeModulePath, r as getSharedRuntimeKey, s as ensureTrailingSlash, t as findSharedKey, u as getCommonSharedSubpaths, v as resolvePublicPath, x as toRelativeImport, y as stripQueryAndHash } from "./sharedKeyMatcher-C04bVN1q.js";
|
|
3
|
-
import { C as
|
|
3
|
+
import { C as sharedCacheHelperCode, D as isReactCoreShare, E as REACT_DOM_CLIENT_SHARE, S as setPackageDetectionCwd, T as REACT_CLIENT_INTERNALS_KEY, _ as isPackageInstalled, a as getDependencyNames, b as resolveImportPath, c as getIsRolldown, d as getPackageName, f as getPackageNameFromNodeModulePath, g as isPackageExportAvailable, h as isNuxtProjectRoot, i as findPackageInDependents, l as getPackageDetectionCwd, m as hasPackageDependency, n as formatDevServerHostForOrigin, o as getInstalledPackageEntry, p as getSharedCacheDescriptor, r as watchFileEvents, s as getInstalledPackageJson, u as getPackageExportSpecifiersForFile, v as packageNameDecode, w as supportsCodeSplittingGroupDebugName, x as resolveModulePath, y as packageNameEncode } from "./dtsConstants-286VtFnC.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import * as fs$2 from "fs";
|
|
6
6
|
import { existsSync, readFileSync, readdirSync, realpathSync, statSync, writeFileSync } from "fs";
|
|
@@ -981,16 +981,6 @@ function getSsrCapabilities(viteMajor, command, hasRemotes, isSsr = false) {
|
|
|
981
981
|
};
|
|
982
982
|
}
|
|
983
983
|
//#endregion
|
|
984
|
-
//#region src/utils/runtimePluginSpecifier.ts
|
|
985
|
-
function getRuntimePluginSpecifier(plugin) {
|
|
986
|
-
return typeof plugin === "string" ? plugin : plugin[0];
|
|
987
|
-
}
|
|
988
|
-
/** Drop SSR-only plugins from a client graph; a server graph keeps them all. */
|
|
989
|
-
function filterRuntimePluginsForTarget(runtimePlugins, ssrOnlySpecifiers, isServer) {
|
|
990
|
-
if (isServer) return [...runtimePlugins];
|
|
991
|
-
return runtimePlugins.filter((plugin) => !ssrOnlySpecifiers.has(getRuntimePluginSpecifier(plugin)));
|
|
992
|
-
}
|
|
993
|
-
//#endregion
|
|
994
984
|
//#region src/utils/serializeRuntimeOptions.ts
|
|
995
985
|
const UNSAFE_JS_CHAR_MAP = {
|
|
996
986
|
"<": "\\u003C",
|
|
@@ -1003,6 +993,11 @@ function toSafeJsLiteral(value) {
|
|
|
1003
993
|
if (json === void 0) return "undefined";
|
|
1004
994
|
return json.replace(UNSAFE_JS_CHAR_PATTERN, (char) => UNSAFE_JS_CHAR_MAP[char]);
|
|
1005
995
|
}
|
|
996
|
+
const JS_IDENTIFIER_PATTERN = `[\$_\\p{ID_Start}][\$_\\u200C\\u200D\\p{ID_Continue}]*`;
|
|
997
|
+
const JS_IDENTIFIER_REGEX = new RegExp(`^${JS_IDENTIFIER_PATTERN}$`, "u");
|
|
998
|
+
function isValidJsIdentifier(name) {
|
|
999
|
+
return JS_IDENTIFIER_REGEX.test(name);
|
|
1000
|
+
}
|
|
1006
1001
|
/**
|
|
1007
1002
|
* Serializes a JavaScript object into a string of source code that can be evaluated.
|
|
1008
1003
|
* This function is used to create runtime plugin options without relying solely on JSON.stringify,
|
|
@@ -1477,240 +1472,117 @@ async function collectTreeShakingImports(code, id, shared, findSharedKey, record
|
|
|
1477
1472
|
await Promise.all(pending);
|
|
1478
1473
|
}
|
|
1479
1474
|
//#endregion
|
|
1480
|
-
//#region src/utils/
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
"
|
|
1485
|
-
|
|
1486
|
-
".
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
".cjs"
|
|
1490
|
-
];
|
|
1491
|
-
function resolveSourceFile(importPath, root) {
|
|
1492
|
-
const cleanImport = stripQueryAndHash(importPath);
|
|
1493
|
-
if (!cleanImport.startsWith(".") && !path$1.isAbsolute(cleanImport)) return;
|
|
1494
|
-
const candidate = path$1.isAbsolute(cleanImport) ? cleanImport : path$1.resolve(root, cleanImport);
|
|
1495
|
-
return [
|
|
1496
|
-
candidate,
|
|
1497
|
-
...SOURCE_EXTENSIONS$1.map((extension) => `${candidate}${extension}`),
|
|
1498
|
-
...SOURCE_EXTENSIONS$1.map((extension) => path$1.join(candidate, `index${extension}`))
|
|
1499
|
-
].find((filePath) => {
|
|
1500
|
-
try {
|
|
1501
|
-
return fs$1.statSync(filePath).isFile();
|
|
1502
|
-
} catch {
|
|
1503
|
-
return false;
|
|
1504
|
-
}
|
|
1505
|
-
});
|
|
1506
|
-
}
|
|
1507
|
-
function localDefaultReexport(source) {
|
|
1508
|
-
const match = source.match(/export\s*{\s*(?:default(?:\s+as\s+default)?|[A-Za-z_$][\w$]*\s+as\s+default)\s*}\s*from\s*["']([^"']+)["']/);
|
|
1509
|
-
return match?.[1]?.startsWith(".") ? match[1] : void 0;
|
|
1510
|
-
}
|
|
1511
|
-
function isReactComponentSource(source, filePath = "component.tsx") {
|
|
1512
|
-
if (!(/\bexport\s+default\b/.test(source) || /\bexport\s*{[^}]*\bdefault\b[^}]*}(?:\s*from\s*["'][^"']+["'])?/.test(source))) return false;
|
|
1513
|
-
const extension = path$1.extname(stripQueryAndHash(filePath)).toLowerCase();
|
|
1514
|
-
const canContainJsx = extension === ".tsx" || extension === ".jsx";
|
|
1515
|
-
const hasJsx = /<>|<\s*[A-Za-z][\w.:-]*(?:\s[^<>]*?)?\s*\/?>/.test(source);
|
|
1516
|
-
const importsReact = /\bfrom\s*["']react["']|\brequire\(\s*["']react["']\s*\)/.test(source);
|
|
1517
|
-
const usesReactApi = /\b(?:React\.)?(?:createElement|jsx|jsxs)\s*\(/.test(source);
|
|
1518
|
-
const isClientModule = /^\s*["']use client["']\s*;?/m.test(source);
|
|
1519
|
-
return canContainJsx && hasJsx || importsReact && (hasJsx || usesReactApi || isClientModule);
|
|
1475
|
+
//#region src/utils/typeArgumentScanner.ts
|
|
1476
|
+
function getTypeArgumentStartContext(source, start) {
|
|
1477
|
+
let previous = start - 1;
|
|
1478
|
+
while (previous >= 0 && /\s/.test(source[previous])) previous--;
|
|
1479
|
+
const previousChar = source[previous] || "";
|
|
1480
|
+
const followsNamedExpression = /[$_\u200C\u200D\p{ID_Continue})\]>]/u.test(previousChar);
|
|
1481
|
+
const startsStandaloneGeneric = previousChar !== "" && "=([{,:".includes(previousChar);
|
|
1482
|
+
if (!followsNamedExpression && !startsStandaloneGeneric) return void 0;
|
|
1483
|
+
return { followsNamedExpression };
|
|
1520
1484
|
}
|
|
1521
|
-
function
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
let source;
|
|
1526
|
-
try {
|
|
1527
|
-
source = fs$1.readFileSync(normalizedPath, "utf8");
|
|
1528
|
-
} catch {
|
|
1529
|
-
return false;
|
|
1485
|
+
function updateTypeArgumentGroupDepth(char, state) {
|
|
1486
|
+
if (char === "(" || char === "[" || char === "{") {
|
|
1487
|
+
state.groupDepth++;
|
|
1488
|
+
return "handled";
|
|
1530
1489
|
}
|
|
1531
|
-
if (
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
return reexportPath ? isReactComponentFile(reexportPath, seen) : false;
|
|
1490
|
+
if (char !== ")" && char !== "]" && char !== "}") return void 0;
|
|
1491
|
+
if (state.groupDepth === 0) return "invalid";
|
|
1492
|
+
state.groupDepth--;
|
|
1493
|
+
return "handled";
|
|
1536
1494
|
}
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
if (options.experiments.ssrMode !== "ISLAND") return /* @__PURE__ */ new Set();
|
|
1544
|
-
if (Object.hasOwn(options.shared, "react")) return /* @__PURE__ */ new Set();
|
|
1545
|
-
const islandExposes = /* @__PURE__ */ new Set();
|
|
1546
|
-
for (const [key, expose] of Object.entries(options.exposes)) {
|
|
1547
|
-
const sourceFile = resolveSourceFile(expose.import, root);
|
|
1548
|
-
if (sourceFile && isReactComponentFile(sourceFile)) islandExposes.add(key);
|
|
1495
|
+
function updateTypeArgumentAngleDepth(source, index, state) {
|
|
1496
|
+
const char = source[index];
|
|
1497
|
+
if (char === "<") {
|
|
1498
|
+
if (source[index + 1] === "=" || source[index + 1] === "<") return "invalid";
|
|
1499
|
+
state.angleDepth++;
|
|
1500
|
+
return "handled";
|
|
1549
1501
|
}
|
|
1550
|
-
return
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
return `
|
|
1555
|
-
exportModule.__mf_island = {
|
|
1556
|
-
version: 1,
|
|
1557
|
-
renderToHtml() {
|
|
1558
|
-
return Promise.reject(new Error("[Module Federation] renderToHtml is only available in the SSR remote entry"));
|
|
1559
|
-
},
|
|
1560
|
-
hydrate(element, props) {
|
|
1561
|
-
const root = element && element.hasAttribute && element.hasAttribute("data-mf-island-state")
|
|
1562
|
-
? element
|
|
1563
|
-
: element && element.querySelector
|
|
1564
|
-
? element.querySelector("[data-mf-island-state]") || element
|
|
1565
|
-
: element;
|
|
1566
|
-
if (!root) {
|
|
1567
|
-
return Promise.reject(new Error("[Module Federation] Cannot hydrate an island without a root element"));
|
|
1568
|
-
}
|
|
1569
|
-
let serverProps = {};
|
|
1570
|
-
const encodedState = root.getAttribute && root.getAttribute("data-mf-island-state");
|
|
1571
|
-
if (encodedState) {
|
|
1572
|
-
try {
|
|
1573
|
-
serverProps = JSON.parse(decodeURIComponent(encodedState));
|
|
1574
|
-
} catch {
|
|
1575
|
-
serverProps = {};
|
|
1576
|
-
}
|
|
1577
|
-
}
|
|
1578
|
-
const finalProps = Object.assign({}, serverProps, props || {});
|
|
1579
|
-
return Promise.all([import("react"), import("react-dom/client")]).then(([React, ReactDOMClient]) => {
|
|
1580
|
-
if (typeof ReactDOMClient.hydrateRoot !== "function") {
|
|
1581
|
-
throw new Error("[Module Federation] react-dom/client does not provide hydrateRoot");
|
|
1582
|
-
}
|
|
1583
|
-
return ReactDOMClient.hydrateRoot(
|
|
1584
|
-
root,
|
|
1585
|
-
React.createElement(importModule.default, finalProps)
|
|
1586
|
-
);
|
|
1587
|
-
});
|
|
1588
|
-
}
|
|
1589
|
-
}`;
|
|
1590
|
-
}
|
|
1591
|
-
function generateReactIslandSSRDefinition(enabled) {
|
|
1592
|
-
if (!enabled) return "";
|
|
1593
|
-
return `
|
|
1594
|
-
exportModule.__mf_island = {
|
|
1595
|
-
version: 1,
|
|
1596
|
-
async renderToHtml(props) {
|
|
1597
|
-
if (typeof importModule.default !== "function" && typeof importModule.default !== "object") {
|
|
1598
|
-
throw new Error("[Module Federation] A React island expose must have a default component export");
|
|
1599
|
-
}
|
|
1600
|
-
const loadedProps = typeof importModule.load === "function" ? await importModule.load() : {};
|
|
1601
|
-
const finalProps = Object.assign({}, loadedProps || {}, props || {});
|
|
1602
|
-
const [React, ReactDOMServer] = await Promise.all([
|
|
1603
|
-
import("react"),
|
|
1604
|
-
import("react-dom/server")
|
|
1605
|
-
]);
|
|
1606
|
-
const body = ReactDOMServer.renderToString(
|
|
1607
|
-
React.createElement(importModule.default, finalProps)
|
|
1608
|
-
);
|
|
1609
|
-
const state = encodeURIComponent(JSON.stringify(finalProps));
|
|
1610
|
-
return '<div data-mf-island-state="' + state + '">' + body + '</div>';
|
|
1611
|
-
},
|
|
1612
|
-
hydrate() {
|
|
1613
|
-
return Promise.reject(new Error("[Module Federation] hydrate is only available in the browser remote entry"));
|
|
1614
|
-
}
|
|
1615
|
-
}`;
|
|
1616
|
-
}
|
|
1617
|
-
const REACT_ISLAND_CLIENT_ID_PREFIX = "virtual:mf-react-island-client:";
|
|
1618
|
-
const REACT_ISLAND_SERVER_ID_PREFIX = "virtual:mf-react-island-server:";
|
|
1619
|
-
const RESOLVED_REACT_ISLAND_CLIENT_ID_PREFIX = `\0${REACT_ISLAND_CLIENT_ID_PREFIX}`;
|
|
1620
|
-
const RESOLVED_REACT_ISLAND_SERVER_ID_PREFIX = `\0${REACT_ISLAND_SERVER_ID_PREFIX}`;
|
|
1621
|
-
function encodeIslandRemoteId(remoteId) {
|
|
1622
|
-
return encodeURIComponent(remoteId);
|
|
1623
|
-
}
|
|
1624
|
-
function decodeIslandRemoteId(encodedRemoteId) {
|
|
1625
|
-
return decodeURIComponent(encodedRemoteId);
|
|
1626
|
-
}
|
|
1627
|
-
function getReactIslandImportRemoteId(source) {
|
|
1628
|
-
const queryIndex = source.indexOf("?");
|
|
1629
|
-
if (queryIndex === -1) return;
|
|
1630
|
-
if (!new URLSearchParams(source.slice(queryIndex + 1)).has("mf-island")) return;
|
|
1631
|
-
return source.slice(0, queryIndex);
|
|
1632
|
-
}
|
|
1633
|
-
function getReactIslandServerImportId(remoteId) {
|
|
1634
|
-
return `${REACT_ISLAND_SERVER_ID_PREFIX}${encodeIslandRemoteId(remoteId)}`;
|
|
1635
|
-
}
|
|
1636
|
-
function getReactIslandClientImportId(remoteId) {
|
|
1637
|
-
return `${REACT_ISLAND_CLIENT_ID_PREFIX}${encodeIslandRemoteId(remoteId)}`;
|
|
1502
|
+
if (char !== ">") return void 0;
|
|
1503
|
+
if (source[index - 1] === "=" || source[index + 1] === "=") return "handled";
|
|
1504
|
+
state.angleDepth--;
|
|
1505
|
+
return state.angleDepth === 0 ? "closed" : "handled";
|
|
1638
1506
|
}
|
|
1639
|
-
function
|
|
1640
|
-
|
|
1641
|
-
|
|
1507
|
+
function hasLikelyTypeArgumentFollower(source, end, codePositions, followsNamedExpression) {
|
|
1508
|
+
let next = end + 1;
|
|
1509
|
+
while (next < source.length && (!codePositions[next] || /\s/.test(source[next]))) next++;
|
|
1510
|
+
if (next >= source.length || /[([.!?=;,)\]}:|&]/.test(source[next])) return true;
|
|
1511
|
+
if (source.slice(end + 1, next).includes("\n")) return true;
|
|
1512
|
+
const followingToken = source.slice(next).match(/^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*/u)?.[0];
|
|
1513
|
+
return followingToken === "as" || followingToken === "satisfies" || !followsNamedExpression && followingToken !== void 0;
|
|
1642
1514
|
}
|
|
1643
|
-
function
|
|
1644
|
-
|
|
1645
|
-
return
|
|
1515
|
+
function isInvalidTypeArgumentTerminator(source, index, followsNamedExpression) {
|
|
1516
|
+
const char = source[index];
|
|
1517
|
+
return char === ";" || char === "=" && source[index + 1] !== ">" && followsNamedExpression;
|
|
1646
1518
|
}
|
|
1647
|
-
/**
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1519
|
+
/**
|
|
1520
|
+
* Finds the end of a balanced, type-like angle-bracket range that contains a
|
|
1521
|
+
* comma. Ambiguous syntax returns `undefined` so callers can fail closed.
|
|
1522
|
+
*/
|
|
1523
|
+
function findLikelyTypeArgumentEnd(source, start, codePositions) {
|
|
1524
|
+
const context = getTypeArgumentStartContext(source, start);
|
|
1525
|
+
if (!context) return void 0;
|
|
1526
|
+
const state = {
|
|
1527
|
+
angleDepth: 1,
|
|
1528
|
+
groupDepth: 0,
|
|
1529
|
+
sawTypeComma: false
|
|
1530
|
+
};
|
|
1531
|
+
for (let index = start + 1; index < source.length; index++) {
|
|
1532
|
+
if (!codePositions[index]) continue;
|
|
1533
|
+
const char = source[index];
|
|
1534
|
+
const groupAction = updateTypeArgumentGroupDepth(char, state);
|
|
1535
|
+
if (groupAction === "invalid") return void 0;
|
|
1536
|
+
if (groupAction === "handled") continue;
|
|
1537
|
+
const angleAction = updateTypeArgumentAngleDepth(source, index, state);
|
|
1538
|
+
if (angleAction === "invalid") return void 0;
|
|
1539
|
+
if (angleAction === "closed") return state.sawTypeComma && hasLikelyTypeArgumentFollower(source, index, codePositions, context.followsNamedExpression) ? index : void 0;
|
|
1540
|
+
if (angleAction === "handled") continue;
|
|
1541
|
+
if (char === "," && state.groupDepth === 0) {
|
|
1542
|
+
state.sawTypeComma = true;
|
|
1543
|
+
continue;
|
|
1544
|
+
}
|
|
1545
|
+
if (state.angleDepth === 1 && state.groupDepth === 0 && isInvalidTypeArgumentTerminator(source, index, context.followsNamedExpression)) return;
|
|
1546
|
+
}
|
|
1660
1547
|
}
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1548
|
+
//#endregion
|
|
1549
|
+
//#region src/utils/sharedExportConditions.ts
|
|
1550
|
+
const DEFAULT_CLIENT_EXPORT_CONDITIONS = [
|
|
1551
|
+
"browser",
|
|
1552
|
+
"import",
|
|
1553
|
+
"module",
|
|
1554
|
+
"default"
|
|
1555
|
+
];
|
|
1556
|
+
const DEFAULT_NODE_SSR_EXPORT_CONDITIONS = [
|
|
1557
|
+
"node",
|
|
1558
|
+
"import",
|
|
1559
|
+
"module",
|
|
1560
|
+
"default"
|
|
1561
|
+
];
|
|
1562
|
+
const DEFAULT_WEBWORKER_SSR_EXPORT_CONDITIONS = [
|
|
1563
|
+
"worker",
|
|
1564
|
+
"browser",
|
|
1565
|
+
"import",
|
|
1566
|
+
"module",
|
|
1567
|
+
"default"
|
|
1568
|
+
];
|
|
1569
|
+
const VITE_DEV_PROD_CONDITION = "development|production";
|
|
1570
|
+
function appendConditions(conditions, fallbackConditions) {
|
|
1571
|
+
return [.../* @__PURE__ */ new Set([...conditions, ...fallbackConditions])];
|
|
1671
1572
|
}
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
return
|
|
1675
|
-
|
|
1676
|
-
import * as React from "react";
|
|
1677
|
-
|
|
1678
|
-
const islandModulePromise = import(${JSON.stringify(remoteId)});
|
|
1679
|
-
|
|
1680
|
-
async function loadIslandModule() {
|
|
1681
|
-
const namespace = await islandModulePromise;
|
|
1682
|
-
const pending = namespace && namespace.__mf_remote_pending;
|
|
1683
|
-
if (pending && typeof pending.then === "function") return pending;
|
|
1684
|
-
return namespace && namespace.__moduleExports || namespace;
|
|
1573
|
+
function resolveViteModeCondition(conditions, isProduction) {
|
|
1574
|
+
const modeCondition = isProduction ? "production" : "development";
|
|
1575
|
+
return [...new Set(conditions.map((condition) => condition === VITE_DEV_PROD_CONDITION ? modeCondition : condition))];
|
|
1685
1576
|
}
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
if (!element) return;
|
|
1693
|
-
void loadIslandModule().then((remoteModule) => {
|
|
1694
|
-
const shell = remoteModule && remoteModule.__mf_island;
|
|
1695
|
-
if (!shell || typeof shell.hydrate !== "function") {
|
|
1696
|
-
throw new Error(${JSON.stringify(`[Module Federation] ${remoteId} does not expose a client island capability`)});
|
|
1697
|
-
}
|
|
1698
|
-
return shell.hydrate(element, islandProps);
|
|
1699
|
-
});
|
|
1700
|
-
}, []);
|
|
1701
|
-
|
|
1702
|
-
return React.createElement("div", {
|
|
1703
|
-
ref,
|
|
1704
|
-
suppressHydrationWarning: true,
|
|
1705
|
-
dangerouslySetInnerHTML: { __html: html },
|
|
1706
|
-
});
|
|
1707
|
-
}`;
|
|
1577
|
+
function getSharedExportConditions({ environmentConditions, isProduction, isSsr, rootConditions, ssrConditions, ssrTarget = "node" }) {
|
|
1578
|
+
if (environmentConditions !== void 0) return resolveViteModeCondition(appendConditions(environmentConditions, ["import", "default"]), isProduction);
|
|
1579
|
+
const defaultConditions = isSsr ? ssrTarget === "webworker" ? DEFAULT_WEBWORKER_SSR_EXPORT_CONDITIONS : DEFAULT_NODE_SSR_EXPORT_CONDITIONS : DEFAULT_CLIENT_EXPORT_CONDITIONS;
|
|
1580
|
+
const configuredConditions = isSsr ? ssrConditions ?? rootConditions : rootConditions;
|
|
1581
|
+
if (configuredConditions !== void 0) return resolveViteModeCondition(appendConditions(configuredConditions, defaultConditions), isProduction);
|
|
1582
|
+
return [...defaultConditions];
|
|
1708
1583
|
}
|
|
1709
|
-
function
|
|
1710
|
-
|
|
1711
|
-
if (serverRemoteId !== void 0) return generateReactIslandConsumerServer(serverRemoteId);
|
|
1712
|
-
const clientRemoteId = remoteIdFromResolvedIslandId(id, RESOLVED_REACT_ISLAND_CLIENT_ID_PREFIX);
|
|
1713
|
-
if (clientRemoteId !== void 0) return generateReactIslandConsumerClient(clientRemoteId);
|
|
1584
|
+
function isReactServerConditions(conditions) {
|
|
1585
|
+
return Boolean(conditions?.includes("react-server"));
|
|
1714
1586
|
}
|
|
1715
1587
|
//#endregion
|
|
1716
1588
|
//#region src/virtualModules/virtualModuleScope.ts
|
|
@@ -1755,158 +1627,17 @@ function stableConfigValue(value, ancestors = /* @__PURE__ */ new WeakSet()) {
|
|
|
1755
1627
|
ancestors.delete(value);
|
|
1756
1628
|
return result;
|
|
1757
1629
|
}
|
|
1758
|
-
function
|
|
1759
|
-
const identity = JSON.stringify(stableConfigValue(
|
|
1760
|
-
|
|
1761
|
-
return `${options.internalName}${MF_OWNER_INFIX}${ownerId}`;
|
|
1630
|
+
function hashConfig(value) {
|
|
1631
|
+
const identity = JSON.stringify(stableConfigValue(value));
|
|
1632
|
+
return BigInt(`0x${createHash("sha256").update(identity).digest("hex").slice(0, 12)}`);
|
|
1762
1633
|
}
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
const
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
return `virtual:mf-exposes:${getVirtualModuleScopeKey(options)}`;
|
|
1771
|
-
}
|
|
1772
|
-
function generateExposes(options, remoteDependencyMap = {}, command = "build", reactIslandExposes = /* @__PURE__ */ new Set()) {
|
|
1773
|
-
return `
|
|
1774
|
-
const cssAssetMap = ${JSON.stringify(options.bundleAllCSS ? EXPOSES_CSS_MAP_PLACEHOLDER : {})};
|
|
1775
|
-
const injectedCssHrefs = new Set();
|
|
1776
|
-
const exposeLoadPromises = new Map();
|
|
1777
|
-
|
|
1778
|
-
// Shared and remote readiness is handled by explicit Promise barriers below
|
|
1779
|
-
// and by remoteEntry's pendingShareLoads barrier. Keep this map scoped to a
|
|
1780
|
-
// single expose: unrelated exposes must stay independent and load in parallel.
|
|
1781
|
-
function loadExposedModule(exposeKey, loader) {
|
|
1782
|
-
let load = exposeLoadPromises.get(exposeKey);
|
|
1783
|
-
if (!load) {
|
|
1784
|
-
load = Promise.resolve()
|
|
1785
|
-
.then(loader)
|
|
1786
|
-
.catch((error) => {
|
|
1787
|
-
exposeLoadPromises.delete(exposeKey);
|
|
1788
|
-
throw error;
|
|
1789
|
-
});
|
|
1790
|
-
exposeLoadPromises.set(exposeKey, load);
|
|
1791
|
-
}
|
|
1792
|
-
return load;
|
|
1793
|
-
}
|
|
1794
|
-
|
|
1795
|
-
async function injectCssAssets(exposeKey) {
|
|
1796
|
-
if (typeof document === "undefined") {
|
|
1797
|
-
return;
|
|
1798
|
-
}
|
|
1799
|
-
|
|
1800
|
-
// Replaced at build time with expose -> css asset paths.
|
|
1801
|
-
const cssAssets = cssAssetMap[exposeKey] || [];
|
|
1802
|
-
|
|
1803
|
-
await Promise.all(
|
|
1804
|
-
cssAssets.map((cssAsset) => {
|
|
1805
|
-
const href = new URL(cssAsset, import.meta.url).href;
|
|
1806
|
-
|
|
1807
|
-
// Same expose can be resolved multiple times in one page.
|
|
1808
|
-
if (injectedCssHrefs.has(href)) {
|
|
1809
|
-
return Promise.resolve();
|
|
1810
|
-
}
|
|
1811
|
-
injectedCssHrefs.add(href);
|
|
1812
|
-
|
|
1813
|
-
// Check for any existing stylesheet with the same href, not just
|
|
1814
|
-
// MF-injected ones. This prevents duplicate <link> tags when Vite's
|
|
1815
|
-
// own CSS module injection or MF runtime's createLink has already
|
|
1816
|
-
// created a <link rel="stylesheet"> for the same URL.
|
|
1817
|
-
const existingLink = document.querySelector(
|
|
1818
|
-
\`link[rel="stylesheet"][href="\${href}"]\`
|
|
1819
|
-
);
|
|
1820
|
-
if (existingLink) {
|
|
1821
|
-
return Promise.resolve();
|
|
1822
|
-
}
|
|
1823
|
-
|
|
1824
|
-
return new Promise((resolve, reject) => {
|
|
1825
|
-
const link = document.createElement("link");
|
|
1826
|
-
link.rel = "stylesheet";
|
|
1827
|
-
link.href = href;
|
|
1828
|
-
link.onload = () => resolve();
|
|
1829
|
-
link.onerror = () => {
|
|
1830
|
-
injectedCssHrefs.delete(href);
|
|
1831
|
-
reject(new Error(\`[Module Federation] Failed to load CSS asset: \${href}\`));
|
|
1832
|
-
};
|
|
1833
|
-
document.head.appendChild(link);
|
|
1834
|
-
});
|
|
1835
|
-
})
|
|
1836
|
-
);
|
|
1837
|
-
}
|
|
1838
|
-
|
|
1839
|
-
export default {
|
|
1840
|
-
${Object.keys(options.exposes).map((key) => {
|
|
1841
|
-
const remoteDependencyPreloads = (remoteDependencyMap[key] ?? []).map((remoteId) => {
|
|
1842
|
-
const virtualRemote = getRemoteVirtualModule(remoteId, command, false, "unified", options);
|
|
1843
|
-
return `import(${JSON.stringify(virtualRemote.getImportId())})
|
|
1844
|
-
.then((mod) => mod.__mf_remote_pending)`;
|
|
1845
|
-
}).join(",");
|
|
1846
|
-
return `
|
|
1847
|
-
${JSON.stringify(key)}: async () => {
|
|
1848
|
-
await injectCssAssets(${JSON.stringify(key)})
|
|
1849
|
-
await Promise.all([${remoteDependencyPreloads}])
|
|
1850
|
-
const importModule = await loadExposedModule(
|
|
1851
|
-
${JSON.stringify(key)},
|
|
1852
|
-
() => import(${JSON.stringify(options.exposes[key].import)})
|
|
1853
|
-
)
|
|
1854
|
-
const dependencyPending = importModule && importModule.__mf_remote_dependency_pending;
|
|
1855
|
-
if (dependencyPending && typeof dependencyPending.then === "function") {
|
|
1856
|
-
await dependencyPending;
|
|
1857
|
-
}
|
|
1858
|
-
const exportModule = {}
|
|
1859
|
-
Object.assign(exportModule, importModule)
|
|
1860
|
-
${generateReactIslandBrowserDefinition(reactIslandExposes.has(key))}
|
|
1861
|
-
Object.defineProperty(exportModule, "__esModule", {
|
|
1862
|
-
value: true,
|
|
1863
|
-
enumerable: false
|
|
1864
|
-
})
|
|
1865
|
-
return exportModule
|
|
1866
|
-
}
|
|
1867
|
-
`;
|
|
1868
|
-
}).join(",")}
|
|
1869
|
-
}
|
|
1870
|
-
`;
|
|
1871
|
-
}
|
|
1872
|
-
//#endregion
|
|
1873
|
-
//#region src/utils/sharedExportConditions.ts
|
|
1874
|
-
const DEFAULT_CLIENT_EXPORT_CONDITIONS = [
|
|
1875
|
-
"browser",
|
|
1876
|
-
"import",
|
|
1877
|
-
"module",
|
|
1878
|
-
"default"
|
|
1879
|
-
];
|
|
1880
|
-
const DEFAULT_NODE_SSR_EXPORT_CONDITIONS = [
|
|
1881
|
-
"node",
|
|
1882
|
-
"import",
|
|
1883
|
-
"module",
|
|
1884
|
-
"default"
|
|
1885
|
-
];
|
|
1886
|
-
const DEFAULT_WEBWORKER_SSR_EXPORT_CONDITIONS = [
|
|
1887
|
-
"worker",
|
|
1888
|
-
"browser",
|
|
1889
|
-
"import",
|
|
1890
|
-
"module",
|
|
1891
|
-
"default"
|
|
1892
|
-
];
|
|
1893
|
-
const VITE_DEV_PROD_CONDITION = "development|production";
|
|
1894
|
-
function appendConditions(conditions, fallbackConditions) {
|
|
1895
|
-
return [.../* @__PURE__ */ new Set([...conditions, ...fallbackConditions])];
|
|
1896
|
-
}
|
|
1897
|
-
function resolveViteModeCondition(conditions, isProduction) {
|
|
1898
|
-
const modeCondition = isProduction ? "production" : "development";
|
|
1899
|
-
return [...new Set(conditions.map((condition) => condition === VITE_DEV_PROD_CONDITION ? modeCondition : condition))];
|
|
1900
|
-
}
|
|
1901
|
-
function getSharedExportConditions({ environmentConditions, isProduction, isSsr, rootConditions, ssrConditions, ssrTarget = "node" }) {
|
|
1902
|
-
if (environmentConditions !== void 0) return resolveViteModeCondition(appendConditions(environmentConditions, ["import", "default"]), isProduction);
|
|
1903
|
-
const defaultConditions = isSsr ? ssrTarget === "webworker" ? DEFAULT_WEBWORKER_SSR_EXPORT_CONDITIONS : DEFAULT_NODE_SSR_EXPORT_CONDITIONS : DEFAULT_CLIENT_EXPORT_CONDITIONS;
|
|
1904
|
-
const configuredConditions = isSsr ? ssrConditions ?? rootConditions : rootConditions;
|
|
1905
|
-
if (configuredConditions !== void 0) return resolveViteModeCondition(appendConditions(configuredConditions, defaultConditions), isProduction);
|
|
1906
|
-
return [...defaultConditions];
|
|
1907
|
-
}
|
|
1908
|
-
function isReactServerConditions(conditions) {
|
|
1909
|
-
return Boolean(conditions?.includes("react-server"));
|
|
1634
|
+
const ownerIdFilenames = /* @__PURE__ */ new Map();
|
|
1635
|
+
function getFederationScopeKey(options) {
|
|
1636
|
+
const { filename, ...identity } = options;
|
|
1637
|
+
let ownerId = hashConfig(identity);
|
|
1638
|
+
if (!ownerIdFilenames.has(ownerId)) ownerIdFilenames.set(ownerId, filename);
|
|
1639
|
+
else if (ownerIdFilenames.get(ownerId) !== filename) ownerId = hashConfig(options);
|
|
1640
|
+
return `${options.internalName}${MF_OWNER_INFIX}${ownerId}`;
|
|
1910
1641
|
}
|
|
1911
1642
|
//#endregion
|
|
1912
1643
|
//#region src/virtualModules/virtualRuntimeInitStatus.ts
|
|
@@ -1938,10 +1669,13 @@ function getRuntimeRemoteAlias(alias, options) {
|
|
|
1938
1669
|
return `${getFederationScopeKey(options)}__${alias}`;
|
|
1939
1670
|
}
|
|
1940
1671
|
function getSsrRuntimeRemotes(remotes, options) {
|
|
1941
|
-
return Object.entries(remotes).map(([
|
|
1942
|
-
|
|
1672
|
+
return Object.entries(remotes).map(([alias, item]) => ({
|
|
1673
|
+
alias,
|
|
1674
|
+
entryGlobalName: item.entryGlobalName,
|
|
1675
|
+
name: getRuntimeRemoteAlias(alias, options),
|
|
1943
1676
|
entry: item.entry,
|
|
1944
|
-
type: item.type ?? "module"
|
|
1677
|
+
type: item.type ?? "module",
|
|
1678
|
+
shareScope: item.shareScope ?? "default"
|
|
1945
1679
|
}));
|
|
1946
1680
|
}
|
|
1947
1681
|
function getRuntimeInitGlobalKey(ownerImportId) {
|
|
@@ -2091,80 +1825,6 @@ ${exportStatement}
|
|
|
2091
1825
|
`);
|
|
2092
1826
|
}
|
|
2093
1827
|
//#endregion
|
|
2094
|
-
//#region src/utils/typeArgumentScanner.ts
|
|
2095
|
-
function getTypeArgumentStartContext(source, start) {
|
|
2096
|
-
let previous = start - 1;
|
|
2097
|
-
while (previous >= 0 && /\s/.test(source[previous])) previous--;
|
|
2098
|
-
const previousChar = source[previous] || "";
|
|
2099
|
-
const followsNamedExpression = /[$_\u200C\u200D\p{ID_Continue})\]>]/u.test(previousChar);
|
|
2100
|
-
const startsStandaloneGeneric = previousChar !== "" && "=([{,:".includes(previousChar);
|
|
2101
|
-
if (!followsNamedExpression && !startsStandaloneGeneric) return void 0;
|
|
2102
|
-
return { followsNamedExpression };
|
|
2103
|
-
}
|
|
2104
|
-
function updateTypeArgumentGroupDepth(char, state) {
|
|
2105
|
-
if (char === "(" || char === "[" || char === "{") {
|
|
2106
|
-
state.groupDepth++;
|
|
2107
|
-
return "handled";
|
|
2108
|
-
}
|
|
2109
|
-
if (char !== ")" && char !== "]" && char !== "}") return void 0;
|
|
2110
|
-
if (state.groupDepth === 0) return "invalid";
|
|
2111
|
-
state.groupDepth--;
|
|
2112
|
-
return "handled";
|
|
2113
|
-
}
|
|
2114
|
-
function updateTypeArgumentAngleDepth(source, index, state) {
|
|
2115
|
-
const char = source[index];
|
|
2116
|
-
if (char === "<") {
|
|
2117
|
-
if (source[index + 1] === "=" || source[index + 1] === "<") return "invalid";
|
|
2118
|
-
state.angleDepth++;
|
|
2119
|
-
return "handled";
|
|
2120
|
-
}
|
|
2121
|
-
if (char !== ">") return void 0;
|
|
2122
|
-
if (source[index - 1] === "=" || source[index + 1] === "=") return "handled";
|
|
2123
|
-
state.angleDepth--;
|
|
2124
|
-
return state.angleDepth === 0 ? "closed" : "handled";
|
|
2125
|
-
}
|
|
2126
|
-
function hasLikelyTypeArgumentFollower(source, end, codePositions, followsNamedExpression) {
|
|
2127
|
-
let next = end + 1;
|
|
2128
|
-
while (next < source.length && (!codePositions[next] || /\s/.test(source[next]))) next++;
|
|
2129
|
-
if (next >= source.length || /[([.!?=;,)\]}:|&]/.test(source[next])) return true;
|
|
2130
|
-
if (source.slice(end + 1, next).includes("\n")) return true;
|
|
2131
|
-
const followingToken = source.slice(next).match(/^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*/u)?.[0];
|
|
2132
|
-
return followingToken === "as" || followingToken === "satisfies" || !followsNamedExpression && followingToken !== void 0;
|
|
2133
|
-
}
|
|
2134
|
-
function isInvalidTypeArgumentTerminator(source, index, followsNamedExpression) {
|
|
2135
|
-
const char = source[index];
|
|
2136
|
-
return char === ";" || char === "=" && source[index + 1] !== ">" && followsNamedExpression;
|
|
2137
|
-
}
|
|
2138
|
-
/**
|
|
2139
|
-
* Finds the end of a balanced, type-like angle-bracket range that contains a
|
|
2140
|
-
* comma. Ambiguous syntax returns `undefined` so callers can fail closed.
|
|
2141
|
-
*/
|
|
2142
|
-
function findLikelyTypeArgumentEnd(source, start, codePositions) {
|
|
2143
|
-
const context = getTypeArgumentStartContext(source, start);
|
|
2144
|
-
if (!context) return void 0;
|
|
2145
|
-
const state = {
|
|
2146
|
-
angleDepth: 1,
|
|
2147
|
-
groupDepth: 0,
|
|
2148
|
-
sawTypeComma: false
|
|
2149
|
-
};
|
|
2150
|
-
for (let index = start + 1; index < source.length; index++) {
|
|
2151
|
-
if (!codePositions[index]) continue;
|
|
2152
|
-
const char = source[index];
|
|
2153
|
-
const groupAction = updateTypeArgumentGroupDepth(char, state);
|
|
2154
|
-
if (groupAction === "invalid") return void 0;
|
|
2155
|
-
if (groupAction === "handled") continue;
|
|
2156
|
-
const angleAction = updateTypeArgumentAngleDepth(source, index, state);
|
|
2157
|
-
if (angleAction === "invalid") return void 0;
|
|
2158
|
-
if (angleAction === "closed") return state.sawTypeComma && hasLikelyTypeArgumentFollower(source, index, codePositions, context.followsNamedExpression) ? index : void 0;
|
|
2159
|
-
if (angleAction === "handled") continue;
|
|
2160
|
-
if (char === "," && state.groupDepth === 0) {
|
|
2161
|
-
state.sawTypeComma = true;
|
|
2162
|
-
continue;
|
|
2163
|
-
}
|
|
2164
|
-
if (state.angleDepth === 1 && state.groupDepth === 0 && isInvalidTypeArgumentTerminator(source, index, context.followsNamedExpression)) return;
|
|
2165
|
-
}
|
|
2166
|
-
}
|
|
2167
|
-
//#endregion
|
|
2168
1828
|
//#region src/virtualModules/shareTags.ts
|
|
2169
1829
|
const LOAD_SHARE_TAG = "__loadShare__";
|
|
2170
1830
|
/** A share's local copy. Reachable only through `import()`, so it stays lazy. */
|
|
@@ -2247,7 +1907,6 @@ function findEagerFallbacksInSharedChunk(bundle) {
|
|
|
2247
1907
|
* 1. __prebuild__: export shareModule (pre-built source code of modules such as vue, react, etc.)
|
|
2248
1908
|
* 2. __loadShare__: load shareModule (mfRuntime.loadShare('vue'))
|
|
2249
1909
|
*/
|
|
2250
|
-
const JS_IDENTIFIER_REGEX = /* @__PURE__ */ new RegExp("^[$_\\p{ID_Start}][$_\\u200C\\u200D\\p{ID_Continue}]*$", "u");
|
|
2251
1910
|
function escapeGeneratedStringLiteral(value) {
|
|
2252
1911
|
return JSON.stringify(value).replace(/[<>\u2028\u2029]/g, (char) => {
|
|
2253
1912
|
switch (char) {
|
|
@@ -2265,13 +1924,9 @@ function getDefaultOrNamespaceExpression(namespace) {
|
|
|
2265
1924
|
function getSharedCacheDescriptorLiteral(pkg, shareItem) {
|
|
2266
1925
|
return JSON.stringify(getSharedCacheDescriptor(pkg, shareItem));
|
|
2267
1926
|
}
|
|
2268
|
-
function isValidJsIdentifier(name) {
|
|
2269
|
-
return JS_IDENTIFIER_REGEX.test(name);
|
|
2270
|
-
}
|
|
2271
1927
|
function isValidEsmExportName(name) {
|
|
2272
1928
|
return !!name && name !== "default" && name !== "__esModule" && isValidJsIdentifier(name);
|
|
2273
1929
|
}
|
|
2274
|
-
const JS_IDENTIFIER_PATTERN = `[\$_\\p{ID_Start}][\$_\\u200C\\u200D\\p{ID_Continue}]*`;
|
|
2275
1930
|
function resolvePackageEntryFromProjectRoot(pkg) {
|
|
2276
1931
|
try {
|
|
2277
1932
|
return resolveModulePath(pkg, path$1.join(getPackageDetectionCwd(), "package.json"));
|
|
@@ -2279,14 +1934,18 @@ function resolvePackageEntryFromProjectRoot(pkg) {
|
|
|
2279
1934
|
return;
|
|
2280
1935
|
}
|
|
2281
1936
|
}
|
|
1937
|
+
let workspaceEntryConditions = [
|
|
1938
|
+
"browser",
|
|
1939
|
+
"import",
|
|
1940
|
+
"module",
|
|
1941
|
+
"default"
|
|
1942
|
+
];
|
|
1943
|
+
function setWorkspaceEntryConditions(conditions) {
|
|
1944
|
+
workspaceEntryConditions = conditions;
|
|
1945
|
+
}
|
|
2282
1946
|
function getPackageEsmEntryPath(pkg) {
|
|
2283
1947
|
return getInstalledPackageEntry(pkg, {
|
|
2284
|
-
conditions:
|
|
2285
|
-
"browser",
|
|
2286
|
-
"import",
|
|
2287
|
-
"module",
|
|
2288
|
-
"default"
|
|
2289
|
-
],
|
|
1948
|
+
conditions: workspaceEntryConditions,
|
|
2290
1949
|
resolveSubpathWithRequire: false
|
|
2291
1950
|
}) || resolvePackageEntryFromProjectRoot(pkg);
|
|
2292
1951
|
}
|
|
@@ -2796,12 +2455,7 @@ function getLocalProviderImportPath(pkg) {
|
|
|
2796
2455
|
return isWorkspaceFilePath(resolved) ? resolved : void 0;
|
|
2797
2456
|
} catch {
|
|
2798
2457
|
const resolved = getInstalledPackageEntry(pkg, {
|
|
2799
|
-
conditions:
|
|
2800
|
-
"browser",
|
|
2801
|
-
"import",
|
|
2802
|
-
"module",
|
|
2803
|
-
"default"
|
|
2804
|
-
],
|
|
2458
|
+
conditions: workspaceEntryConditions,
|
|
2805
2459
|
resolveSubpathWithRequire: false
|
|
2806
2460
|
});
|
|
2807
2461
|
return isWorkspaceFilePath(resolved) ? resolved : void 0;
|
|
@@ -2839,12 +2493,7 @@ function resolveWorkspaceEsmEntry(pkg, resolved, cwd = getPackageDetectionCwd())
|
|
|
2839
2493
|
if (!isWorkspaceFilePath(resolved)) return resolved;
|
|
2840
2494
|
const esmEntry = getInstalledPackageEntry(pkg, {
|
|
2841
2495
|
cwd,
|
|
2842
|
-
conditions:
|
|
2843
|
-
"browser",
|
|
2844
|
-
"import",
|
|
2845
|
-
"module",
|
|
2846
|
-
"default"
|
|
2847
|
-
],
|
|
2496
|
+
conditions: workspaceEntryConditions,
|
|
2848
2497
|
resolveSubpathWithRequire: false
|
|
2849
2498
|
});
|
|
2850
2499
|
if (esmEntry && isWorkspaceFilePath(esmEntry)) return esmEntry;
|
|
@@ -2965,7 +2614,7 @@ function resolveConcreteSharedImportSource(pkg, projectRoot) {
|
|
|
2965
2614
|
currentDir = path$1.dirname(currentDir);
|
|
2966
2615
|
}
|
|
2967
2616
|
return tryResolveImportFromPackageRoot(pkg, currentDir) ?? getInstalledPackageEntry(pkg, {
|
|
2968
|
-
conditions:
|
|
2617
|
+
conditions: workspaceEntryConditions,
|
|
2969
2618
|
resolveSubpathWithRequire: false
|
|
2970
2619
|
});
|
|
2971
2620
|
}
|
|
@@ -3630,9 +3279,426 @@ function writeLoadShareModule(pkg, shareItem, command, options, exportConditions
|
|
|
3630
3279
|
if (exportModule === undefined) {
|
|
3631
3280
|
${initBlock}
|
|
3632
3281
|
}
|
|
3633
|
-
${exportLine}
|
|
3282
|
+
${exportLine}
|
|
3283
|
+
`;
|
|
3284
|
+
loadShareCacheMap[pkg].writeSync(moduleBody, true);
|
|
3285
|
+
}
|
|
3286
|
+
//#endregion
|
|
3287
|
+
//#region src/utils/localShareImports.ts
|
|
3288
|
+
/**
|
|
3289
|
+
* The source file of a share whose `import` points at a project file rather than an installed
|
|
3290
|
+
* package, such as an application module shared with its micro frontends. Installed packages
|
|
3291
|
+
* describe their dependencies in `package.json`, so a path import of an installed package (a shim)
|
|
3292
|
+
* is not local. Undefined when the file cannot be found.
|
|
3293
|
+
*/
|
|
3294
|
+
function getLocalShareSourceFile(pkg, shareItem) {
|
|
3295
|
+
const importSource = shareItem?.shareConfig?.import;
|
|
3296
|
+
if (typeof importSource !== "string") return void 0;
|
|
3297
|
+
if (!importSource.startsWith(".") && !path$1.isAbsolute(importSource)) return void 0;
|
|
3298
|
+
if (getInstalledPackageJson(getPackageName(pkg)) !== void 0) return void 0;
|
|
3299
|
+
return resolveConfiguredImportPath(importSource);
|
|
3300
|
+
}
|
|
3301
|
+
const specifiersByFile = /* @__PURE__ */ new Map();
|
|
3302
|
+
/** Specifiers a file evaluates (static, not type-only), cached until the file changes; empty when it cannot be read. */
|
|
3303
|
+
function readStaticImportSpecifiers(file) {
|
|
3304
|
+
try {
|
|
3305
|
+
const { mtimeMs } = statSync(file);
|
|
3306
|
+
const cached = specifiersByFile.get(file);
|
|
3307
|
+
if (cached && cached.mtimeMs === mtimeMs) return cached.specifiers;
|
|
3308
|
+
const specifiers = findModuleImportDescriptors(readFileSync(file, "utf-8")).filter(({ kind, typeOnly }) => kind === "static" && !typeOnly).map(({ source }) => source);
|
|
3309
|
+
specifiersByFile.set(file, {
|
|
3310
|
+
mtimeMs,
|
|
3311
|
+
specifiers
|
|
3312
|
+
});
|
|
3313
|
+
return specifiers;
|
|
3314
|
+
} catch {
|
|
3315
|
+
return [];
|
|
3316
|
+
}
|
|
3317
|
+
}
|
|
3318
|
+
/**
|
|
3319
|
+
* Keys of the other local shares that `sourceFile` imports at evaluation time, by key (or request)
|
|
3320
|
+
* or by source file, directly or through relative imports of project files that are not shared.
|
|
3321
|
+
* `localShareFiles` maps each local share's key to its source file; `requests` maps a share's
|
|
3322
|
+
* request to its key when they differ.
|
|
3323
|
+
*/
|
|
3324
|
+
function getImportedLocalShares(sourceFile, localShareFiles, requests = /* @__PURE__ */ new Map()) {
|
|
3325
|
+
const keysByFile = new Map(Array.from(localShareFiles, ([key, file]) => [file, key]));
|
|
3326
|
+
const imported = /* @__PURE__ */ new Set();
|
|
3327
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3328
|
+
const visit = (file) => {
|
|
3329
|
+
if (visited.has(file)) return;
|
|
3330
|
+
visited.add(file);
|
|
3331
|
+
for (const specifier of readStaticImportSpecifiers(file)) if (specifier.startsWith(".")) {
|
|
3332
|
+
const resolved = resolveRelativeModule(file, specifier);
|
|
3333
|
+
if (!resolved || resolved.split(path$1.sep).includes("node_modules")) continue;
|
|
3334
|
+
const key = keysByFile.get(resolved);
|
|
3335
|
+
if (key !== void 0) imported.add(key);
|
|
3336
|
+
else visit(resolved);
|
|
3337
|
+
} else {
|
|
3338
|
+
const key = localShareFiles.has(specifier) ? specifier : requests.get(specifier);
|
|
3339
|
+
if (key !== void 0) imported.add(key);
|
|
3340
|
+
}
|
|
3341
|
+
};
|
|
3342
|
+
visit(sourceFile);
|
|
3343
|
+
const self = keysByFile.get(sourceFile);
|
|
3344
|
+
if (self !== void 0) imported.delete(self);
|
|
3345
|
+
return [...imported];
|
|
3346
|
+
}
|
|
3347
|
+
//#endregion
|
|
3348
|
+
//#region src/utils/runtimePluginSpecifier.ts
|
|
3349
|
+
function getRuntimePluginSpecifier(plugin) {
|
|
3350
|
+
return typeof plugin === "string" ? plugin : plugin[0];
|
|
3351
|
+
}
|
|
3352
|
+
/** Drop SSR-only plugins from a client graph; a server graph keeps them all. */
|
|
3353
|
+
function filterRuntimePluginsForTarget(runtimePlugins, ssrOnlySpecifiers, isServer) {
|
|
3354
|
+
if (isServer) return [...runtimePlugins];
|
|
3355
|
+
return runtimePlugins.filter((plugin) => !ssrOnlySpecifiers.has(getRuntimePluginSpecifier(plugin)));
|
|
3356
|
+
}
|
|
3357
|
+
//#endregion
|
|
3358
|
+
//#region src/utils/reactIsland.ts
|
|
3359
|
+
const SOURCE_EXTENSIONS$1 = [
|
|
3360
|
+
".tsx",
|
|
3361
|
+
".jsx",
|
|
3362
|
+
".ts",
|
|
3363
|
+
".js",
|
|
3364
|
+
".mts",
|
|
3365
|
+
".mjs",
|
|
3366
|
+
".cts",
|
|
3367
|
+
".cjs"
|
|
3368
|
+
];
|
|
3369
|
+
function resolveSourceFile(importPath, root) {
|
|
3370
|
+
const cleanImport = stripQueryAndHash(importPath);
|
|
3371
|
+
if (!cleanImport.startsWith(".") && !path$1.isAbsolute(cleanImport)) return;
|
|
3372
|
+
const candidate = path$1.isAbsolute(cleanImport) ? cleanImport : path$1.resolve(root, cleanImport);
|
|
3373
|
+
return [
|
|
3374
|
+
candidate,
|
|
3375
|
+
...SOURCE_EXTENSIONS$1.map((extension) => `${candidate}${extension}`),
|
|
3376
|
+
...SOURCE_EXTENSIONS$1.map((extension) => path$1.join(candidate, `index${extension}`))
|
|
3377
|
+
].find((filePath) => {
|
|
3378
|
+
try {
|
|
3379
|
+
return fs$1.statSync(filePath).isFile();
|
|
3380
|
+
} catch {
|
|
3381
|
+
return false;
|
|
3382
|
+
}
|
|
3383
|
+
});
|
|
3384
|
+
}
|
|
3385
|
+
function localDefaultReexport(source) {
|
|
3386
|
+
const match = source.match(/export\s*{\s*(?:default(?:\s+as\s+default)?|[A-Za-z_$][\w$]*\s+as\s+default)\s*}\s*from\s*["']([^"']+)["']/);
|
|
3387
|
+
return match?.[1]?.startsWith(".") ? match[1] : void 0;
|
|
3388
|
+
}
|
|
3389
|
+
function isReactComponentSource(source, filePath = "component.tsx") {
|
|
3390
|
+
if (!(/\bexport\s+default\b/.test(source) || /\bexport\s*{[^}]*\bdefault\b[^}]*}(?:\s*from\s*["'][^"']+["'])?/.test(source))) return false;
|
|
3391
|
+
const extension = path$1.extname(stripQueryAndHash(filePath)).toLowerCase();
|
|
3392
|
+
const canContainJsx = extension === ".tsx" || extension === ".jsx";
|
|
3393
|
+
const hasJsx = /<>|<\s*[A-Za-z][\w.:-]*(?:\s[^<>]*?)?\s*\/?>/.test(source);
|
|
3394
|
+
const importsReact = /\bfrom\s*["']react["']|\brequire\(\s*["']react["']\s*\)/.test(source);
|
|
3395
|
+
const usesReactApi = /\b(?:React\.)?(?:createElement|jsx|jsxs)\s*\(/.test(source);
|
|
3396
|
+
const isClientModule = /^\s*["']use client["']\s*;?/m.test(source);
|
|
3397
|
+
return canContainJsx && hasJsx || importsReact && (hasJsx || usesReactApi || isClientModule);
|
|
3398
|
+
}
|
|
3399
|
+
function isReactComponentFile(filePath, seen = /* @__PURE__ */ new Set()) {
|
|
3400
|
+
const normalizedPath = path$1.resolve(filePath);
|
|
3401
|
+
if (seen.has(normalizedPath)) return false;
|
|
3402
|
+
seen.add(normalizedPath);
|
|
3403
|
+
let source;
|
|
3404
|
+
try {
|
|
3405
|
+
source = fs$1.readFileSync(normalizedPath, "utf8");
|
|
3406
|
+
} catch {
|
|
3407
|
+
return false;
|
|
3408
|
+
}
|
|
3409
|
+
if (isReactComponentSource(source, normalizedPath)) return true;
|
|
3410
|
+
const reexport = localDefaultReexport(source);
|
|
3411
|
+
if (!reexport) return false;
|
|
3412
|
+
const reexportPath = resolveSourceFile(reexport, path$1.dirname(normalizedPath));
|
|
3413
|
+
return reexportPath ? isReactComponentFile(reexportPath, seen) : false;
|
|
3414
|
+
}
|
|
3415
|
+
/**
|
|
3416
|
+
* React is shared by the normal MF runtime when explicitly configured. When it
|
|
3417
|
+
* is local, UI exposes can safely advertise an island capability in addition
|
|
3418
|
+
* to their unchanged default export.
|
|
3419
|
+
*/
|
|
3420
|
+
function getReactIslandExposes(options, root) {
|
|
3421
|
+
if (options.experiments.ssrMode !== "ISLAND") return /* @__PURE__ */ new Set();
|
|
3422
|
+
if (Object.hasOwn(options.shared, "react")) return /* @__PURE__ */ new Set();
|
|
3423
|
+
const islandExposes = /* @__PURE__ */ new Set();
|
|
3424
|
+
for (const [key, expose] of Object.entries(options.exposes)) {
|
|
3425
|
+
const sourceFile = resolveSourceFile(expose.import, root);
|
|
3426
|
+
if (sourceFile && isReactComponentFile(sourceFile)) islandExposes.add(key);
|
|
3427
|
+
}
|
|
3428
|
+
return islandExposes;
|
|
3429
|
+
}
|
|
3430
|
+
function generateReactIslandBrowserDefinition(enabled) {
|
|
3431
|
+
if (!enabled) return "";
|
|
3432
|
+
return `
|
|
3433
|
+
exportModule.__mf_island = {
|
|
3434
|
+
version: 1,
|
|
3435
|
+
renderToHtml() {
|
|
3436
|
+
return Promise.reject(new Error("[Module Federation] renderToHtml is only available in the SSR remote entry"));
|
|
3437
|
+
},
|
|
3438
|
+
hydrate(element, props) {
|
|
3439
|
+
const root = element && element.hasAttribute && element.hasAttribute("data-mf-island-state")
|
|
3440
|
+
? element
|
|
3441
|
+
: element && element.querySelector
|
|
3442
|
+
? element.querySelector("[data-mf-island-state]") || element
|
|
3443
|
+
: element;
|
|
3444
|
+
if (!root) {
|
|
3445
|
+
return Promise.reject(new Error("[Module Federation] Cannot hydrate an island without a root element"));
|
|
3446
|
+
}
|
|
3447
|
+
let serverProps = {};
|
|
3448
|
+
const encodedState = root.getAttribute && root.getAttribute("data-mf-island-state");
|
|
3449
|
+
if (encodedState) {
|
|
3450
|
+
try {
|
|
3451
|
+
serverProps = JSON.parse(decodeURIComponent(encodedState));
|
|
3452
|
+
} catch {
|
|
3453
|
+
serverProps = {};
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
const finalProps = Object.assign({}, serverProps, props || {});
|
|
3457
|
+
return Promise.all([import("react"), import("react-dom/client")]).then(([React, ReactDOMClient]) => {
|
|
3458
|
+
if (typeof ReactDOMClient.hydrateRoot !== "function") {
|
|
3459
|
+
throw new Error("[Module Federation] react-dom/client does not provide hydrateRoot");
|
|
3460
|
+
}
|
|
3461
|
+
return ReactDOMClient.hydrateRoot(
|
|
3462
|
+
root,
|
|
3463
|
+
React.createElement(importModule.default, finalProps)
|
|
3464
|
+
);
|
|
3465
|
+
});
|
|
3466
|
+
}
|
|
3467
|
+
}`;
|
|
3468
|
+
}
|
|
3469
|
+
function generateReactIslandSSRDefinition(enabled) {
|
|
3470
|
+
if (!enabled) return "";
|
|
3471
|
+
return `
|
|
3472
|
+
exportModule.__mf_island = {
|
|
3473
|
+
version: 1,
|
|
3474
|
+
async renderToHtml(props) {
|
|
3475
|
+
if (typeof importModule.default !== "function" && typeof importModule.default !== "object") {
|
|
3476
|
+
throw new Error("[Module Federation] A React island expose must have a default component export");
|
|
3477
|
+
}
|
|
3478
|
+
const loadedProps = typeof importModule.load === "function" ? await importModule.load() : {};
|
|
3479
|
+
const finalProps = Object.assign({}, loadedProps || {}, props || {});
|
|
3480
|
+
const [React, ReactDOMServer] = await Promise.all([
|
|
3481
|
+
import("react"),
|
|
3482
|
+
import("react-dom/server")
|
|
3483
|
+
]);
|
|
3484
|
+
const body = ReactDOMServer.renderToString(
|
|
3485
|
+
React.createElement(importModule.default, finalProps)
|
|
3486
|
+
);
|
|
3487
|
+
const state = encodeURIComponent(JSON.stringify(finalProps));
|
|
3488
|
+
return '<div data-mf-island-state="' + state + '">' + body + '</div>';
|
|
3489
|
+
},
|
|
3490
|
+
hydrate() {
|
|
3491
|
+
return Promise.reject(new Error("[Module Federation] hydrate is only available in the browser remote entry"));
|
|
3492
|
+
}
|
|
3493
|
+
}`;
|
|
3494
|
+
}
|
|
3495
|
+
const REACT_ISLAND_CLIENT_ID_PREFIX = "virtual:mf-react-island-client:";
|
|
3496
|
+
const REACT_ISLAND_SERVER_ID_PREFIX = "virtual:mf-react-island-server:";
|
|
3497
|
+
const RESOLVED_REACT_ISLAND_CLIENT_ID_PREFIX = `\0${REACT_ISLAND_CLIENT_ID_PREFIX}`;
|
|
3498
|
+
const RESOLVED_REACT_ISLAND_SERVER_ID_PREFIX = `\0${REACT_ISLAND_SERVER_ID_PREFIX}`;
|
|
3499
|
+
function encodeIslandRemoteId(remoteId) {
|
|
3500
|
+
return encodeURIComponent(remoteId);
|
|
3501
|
+
}
|
|
3502
|
+
function decodeIslandRemoteId(encodedRemoteId) {
|
|
3503
|
+
return decodeURIComponent(encodedRemoteId);
|
|
3504
|
+
}
|
|
3505
|
+
function getReactIslandImportRemoteId(source) {
|
|
3506
|
+
const queryIndex = source.indexOf("?");
|
|
3507
|
+
if (queryIndex === -1) return;
|
|
3508
|
+
if (!new URLSearchParams(source.slice(queryIndex + 1)).has("mf-island")) return;
|
|
3509
|
+
return source.slice(0, queryIndex);
|
|
3510
|
+
}
|
|
3511
|
+
function getReactIslandServerImportId(remoteId) {
|
|
3512
|
+
return `${REACT_ISLAND_SERVER_ID_PREFIX}${encodeIslandRemoteId(remoteId)}`;
|
|
3513
|
+
}
|
|
3514
|
+
function getReactIslandClientImportId(remoteId) {
|
|
3515
|
+
return `${REACT_ISLAND_CLIENT_ID_PREFIX}${encodeIslandRemoteId(remoteId)}`;
|
|
3516
|
+
}
|
|
3517
|
+
function resolveReactIslandConsumerId(id) {
|
|
3518
|
+
if (id.startsWith("virtual:mf-react-island-server:")) return `\0${id}`;
|
|
3519
|
+
if (id.startsWith("virtual:mf-react-island-client:")) return `\0${id}`;
|
|
3520
|
+
}
|
|
3521
|
+
function remoteIdFromResolvedIslandId(id, prefix) {
|
|
3522
|
+
if (!id.startsWith(prefix)) return;
|
|
3523
|
+
return decodeIslandRemoteId(id.slice(prefix.length));
|
|
3524
|
+
}
|
|
3525
|
+
/** Generates the server half of the opt-in `?mf-island` consumer component. */
|
|
3526
|
+
function generateReactIslandConsumerServer(remoteId) {
|
|
3527
|
+
const source = JSON.stringify(remoteId);
|
|
3528
|
+
return `import * as React from "react";
|
|
3529
|
+
import IslandClient from ${JSON.stringify(getReactIslandClientImportId(remoteId))};
|
|
3530
|
+
|
|
3531
|
+
const islandModulePromise = import(${source});
|
|
3532
|
+
|
|
3533
|
+
async function loadIslandModule() {
|
|
3534
|
+
const namespace = await islandModulePromise;
|
|
3535
|
+
const pending = namespace && namespace.__mf_remote_pending;
|
|
3536
|
+
if (pending && typeof pending.then === "function") return pending;
|
|
3537
|
+
return namespace && namespace.__moduleExports || namespace;
|
|
3538
|
+
}
|
|
3539
|
+
|
|
3540
|
+
export default async function ModuleFederationIsland(props) {
|
|
3541
|
+
const remoteModule = await loadIslandModule();
|
|
3542
|
+
const shell = remoteModule && remoteModule.__mf_island;
|
|
3543
|
+
if (!shell || typeof shell.renderToHtml !== "function") {
|
|
3544
|
+
throw new Error(${JSON.stringify(`[Module Federation] ${remoteId} does not expose an SSR island capability`)});
|
|
3545
|
+
}
|
|
3546
|
+
const html = await shell.renderToHtml(props);
|
|
3547
|
+
return React.createElement(IslandClient, { html, islandProps: props });
|
|
3548
|
+
}`;
|
|
3549
|
+
}
|
|
3550
|
+
/** Generates the client boundary which hydrates with the remote-owned React. */
|
|
3551
|
+
function generateReactIslandConsumerClient(remoteId) {
|
|
3552
|
+
return `"use client";
|
|
3553
|
+
|
|
3554
|
+
import * as React from "react";
|
|
3555
|
+
|
|
3556
|
+
const islandModulePromise = import(${JSON.stringify(remoteId)});
|
|
3557
|
+
|
|
3558
|
+
async function loadIslandModule() {
|
|
3559
|
+
const namespace = await islandModulePromise;
|
|
3560
|
+
const pending = namespace && namespace.__mf_remote_pending;
|
|
3561
|
+
if (pending && typeof pending.then === "function") return pending;
|
|
3562
|
+
return namespace && namespace.__moduleExports || namespace;
|
|
3563
|
+
}
|
|
3564
|
+
|
|
3565
|
+
export default function ModuleFederationIslandClient({ html, islandProps }) {
|
|
3566
|
+
const ref = React.useRef(null);
|
|
3567
|
+
|
|
3568
|
+
React.useEffect(() => {
|
|
3569
|
+
const element = ref.current;
|
|
3570
|
+
if (!element) return;
|
|
3571
|
+
void loadIslandModule().then((remoteModule) => {
|
|
3572
|
+
const shell = remoteModule && remoteModule.__mf_island;
|
|
3573
|
+
if (!shell || typeof shell.hydrate !== "function") {
|
|
3574
|
+
throw new Error(${JSON.stringify(`[Module Federation] ${remoteId} does not expose a client island capability`)});
|
|
3575
|
+
}
|
|
3576
|
+
return shell.hydrate(element, islandProps);
|
|
3577
|
+
});
|
|
3578
|
+
}, []);
|
|
3579
|
+
|
|
3580
|
+
return React.createElement("div", {
|
|
3581
|
+
ref,
|
|
3582
|
+
suppressHydrationWarning: true,
|
|
3583
|
+
dangerouslySetInnerHTML: { __html: html },
|
|
3584
|
+
});
|
|
3585
|
+
}`;
|
|
3586
|
+
}
|
|
3587
|
+
function loadReactIslandConsumerModule(id) {
|
|
3588
|
+
const serverRemoteId = remoteIdFromResolvedIslandId(id, RESOLVED_REACT_ISLAND_SERVER_ID_PREFIX);
|
|
3589
|
+
if (serverRemoteId !== void 0) return generateReactIslandConsumerServer(serverRemoteId);
|
|
3590
|
+
const clientRemoteId = remoteIdFromResolvedIslandId(id, RESOLVED_REACT_ISLAND_CLIENT_ID_PREFIX);
|
|
3591
|
+
if (clientRemoteId !== void 0) return generateReactIslandConsumerClient(clientRemoteId);
|
|
3592
|
+
}
|
|
3593
|
+
//#endregion
|
|
3594
|
+
//#region src/virtualModules/virtualExposes.ts
|
|
3595
|
+
const EXPOSES_CSS_MAP_PLACEHOLDER = "__MF_EXPOSES_CSS_MAP__";
|
|
3596
|
+
function getExposesCssMapPlaceholder() {
|
|
3597
|
+
return EXPOSES_CSS_MAP_PLACEHOLDER;
|
|
3598
|
+
}
|
|
3599
|
+
function getVirtualExposesId(options) {
|
|
3600
|
+
return `virtual:mf-exposes:${getVirtualModuleScopeKey(options)}`;
|
|
3601
|
+
}
|
|
3602
|
+
function generateExposes(options, remoteDependencyMap = {}, command = "build", reactIslandExposes = /* @__PURE__ */ new Set()) {
|
|
3603
|
+
return `
|
|
3604
|
+
const cssAssetMap = ${JSON.stringify(options.bundleAllCSS ? EXPOSES_CSS_MAP_PLACEHOLDER : {})};
|
|
3605
|
+
const injectedCssHrefs = new Set();
|
|
3606
|
+
const exposeLoadPromises = new Map();
|
|
3607
|
+
|
|
3608
|
+
// Shared and remote readiness is handled by explicit Promise barriers below
|
|
3609
|
+
// and by remoteEntry's pendingShareLoads barrier. Keep this map scoped to a
|
|
3610
|
+
// single expose: unrelated exposes must stay independent and load in parallel.
|
|
3611
|
+
function loadExposedModule(exposeKey, loader) {
|
|
3612
|
+
let load = exposeLoadPromises.get(exposeKey);
|
|
3613
|
+
if (!load) {
|
|
3614
|
+
load = Promise.resolve()
|
|
3615
|
+
.then(loader)
|
|
3616
|
+
.catch((error) => {
|
|
3617
|
+
exposeLoadPromises.delete(exposeKey);
|
|
3618
|
+
throw error;
|
|
3619
|
+
});
|
|
3620
|
+
exposeLoadPromises.set(exposeKey, load);
|
|
3621
|
+
}
|
|
3622
|
+
return load;
|
|
3623
|
+
}
|
|
3624
|
+
|
|
3625
|
+
async function injectCssAssets(exposeKey) {
|
|
3626
|
+
if (typeof document === "undefined") {
|
|
3627
|
+
return;
|
|
3628
|
+
}
|
|
3629
|
+
|
|
3630
|
+
// Replaced at build time with expose -> css asset paths.
|
|
3631
|
+
const cssAssets = cssAssetMap[exposeKey] || [];
|
|
3632
|
+
|
|
3633
|
+
await Promise.all(
|
|
3634
|
+
cssAssets.map((cssAsset) => {
|
|
3635
|
+
const href = new URL(cssAsset, import.meta.url).href;
|
|
3636
|
+
|
|
3637
|
+
// Same expose can be resolved multiple times in one page.
|
|
3638
|
+
if (injectedCssHrefs.has(href)) {
|
|
3639
|
+
return Promise.resolve();
|
|
3640
|
+
}
|
|
3641
|
+
injectedCssHrefs.add(href);
|
|
3642
|
+
|
|
3643
|
+
// Check for any existing stylesheet with the same href, not just
|
|
3644
|
+
// MF-injected ones. This prevents duplicate <link> tags when Vite's
|
|
3645
|
+
// own CSS module injection or MF runtime's createLink has already
|
|
3646
|
+
// created a <link rel="stylesheet"> for the same URL.
|
|
3647
|
+
const existingLink = document.querySelector(
|
|
3648
|
+
\`link[rel="stylesheet"][href="\${href}"]\`
|
|
3649
|
+
);
|
|
3650
|
+
if (existingLink) {
|
|
3651
|
+
return Promise.resolve();
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3654
|
+
return new Promise((resolve, reject) => {
|
|
3655
|
+
const link = document.createElement("link");
|
|
3656
|
+
link.rel = "stylesheet";
|
|
3657
|
+
link.href = href;
|
|
3658
|
+
link.onload = () => resolve();
|
|
3659
|
+
link.onerror = () => {
|
|
3660
|
+
injectedCssHrefs.delete(href);
|
|
3661
|
+
link.remove();
|
|
3662
|
+
reject(new Error(\`[Module Federation] Failed to load CSS asset: \${href}\`));
|
|
3663
|
+
};
|
|
3664
|
+
document.head.appendChild(link);
|
|
3665
|
+
});
|
|
3666
|
+
})
|
|
3667
|
+
);
|
|
3668
|
+
}
|
|
3669
|
+
|
|
3670
|
+
export default {
|
|
3671
|
+
${Object.keys(options.exposes).map((key) => {
|
|
3672
|
+
const remoteDependencyPreloads = (remoteDependencyMap[key] ?? []).map((remoteId) => {
|
|
3673
|
+
const virtualRemote = getRemoteVirtualModule(remoteId, command, false, "unified", options);
|
|
3674
|
+
return `import(${JSON.stringify(virtualRemote.getImportId())})
|
|
3675
|
+
.then((mod) => mod.__mf_remote_pending)`;
|
|
3676
|
+
}).join(",");
|
|
3677
|
+
return `
|
|
3678
|
+
${JSON.stringify(key)}: async () => {
|
|
3679
|
+
await injectCssAssets(${JSON.stringify(key)})
|
|
3680
|
+
await Promise.all([${remoteDependencyPreloads}])
|
|
3681
|
+
const importModule = await loadExposedModule(
|
|
3682
|
+
${JSON.stringify(key)},
|
|
3683
|
+
() => import(${JSON.stringify(options.exposes[key].import)})
|
|
3684
|
+
)
|
|
3685
|
+
const dependencyPending = importModule && importModule.__mf_remote_dependency_pending;
|
|
3686
|
+
if (dependencyPending && typeof dependencyPending.then === "function") {
|
|
3687
|
+
await dependencyPending;
|
|
3688
|
+
}
|
|
3689
|
+
const exportModule = {}
|
|
3690
|
+
Object.assign(exportModule, importModule)
|
|
3691
|
+
${generateReactIslandBrowserDefinition(reactIslandExposes.has(key))}
|
|
3692
|
+
Object.defineProperty(exportModule, "__esModule", {
|
|
3693
|
+
value: true,
|
|
3694
|
+
enumerable: false
|
|
3695
|
+
})
|
|
3696
|
+
return exportModule
|
|
3697
|
+
}
|
|
3698
|
+
`;
|
|
3699
|
+
}).join(",")}
|
|
3700
|
+
}
|
|
3634
3701
|
`;
|
|
3635
|
-
loadShareCacheMap[pkg].writeSync(moduleBody, true);
|
|
3636
3702
|
}
|
|
3637
3703
|
//#endregion
|
|
3638
3704
|
//#region src/virtualModules/virtualRemoteEntry.ts
|
|
@@ -3947,7 +4013,7 @@ function getOrderedUsedShares(options) {
|
|
|
3947
4013
|
return orderSharedDependenciesFirst(Array.from(shares).sort((a, b) => {
|
|
3948
4014
|
const priority = (pkg) => pkg === "react" ? 0 : pkg === "react-dom" ? 1 : pkg.startsWith("react/") ? 2 : 3;
|
|
3949
4015
|
return priority(a) - priority(b) || a.localeCompare(b);
|
|
3950
|
-
}));
|
|
4016
|
+
}), options);
|
|
3951
4017
|
}
|
|
3952
4018
|
function getMaterializedShares(options) {
|
|
3953
4019
|
const shares = new Set(materializedSharesByOptions.get(options));
|
|
@@ -3959,14 +4025,20 @@ function getMaterializedShares(options) {
|
|
|
3959
4025
|
else shares.add(pkg);
|
|
3960
4026
|
}
|
|
3961
4027
|
const configured = /* @__PURE__ */ new Map();
|
|
3962
|
-
|
|
4028
|
+
const orderedUsed = getOrderedUsedShares(options);
|
|
4029
|
+
for (const pkg of orderedUsed) {
|
|
3963
4030
|
const packageName = getPackageName(pkg);
|
|
3964
4031
|
if (!configured.has(packageName) || pkg === packageName) configured.set(packageName, pkg);
|
|
3965
4032
|
}
|
|
4033
|
+
const localImports = getLocalShareImports(orderedUsed, options);
|
|
3966
4034
|
const pending = [...shares];
|
|
3967
4035
|
while (pending.length) {
|
|
3968
4036
|
const pkg = pending.pop();
|
|
3969
4037
|
const share = getNormalizeShareItem(pkg, options);
|
|
4038
|
+
for (const imported of localImports.get(pkg) ?? []) if (!shares.has(imported) && getNormalizeShareItem(imported, options)?.scope === share?.scope) {
|
|
4039
|
+
shares.add(imported);
|
|
4040
|
+
pending.push(imported);
|
|
4041
|
+
}
|
|
3970
4042
|
const packageName = getPackageName(pkg);
|
|
3971
4043
|
const packageJson = getInstalledPackageJson(pkg)?.packageJson ?? (pkg !== packageName ? getInstalledPackageJson(packageName)?.packageJson : void 0);
|
|
3972
4044
|
const dependencies = {
|
|
@@ -3991,10 +4063,39 @@ function getMaterializedShares(options) {
|
|
|
3991
4063
|
return orderSharedDependenciesFirst([...new Set(sorted.map((pkg) => {
|
|
3992
4064
|
const shareItem = getNormalizeShareItem(pkg, options);
|
|
3993
4065
|
return shareItem ? getCanonicalSharedKey(pkg, shareItem) : pkg;
|
|
3994
|
-
}))]);
|
|
4066
|
+
}))], options);
|
|
4067
|
+
}
|
|
4068
|
+
/**
|
|
4069
|
+
* The other local shares each local share (one whose `import` is a project file) imports at module
|
|
4070
|
+
* evaluation, found through the static imports of its source and of the unshared project files it
|
|
4071
|
+
* imports, keyed by share. Only local shares have an entry.
|
|
4072
|
+
*/
|
|
4073
|
+
function getLocalShareImports(shares, options) {
|
|
4074
|
+
const localShareFiles = /* @__PURE__ */ new Map();
|
|
4075
|
+
const requests = /* @__PURE__ */ new Map();
|
|
4076
|
+
for (const pkg of shares) {
|
|
4077
|
+
const shareItem = getNormalizeShareItem(pkg, options);
|
|
4078
|
+
const sourceFile = getLocalShareSourceFile(pkg, shareItem);
|
|
4079
|
+
if (sourceFile === void 0) continue;
|
|
4080
|
+
localShareFiles.set(pkg, sourceFile);
|
|
4081
|
+
const request = getSharedRequest(pkg, shareItem);
|
|
4082
|
+
if (request !== pkg) requests.set(request, pkg);
|
|
4083
|
+
}
|
|
4084
|
+
return new Map(Array.from(localShareFiles, ([pkg, sourceFile]) => [pkg, getImportedLocalShares(sourceFile, localShareFiles, requests)]));
|
|
4085
|
+
}
|
|
4086
|
+
/**
|
|
4087
|
+
* Shares that must be materialized before each local share, keyed by share. A project file has no
|
|
4088
|
+
* package.json to read dependencies from and may import any shared package, directly or through
|
|
4089
|
+
* other project files, so every installed-package share comes first, followed by the local shares
|
|
4090
|
+
* its source imports (see #1507).
|
|
4091
|
+
*/
|
|
4092
|
+
function getLocalSharePrerequisites(shares, options) {
|
|
4093
|
+
const localImports = getLocalShareImports(shares, options);
|
|
4094
|
+
const packageShares = shares.filter((pkg) => !localImports.has(pkg));
|
|
4095
|
+
return new Map(Array.from(localImports, ([pkg, imports]) => [pkg, [...packageShares, ...imports]]));
|
|
3995
4096
|
}
|
|
3996
4097
|
/** Shared keys a share's package.json depends on (roots stand in for their subpaths, subpaths for their root), keyed by share. */
|
|
3997
|
-
function getSharePrerequisites(ordered) {
|
|
4098
|
+
function getSharePrerequisites(ordered, options) {
|
|
3998
4099
|
const roots = /* @__PURE__ */ new Map();
|
|
3999
4100
|
const subpaths = /* @__PURE__ */ new Map();
|
|
4000
4101
|
for (const pkg of ordered) {
|
|
@@ -4003,7 +4104,13 @@ function getSharePrerequisites(ordered) {
|
|
|
4003
4104
|
else subpaths.set(packageName, [...subpaths.get(packageName) ?? [], pkg]);
|
|
4004
4105
|
}
|
|
4005
4106
|
const prerequisitesByShare = /* @__PURE__ */ new Map();
|
|
4107
|
+
const localPrerequisites = getLocalSharePrerequisites(ordered, options);
|
|
4006
4108
|
for (const pkg of ordered) {
|
|
4109
|
+
const local = localPrerequisites.get(pkg);
|
|
4110
|
+
if (local) {
|
|
4111
|
+
prerequisitesByShare.set(pkg, local);
|
|
4112
|
+
continue;
|
|
4113
|
+
}
|
|
4007
4114
|
const packageName = getPackageName(pkg);
|
|
4008
4115
|
const packageJson = getInstalledPackageJson(pkg)?.packageJson ?? (pkg !== packageName ? getInstalledPackageJson(packageName)?.packageJson : void 0);
|
|
4009
4116
|
const dependencies = {
|
|
@@ -4023,14 +4130,15 @@ function getSharePrerequisites(ordered) {
|
|
|
4023
4130
|
}
|
|
4024
4131
|
function getShareBatches(options, materializedOnly = true) {
|
|
4025
4132
|
const ordered = materializedOnly ? getMaterializedShares(options) : getOrderedUsedShares(options);
|
|
4026
|
-
const prerequisitesByShare = getSharePrerequisites(ordered);
|
|
4133
|
+
const prerequisitesByShare = getSharePrerequisites(ordered, options);
|
|
4027
4134
|
const levels = /* @__PURE__ */ new Map();
|
|
4028
4135
|
for (const pkg of ordered) levels.set(pkg, (prerequisitesByShare.get(pkg) ?? []).reduce((level, dependency) => Math.max(level, (levels.get(dependency) ?? 0) + 1), 0));
|
|
4029
4136
|
const batches = [];
|
|
4030
4137
|
for (const pkg of ordered) (batches[levels.get(pkg) ?? 0] ??= []).push(pkg);
|
|
4031
4138
|
return batches.filter(Boolean);
|
|
4032
4139
|
}
|
|
4033
|
-
function orderSharedDependenciesFirst(sharedPackages) {
|
|
4140
|
+
function orderSharedDependenciesFirst(sharedPackages, options) {
|
|
4141
|
+
const localPrerequisites = getLocalSharePrerequisites(sharedPackages, options);
|
|
4034
4142
|
const sharedKeyByPackageName = /* @__PURE__ */ new Map();
|
|
4035
4143
|
const subpathKeysByPackageName = /* @__PURE__ */ new Map();
|
|
4036
4144
|
sharedPackages.forEach((pkg) => {
|
|
@@ -4049,6 +4157,14 @@ function orderSharedDependenciesFirst(sharedPackages) {
|
|
|
4049
4157
|
if (visited.has(pkg)) return;
|
|
4050
4158
|
if (visiting.has(pkg)) return;
|
|
4051
4159
|
visiting.add(pkg);
|
|
4160
|
+
const local = localPrerequisites.get(pkg);
|
|
4161
|
+
if (local) {
|
|
4162
|
+
local.forEach(visit);
|
|
4163
|
+
visiting.delete(pkg);
|
|
4164
|
+
visited.add(pkg);
|
|
4165
|
+
ordered.push(pkg);
|
|
4166
|
+
return;
|
|
4167
|
+
}
|
|
4052
4168
|
const packageName = getPackageName(pkg);
|
|
4053
4169
|
const packageJson = getInstalledPackageJson(pkg)?.packageJson ?? (pkg !== packageName ? getInstalledPackageJson(packageName)?.packageJson : void 0);
|
|
4054
4170
|
const dependencies = {
|
|
@@ -4329,7 +4445,7 @@ function generateRuntimeSharedCacheSeedCode(shareStrategy, options, command = "b
|
|
|
4329
4445
|
const seedBatches = getShareBatches(options, false);
|
|
4330
4446
|
const seedOrder = seedBatches.flat();
|
|
4331
4447
|
const seedIndex = new Map(seedOrder.map((pkg, index) => [pkg, index]));
|
|
4332
|
-
const seedPrerequisites = Object.fromEntries(Array.from(getSharePrerequisites(seedOrder)).filter(([, prerequisites]) => prerequisites.length > 0).map(([pkg, prerequisites]) => [seedIndex.get(pkg), prerequisites.map((prerequisite) => seedIndex.get(prerequisite))]));
|
|
4448
|
+
const seedPrerequisites = Object.fromEntries(Array.from(getSharePrerequisites(seedOrder, options)).filter(([, prerequisites]) => prerequisites.length > 0).map(([pkg, prerequisites]) => [seedIndex.get(pkg), prerequisites.map((prerequisite) => seedIndex.get(prerequisite))]));
|
|
4333
4449
|
return `
|
|
4334
4450
|
const __mfSeedOrder = ${toSafeJsLiteral(seedOrder)};
|
|
4335
4451
|
const __mfSeedBatches = ${toSafeJsLiteral(seedBatches)};
|
|
@@ -8259,7 +8375,7 @@ function ${helperName}(names) {
|
|
|
8259
8375
|
}
|
|
8260
8376
|
//#endregion
|
|
8261
8377
|
//#region package.json
|
|
8262
|
-
var version$1 = "1.23.
|
|
8378
|
+
var version$1 = "1.23.8";
|
|
8263
8379
|
//#endregion
|
|
8264
8380
|
//#region src/virtualModules/virtualExposesSSR.ts
|
|
8265
8381
|
/**
|
|
@@ -8306,6 +8422,15 @@ const REMOTE_ENTRY_SSR_ID = "virtual:mf-REMOTE_ENTRY_SSR_ID";
|
|
|
8306
8422
|
function getRemoteEntrySSRId(options) {
|
|
8307
8423
|
return `${REMOTE_ENTRY_SSR_ID}:${getVirtualModuleScopeKey(options)}`;
|
|
8308
8424
|
}
|
|
8425
|
+
const SSR_HOST_INIT_ID = "virtual:mf-ssr-host-init";
|
|
8426
|
+
/**
|
|
8427
|
+
* The SSR entry's import of the host bootstrap. Keyed by config scope, not by federation()
|
|
8428
|
+
* instance: under the Vite builder the entry plugin is shared by every environment, so the
|
|
8429
|
+
* instance building each environment resolves it to its own bootstrap.
|
|
8430
|
+
*/
|
|
8431
|
+
function getSsrHostInitId(options) {
|
|
8432
|
+
return `${SSR_HOST_INIT_ID}:${getVirtualModuleScopeKey(options)}`;
|
|
8433
|
+
}
|
|
8309
8434
|
const FILE_EXTENSION_RE = /\.[^.]+$/;
|
|
8310
8435
|
function getSsrFileNameParts(browserFilename) {
|
|
8311
8436
|
const filename = resolveHashPlaceholderFileName(browserFilename);
|
|
@@ -8356,7 +8481,7 @@ function generateRemoteEntrySSR(options) {
|
|
|
8356
8481
|
const virtualExposesSSRId = getVirtualExposesSSRId(options);
|
|
8357
8482
|
const sharedSingletons = getSsrSharedSingletons(options);
|
|
8358
8483
|
return `
|
|
8359
|
-
${hasRemotes(options) ? `import { hostInitPromise } from ${JSON.stringify(
|
|
8484
|
+
${hasRemotes(options) ? `import { hostInitPromise } from ${JSON.stringify(getSsrHostInitId(options))};` : "import { init as runtimeInit } from \"@module-federation/runtime\";"}
|
|
8360
8485
|
|
|
8361
8486
|
const sharedSingletons = ${JSON.stringify(sharedSingletons)};
|
|
8362
8487
|
const moduleCacheKey = Symbol.for(${JSON.stringify(MODULE_CACHE_SHARE_SCOPE_KEY)});
|
|
@@ -8614,7 +8739,7 @@ function getRemoteContainerName(remoteKey, remote) {
|
|
|
8614
8739
|
}
|
|
8615
8740
|
const Manifest = (providedOptions) => {
|
|
8616
8741
|
const mfOptions = providedOptions ?? getNormalizeModuleFederationOptions();
|
|
8617
|
-
const {
|
|
8742
|
+
const { filename, getPublicPath, manifest: manifestOptions } = mfOptions;
|
|
8618
8743
|
let mfManifestName = manifestOptions === true ? "mf-manifest.json" : typeof manifestOptions === "object" ? normalizePathForImport(path$1.join(manifestOptions?.filePath || "", manifestOptions?.fileName || "mf-manifest.json")) : void 0;
|
|
8619
8744
|
let mfManifestStatsName = mfManifestName ? getStatsFileName(mfManifestName) : void 0;
|
|
8620
8745
|
const isConsumerProject = !isRemoteContainer(mfOptions);
|
|
@@ -8659,39 +8784,7 @@ const Manifest = (providedOptions) => {
|
|
|
8659
8784
|
res.setHeader("Content-Type", "application/json");
|
|
8660
8785
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
8661
8786
|
(async () => {
|
|
8662
|
-
const manifest = await applyManifestAdditionalData({
|
|
8663
|
-
...generateMFManifest({}, disableAssetsAnalyze),
|
|
8664
|
-
id: name,
|
|
8665
|
-
name,
|
|
8666
|
-
metaData: {
|
|
8667
|
-
name,
|
|
8668
|
-
type: "app",
|
|
8669
|
-
buildInfo: {
|
|
8670
|
-
buildVersion: getBuildVersion(),
|
|
8671
|
-
buildName: name,
|
|
8672
|
-
...getTreeShakingBuildInfo(mfOptions)
|
|
8673
|
-
},
|
|
8674
|
-
remoteEntry: {
|
|
8675
|
-
name: devRemoteEntryFile,
|
|
8676
|
-
path: "",
|
|
8677
|
-
type: "module"
|
|
8678
|
-
},
|
|
8679
|
-
ssrRemoteEntry: {
|
|
8680
|
-
name: getSsrRemoteEntryFileName(mfOptions, devRemoteEntryFile),
|
|
8681
|
-
path: "/__mf_ssr__/",
|
|
8682
|
-
type: "module"
|
|
8683
|
-
},
|
|
8684
|
-
varRemoteEntry: varFilename ? {
|
|
8685
|
-
name: varFilename,
|
|
8686
|
-
path: "",
|
|
8687
|
-
type: "var"
|
|
8688
|
-
} : void 0,
|
|
8689
|
-
types: resolveTypesMeta(mfOptions.dts),
|
|
8690
|
-
globalName: name,
|
|
8691
|
-
pluginVersion: version$1,
|
|
8692
|
-
...getPublicPath ? { getPublicPath } : { publicPath }
|
|
8693
|
-
}
|
|
8694
|
-
});
|
|
8787
|
+
const manifest = await applyManifestAdditionalData(generateMFManifest({}, disableAssetsAnalyze));
|
|
8695
8788
|
res.end(JSON.stringify(manifest));
|
|
8696
8789
|
})().catch(next);
|
|
8697
8790
|
} else next();
|
|
@@ -8766,7 +8859,7 @@ const Manifest = (providedOptions) => {
|
|
|
8766
8859
|
const expectedSsrRemoteEntryFile = getSsrRemoteEntryFileName(mfOptions);
|
|
8767
8860
|
const foundSsrRemoteEntryFile = Object.values(bundle).find((file) => file.fileName === expectedSsrRemoteEntryFile)?.fileName;
|
|
8768
8861
|
if (foundRemoteEntryFile) remoteEntryFile = foundRemoteEntryFile;
|
|
8769
|
-
ssrRemoteEntryFile = foundSsrRemoteEntryFile
|
|
8862
|
+
ssrRemoteEntryFile = foundSsrRemoteEntryFile;
|
|
8770
8863
|
const allCssAssets = mfOptions.bundleAllCSS && !disableAssetsAnalyze ? collectCssAssets(bundle) : /* @__PURE__ */ new Set();
|
|
8771
8864
|
if (allCssAssets.size > 0) {
|
|
8772
8865
|
const secondaryCss = /* @__PURE__ */ new Set();
|
|
@@ -8836,13 +8929,13 @@ const Manifest = (providedOptions) => {
|
|
|
8836
8929
|
function generateMFManifest(preloadMap, disableAssetsAnalyze = false) {
|
|
8837
8930
|
const options = mfOptions;
|
|
8838
8931
|
const { name, varFilename } = options;
|
|
8839
|
-
const resolvedRemoteEntryFile = _command === "serve" ?
|
|
8932
|
+
const resolvedRemoteEntryFile = _command === "serve" ? resolveHashPlaceholderFileName(filename) : remoteEntryFile;
|
|
8840
8933
|
const remoteEntry = {
|
|
8841
8934
|
name: resolvedRemoteEntryFile,
|
|
8842
8935
|
path: "",
|
|
8843
8936
|
type: "module"
|
|
8844
8937
|
};
|
|
8845
|
-
const resolvedSsrRemoteEntryFile = _command === "serve" ?
|
|
8938
|
+
const resolvedSsrRemoteEntryFile = _command === "serve" ? getSsrRemoteEntryFileName(mfOptions, resolvedRemoteEntryFile) : ssrRemoteEntryFile;
|
|
8846
8939
|
const ssrRemoteEntry = resolvedSsrRemoteEntryFile ? {
|
|
8847
8940
|
name: resolvedSsrRemoteEntryFile,
|
|
8848
8941
|
path: _command === "serve" ? "/__mf_ssr__/" : "",
|
|
@@ -9478,6 +9571,21 @@ function shouldScanResolvedImport(id) {
|
|
|
9478
9571
|
if (isNodeModulePath(id)) return false;
|
|
9479
9572
|
return /\.(?:[cm]?[jt]sx?|vue|svelte)(?:\?|$)/.test(id);
|
|
9480
9573
|
}
|
|
9574
|
+
const TS_MODULE_RE = /\.[cm]?tsx?$/;
|
|
9575
|
+
/**
|
|
9576
|
+
* The module as Vite's TypeScript transform leaves it. A value-style import used only as a type
|
|
9577
|
+
* (`import { Props } from 'remote/Widget'`) is dropped there, so it loads nothing at runtime.
|
|
9578
|
+
* `transformWithOxc` is Vite 8+; `transformWithEsbuild` needs esbuild, which Vite 8 no longer ships.
|
|
9579
|
+
*/
|
|
9580
|
+
async function withoutTypeOnlyImports(id, code) {
|
|
9581
|
+
if (!TS_MODULE_RE.test(id)) return code;
|
|
9582
|
+
const { transformWithOxc } = vite;
|
|
9583
|
+
try {
|
|
9584
|
+
return (transformWithOxc ? await transformWithOxc(code, id, { jsx: "preserve" }) : await vite.transformWithEsbuild(code, id, { jsx: "preserve" })).code;
|
|
9585
|
+
} catch {
|
|
9586
|
+
return code;
|
|
9587
|
+
}
|
|
9588
|
+
}
|
|
9481
9589
|
async function readModuleEdges(ctx, id, isRemoteImport) {
|
|
9482
9590
|
let code;
|
|
9483
9591
|
try {
|
|
@@ -9489,12 +9597,14 @@ async function readModuleEdges(ctx, id, isRemoteImport) {
|
|
|
9489
9597
|
dynamicImports: []
|
|
9490
9598
|
};
|
|
9491
9599
|
}
|
|
9600
|
+
let sources = collectImportSources(code);
|
|
9601
|
+
if (sources.some(({ source }) => isRemoteImport(source))) sources = collectImportSources(await withoutTypeOnlyImports(id, code));
|
|
9492
9602
|
const edges = {
|
|
9493
9603
|
remotes: [],
|
|
9494
9604
|
staticImports: [],
|
|
9495
9605
|
dynamicImports: []
|
|
9496
9606
|
};
|
|
9497
|
-
for (const { source, dynamic } of
|
|
9607
|
+
for (const { source, dynamic } of sources) {
|
|
9498
9608
|
if (isRemoteImport(source)) {
|
|
9499
9609
|
if (!dynamic) edges.remotes.push(source);
|
|
9500
9610
|
continue;
|
|
@@ -10206,6 +10316,8 @@ function proxySharedModule(options) {
|
|
|
10206
10316
|
let devServer;
|
|
10207
10317
|
const materializedLoadShareSources = /* @__PURE__ */ new Set();
|
|
10208
10318
|
const emittedTreeShakingProviders = /* @__PURE__ */ new Set();
|
|
10319
|
+
const concreteShareSources = /* @__PURE__ */ new Map();
|
|
10320
|
+
let concreteShareSourcesSize = -1;
|
|
10209
10321
|
const hasAnalyzableShares = Object.values(shared).some((share) => shouldAnalyzeSharedExports(share));
|
|
10210
10322
|
const getEnvironmentConfig = (context) => context.environment?.config;
|
|
10211
10323
|
const getEnvironmentConditions = (context) => getEnvironmentConfig(context)?.resolve?.conditions;
|
|
@@ -10443,6 +10555,23 @@ function proxySharedModule(options) {
|
|
|
10443
10555
|
name: "proxyPreBuildShared:resolve-prebuild",
|
|
10444
10556
|
enforce: "pre",
|
|
10445
10557
|
async resolveId(source, importer) {
|
|
10558
|
+
if (_command === "serve" && path$1.isAbsolute(source)) {
|
|
10559
|
+
const usedShares = getUsedShares(federationOptions);
|
|
10560
|
+
if (concreteShareSourcesSize !== usedShares.size) {
|
|
10561
|
+
concreteShareSourcesSize = usedShares.size;
|
|
10562
|
+
concreteShareSources.clear();
|
|
10563
|
+
for (const used of usedShares) {
|
|
10564
|
+
const concrete = getConcreteSharedImportSource(used);
|
|
10565
|
+
if (concrete) concreteShareSources.set(concrete.replaceAll("\\", "/"), used);
|
|
10566
|
+
}
|
|
10567
|
+
}
|
|
10568
|
+
const share = concreteShareSources.get(source.replaceAll("\\", "/"));
|
|
10569
|
+
if (!share) return;
|
|
10570
|
+
const dependent = findPackageInDependents(getPackageName(share), getPackageDetectionCwd());
|
|
10571
|
+
if (!dependent) return;
|
|
10572
|
+
const dependentPackageJson = path$1.join(dependent.dependentDir, "package.json");
|
|
10573
|
+
return resolveInternally(this, share, dependentPackageJson);
|
|
10574
|
+
}
|
|
10446
10575
|
if (!source.includes("__prebuild__")) return;
|
|
10447
10576
|
if (source.startsWith(".")) return;
|
|
10448
10577
|
const pkgName = assertModuleFound(PREBUILD_TAG, source).name;
|
|
@@ -10927,6 +11056,8 @@ function readBoundedRunnerBody(req, res) {
|
|
|
10927
11056
|
*/
|
|
10928
11057
|
function pluginSSRRemoteEntry(options) {
|
|
10929
11058
|
const remoteEntrySSRId = getRemoteEntrySSRId(options);
|
|
11059
|
+
const ssrHostInitId = getSsrHostInitId(options);
|
|
11060
|
+
let hostInitChunkRef;
|
|
10930
11061
|
const virtualExposesSSRId = getVirtualExposesSSRId(options);
|
|
10931
11062
|
let cachedSsrRemoteEntrySource;
|
|
10932
11063
|
const ssrOutputFilename = getSsrRemoteEntryFileName(options);
|
|
@@ -10990,6 +11121,7 @@ function pluginSSRRemoteEntry(options) {
|
|
|
10990
11121
|
resolveId(id, importer) {
|
|
10991
11122
|
if (id === remoteEntrySSRId || id.startsWith(remoteEntrySSRId)) return id;
|
|
10992
11123
|
if (id === virtualExposesSSRId || id.startsWith(virtualExposesSSRId)) return id;
|
|
11124
|
+
if (id === ssrHostInitId) return this.resolve(getHostAutoInitPath(options), importer, { skipSelf: true });
|
|
10993
11125
|
if (!importer || !ssrModuleIds.has(importer)) return;
|
|
10994
11126
|
if (ssrOnlyExternalPattern.test(id) && !isNoExternal(id)) return {
|
|
10995
11127
|
id,
|
|
@@ -11102,9 +11234,9 @@ function pluginSSRRemoteEntry(options) {
|
|
|
11102
11234
|
const isRolldown = getIsRolldown(this);
|
|
11103
11235
|
const environment = this.environment;
|
|
11104
11236
|
if (!isSsrRemoteEntryBuild(environment)) return;
|
|
11105
|
-
if (!isRolldown && hasRemotes(options)) this.emitFile({
|
|
11237
|
+
if (!isRolldown && hasRemotes(options)) hostInitChunkRef = this.emitFile({
|
|
11106
11238
|
type: "chunk",
|
|
11107
|
-
id:
|
|
11239
|
+
id: ssrHostInitId,
|
|
11108
11240
|
name: "hostInit",
|
|
11109
11241
|
preserveSignature: "strict"
|
|
11110
11242
|
});
|
|
@@ -11130,11 +11262,7 @@ function pluginSSRRemoteEntry(options) {
|
|
|
11130
11262
|
const exposesChunk = findNuxtExposesChunk(bundle) ?? findEmittedExposesChunk(bundle);
|
|
11131
11263
|
if (!isRolldown && isSsrRemoteEntryBuild(environment)) {
|
|
11132
11264
|
let source = getSsrRemoteEntrySource();
|
|
11133
|
-
if (hasRemotes(options))
|
|
11134
|
-
const hostInitId = getHostAutoInitPath(options);
|
|
11135
|
-
const hostInitChunk = Object.values(bundle).find((file) => file.type === "chunk" && file.facadeModuleId?.includes(hostInitId));
|
|
11136
|
-
if (hostInitChunk) source = source.replace(JSON.stringify(hostInitId), JSON.stringify(toRelativeImport(ssrOutputFilename, hostInitChunk.fileName)));
|
|
11137
|
-
}
|
|
11265
|
+
if (hasRemotes(options) && hostInitChunkRef) source = source.replace(JSON.stringify(ssrHostInitId), JSON.stringify(toRelativeImport(ssrOutputFilename, this.getFileName(hostInitChunkRef))));
|
|
11138
11266
|
if (exposesChunk) source = source.replace(/import\("virtual:mf-exposes-ssr:[^"]+"\)/g, `import("${toRelativeImport(ssrOutputFilename, exposesChunk)}")`);
|
|
11139
11267
|
this.emitFile({
|
|
11140
11268
|
type: "asset",
|
|
@@ -11266,7 +11394,13 @@ const VarRemoteEntry = (providedOptions) => {
|
|
|
11266
11394
|
}
|
|
11267
11395
|
}];
|
|
11268
11396
|
function isValidVarName(name) {
|
|
11269
|
-
|
|
11397
|
+
if (!isValidJsIdentifier(name)) return false;
|
|
11398
|
+
try {
|
|
11399
|
+
new Function(`var ${name};`);
|
|
11400
|
+
return true;
|
|
11401
|
+
} catch {
|
|
11402
|
+
return false;
|
|
11403
|
+
}
|
|
11270
11404
|
}
|
|
11271
11405
|
/**
|
|
11272
11406
|
* Generates the final "var" remote entry file
|
|
@@ -11278,23 +11412,35 @@ const VarRemoteEntry = (providedOptions) => {
|
|
|
11278
11412
|
const isValidName = isValidVarName(name);
|
|
11279
11413
|
return `
|
|
11280
11414
|
${isValidName ? `var ${name};` : ""}
|
|
11281
|
-
|
|
11415
|
+
(function (global) {
|
|
11416
|
+
const name = ${toSafeJsLiteral(name)};
|
|
11417
|
+
const descriptor = Object.getOwnPropertyDescriptor(global, name);
|
|
11418
|
+
const prototype = Object.getPrototypeOf(global);
|
|
11419
|
+
const emptyVarSlot = ${isValidName} && descriptor && 'value' in descriptor && descriptor.value === undefined && descriptor.writable && !(prototype && name in prototype);
|
|
11420
|
+
if (name in global && !emptyVarSlot) {
|
|
11421
|
+
const existing = descriptor && 'value' in descriptor ? descriptor.value : undefined;
|
|
11422
|
+
if (existing && typeof existing.get === 'function' && typeof existing.init === 'function') {
|
|
11423
|
+
return;
|
|
11424
|
+
}
|
|
11425
|
+
throw new Error('[Module Federation] Cannot register var remote "' + name + '" because the global already exists. Choose a different federation name or use an ESM remote.');
|
|
11426
|
+
}
|
|
11427
|
+
|
|
11282
11428
|
function getScriptUrl() {
|
|
11283
11429
|
const currentScript = document.currentScript;
|
|
11284
11430
|
if (!currentScript) {
|
|
11285
|
-
console.error(
|
|
11431
|
+
console.error(${toSafeJsLiteral(`[Module Federation] ${varFilename} script should be called from sync <script> tag (document.currentScript is undefined)`)})
|
|
11286
11432
|
return '/';
|
|
11287
11433
|
}
|
|
11288
11434
|
return document.currentScript.src.replace(/\\/[^/]*$/, '/');
|
|
11289
11435
|
}
|
|
11290
11436
|
|
|
11291
|
-
const entry = getScriptUrl() +
|
|
11437
|
+
const entry = getScriptUrl() + ${toSafeJsLiteral(remoteEntryFile)};
|
|
11292
11438
|
|
|
11293
|
-
|
|
11439
|
+
global[name] = {
|
|
11294
11440
|
get: (...args) => import(entry).then(m => m.get(...args)),
|
|
11295
11441
|
init: (...args) => import(entry).then(m => m.init(...args)),
|
|
11296
11442
|
};
|
|
11297
|
-
})();
|
|
11443
|
+
})(globalThis);
|
|
11298
11444
|
`;
|
|
11299
11445
|
}
|
|
11300
11446
|
};
|
|
@@ -11331,6 +11477,7 @@ function pluginSsrRuntimeInit(options) {
|
|
|
11331
11477
|
if (isOwnedHostAutoInitId(id, options)) {
|
|
11332
11478
|
const pluginImports = options.runtimePlugins.map((plugin, index) => `import plugin${index} from ${toSafeJsLiteral(getRuntimePluginSpecifier(plugin))};`).join("\n");
|
|
11333
11479
|
const plugins = options.runtimePlugins.map((plugin, index) => `plugin${index}(${Array.isArray(plugin) ? serializeRuntimeOptions(plugin[1]) : ""})`).join(",");
|
|
11480
|
+
const fallbackRemotes = toSafeJsLiteral(getSsrRuntimeRemotes(options.remotes, options));
|
|
11334
11481
|
return {
|
|
11335
11482
|
code: `
|
|
11336
11483
|
import { init } from ${toSafeJsLiteral(options.implementation)};
|
|
@@ -11338,11 +11485,33 @@ function pluginSsrRuntimeInit(options) {
|
|
|
11338
11485
|
${pluginImports}
|
|
11339
11486
|
${getRuntimeInitBootstrapCode(false, getRuntimeInitStatusImportId(options))}
|
|
11340
11487
|
globalThis[globalKey].ssrInitStarted = true;
|
|
11488
|
+
// These remotes are registered before application code, under owner-scoped
|
|
11489
|
+
// names aliased to their configured names, and the runtime resolves an id
|
|
11490
|
+
// against the first remote whose name or alias matches. Drop the alias once the
|
|
11491
|
+
// application registers a remote under that name or alias, so its entry wins.
|
|
11492
|
+
const bootstrapRemotes = Array.isArray(usedRemotes) ? usedRemotes : ${fallbackRemotes};
|
|
11493
|
+
const bootstrapRemoteNames = new Set(bootstrapRemotes.map((remote) => remote.name));
|
|
11494
|
+
const applicationRemotePlugin = {
|
|
11495
|
+
name: 'vite-ssr-application-remote-plugin',
|
|
11496
|
+
beforeRegisterRemote(args) {
|
|
11497
|
+
const { name, alias } = args.remote;
|
|
11498
|
+
if (bootstrapRemoteNames.has(name)) return args;
|
|
11499
|
+
for (const registered of args.origin.options.remotes) {
|
|
11500
|
+
if (
|
|
11501
|
+
bootstrapRemoteNames.has(registered.name) &&
|
|
11502
|
+
(registered.alias === name || registered.alias === alias)
|
|
11503
|
+
) {
|
|
11504
|
+
delete registered.alias;
|
|
11505
|
+
}
|
|
11506
|
+
}
|
|
11507
|
+
return args;
|
|
11508
|
+
},
|
|
11509
|
+
};
|
|
11341
11510
|
const runtime = init({
|
|
11342
11511
|
name: ${toSafeJsLiteral(options.name)},
|
|
11343
|
-
remotes:
|
|
11512
|
+
remotes: bootstrapRemotes,
|
|
11344
11513
|
shared: usedShared,
|
|
11345
|
-
plugins: [${plugins}],
|
|
11514
|
+
plugins: [applicationRemotePlugin, ${plugins}],
|
|
11346
11515
|
shareStrategy: ${toSafeJsLiteral(options.shareStrategy)},
|
|
11347
11516
|
});
|
|
11348
11517
|
const hostInitPromise = Promise.resolve(runtime);
|
|
@@ -11882,6 +12051,11 @@ function canResolveSharedSubpath(subpath, projectRoot) {
|
|
|
11882
12051
|
return false;
|
|
11883
12052
|
}
|
|
11884
12053
|
}
|
|
12054
|
+
function getSharedIncludeEntry(subpath, projectRoot) {
|
|
12055
|
+
if (canResolveSharedSubpath(subpath, projectRoot)) return subpath;
|
|
12056
|
+
const dependent = findPackageInDependents(getPackageName(subpath), projectRoot);
|
|
12057
|
+
if (dependent && canResolveSharedSubpath(subpath, dependent.dependentDir)) return [...dependent.chain, subpath].join(" > ");
|
|
12058
|
+
}
|
|
11885
12059
|
const VITE_DEV_IMPORT_CONDITIONS = /* @__PURE__ */ new Set([
|
|
11886
12060
|
"browser",
|
|
11887
12061
|
"development",
|
|
@@ -12071,13 +12245,18 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
12071
12245
|
return {
|
|
12072
12246
|
name: "vite:module-federation-early-init",
|
|
12073
12247
|
enforce: "pre",
|
|
12074
|
-
config(config, { command: _command }) {
|
|
12248
|
+
config(config, { command: _command, mode }) {
|
|
12075
12249
|
if (_command === "serve") ignoreFederationGeneratedFiles(config, options);
|
|
12076
12250
|
const root = config.root || process.cwd();
|
|
12077
12251
|
const buildInput = getBuildInput(config);
|
|
12078
12252
|
const resolvedConfiguredEntryFiles = (typeof buildInput === "string" ? [buildInput] : Array.isArray(buildInput) ? buildInput : buildInput && typeof buildInput === "object" ? Object.values(buildInput) : []).map((entry) => String(entry)).filter((entry) => !isReactRouterBuildClientRouteInput(entry)).map((entry) => entry.split(/[?#]/)[0]).map((entry) => path$1.isAbsolute(entry) ? entry : path$1.resolve(root, entry));
|
|
12079
12253
|
resetConcreteSharedImportSourceCache();
|
|
12080
12254
|
setPackageDetectionCwd(root);
|
|
12255
|
+
setWorkspaceEntryConditions(getSharedExportConditions({
|
|
12256
|
+
isProduction: mode === "production",
|
|
12257
|
+
isSsr: false,
|
|
12258
|
+
rootConditions: config.resolve?.conditions
|
|
12259
|
+
}));
|
|
12081
12260
|
resolveSharedVersions(shared, root);
|
|
12082
12261
|
const isVinext = hasPackageDependency("vinext");
|
|
12083
12262
|
initVirtualModules(_command, getRemoteEntryId(options), false, options);
|
|
@@ -12223,7 +12402,8 @@ export default __mfShared.default ?? __mfShared;`
|
|
|
12223
12402
|
optimizeDeps.exclude ??= [];
|
|
12224
12403
|
for (const subpath of getCommonSharedSubpaths(request)) {
|
|
12225
12404
|
writePreBuildLibPath(subpath, shareItem, options);
|
|
12226
|
-
|
|
12405
|
+
const includeEntry = getSharedIncludeEntry(subpath, root);
|
|
12406
|
+
if (includeEntry) optimizeDeps.include.push(includeEntry);
|
|
12227
12407
|
else optimizeDeps.exclude.push(subpath);
|
|
12228
12408
|
}
|
|
12229
12409
|
}
|
|
@@ -12241,18 +12421,18 @@ export default __mfShared.default ?? __mfShared;`
|
|
|
12241
12421
|
const optimizeDeps = config.optimizeDeps ??= {};
|
|
12242
12422
|
optimizeDeps.include ??= [];
|
|
12243
12423
|
optimizeDeps.exclude ??= [];
|
|
12244
|
-
const
|
|
12424
|
+
const includeEntry = isLitShare(runtimeKey) ? void 0 : getSharedIncludeEntry(runtimeKey, root);
|
|
12245
12425
|
if (optimizeDeps.include.includes(runtimeKey)) optimizeDeps.exclude = optimizeDeps.exclude.filter((dep) => dep !== runtimeKey);
|
|
12246
|
-
else if (
|
|
12247
|
-
else optimizeDeps.include.push(
|
|
12426
|
+
else if (!includeEntry || optimizeDeps.exclude.includes(runtimeKey)) optimizeDeps.exclude.push(runtimeKey);
|
|
12427
|
+
else optimizeDeps.include.push(includeEntry);
|
|
12248
12428
|
const commonSubpaths = shareItem.shareConfig.request === void 0 && shareItem.shareConfig.shareKey === void 0 ? getCommonSharedSubpaths(runtimeKey) : [];
|
|
12249
12429
|
for (const subpath of commonSubpaths) {
|
|
12250
|
-
const
|
|
12430
|
+
const subpathIncludeEntry = getSharedIncludeEntry(subpath, root);
|
|
12251
12431
|
if ([
|
|
12252
12432
|
"react/compiler-runtime",
|
|
12253
12433
|
"react-dom/client",
|
|
12254
12434
|
"react-dom/profiling"
|
|
12255
|
-
].includes(subpath) && !
|
|
12435
|
+
].includes(subpath) && !subpathIncludeEntry) {
|
|
12256
12436
|
optimizeDeps.exclude.push(subpath);
|
|
12257
12437
|
continue;
|
|
12258
12438
|
}
|
|
@@ -12260,9 +12440,9 @@ export default __mfShared.default ?? __mfShared;`
|
|
|
12260
12440
|
writeLoadShareModule(subpath, shareItem, _command, options);
|
|
12261
12441
|
writePreBuildLibPath(subpath, shareItem, options);
|
|
12262
12442
|
addConfiguredShare(subpath, options);
|
|
12263
|
-
if (
|
|
12264
|
-
optimizeDeps.include.push(
|
|
12265
|
-
if (runtimeKey === "react-dom") optimizeDeps.include.push(`${
|
|
12443
|
+
if (subpathIncludeEntry) {
|
|
12444
|
+
optimizeDeps.include.push(subpathIncludeEntry);
|
|
12445
|
+
if (runtimeKey === "react-dom" && includeEntry) optimizeDeps.include.push(`${includeEntry} > ${subpath}`);
|
|
12266
12446
|
} else optimizeDeps.exclude.push(subpath);
|
|
12267
12447
|
}
|
|
12268
12448
|
}
|
|
@@ -12305,12 +12485,15 @@ export default __mfShared.default ?? __mfShared;`
|
|
|
12305
12485
|
"@module-federation/sdk"
|
|
12306
12486
|
];
|
|
12307
12487
|
const resolvedShared = {};
|
|
12308
|
-
for (const pkg of [...commonSharedPkgs, ...sharedKeys])
|
|
12309
|
-
|
|
12310
|
-
} catch {
|
|
12488
|
+
for (const pkg of [...commonSharedPkgs, ...sharedKeys]) {
|
|
12489
|
+
const resolutionSpecifier = removeTrailingSlash(pkg);
|
|
12311
12490
|
try {
|
|
12312
|
-
resolvedShared[pkg] =
|
|
12313
|
-
} catch {
|
|
12491
|
+
resolvedShared[pkg] = projectRequire.resolve(resolutionSpecifier);
|
|
12492
|
+
} catch {
|
|
12493
|
+
try {
|
|
12494
|
+
resolvedShared[pkg] = resolveImportPath(resolutionSpecifier);
|
|
12495
|
+
} catch {}
|
|
12496
|
+
}
|
|
12314
12497
|
}
|
|
12315
12498
|
const ssrEntryLoaderSpecifier = SSR_ENTRY_LOADER_SPECIFIER;
|
|
12316
12499
|
try {
|
|
@@ -12347,7 +12530,7 @@ function withoutDynamicRemoteTypeHints(options) {
|
|
|
12347
12530
|
}
|
|
12348
12531
|
function loadPluginDts(options) {
|
|
12349
12532
|
if (options.dts === false) return [];
|
|
12350
|
-
return [import("./pluginDts-
|
|
12533
|
+
return [import("./pluginDts-DvTJxjaE.js").then(({ default: pluginDts }) => pluginDts(options))];
|
|
12351
12534
|
}
|
|
12352
12535
|
const INJECT_EXTERNAL_RUNTIME_CORE_PLUGIN = "@module-federation/vite/injectExternalRuntimeCorePlugin";
|
|
12353
12536
|
function isInjectExternalRuntimeCorePlugin(specifier) {
|