@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/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 supportsCodeSplittingGroupDebugName, E as isReactCoreShare, S as sharedCacheHelperCode, T as REACT_DOM_CLIENT_SHARE, _ as packageNameDecode, a as getInstalledPackageEntry, b as resolveModulePath, c as getPackageDetectionCwd, d as getPackageNameFromNodeModulePath, f as getSharedCacheDescriptor, g as isPackageInstalled, h as isPackageExportAvailable, i as getDependencyNames, l as getPackageExportSpecifiersForFile, m as isNuxtProjectRoot, n as formatDevServerHostForOrigin, o as getInstalledPackageJson, p as hasPackageDependency, r as watchFileEvents, s as getIsRolldown, u as getPackageName, v as packageNameEncode, w as REACT_CLIENT_INTERNALS_KEY, x as setPackageDetectionCwd, y as resolveImportPath } from "./dtsConstants-CDuC8Bb7.js";
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/reactIsland.ts
1481
- const SOURCE_EXTENSIONS$1 = [
1482
- ".tsx",
1483
- ".jsx",
1484
- ".ts",
1485
- ".js",
1486
- ".mts",
1487
- ".mjs",
1488
- ".cts",
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 isReactComponentFile(filePath, seen = /* @__PURE__ */ new Set()) {
1522
- const normalizedPath = path$1.resolve(filePath);
1523
- if (seen.has(normalizedPath)) return false;
1524
- seen.add(normalizedPath);
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 (isReactComponentSource(source, normalizedPath)) return true;
1532
- const reexport = localDefaultReexport(source);
1533
- if (!reexport) return false;
1534
- const reexportPath = resolveSourceFile(reexport, path$1.dirname(normalizedPath));
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
- * React is shared by the normal MF runtime when explicitly configured. When it
1539
- * is local, UI exposes can safely advertise an island capability in addition
1540
- * to their unchanged default export.
1541
- */
1542
- function getReactIslandExposes(options, root) {
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 islandExposes;
1551
- }
1552
- function generateReactIslandBrowserDefinition(enabled) {
1553
- if (!enabled) return "";
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 resolveReactIslandConsumerId(id) {
1640
- if (id.startsWith("virtual:mf-react-island-server:")) return `\0${id}`;
1641
- if (id.startsWith("virtual:mf-react-island-client:")) return `\0${id}`;
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 remoteIdFromResolvedIslandId(id, prefix) {
1644
- if (!id.startsWith(prefix)) return;
1645
- return decodeIslandRemoteId(id.slice(prefix.length));
1515
+ function isInvalidTypeArgumentTerminator(source, index, followsNamedExpression) {
1516
+ const char = source[index];
1517
+ return char === ";" || char === "=" && source[index + 1] !== ">" && followsNamedExpression;
1646
1518
  }
1647
- /** Generates the server half of the opt-in `?mf-island` consumer component. */
1648
- function generateReactIslandConsumerServer(remoteId) {
1649
- const source = JSON.stringify(remoteId);
1650
- return `import * as React from "react";
1651
- import IslandClient from ${JSON.stringify(getReactIslandClientImportId(remoteId))};
1652
-
1653
- const islandModulePromise = import(${source});
1654
-
1655
- async function loadIslandModule() {
1656
- const namespace = await islandModulePromise;
1657
- const pending = namespace && namespace.__mf_remote_pending;
1658
- if (pending && typeof pending.then === "function") return pending;
1659
- return namespace && namespace.__moduleExports || namespace;
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
- export default async function ModuleFederationIsland(props) {
1663
- const remoteModule = await loadIslandModule();
1664
- const shell = remoteModule && remoteModule.__mf_island;
1665
- if (!shell || typeof shell.renderToHtml !== "function") {
1666
- throw new Error(${JSON.stringify(`[Module Federation] ${remoteId} does not expose an SSR island capability`)});
1667
- }
1668
- const html = await shell.renderToHtml(props);
1669
- return React.createElement(IslandClient, { html, islandProps: props });
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
- /** Generates the client boundary which hydrates with the remote-owned React. */
1673
- function generateReactIslandConsumerClient(remoteId) {
1674
- return `"use client";
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
- export default function ModuleFederationIslandClient({ html, islandProps }) {
1688
- const ref = React.useRef(null);
1689
-
1690
- React.useEffect(() => {
1691
- const element = ref.current;
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 loadReactIslandConsumerModule(id) {
1710
- const serverRemoteId = remoteIdFromResolvedIslandId(id, RESOLVED_REACT_ISLAND_SERVER_ID_PREFIX);
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 getFederationScopeKey(options) {
1759
- const identity = JSON.stringify(stableConfigValue(options));
1760
- const ownerId = BigInt(`0x${createHash("sha256").update(identity).digest("hex").slice(0, 12)}`);
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
- //#endregion
1764
- //#region src/virtualModules/virtualExposes.ts
1765
- const EXPOSES_CSS_MAP_PLACEHOLDER = "__MF_EXPOSES_CSS_MAP__";
1766
- function getExposesCssMapPlaceholder() {
1767
- return EXPOSES_CSS_MAP_PLACEHOLDER;
1768
- }
1769
- function getVirtualExposesId(options) {
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(([name, item]) => ({
1942
- name: getRuntimeRemoteAlias(name, options),
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: DEFAULT_SHARED_EXPORT_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
- for (const pkg of getOrderedUsedShares(options)) {
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.6";
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(getHostAutoInitPath(options))};` : "import { init as runtimeInit } from \"@module-federation/runtime\";"}
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 { name, filename, getPublicPath, manifest: manifestOptions, varFilename } = mfOptions;
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 || (_command === "serve" ? getSsrRemoteEntryFileName(mfOptions, resolveHashPlaceholderFileName(mfOptions.filename)) : void 0);
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" ? remoteEntryFile || resolveHashPlaceholderFileName(filename) : remoteEntryFile;
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" ? ssrRemoteEntryFile || getSsrRemoteEntryFileName(mfOptions, resolveHashPlaceholderFileName(filename)) : ssrRemoteEntryFile;
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 collectImportSources(code)) {
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: getHostAutoInitPath(options),
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
- return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
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
- ${isValidName ? name : `globalThis['${name}']`} = (function () {
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("[Module Federation] ${varFilename} script should be called from sync <script> tag (document.currentScript is undefined)")
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() + '${remoteEntryFile}';
11437
+ const entry = getScriptUrl() + ${toSafeJsLiteral(remoteEntryFile)};
11292
11438
 
11293
- return {
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: usedRemotes,
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
- if (canResolveSharedSubpath(subpath, root)) optimizeDeps.include.push(subpath);
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 shouldBypassOptimizeDep = isLitShare(runtimeKey) || !canResolveSharedSubpath(runtimeKey, root);
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 (shouldBypassOptimizeDep || optimizeDeps.exclude.includes(runtimeKey)) optimizeDeps.exclude.push(runtimeKey);
12247
- else optimizeDeps.include.push(runtimeKey);
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 canResolveSubpath = canResolveSharedSubpath(subpath, root);
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) && !canResolveSubpath) {
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 (canResolveSubpath) {
12264
- optimizeDeps.include.push(subpath);
12265
- if (runtimeKey === "react-dom") optimizeDeps.include.push(`${runtimeKey} > ${subpath}`);
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]) try {
12309
- resolvedShared[pkg] = projectRequire.resolve(pkg);
12310
- } catch {
12488
+ for (const pkg of [...commonSharedPkgs, ...sharedKeys]) {
12489
+ const resolutionSpecifier = removeTrailingSlash(pkg);
12311
12490
  try {
12312
- resolvedShared[pkg] = resolveImportPath(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-rZMRTCTz.js").then(({ default: pluginDts }) => pluginDts(options))];
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) {