@module-federation/vite 1.16.9 → 1.16.10
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 +79 -4
- package/lib/utils/ssrEntryLoader.js +25 -3
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -797,6 +797,19 @@ globalThis[__mfCacheGlobalKey] ||= { share: {}, remote: {} };
|
|
|
797
797
|
globalThis[__mfCacheGlobalKey].share ||= {};
|
|
798
798
|
globalThis[__mfCacheGlobalKey].remote ||= {};
|
|
799
799
|
const __mfModuleCache = globalThis[__mfCacheGlobalKey];
|
|
800
|
+
for (const __mfShareKey of Object.keys(__mfModuleCache.share)) {
|
|
801
|
+
if (__mfShareKey.startsWith("default:")) {
|
|
802
|
+
const __mfLegacyShareKey = __mfShareKey.slice("default:".length);
|
|
803
|
+
if (__mfModuleCache.share[__mfLegacyShareKey] === undefined) {
|
|
804
|
+
__mfModuleCache.share[__mfLegacyShareKey] = __mfModuleCache.share[__mfShareKey];
|
|
805
|
+
}
|
|
806
|
+
} else if (!__mfShareKey.includes(":")) {
|
|
807
|
+
const __mfDefaultShareKey = "default:" + __mfShareKey;
|
|
808
|
+
if (__mfModuleCache.share[__mfDefaultShareKey] === undefined) {
|
|
809
|
+
__mfModuleCache.share[__mfDefaultShareKey] = __mfModuleCache.share[__mfShareKey];
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
800
813
|
`;
|
|
801
814
|
}
|
|
802
815
|
function getRuntimeInitPromiseBootstrapCode(enableSsrInit = false) {
|
|
@@ -1489,6 +1502,7 @@ function generateLocalSharedImportMap() {
|
|
|
1489
1502
|
shareConfig: {
|
|
1490
1503
|
singleton: ${shareItem.shareConfig.singleton},
|
|
1491
1504
|
requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)},
|
|
1505
|
+
strictVersion: ${shareItem.shareConfig.strictVersion},
|
|
1492
1506
|
${shareItem.shareConfig.import === false ? "import: false," : ""}
|
|
1493
1507
|
}
|
|
1494
1508
|
}
|
|
@@ -1526,6 +1540,7 @@ function generateUsedSharedPreloadConfig() {
|
|
|
1526
1540
|
shareConfig: {
|
|
1527
1541
|
singleton: ${shareItem.shareConfig.singleton},
|
|
1528
1542
|
requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)},
|
|
1543
|
+
strictVersion: ${shareItem.shareConfig.strictVersion},
|
|
1529
1544
|
${shareItem.shareConfig.import === false ? "import: false," : ""}
|
|
1530
1545
|
}
|
|
1531
1546
|
}`;
|
|
@@ -1610,6 +1625,40 @@ const normalizeRuntimeShareCode = `const __mfNormalizeRuntimeShare = (mod) => {
|
|
|
1610
1625
|
}
|
|
1611
1626
|
return current;
|
|
1612
1627
|
};`;
|
|
1628
|
+
const sharedProviderSelectionHelperCode = `const __mfOriginalProviderKey = Symbol("mf.originalSharedProvider");
|
|
1629
|
+
const __mfResolveShareHook = { emit: (params) => params };
|
|
1630
|
+
const __mfCreateProviderSelectionVersions = (versions, strategy) => {
|
|
1631
|
+
if (strategy !== "version-first") return versions;
|
|
1632
|
+
const selectionVersions = {};
|
|
1633
|
+
for (const [version, provider] of Object.entries(versions)) {
|
|
1634
|
+
selectionVersions[version] = Object.assign({}, provider, {
|
|
1635
|
+
loaded: false,
|
|
1636
|
+
loading: undefined,
|
|
1637
|
+
lib: undefined,
|
|
1638
|
+
[__mfOriginalProviderKey]: provider
|
|
1639
|
+
});
|
|
1640
|
+
}
|
|
1641
|
+
return selectionVersions;
|
|
1642
|
+
};
|
|
1643
|
+
const __mfSelectSharedProvider = (versions, pkg, share, strategy) => {
|
|
1644
|
+
if (!versions || !share) return undefined;
|
|
1645
|
+
const scopes = Array.isArray(share.scope) ? share.scope : [share.scope || "default"];
|
|
1646
|
+
const selectionVersions = __mfCreateProviderSelectionVersions(versions, strategy);
|
|
1647
|
+
const shareScopeMap = {};
|
|
1648
|
+
for (const scope of scopes) {
|
|
1649
|
+
shareScopeMap[scope || "default"] = { [pkg]: selectionVersions };
|
|
1650
|
+
}
|
|
1651
|
+
const selected = runtimeShare.getRegisteredShare(
|
|
1652
|
+
shareScopeMap,
|
|
1653
|
+
pkg,
|
|
1654
|
+
{ ...share, scope: scopes, strategy },
|
|
1655
|
+
__mfResolveShareHook
|
|
1656
|
+
)?.shared;
|
|
1657
|
+
return selected?.[__mfOriginalProviderKey] || selected;
|
|
1658
|
+
};`;
|
|
1659
|
+
function hasImportFalseShared$1(options) {
|
|
1660
|
+
return Object.values(options.shared ?? {}).some((share) => share?.shareConfig?.import === false);
|
|
1661
|
+
}
|
|
1613
1662
|
function generateDirectSharedCacheSeedCode(command = "build") {
|
|
1614
1663
|
return getOrderedUsedShares().map((pkg) => {
|
|
1615
1664
|
const shareItem = getShareItemForPreload(pkg);
|
|
@@ -1647,6 +1696,7 @@ const SSR_ONLY_PLUGIN_SPECIFIERS = new Set(["@module-federation/vite/ssrEntryLoa
|
|
|
1647
1696
|
const isSsrOnlyPlugin = (importStatement) => [...SSR_ONLY_PLUGIN_SPECIFIERS].some((s) => importStatement.includes(s));
|
|
1648
1697
|
const getSsrOnlyPluginSpecifier = (importStatement) => [...SSR_ONLY_PLUGIN_SPECIFIERS].find((s) => importStatement.includes(s));
|
|
1649
1698
|
function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(options), command = "build") {
|
|
1699
|
+
const needsSharedProviderSelectionHelper = hasImportFalseShared$1(options);
|
|
1650
1700
|
const pluginImportNames = options.runtimePlugins.map((p, i) => {
|
|
1651
1701
|
if (typeof p === "string") return [
|
|
1652
1702
|
`$runtimePlugin_${i}`,
|
|
@@ -1669,6 +1719,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1669
1719
|
globalThis.__VUE_HMR_RUNTIME__ = { createRecord() {}, rerender() {}, reload() {} };
|
|
1670
1720
|
}
|
|
1671
1721
|
import {init as runtimeInit, loadRemote} from "@module-federation/runtime";
|
|
1722
|
+
${needsSharedProviderSelectionHelper ? "import {share as runtimeShare} from \"@module-federation/runtime/helpers\";" : ""}
|
|
1672
1723
|
${pluginImportNames.filter((item) => !isSsrOnlyPlugin(item[1])).map((item) => item[1]).join("\n")}
|
|
1673
1724
|
${command === "build" ? getRuntimeInitResolveBootstrapCode() : getRuntimeInitBootstrapCode() + "\n const { initResolve } = globalThis[globalKey];"}
|
|
1674
1725
|
${getRuntimeModuleCacheBootstrapCode()}
|
|
@@ -1696,6 +1747,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1696
1747
|
}
|
|
1697
1748
|
}
|
|
1698
1749
|
}
|
|
1750
|
+
${needsSharedProviderSelectionHelper ? sharedProviderSelectionHelperCode : ""}
|
|
1699
1751
|
|
|
1700
1752
|
async function getLocalSharedImportMap() {
|
|
1701
1753
|
if (!localSharedImportMapPromise) {
|
|
@@ -1725,7 +1777,14 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1725
1777
|
const scopeShare = scopes?.['${options.shareScope}'];
|
|
1726
1778
|
if (!scopeShare) continue;
|
|
1727
1779
|
for (const [pkg, versionMap] of Object.entries(scopeShare)) {
|
|
1728
|
-
|
|
1780
|
+
const usedShare = usedShared?.[pkg];
|
|
1781
|
+
const selectedProvider = usedShare?.shareConfig?.import === false
|
|
1782
|
+
? __mfSelectSharedProvider(versionMap, pkg, usedShare, '${options.shareStrategy}')
|
|
1783
|
+
: undefined;
|
|
1784
|
+
const providerEntries = usedShare?.shareConfig?.import === false
|
|
1785
|
+
? Object.entries(versionMap).filter(([, provider]) => provider === selectedProvider)
|
|
1786
|
+
: Object.entries(versionMap);
|
|
1787
|
+
for (const [version, provider] of providerEntries) {
|
|
1729
1788
|
if (!provider.lib) continue;
|
|
1730
1789
|
const cacheKey = __mfGetSharedCacheKey(pkg, provider.shareConfig?.singleton, version, ${JSON.stringify(options.shareScope)});
|
|
1731
1790
|
if (__mfModuleCache.share[cacheKey] !== undefined) continue;
|
|
@@ -1733,7 +1792,6 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1733
1792
|
const resolved = await Promise.resolve(mod);
|
|
1734
1793
|
const normalized = __mfNormalizeRuntimeShare(resolved);
|
|
1735
1794
|
__mfModuleCache.share[cacheKey] = normalized;
|
|
1736
|
-
const usedShare = usedShared?.[pkg];
|
|
1737
1795
|
if (provider.shareConfig?.singleton && usedShare) {
|
|
1738
1796
|
const usedCacheKey = __mfGetSharedCacheKey(pkg, usedShare.shareConfig?.singleton, usedShare.version, usedShare.scope);
|
|
1739
1797
|
if (__mfModuleCache.share[usedCacheKey] === undefined) {
|
|
@@ -1795,7 +1853,7 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1795
1853
|
if (share.shareConfig?.import !== false || __mfModuleCache.share[cacheKey] !== undefined) continue;
|
|
1796
1854
|
${normalizeRuntimeShareCode}
|
|
1797
1855
|
const versions = shared?.[pkg];
|
|
1798
|
-
const provider = versions
|
|
1856
|
+
const provider = __mfSelectSharedProvider(versions, pkg, share, '${options.shareStrategy}');
|
|
1799
1857
|
if (!provider) continue;
|
|
1800
1858
|
const factory = provider.lib || (provider.loading ? await provider.loading : await provider.get?.());
|
|
1801
1859
|
const mod = typeof factory === "function" ? factory() : factory;
|
|
@@ -5160,6 +5218,17 @@ function appendResolveAlias(config, alias) {
|
|
|
5160
5218
|
replacement
|
|
5161
5219
|
})), alias];
|
|
5162
5220
|
}
|
|
5221
|
+
function hasImportFalseShared(options) {
|
|
5222
|
+
return Object.values(options.shared ?? {}).some((share) => share?.shareConfig?.import === false);
|
|
5223
|
+
}
|
|
5224
|
+
function getRuntimeHelpersImplementation(runtimeImplementation) {
|
|
5225
|
+
const indexEntryMatch = runtimeImplementation.match(/^(.*[\\/])index(\.[cm]?js)$/);
|
|
5226
|
+
if (indexEntryMatch) return `${indexEntryMatch[1]}helpers${indexEntryMatch[2]}`;
|
|
5227
|
+
const extension = path$1.extname(runtimeImplementation);
|
|
5228
|
+
if (extension) return path$1.join(path$1.dirname(runtimeImplementation), `helpers${extension}`);
|
|
5229
|
+
if (path$1.isAbsolute(runtimeImplementation) || runtimeImplementation.startsWith(".")) return path$1.join(runtimeImplementation, "helpers");
|
|
5230
|
+
return `${runtimeImplementation.replace(/\/$/, "")}/helpers`;
|
|
5231
|
+
}
|
|
5163
5232
|
const UNSAFE_JS_SOURCE_CHAR_MAP = {
|
|
5164
5233
|
"<": "\\u003C",
|
|
5165
5234
|
">": "\\u003E",
|
|
@@ -5687,8 +5756,13 @@ function federation(mfUserOptions) {
|
|
|
5687
5756
|
config(config, { command: _command }) {
|
|
5688
5757
|
const isRolldown = getIsRolldown(this);
|
|
5689
5758
|
isSsrBuild = _command === "build" && config.build?.ssr === true;
|
|
5759
|
+
const needsSharedProviderSelectionHelper = hasImportFalseShared(options);
|
|
5760
|
+
if (needsSharedProviderSelectionHelper) appendResolveAlias(config, {
|
|
5761
|
+
find: /^@module-federation\/runtime\/helpers$/,
|
|
5762
|
+
replacement: getRuntimeHelpersImplementation(options.implementation)
|
|
5763
|
+
});
|
|
5690
5764
|
appendResolveAlias(config, {
|
|
5691
|
-
find:
|
|
5765
|
+
find: /^@module-federation\/runtime$/,
|
|
5692
5766
|
replacement: options.implementation
|
|
5693
5767
|
});
|
|
5694
5768
|
config.build ||= {};
|
|
@@ -5697,6 +5771,7 @@ function federation(mfUserOptions) {
|
|
|
5697
5771
|
config.optimizeDeps ||= {};
|
|
5698
5772
|
config.optimizeDeps.include ||= [];
|
|
5699
5773
|
config.optimizeDeps.include.push("@module-federation/runtime");
|
|
5774
|
+
if (needsSharedProviderSelectionHelper) config.optimizeDeps.include.push("@module-federation/runtime/helpers");
|
|
5700
5775
|
options.runtimePlugins.forEach((p) => {
|
|
5701
5776
|
const pluginPath = typeof p === "string" ? p : p[0];
|
|
5702
5777
|
if (SSR_ONLY_PLUGINS.has(pluginPath)) return;
|
|
@@ -89,6 +89,22 @@ const _crypto = () => nodeImport("crypto");
|
|
|
89
89
|
const _module = () => nodeImport("module");
|
|
90
90
|
const ssrEntryCache = /* @__PURE__ */ new Map();
|
|
91
91
|
const manifestFetchCache = /* @__PURE__ */ new Map();
|
|
92
|
+
var SsrEntryHttpError = class extends Error {
|
|
93
|
+
constructor(url, status, statusText, bodyPreview) {
|
|
94
|
+
super(`Failed to fetch SSR module "${url}": ${status} ${statusText}` + (bodyPreview ? `\npreview: ${bodyPreview}` : ""));
|
|
95
|
+
this.url = url;
|
|
96
|
+
this.status = status;
|
|
97
|
+
this.statusText = statusText;
|
|
98
|
+
this.bodyPreview = bodyPreview;
|
|
99
|
+
this.name = "SsrEntryHttpError";
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
function getBodyPreview(body) {
|
|
103
|
+
return body.slice(0, 240).replace(/\s+/g, " ").trim();
|
|
104
|
+
}
|
|
105
|
+
function isSsrEntryHttpError(error) {
|
|
106
|
+
return error instanceof SsrEntryHttpError;
|
|
107
|
+
}
|
|
92
108
|
async function fetchManifest(manifestUrl) {
|
|
93
109
|
try {
|
|
94
110
|
const res = await fetch(manifestUrl);
|
|
@@ -253,6 +269,9 @@ function transformSsrCode(code, base, sharedPkgMap) {
|
|
|
253
269
|
code = code.replace(/\b([A-Za-z_$][\w$]*)\s*\(\s*\(\s*\)\s*=>\s*import\(([^)]*)\)\s*,\s*\[\]\s*\)/g, "import($2)");
|
|
254
270
|
return code;
|
|
255
271
|
}
|
|
272
|
+
function isVitePreloadHelperSpecifier(specifier) {
|
|
273
|
+
return specifier.includes("preload-helper");
|
|
274
|
+
}
|
|
256
275
|
/**
|
|
257
276
|
* Fetch an HTTP ESM module, transform it, write it to a temp .js file and
|
|
258
277
|
* return the file path. Recursively does the same for HTTP transitive imports
|
|
@@ -262,12 +281,14 @@ async function fetchEsmToTempFile(url, tmpDir, visited, sharedPkgMap) {
|
|
|
262
281
|
if (visited.has(url)) return visited.get(url);
|
|
263
282
|
if (tempFileCache.has(url)) return tempFileCache.get(url);
|
|
264
283
|
const promise = (async () => {
|
|
265
|
-
|
|
284
|
+
const res = await fetch(url);
|
|
285
|
+
let code = await res.text();
|
|
286
|
+
if (!res.ok) throw new SsrEntryHttpError(url, res.status, res.statusText, getBodyPreview(code));
|
|
266
287
|
const base = url.replace(/\/[^/]*$/, "/");
|
|
267
288
|
const relImports = [];
|
|
268
289
|
const relRegex = /(?:from|export\s*\*\s*from|import\s*(?:\(|\s))\s*["'`]([^"'`\s]+)["'`]/g;
|
|
269
290
|
let m;
|
|
270
|
-
while ((m = relRegex.exec(code)) !== null) if (m[1].startsWith("./") || m[1].startsWith("../")) relImports.push(new URL(m[1], base).href);
|
|
291
|
+
while ((m = relRegex.exec(code)) !== null) if ((m[1].startsWith("./") || m[1].startsWith("../")) && !isVitePreloadHelperSpecifier(m[1])) relImports.push(new URL(m[1], base).href);
|
|
271
292
|
const subMap = /* @__PURE__ */ new Map();
|
|
272
293
|
await Promise.all([...new Set(relImports)].filter((u) => u.startsWith("http://") || u.startsWith("https://")).map(async (u) => {
|
|
273
294
|
const tmpPath = await fetchEsmToTempFile(u, tmpDir, visited, sharedPkgMap);
|
|
@@ -322,7 +343,8 @@ async function loadSSRRemoteEntry(ssrEntry, resolvedShared = {}) {
|
|
|
322
343
|
const sharedPkgMap = new Map(Object.entries(resolvedShared));
|
|
323
344
|
try {
|
|
324
345
|
return await importTempModule(await fetchEsmToTempFile(url, cacheDir, /* @__PURE__ */ new Map(), sharedPkgMap));
|
|
325
|
-
} catch {
|
|
346
|
+
} catch (error) {
|
|
347
|
+
if (isSsrEntryHttpError(error)) throw error;
|
|
326
348
|
return null;
|
|
327
349
|
}
|
|
328
350
|
}
|