@module-federation/vite 1.13.1 → 1.13.3
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.cjs +429 -83
- package/lib/index.mjs +429 -83
- package/package.json +7 -5
package/lib/index.cjs
CHANGED
|
@@ -49,38 +49,60 @@ async function mapCodeToCodeWithSourcemap(code) {
|
|
|
49
49
|
//#endregion
|
|
50
50
|
//#region src/utils/htmlEntryUtils.ts
|
|
51
51
|
function sanitizeDevEntryPath(devEntryPath) {
|
|
52
|
-
return devEntryPath.replace(
|
|
52
|
+
return devEntryPath.replace(/\\\\?/g, "/");
|
|
53
53
|
}
|
|
54
54
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* If no entry scripts are found, falls back to injecting a separate script tag.
|
|
60
|
-
*
|
|
61
|
-
* @example
|
|
62
|
-
* // Before (two separate scripts, race condition):
|
|
63
|
-
* // <script type="module" src="/__mf__virtual/hostAutoInit.js"><\/script>
|
|
64
|
-
* // <script type="module" src="/src/main.js"><\/script>
|
|
65
|
-
* // After (single inline script, sequential execution):
|
|
66
|
-
* // <script type="module">await import("/__mf__virtual/hostAutoInit.js");await import("/src/main.js");<\/script>
|
|
55
|
+
* Rewrites entry module script tags to point at an external wrapper module.
|
|
56
|
+
* The wrapper can then sequence federation init before the app entry without
|
|
57
|
+
* relying on CSP-breaking inline `<script type="module">`.
|
|
67
58
|
*/
|
|
68
|
-
function
|
|
69
|
-
|
|
70
|
-
const scriptTagRegex = /<script\s+([^>]*\btype=["']module["'][^>]*\bsrc=["'][^"']+["'][^>]*)>/gi;
|
|
71
|
-
let hasEntry = false;
|
|
72
|
-
const result = html.replace(scriptTagRegex, (match, attrs) => {
|
|
59
|
+
function rewriteEntryScripts(html, createProxySrc) {
|
|
60
|
+
return html.replace(/<script\s+([^>]*\btype=["']module["'][^>]*\bsrc=["'][^"']+["'][^>]*)>/gi, (match, attrs) => {
|
|
73
61
|
const srcMatch = attrs.match(/\bsrc=["']([^"']+)["']/i);
|
|
74
62
|
if (!srcMatch) return match;
|
|
75
63
|
const originalSrc = srcMatch[1];
|
|
76
64
|
if (originalSrc.includes("@vite/client")) return match;
|
|
77
|
-
|
|
78
|
-
return
|
|
65
|
+
const proxySrc = createProxySrc(originalSrc);
|
|
66
|
+
return match.replace(srcMatch[0], `src=${JSON.stringify(proxySrc)}`);
|
|
79
67
|
});
|
|
80
|
-
|
|
68
|
+
}
|
|
69
|
+
function injectEntryScript(html, initSrc) {
|
|
70
|
+
const src = sanitizeDevEntryPath(initSrc);
|
|
81
71
|
return html.replace("<head>", `<head><script type="module" src=${JSON.stringify(src)}><\/script>`);
|
|
82
72
|
}
|
|
83
73
|
//#endregion
|
|
74
|
+
//#region src/utils/logger.ts
|
|
75
|
+
const MODULE_FEDERATION_LOG_PREFIX = "[Module Federation]";
|
|
76
|
+
function formatModuleFederationMessage(message) {
|
|
77
|
+
return `${MODULE_FEDERATION_LOG_PREFIX} ${message}`;
|
|
78
|
+
}
|
|
79
|
+
function createModuleFederationError(message) {
|
|
80
|
+
return new Error(formatModuleFederationMessage(message));
|
|
81
|
+
}
|
|
82
|
+
function toConsoleArgs(message, rest = []) {
|
|
83
|
+
if (typeof message === "string") return [formatModuleFederationMessage(message), ...rest];
|
|
84
|
+
if (message === void 0) return [MODULE_FEDERATION_LOG_PREFIX, ...rest];
|
|
85
|
+
return [
|
|
86
|
+
MODULE_FEDERATION_LOG_PREFIX,
|
|
87
|
+
message,
|
|
88
|
+
...rest
|
|
89
|
+
];
|
|
90
|
+
}
|
|
91
|
+
const moduleFederationConsole = {
|
|
92
|
+
log(message, ...rest) {
|
|
93
|
+
console.log(...toConsoleArgs(message, rest));
|
|
94
|
+
},
|
|
95
|
+
warn(message, ...rest) {
|
|
96
|
+
console.warn(...toConsoleArgs(message, rest));
|
|
97
|
+
},
|
|
98
|
+
error(message, ...rest) {
|
|
99
|
+
console.error(...toConsoleArgs(message, rest));
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
moduleFederationConsole.log;
|
|
103
|
+
const mfWarn = moduleFederationConsole.warn;
|
|
104
|
+
const mfError = moduleFederationConsole.error;
|
|
105
|
+
//#endregion
|
|
84
106
|
//#region src/utils/packageUtils.ts
|
|
85
107
|
const dependencyPresenceCache = /* @__PURE__ */ new Map();
|
|
86
108
|
let packageDetectionCwd;
|
|
@@ -90,6 +112,9 @@ function getDependencyCacheKey(cwd, dependencyName) {
|
|
|
90
112
|
function setPackageDetectionCwd(cwd) {
|
|
91
113
|
packageDetectionCwd = cwd;
|
|
92
114
|
}
|
|
115
|
+
function getPackageDetectionCwd() {
|
|
116
|
+
return packageDetectionCwd || process.cwd();
|
|
117
|
+
}
|
|
93
118
|
/**
|
|
94
119
|
* Escaping rules:
|
|
95
120
|
* Convert using the format __${mapping}__, where _ and $ are not allowed in npm package names but can be used in variable names.
|
|
@@ -104,7 +129,7 @@ function setPackageDetectionCwd(cwd) {
|
|
|
104
129
|
* @returns {string} - The encoded file name.
|
|
105
130
|
*/
|
|
106
131
|
function packageNameEncode(name) {
|
|
107
|
-
if (typeof name !== "string") throw
|
|
132
|
+
if (typeof name !== "string") throw createModuleFederationError("A string package name is required");
|
|
108
133
|
return name.replace(/@/g, "_mf_0_").replace(/\//g, "_mf_1_").replace(/-/g, "_mf_2_").replace(/\./g, "_mf_3_");
|
|
109
134
|
}
|
|
110
135
|
/**
|
|
@@ -113,7 +138,7 @@ function packageNameEncode(name) {
|
|
|
113
138
|
* @returns {string} - The decoded package name.
|
|
114
139
|
*/
|
|
115
140
|
function packageNameDecode(encoded) {
|
|
116
|
-
if (typeof encoded !== "string") throw
|
|
141
|
+
if (typeof encoded !== "string") throw createModuleFederationError("A string encoded file name is required");
|
|
117
142
|
return encoded.replace(/_mf_0_/g, "@").replace(/_mf_1_/g, "/").replace(/_mf_2_/g, "-").replace(/_mf_3_/g, ".");
|
|
118
143
|
}
|
|
119
144
|
/**
|
|
@@ -125,6 +150,13 @@ function removePathFromNpmPackage(packageString) {
|
|
|
125
150
|
const match = packageString.match(/^(?:@[^/]+\/)?[^/]+/);
|
|
126
151
|
return match ? match[0] : packageString;
|
|
127
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Detect whether the current bundler is Rolldown (Vite 8+) by checking
|
|
155
|
+
* for `meta.rolldownVersion` on the plugin hook context.
|
|
156
|
+
*/
|
|
157
|
+
function getIsRolldown(ctx) {
|
|
158
|
+
return !!ctx?.meta?.rolldownVersion;
|
|
159
|
+
}
|
|
128
160
|
function hasPackageDependency(dependencyName, cwd = packageDetectionCwd || process.cwd()) {
|
|
129
161
|
const cacheKey = getDependencyCacheKey(cwd, dependencyName);
|
|
130
162
|
const cached = dependencyPresenceCache.get(cacheKey);
|
|
@@ -150,6 +182,7 @@ function getFirstHtmlEntryFile(entryFiles) {
|
|
|
150
182
|
return entryFiles.find((file) => file.endsWith(".html"));
|
|
151
183
|
}
|
|
152
184
|
const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
185
|
+
const DEV_HTML_PROXY_PREFIX = "virtual:mf-html-entry-proxy?";
|
|
153
186
|
const getEntryPath = () => typeof entryPath === "function" ? entryPath() : entryPath;
|
|
154
187
|
let devEntryPath = "";
|
|
155
188
|
let entryFiles = [];
|
|
@@ -173,8 +206,13 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
173
206
|
configResolved(config) {
|
|
174
207
|
viteConfig = config;
|
|
175
208
|
const resolvedEntryPath = getEntryPath();
|
|
176
|
-
|
|
177
|
-
|
|
209
|
+
if (resolvedEntryPath.startsWith("virtual:mf")) devEntryPath = config.base + "@id/" + resolvedEntryPath;
|
|
210
|
+
else {
|
|
211
|
+
const normalized = resolvedEntryPath.replace(/\\\\?/g, "/");
|
|
212
|
+
const root = config.root.replace(/\\\\?/g, "/").replace(/\/$/, "");
|
|
213
|
+
const relativePath = normalized.startsWith(root + "/") ? normalized.slice(root.length) : "/" + normalized.replace(/^[A-Za-z]:[\\/]/, "");
|
|
214
|
+
devEntryPath = config.base + relativePath.replace(/^\//, "");
|
|
215
|
+
}
|
|
178
216
|
},
|
|
179
217
|
configureServer(server) {
|
|
180
218
|
server.middlewares.use((req, res, next) => {
|
|
@@ -189,7 +227,29 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
189
227
|
transformIndexHtml(c) {
|
|
190
228
|
if (!injectHtml()) return;
|
|
191
229
|
clientInjected = true;
|
|
192
|
-
|
|
230
|
+
const html = rewriteEntryScripts(c, (originalSrc) => {
|
|
231
|
+
const query = new URLSearchParams({
|
|
232
|
+
init: sanitizeDevEntryPath(devEntryPath),
|
|
233
|
+
entry: originalSrc
|
|
234
|
+
}).toString();
|
|
235
|
+
return `${viteConfig.base}@id/${DEV_HTML_PROXY_PREFIX}${query}`;
|
|
236
|
+
});
|
|
237
|
+
return html === c ? injectEntryScript(c, devEntryPath) : html;
|
|
238
|
+
},
|
|
239
|
+
resolveId(id) {
|
|
240
|
+
if (id.startsWith(DEV_HTML_PROXY_PREFIX)) return id;
|
|
241
|
+
},
|
|
242
|
+
load(id) {
|
|
243
|
+
if (!id.startsWith(DEV_HTML_PROXY_PREFIX)) return;
|
|
244
|
+
const params = new URLSearchParams(id.slice(28));
|
|
245
|
+
const initSrc = params.get("init");
|
|
246
|
+
const entrySrc = params.get("entry");
|
|
247
|
+
if (!initSrc || !entrySrc) return;
|
|
248
|
+
return `
|
|
249
|
+
const baseUrl = document.baseURI || window.location.href;
|
|
250
|
+
await import(new URL(${JSON.stringify(initSrc)}, baseUrl).href);
|
|
251
|
+
await import(new URL(${JSON.stringify(entrySrc)}, baseUrl).href);
|
|
252
|
+
`;
|
|
193
253
|
},
|
|
194
254
|
transform(code, id) {
|
|
195
255
|
if (id.includes("node_modules") || inject !== "html" || htmlFilePath) return;
|
|
@@ -245,7 +305,7 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
245
305
|
if (typeof result === "string") return result;
|
|
246
306
|
if (result && typeof result === "object") {
|
|
247
307
|
if ("runtime" in result) {
|
|
248
|
-
|
|
308
|
+
mfWarn("renderBuiltUrl returned runtime code for HTML injection. Runtime code cannot be used in <script src=\"\">. Falling back to base path.");
|
|
249
309
|
return viteConfig.base + file;
|
|
250
310
|
}
|
|
251
311
|
if (result.relative) return file;
|
|
@@ -310,11 +370,11 @@ function checkAliasConflicts(options) {
|
|
|
310
370
|
});
|
|
311
371
|
}
|
|
312
372
|
if (conflicts.length > 0) {
|
|
313
|
-
|
|
373
|
+
mfWarn("Detected alias conflicts with shared modules:");
|
|
314
374
|
conflicts.forEach(({ sharedModule, alias, target }) => {
|
|
315
|
-
|
|
375
|
+
mfWarn(`Shared module "${sharedModule}" is aliased by "${alias}" to "${target}"`);
|
|
316
376
|
});
|
|
317
|
-
|
|
377
|
+
mfWarn("This may cause runtime errors as the shared module will bypass Module Federation's sharing mechanism.");
|
|
318
378
|
}
|
|
319
379
|
}
|
|
320
380
|
};
|
|
@@ -343,7 +403,7 @@ function PluginDevProxyModuleTopLevelAwait() {
|
|
|
343
403
|
try {
|
|
344
404
|
ast = this.parse(code, { allowReturnOutsideFunction: true });
|
|
345
405
|
} catch (e) {
|
|
346
|
-
throw
|
|
406
|
+
throw createModuleFederationError(`${id}: ${e}`);
|
|
347
407
|
}
|
|
348
408
|
const magicString = new magic_string.default(code);
|
|
349
409
|
const walk = await loadWalk();
|
|
@@ -471,7 +531,7 @@ const normalizeDevDtsOptions = (dts, context) => {
|
|
|
471
531
|
const logDtsError = (error, dtsOptions) => {
|
|
472
532
|
if (dtsOptions === false) return;
|
|
473
533
|
if (typeof dtsOptions === "object" && dtsOptions && dtsOptions.displayErrorInTerminal === false) return;
|
|
474
|
-
|
|
534
|
+
mfError(error);
|
|
475
535
|
};
|
|
476
536
|
function pluginDts(options) {
|
|
477
537
|
if (options.dts === false) return [];
|
|
@@ -499,7 +559,7 @@ function pluginDts(options) {
|
|
|
499
559
|
if (!normalizedDevOptions || !resolvedConfig) return;
|
|
500
560
|
const devOptions = normalizedDevOptions;
|
|
501
561
|
if (devOptions.disableDynamicRemoteTypeHints && devOptions.disableHotTypesReload && devOptions.disableLiveReload) return;
|
|
502
|
-
if (!options.name) throw
|
|
562
|
+
if (!options.name) throw createModuleFederationError("name is required if you want to enable dev server!");
|
|
503
563
|
const outputDir = resolveOutputDir(resolvedConfig);
|
|
504
564
|
const normalizedDtsOptions = normalizeDevDtsOptions(options.dts, resolvedConfig.root);
|
|
505
565
|
if (typeof normalizedDtsOptions !== "object") return;
|
|
@@ -695,11 +755,11 @@ function normalizeShareItem(key, shareItem) {
|
|
|
695
755
|
version = require(localPath).version;
|
|
696
756
|
} catch (e2) {
|
|
697
757
|
version = searchPackageVersion(key);
|
|
698
|
-
if (!version)
|
|
758
|
+
if (!version) mfError(e1);
|
|
699
759
|
}
|
|
700
760
|
}
|
|
701
761
|
} catch (e) {
|
|
702
|
-
|
|
762
|
+
mfError(`Unexpected error resolving version for ${key}:`, e);
|
|
703
763
|
}
|
|
704
764
|
if (typeof shareItem === "string") return {
|
|
705
765
|
name: shareItem,
|
|
@@ -760,7 +820,7 @@ function getNormalizeShareItem(key) {
|
|
|
760
820
|
return options.shared[key] || options.shared[removePathFromNpmPackage(key)] || options.shared[removePathFromNpmPackage(key) + "/"];
|
|
761
821
|
}
|
|
762
822
|
function normalizeModuleFederationOptions(options) {
|
|
763
|
-
if (options.virtualModuleDir && options.virtualModuleDir.includes("/")) throw
|
|
823
|
+
if (options.virtualModuleDir && options.virtualModuleDir.includes("/")) throw createModuleFederationError(`Invalid virtualModuleDir: "${options.virtualModuleDir}". The virtualModuleDir option cannot contain slashes (/). Please use a single directory name like '__mf__virtual__your_app_name'.`);
|
|
764
824
|
return config = {
|
|
765
825
|
exposes: normalizeExposes(options.exposes),
|
|
766
826
|
filename: options.filename || "remoteEntry-[hash]",
|
|
@@ -895,7 +955,7 @@ const cacheMap = {};
|
|
|
895
955
|
*/
|
|
896
956
|
function assertModuleFound(tag, str = "") {
|
|
897
957
|
const module = VirtualModule.findModule(tag, str);
|
|
898
|
-
if (!module) throw
|
|
958
|
+
if (!module) throw createModuleFederationError(`Module Federation shared module '${str}' not found. Please ensure it's installed as a dependency in your package.json.`);
|
|
899
959
|
return module;
|
|
900
960
|
}
|
|
901
961
|
var VirtualModule = class {
|
|
@@ -956,15 +1016,61 @@ var VirtualModule = class {
|
|
|
956
1016
|
};
|
|
957
1017
|
//#endregion
|
|
958
1018
|
//#region src/virtualModules/virtualExposes.ts
|
|
1019
|
+
const EXPOSES_CSS_MAP_PLACEHOLDER = "__MF_EXPOSES_CSS_MAP__";
|
|
1020
|
+
function getExposesCssMapPlaceholder() {
|
|
1021
|
+
return EXPOSES_CSS_MAP_PLACEHOLDER;
|
|
1022
|
+
}
|
|
959
1023
|
function getVirtualExposesId(options) {
|
|
960
1024
|
return `virtual:mf-exposes:${`${options.name}__${options.filename}`.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
|
|
961
1025
|
}
|
|
962
1026
|
function generateExposes(options) {
|
|
963
1027
|
return `
|
|
1028
|
+
const cssAssetMap = ${JSON.stringify(options.bundleAllCSS ? EXPOSES_CSS_MAP_PLACEHOLDER : {})};
|
|
1029
|
+
const injectedCssHrefs = new Set();
|
|
1030
|
+
|
|
1031
|
+
async function injectCssAssets(exposeKey) {
|
|
1032
|
+
if (typeof document === "undefined") {
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
// Replaced at build time with expose -> css asset paths.
|
|
1037
|
+
const cssAssets = cssAssetMap[exposeKey] || [];
|
|
1038
|
+
|
|
1039
|
+
await Promise.all(
|
|
1040
|
+
cssAssets.map((cssAsset) => {
|
|
1041
|
+
const href = new URL(cssAsset, import.meta.url).href;
|
|
1042
|
+
|
|
1043
|
+
// Same expose can be resolved multiple times in one page.
|
|
1044
|
+
if (injectedCssHrefs.has(href)) {
|
|
1045
|
+
return Promise.resolve();
|
|
1046
|
+
}
|
|
1047
|
+
injectedCssHrefs.add(href);
|
|
1048
|
+
|
|
1049
|
+
const existingLink = document.querySelector(
|
|
1050
|
+
\`link[rel="stylesheet"][data-mf-href="\${href}"]\`
|
|
1051
|
+
);
|
|
1052
|
+
if (existingLink) {
|
|
1053
|
+
return Promise.resolve();
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
return new Promise((resolve, reject) => {
|
|
1057
|
+
const link = document.createElement("link");
|
|
1058
|
+
link.rel = "stylesheet";
|
|
1059
|
+
link.href = href;
|
|
1060
|
+
link.setAttribute("data-mf-href", href);
|
|
1061
|
+
link.onload = () => resolve();
|
|
1062
|
+
link.onerror = () => reject(new Error(\`[Module Federation] Failed to load CSS asset: \${href}\`));
|
|
1063
|
+
document.head.appendChild(link);
|
|
1064
|
+
});
|
|
1065
|
+
})
|
|
1066
|
+
);
|
|
1067
|
+
}
|
|
1068
|
+
|
|
964
1069
|
export default {
|
|
965
1070
|
${Object.keys(options.exposes).map((key) => {
|
|
966
1071
|
return `
|
|
967
1072
|
${JSON.stringify(key)}: async () => {
|
|
1073
|
+
await injectCssAssets(${JSON.stringify(key)})
|
|
968
1074
|
const importModule = await import(${JSON.stringify(options.exposes[key].import)})
|
|
969
1075
|
const exportModule = {}
|
|
970
1076
|
Object.assign(exportModule, importModule)
|
|
@@ -1111,36 +1217,167 @@ function generateRemotes(id, command, isRolldown) {
|
|
|
1111
1217
|
* 1. __prebuild__: export shareModule (pre-built source code of modules such as vue, react, etc.)
|
|
1112
1218
|
* 2. __loadShare__: load shareModule (mfRuntime.loadShare('vue'))
|
|
1113
1219
|
*/
|
|
1220
|
+
function escapeGeneratedStringLiteral(value) {
|
|
1221
|
+
return JSON.stringify(value).replace(/[<>\u2028\u2029]/g, (char) => {
|
|
1222
|
+
switch (char) {
|
|
1223
|
+
case "<": return "\\u003C";
|
|
1224
|
+
case ">": return "\\u003E";
|
|
1225
|
+
case "\u2028": return "\\u2028";
|
|
1226
|
+
case "\u2029": return "\\u2029";
|
|
1227
|
+
default: return char;
|
|
1228
|
+
}
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
const localRequire = (0, module$1.createRequire)(require("url").pathToFileURL(__filename).href);
|
|
1232
|
+
function resolvePackageEntryFromProjectRoot(pkg) {
|
|
1233
|
+
try {
|
|
1234
|
+
return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
|
|
1235
|
+
} catch {
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
function getInstalledPackageJsonPath(pkg) {
|
|
1240
|
+
try {
|
|
1241
|
+
const packageName = removePathFromNpmPackage(pkg);
|
|
1242
|
+
const projectRequire = (0, module$1.createRequire)(new URL(`file://${pathe.default.join(getPackageDetectionCwd(), "package.json")}`));
|
|
1243
|
+
let resolvedPath;
|
|
1244
|
+
try {
|
|
1245
|
+
resolvedPath = projectRequire.resolve(pkg);
|
|
1246
|
+
} catch {
|
|
1247
|
+
resolvedPath = projectRequire.resolve(packageName);
|
|
1248
|
+
}
|
|
1249
|
+
let currentDir = pathe.default.dirname(resolvedPath);
|
|
1250
|
+
const rootDir = pathe.default.parse(currentDir).root;
|
|
1251
|
+
while (currentDir !== rootDir) {
|
|
1252
|
+
const packageJsonPath = pathe.default.join(currentDir, "package.json");
|
|
1253
|
+
if ((0, fs.existsSync)(packageJsonPath)) {
|
|
1254
|
+
if (JSON.parse((0, fs.readFileSync)(packageJsonPath, "utf-8")).name === packageName) return packageJsonPath;
|
|
1255
|
+
}
|
|
1256
|
+
currentDir = pathe.default.dirname(currentDir);
|
|
1257
|
+
}
|
|
1258
|
+
const rootPackageJsonPath = pathe.default.join(rootDir, "package.json");
|
|
1259
|
+
if ((0, fs.existsSync)(rootPackageJsonPath)) {
|
|
1260
|
+
if (JSON.parse((0, fs.readFileSync)(rootPackageJsonPath, "utf-8")).name === packageName) return rootPackageJsonPath;
|
|
1261
|
+
}
|
|
1262
|
+
} catch {
|
|
1263
|
+
const packageName = removePathFromNpmPackage(pkg);
|
|
1264
|
+
let currentDir = getPackageDetectionCwd();
|
|
1265
|
+
const rootDir = pathe.default.parse(currentDir).root;
|
|
1266
|
+
while (currentDir !== rootDir) {
|
|
1267
|
+
const packageJsonPath = pathe.default.join(currentDir, "node_modules", packageName, "package.json");
|
|
1268
|
+
if ((0, fs.existsSync)(packageJsonPath)) return packageJsonPath;
|
|
1269
|
+
currentDir = pathe.default.dirname(currentDir);
|
|
1270
|
+
}
|
|
1271
|
+
const rootPackageJsonPath = pathe.default.join(rootDir, "node_modules", packageName, "package.json");
|
|
1272
|
+
return (0, fs.existsSync)(rootPackageJsonPath) ? rootPackageJsonPath : void 0;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
function resolveImportTarget(exportsField) {
|
|
1276
|
+
if (typeof exportsField === "string") return exportsField;
|
|
1277
|
+
if (!exportsField || typeof exportsField !== "object") return void 0;
|
|
1278
|
+
const record = exportsField;
|
|
1279
|
+
for (const condition of [
|
|
1280
|
+
"import",
|
|
1281
|
+
"module",
|
|
1282
|
+
"default"
|
|
1283
|
+
]) {
|
|
1284
|
+
const target = resolveImportTarget(record[condition]);
|
|
1285
|
+
if (target) return target;
|
|
1286
|
+
}
|
|
1287
|
+
for (const target of Object.values(record)) {
|
|
1288
|
+
const resolved = resolveImportTarget(target);
|
|
1289
|
+
if (resolved) return resolved;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
function getPackageEsmEntryPath(pkg) {
|
|
1293
|
+
try {
|
|
1294
|
+
const resolvedEntryPath = resolvePackageEntryFromProjectRoot(pkg);
|
|
1295
|
+
const packageJsonPath = getInstalledPackageJsonPath(pkg);
|
|
1296
|
+
if (!packageJsonPath) return resolvedEntryPath;
|
|
1297
|
+
const packageName = removePathFromNpmPackage(pkg);
|
|
1298
|
+
const packageJson = JSON.parse((0, fs.readFileSync)(packageJsonPath, "utf-8"));
|
|
1299
|
+
const subpath = pkg === packageName ? "." : `.${pkg.slice(packageName.length)}`;
|
|
1300
|
+
const target = resolveImportTarget(typeof packageJson.exports === "string" ? subpath === "." ? packageJson.exports : void 0 : packageJson.exports?.[subpath] ?? (subpath === "." ? packageJson.exports?.["."] ?? (packageJson.exports && !Object.keys(packageJson.exports).some((key) => key.startsWith(".")) ? packageJson.exports : void 0) : void 0)) || packageJson.module;
|
|
1301
|
+
if (!target) return resolvedEntryPath;
|
|
1302
|
+
return pathe.default.resolve(pathe.default.dirname(packageJsonPath), target);
|
|
1303
|
+
} catch {
|
|
1304
|
+
return resolvePackageEntryFromProjectRoot(pkg);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
function getEsmNamedExports(pkg) {
|
|
1308
|
+
try {
|
|
1309
|
+
const entryPath = getPackageEsmEntryPath(pkg);
|
|
1310
|
+
if (!entryPath) return [];
|
|
1311
|
+
const { initSync, parse } = localRequire("es-module-lexer");
|
|
1312
|
+
initSync();
|
|
1313
|
+
const [, exports] = parse((0, fs.readFileSync)(entryPath, "utf-8"), entryPath);
|
|
1314
|
+
return exports.map((item) => item.n).filter((name) => !!name && name !== "default" && name !== "__esModule" && /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name));
|
|
1315
|
+
} catch {
|
|
1316
|
+
return [];
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1114
1319
|
function getPackageNamedExports(pkg) {
|
|
1115
1320
|
try {
|
|
1116
|
-
const mod = (0, module$1.createRequire)(new URL(
|
|
1321
|
+
const mod = (0, module$1.createRequire)(new URL(`file://${pathe.default.join(getPackageDetectionCwd(), "package.json")}`))(pkg);
|
|
1117
1322
|
return Object.keys(mod).filter((k) => k !== "default" && k !== "__esModule" && /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(k));
|
|
1118
1323
|
} catch {
|
|
1119
|
-
return
|
|
1324
|
+
return getEsmNamedExports(pkg);
|
|
1120
1325
|
}
|
|
1121
1326
|
}
|
|
1122
1327
|
function getLocalProviderImportPath(pkg) {
|
|
1123
1328
|
try {
|
|
1124
|
-
const resolved = (0, module$1.createRequire)(new URL(
|
|
1329
|
+
const resolved = (0, module$1.createRequire)(new URL(`file://${pathe.default.join(getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
|
|
1125
1330
|
return resolved.includes("/node_modules/") || resolved.includes("\\node_modules\\") ? void 0 : resolved;
|
|
1126
1331
|
} catch {
|
|
1127
1332
|
return;
|
|
1128
1333
|
}
|
|
1129
1334
|
}
|
|
1335
|
+
function tryResolveImportFromPackageRoot(pkg, root) {
|
|
1336
|
+
try {
|
|
1337
|
+
return (0, module$1.createRequire)(new URL(`file://${pathe.default.join(root, "package.json")}`)).resolve(pkg);
|
|
1338
|
+
} catch {
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
function getConcreteSharedImportSource(pkg, shareItem) {
|
|
1343
|
+
const configuredImport = shareItem?.shareConfig.import;
|
|
1344
|
+
if (typeof configuredImport === "string") return configuredImport;
|
|
1345
|
+
const projectRoot = getPackageDetectionCwd();
|
|
1346
|
+
if (tryResolveImportFromPackageRoot(pkg, projectRoot)) return;
|
|
1347
|
+
let currentDir = pathe.default.dirname(projectRoot);
|
|
1348
|
+
while (currentDir !== pathe.default.dirname(currentDir)) {
|
|
1349
|
+
const resolved = tryResolveImportFromPackageRoot(pkg, currentDir);
|
|
1350
|
+
if (resolved) return resolved;
|
|
1351
|
+
currentDir = pathe.default.dirname(currentDir);
|
|
1352
|
+
}
|
|
1353
|
+
return tryResolveImportFromPackageRoot(pkg, currentDir);
|
|
1354
|
+
}
|
|
1130
1355
|
const preBuildCacheMap = {};
|
|
1356
|
+
const preBuildShareItemMap = {};
|
|
1131
1357
|
const PREBUILD_TAG = "__prebuild__";
|
|
1132
|
-
function writePreBuildLibPath(pkg) {
|
|
1358
|
+
function writePreBuildLibPath(pkg, shareItem) {
|
|
1133
1359
|
if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
|
|
1134
|
-
|
|
1360
|
+
preBuildShareItemMap[pkg] = shareItem;
|
|
1361
|
+
preBuildCacheMap[pkg].writeSync("", true);
|
|
1135
1362
|
}
|
|
1136
1363
|
function getPreBuildLibImportId(pkg) {
|
|
1137
1364
|
if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
|
|
1138
1365
|
return preBuildCacheMap[pkg].getImportId();
|
|
1139
1366
|
}
|
|
1367
|
+
function getPreBuildShareItem(pkg) {
|
|
1368
|
+
return preBuildShareItemMap[pkg];
|
|
1369
|
+
}
|
|
1370
|
+
function getSharedImportSource(pkg, shareItem) {
|
|
1371
|
+
return getConcreteSharedImportSource(pkg, shareItem) || getPreBuildLibImportId(pkg);
|
|
1372
|
+
}
|
|
1140
1373
|
const LOAD_SHARE_TAG = "__loadShare__";
|
|
1141
1374
|
const loadShareCacheMap = {};
|
|
1142
|
-
function
|
|
1375
|
+
function getLoadShareImportId(pkg, isRolldown, command) {
|
|
1143
1376
|
if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, isRolldown || command === "build" ? ".mjs" : ".js");
|
|
1377
|
+
return loadShareCacheMap[pkg].getImportId();
|
|
1378
|
+
}
|
|
1379
|
+
function getLoadShareModulePath(pkg, isRolldown, command) {
|
|
1380
|
+
if (!loadShareCacheMap[pkg]) getLoadShareImportId(pkg, isRolldown, command);
|
|
1144
1381
|
return loadShareCacheMap[pkg].getPath();
|
|
1145
1382
|
}
|
|
1146
1383
|
function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
@@ -1150,22 +1387,25 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
|
1150
1387
|
const { initPromise } = globalThis[globalKey];` : `const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")`;
|
|
1151
1388
|
const awaitOrPlaceholder = useESM ? "await " : "/*mf top-level-await placeholder replacement mf*/";
|
|
1152
1389
|
const useSsrProviderFallback = hasPackageDependency("vinext") && command === "build" && pkg === "react";
|
|
1153
|
-
const
|
|
1390
|
+
const concreteSharedImportSource = getConcreteSharedImportSource(pkg, shareItem);
|
|
1391
|
+
const sharedImportSource = concreteSharedImportSource || getPreBuildLibImportId(pkg);
|
|
1392
|
+
const devImportSource = concreteSharedImportSource || pkg;
|
|
1393
|
+
const providerImportId = getLocalProviderImportPath(pkg) || concreteSharedImportSource || sharedImportSource;
|
|
1154
1394
|
const namedExports = getPackageNamedExports(pkg);
|
|
1155
1395
|
let exportLine;
|
|
1156
1396
|
if (namedExports.length > 0) {
|
|
1157
1397
|
const destructure = `const { ${namedExports.map((name, i) => `${name}: __mf_${i}`).join(", ")} } = exportModule;`;
|
|
1158
1398
|
const namedExportLine = `export { ${namedExports.map((name, i) => `__mf_${i} as ${name}`).join(", ")} };`;
|
|
1159
|
-
exportLine = useESM ? `export default exportModule;\n ${destructure}\n ${namedExportLine}` : `module.exports = exportModule;\n ${destructure}\n Object.assign(module.exports, { ${namedExports.map((name, i) => `"${name}": __mf_${i}`).join(", ")} });`;
|
|
1160
|
-
} else exportLine = useESM ? `export default exportModule\n export * from ${
|
|
1399
|
+
exportLine = useESM ? `export default exportModule.default ?? exportModule;\n ${destructure}\n ${namedExportLine}` : `module.exports = exportModule;\n ${destructure}\n Object.assign(module.exports, { ${namedExports.map((name, i) => `"${name}": __mf_${i}`).join(", ")} });`;
|
|
1400
|
+
} else exportLine = useESM ? `export default exportModule.default ?? exportModule\n export * from ${escapeGeneratedStringLiteral(sharedImportSource)}` : "module.exports = exportModule";
|
|
1161
1401
|
loadShareCacheMap[pkg].writeSync(`
|
|
1162
|
-
import ${
|
|
1163
|
-
${command !== "build" ? `;() => import(${
|
|
1402
|
+
import ${escapeGeneratedStringLiteral(sharedImportSource)};
|
|
1403
|
+
${command !== "build" ? `;() => import(${escapeGeneratedStringLiteral(devImportSource)}).catch(() => {});` : ""}
|
|
1164
1404
|
${importLine}
|
|
1165
1405
|
${useSsrProviderFallback ? `const providerModulePromise = typeof window === "undefined"
|
|
1166
|
-
? import(${
|
|
1406
|
+
? import(${escapeGeneratedStringLiteral(providerImportId)})
|
|
1167
1407
|
: undefined` : ""}
|
|
1168
|
-
const res = initPromise.then(runtime => runtime.loadShare(${
|
|
1408
|
+
const res = initPromise.then(runtime => runtime.loadShare(${escapeGeneratedStringLiteral(pkg)}, {
|
|
1169
1409
|
customShareInfo: {shareConfig:{
|
|
1170
1410
|
singleton: ${shareItem.shareConfig.singleton},
|
|
1171
1411
|
strictVersion: ${shareItem.shareConfig.strictVersion},
|
|
@@ -1176,7 +1416,7 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
|
1176
1416
|
? ((await providerModulePromise)?.default ?? await providerModulePromise)
|
|
1177
1417
|
: ${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory)))` : `${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory))`}
|
|
1178
1418
|
${exportLine}
|
|
1179
|
-
|
|
1419
|
+
`, true);
|
|
1180
1420
|
}
|
|
1181
1421
|
//#endregion
|
|
1182
1422
|
//#region src/virtualModules/virtualRemoteEntry.ts
|
|
@@ -1209,8 +1449,8 @@ function generateLocalSharedImportMap() {
|
|
|
1209
1449
|
const shareItem = getNormalizeShareItem(pkg);
|
|
1210
1450
|
return `
|
|
1211
1451
|
${JSON.stringify(pkg)}: async () => {
|
|
1212
|
-
${shareItem?.shareConfig.import === false ? `throw new Error(\`Shared module '\${${JSON.stringify(pkg)}}' must be provided by host\`);` : isVinext && pkg === "react" ? `let pkg = await import("react");
|
|
1213
|
-
return pkg;` : `let pkg = await import(
|
|
1452
|
+
${shareItem?.shareConfig.import === false ? `throw new Error(\`[Module Federation] Shared module '\${${JSON.stringify(pkg)}}' must be provided by host\`);` : isVinext && pkg === "react" ? `let pkg = await import("react");
|
|
1453
|
+
return pkg;` : `let pkg = await import(${JSON.stringify(getSharedImportSource(pkg, shareItem))});
|
|
1214
1454
|
return pkg;`}
|
|
1215
1455
|
}
|
|
1216
1456
|
`;
|
|
@@ -1229,7 +1469,7 @@ function generateLocalSharedImportMap() {
|
|
|
1229
1469
|
from: ${JSON.stringify(options.name)},
|
|
1230
1470
|
async get () {
|
|
1231
1471
|
if (${shareItem.shareConfig.import === false}) {
|
|
1232
|
-
throw new Error(\`Shared module '\${${JSON.stringify(key)}}' must be provided by host\`);
|
|
1472
|
+
throw new Error(\`[Module Federation] Shared module '\${${JSON.stringify(key)}}' must be provided by host\`);
|
|
1233
1473
|
}
|
|
1234
1474
|
usedShared[${JSON.stringify(key)}].loaded = true
|
|
1235
1475
|
const {${JSON.stringify(key)}: pkgDynamicImport} = importMap
|
|
@@ -1336,14 +1576,14 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1336
1576
|
initScope
|
|
1337
1577
|
}));
|
|
1338
1578
|
} catch (e) {
|
|
1339
|
-
console.error(e)
|
|
1579
|
+
console.error('[Module Federation]', e)
|
|
1340
1580
|
}
|
|
1341
1581
|
return initRes
|
|
1342
1582
|
}
|
|
1343
1583
|
|
|
1344
1584
|
async function getExposes(moduleName) {
|
|
1345
1585
|
const exposesMap = await getExposesMap()
|
|
1346
|
-
if (!(moduleName in exposesMap)) throw new Error(\`Module \${moduleName} does not exist in container.\`)
|
|
1586
|
+
if (!(moduleName in exposesMap)) throw new Error(\`[Module Federation] Module \${moduleName} does not exist in container.\`)
|
|
1347
1587
|
return (exposesMap[moduleName])().then(res => () => res)
|
|
1348
1588
|
}
|
|
1349
1589
|
export {
|
|
@@ -1492,6 +1732,18 @@ const processModuleAssets = (bundle, filesMap, moduleMatcher) => {
|
|
|
1492
1732
|
}
|
|
1493
1733
|
};
|
|
1494
1734
|
/**
|
|
1735
|
+
* Adds global CSS assets to all module exports
|
|
1736
|
+
* @param filesMap - The preload map to update
|
|
1737
|
+
* @param cssAssets - Set of CSS asset filenames to add
|
|
1738
|
+
*/
|
|
1739
|
+
const addCssAssetsToAllExports = (filesMap, cssAssets) => {
|
|
1740
|
+
Object.keys(filesMap).forEach((key) => {
|
|
1741
|
+
cssAssets.forEach((cssAsset) => {
|
|
1742
|
+
trackAsset(filesMap, key, cssAsset, false, "css");
|
|
1743
|
+
});
|
|
1744
|
+
});
|
|
1745
|
+
};
|
|
1746
|
+
/**
|
|
1495
1747
|
* Deduplicates assets in the files map
|
|
1496
1748
|
* @param filesMap - The preload map to deduplicate
|
|
1497
1749
|
* @returns New deduplicated preload map
|
|
@@ -1760,14 +2012,14 @@ const promise = new Promise((resolve, reject) => {
|
|
|
1760
2012
|
});
|
|
1761
2013
|
function setParseTimeout(timeout) {
|
|
1762
2014
|
if (!_parseTimeout) _parseTimeout = setTimeout(() => {
|
|
1763
|
-
|
|
2015
|
+
mfWarn(`Parse timeout (${timeout}s) - forcing resolve`);
|
|
1764
2016
|
_resolve(1);
|
|
1765
2017
|
}, timeout * 1e3);
|
|
1766
2018
|
}
|
|
1767
2019
|
function resetIdleTimeout(timeout) {
|
|
1768
2020
|
clearTimeout(_parseTimeout);
|
|
1769
2021
|
_parseTimeout = setTimeout(() => {
|
|
1770
|
-
|
|
2022
|
+
mfWarn(`moduleParseIdleTimeout: no module activity for ${timeout}s, forcing resolve. Some shared/remote dependencies may be missing. Consider increasing moduleParseIdleTimeout.`);
|
|
1771
2023
|
_resolve(1);
|
|
1772
2024
|
}, timeout * 1e3);
|
|
1773
2025
|
}
|
|
@@ -1817,12 +2069,13 @@ function pluginModuleParseEnd_default(excludeFn, options) {
|
|
|
1817
2069
|
//#region src/plugins/pluginProxyRemoteEntry.ts
|
|
1818
2070
|
const filter = (0, _rollup_pluginutils.createFilter)();
|
|
1819
2071
|
function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposesId }) {
|
|
1820
|
-
let viteConfig, _command;
|
|
2072
|
+
let viteConfig, _command, root;
|
|
1821
2073
|
return {
|
|
1822
2074
|
name: "proxyRemoteEntry",
|
|
1823
2075
|
enforce: "post",
|
|
1824
2076
|
configResolved(config) {
|
|
1825
2077
|
viteConfig = config;
|
|
2078
|
+
root = config.root;
|
|
1826
2079
|
},
|
|
1827
2080
|
config(config, { command }) {
|
|
1828
2081
|
_command = command;
|
|
@@ -1877,6 +2130,51 @@ function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposes
|
|
|
1877
2130
|
return code;
|
|
1878
2131
|
}
|
|
1879
2132
|
})());
|
|
2133
|
+
},
|
|
2134
|
+
generateBundle(_, bundle) {
|
|
2135
|
+
if (_command !== "build") return;
|
|
2136
|
+
const filesMap = {};
|
|
2137
|
+
const exposeEntries = Object.entries(options.exposes);
|
|
2138
|
+
const allCssAssets = options.bundleAllCSS ? collectCssAssets(bundle) : /* @__PURE__ */ new Set();
|
|
2139
|
+
processModuleAssets(bundle, filesMap, (modulePath) => {
|
|
2140
|
+
const absoluteModulePath = pathe.resolve(root, modulePath);
|
|
2141
|
+
return exposeEntries.find(([_, exposeOptions]) => {
|
|
2142
|
+
const exposePath = pathe.resolve(root, exposeOptions.import);
|
|
2143
|
+
if (absoluteModulePath === exposePath) return true;
|
|
2144
|
+
const stripKnownJsExt = (filePath) => {
|
|
2145
|
+
const ext = pathe.extname(filePath);
|
|
2146
|
+
return [
|
|
2147
|
+
".ts",
|
|
2148
|
+
".tsx",
|
|
2149
|
+
".jsx",
|
|
2150
|
+
".mjs",
|
|
2151
|
+
".cjs"
|
|
2152
|
+
].includes(ext) ? pathe.join(pathe.dirname(filePath), pathe.basename(filePath, ext)) : filePath;
|
|
2153
|
+
};
|
|
2154
|
+
return stripKnownJsExt(absoluteModulePath) === stripKnownJsExt(exposePath);
|
|
2155
|
+
})?.[1].import;
|
|
2156
|
+
});
|
|
2157
|
+
if (options.bundleAllCSS) addCssAssetsToAllExports(filesMap, allCssAssets);
|
|
2158
|
+
const ensureRelativeImportPath = (fromFile, toFile) => {
|
|
2159
|
+
let relativePath = pathe.relative(pathe.dirname(fromFile), toFile);
|
|
2160
|
+
if (!relativePath.startsWith(".")) relativePath = `./${relativePath}`;
|
|
2161
|
+
return relativePath;
|
|
2162
|
+
};
|
|
2163
|
+
const placeholderValue = getExposesCssMapPlaceholder();
|
|
2164
|
+
const placeholderPatterns = [
|
|
2165
|
+
JSON.stringify(placeholderValue),
|
|
2166
|
+
`'${placeholderValue}'`,
|
|
2167
|
+
`\`${placeholderValue}\``
|
|
2168
|
+
];
|
|
2169
|
+
for (const file of Object.values(bundle)) {
|
|
2170
|
+
if (file.type !== "chunk" || !file.code.includes(placeholderValue)) continue;
|
|
2171
|
+
const cssAssetMap = exposeEntries.reduce((acc, [exposeKey, expose]) => {
|
|
2172
|
+
const assets = filesMap[expose.import] || createEmptyAssetMap();
|
|
2173
|
+
acc[exposeKey] = [...assets.css.sync, ...assets.css.async].map((cssAsset) => ensureRelativeImportPath(file.fileName, cssAsset));
|
|
2174
|
+
return acc;
|
|
2175
|
+
}, {});
|
|
2176
|
+
for (const placeholderPattern of placeholderPatterns) file.code = file.code.replace(placeholderPattern, JSON.stringify(cssAssetMap));
|
|
2177
|
+
}
|
|
1880
2178
|
}
|
|
1881
2179
|
};
|
|
1882
2180
|
}
|
|
@@ -1888,7 +2186,7 @@ function pluginProxyRemotes_default(options) {
|
|
|
1888
2186
|
return {
|
|
1889
2187
|
name: "proxyRemotes",
|
|
1890
2188
|
config(config, { command: _command }) {
|
|
1891
|
-
const isRolldown =
|
|
2189
|
+
const isRolldown = getIsRolldown(this);
|
|
1892
2190
|
Object.keys(remotes).forEach((key) => {
|
|
1893
2191
|
const remote = remotes[key];
|
|
1894
2192
|
config.resolve.alias.push({
|
|
@@ -1939,6 +2237,9 @@ var PromiseStore = class {
|
|
|
1939
2237
|
};
|
|
1940
2238
|
//#endregion
|
|
1941
2239
|
//#region src/plugins/pluginProxySharedModule_preBuild.ts
|
|
2240
|
+
function getPrebuildResolutionSource(pkgName, shareItem) {
|
|
2241
|
+
return getConcreteSharedImportSource(pkgName, shareItem) || pkgName;
|
|
2242
|
+
}
|
|
1942
2243
|
function proxySharedModule(options) {
|
|
1943
2244
|
const { shared = {} } = options;
|
|
1944
2245
|
let _config;
|
|
@@ -1960,7 +2261,7 @@ function proxySharedModule(options) {
|
|
|
1960
2261
|
config(config, { command }) {
|
|
1961
2262
|
setPackageDetectionCwd(config.root || process.cwd());
|
|
1962
2263
|
isVinext = hasPackageDependency("vinext");
|
|
1963
|
-
const isRolldown =
|
|
2264
|
+
const isRolldown = getIsRolldown(this);
|
|
1964
2265
|
_command = command;
|
|
1965
2266
|
config.resolve.alias.push(...Object.keys(shared).filter((key) => !(isVinext && key === "react")).map((key) => {
|
|
1966
2267
|
const keyBase = key.endsWith("/") ? key.slice(0, -1) : key;
|
|
@@ -1977,7 +2278,7 @@ function proxySharedModule(options) {
|
|
|
1977
2278
|
if (key.endsWith("/") && source !== key.slice(0, -1)) return;
|
|
1978
2279
|
const loadSharePath = getLoadShareModulePath(source, isRolldown, command);
|
|
1979
2280
|
writeLoadShareModule(source, shared[key], command, isRolldown);
|
|
1980
|
-
writePreBuildLibPath(source);
|
|
2281
|
+
writePreBuildLibPath(source, shared[key]);
|
|
1981
2282
|
addUsedShares(source);
|
|
1982
2283
|
writeLocalSharedImportMap();
|
|
1983
2284
|
return this.resolve(loadSharePath, importer);
|
|
@@ -1988,14 +2289,18 @@ function proxySharedModule(options) {
|
|
|
1988
2289
|
return command === "build" ? {
|
|
1989
2290
|
find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
|
|
1990
2291
|
replacement: function($1) {
|
|
1991
|
-
|
|
2292
|
+
const pkgName = assertModuleFound(PREBUILD_TAG, $1).name;
|
|
2293
|
+
return getPrebuildResolutionSource(pkgName, getPreBuildShareItem(pkgName));
|
|
1992
2294
|
}
|
|
1993
2295
|
} : {
|
|
1994
2296
|
find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
|
|
1995
2297
|
replacement: "$1",
|
|
1996
2298
|
async customResolver(source, importer) {
|
|
1997
2299
|
const pkgName = assertModuleFound(PREBUILD_TAG, source).name;
|
|
1998
|
-
const
|
|
2300
|
+
const importSource = getPrebuildResolutionSource(pkgName, getPreBuildShareItem(pkgName));
|
|
2301
|
+
const resolved = await this.resolve(importSource, importer);
|
|
2302
|
+
if (!resolved?.id) return;
|
|
2303
|
+
const result = resolved.id;
|
|
1999
2304
|
if (_config && !result.includes(_config.cacheDir)) savePrebuild.set(pkgName, Promise.resolve(result));
|
|
2000
2305
|
return await this.resolve(await savePrebuild.get(pkgName), importer);
|
|
2001
2306
|
}
|
|
@@ -2012,7 +2317,7 @@ function proxySharedModule(options) {
|
|
|
2012
2317
|
return;
|
|
2013
2318
|
}
|
|
2014
2319
|
writeLoadShareModule(key, shared[key], _command, isRolldown);
|
|
2015
|
-
writePreBuildLibPath(key);
|
|
2320
|
+
writePreBuildLibPath(key, shared[key]);
|
|
2016
2321
|
addUsedShares(key);
|
|
2017
2322
|
});
|
|
2018
2323
|
writeLocalSharedImportMap();
|
|
@@ -2040,7 +2345,6 @@ const VarRemoteEntry = () => {
|
|
|
2040
2345
|
if (req.url?.replace(/\?.*/, "") === (viteConfig.base + varFilename).replace(/^\/?/, "/")) {
|
|
2041
2346
|
res.setHeader("Content-Type", "text/javascript");
|
|
2042
2347
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
2043
|
-
console.log({ filename });
|
|
2044
2348
|
res.end(generateVarRemoteEntry(filename));
|
|
2045
2349
|
} else next();
|
|
2046
2350
|
});
|
|
@@ -2056,9 +2360,9 @@ const VarRemoteEntry = () => {
|
|
|
2056
2360
|
},
|
|
2057
2361
|
async generateBundle(options, bundle) {
|
|
2058
2362
|
if (!varFilename) return;
|
|
2059
|
-
if (!isValidVarName(name))
|
|
2363
|
+
if (!isValidVarName(name)) mfWarn(`Provided remote name "${name}" is not valid for "var" remoteEntry type, thus it's placed in globalThis['${name}'].\nIt may cause problems, so you would better want to use valid var name (see https://www.w3schools.com/js/js_variables.asp).`);
|
|
2060
2364
|
const remoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
|
|
2061
|
-
if (!remoteEntryFile) throw
|
|
2365
|
+
if (!remoteEntryFile) throw createModuleFederationError(`Couldn't find a remoteEntry chunk file for ${mfOptions.filename}, can't generate varRemoteEntry file`);
|
|
2062
2366
|
this.emitFile({
|
|
2063
2367
|
type: "asset",
|
|
2064
2368
|
fileName: varFilename,
|
|
@@ -2083,7 +2387,7 @@ const VarRemoteEntry = () => {
|
|
|
2083
2387
|
function getScriptUrl() {
|
|
2084
2388
|
const currentScript = document.currentScript;
|
|
2085
2389
|
if (!currentScript) {
|
|
2086
|
-
console.error("[
|
|
2390
|
+
console.error("[Module Federation] ${varFilename} script should be called from sync <script> tag (document.currentScript is undefined)")
|
|
2087
2391
|
return '/';
|
|
2088
2392
|
}
|
|
2089
2393
|
return document.currentScript.src.replace(/\\/[^/]*$/, '/');
|
|
@@ -2135,14 +2439,19 @@ function stripEmptyPreloadCalls(code) {
|
|
|
2135
2439
|
while (cursor < nextCode.length) {
|
|
2136
2440
|
const char = nextCode[cursor];
|
|
2137
2441
|
if (char === "(") depth++;
|
|
2138
|
-
else if (char === ")")
|
|
2139
|
-
|
|
2442
|
+
else if (char === ")") {
|
|
2443
|
+
depth--;
|
|
2444
|
+
if (depth < 0) break;
|
|
2445
|
+
} else if (depth === 0 && nextCode.startsWith(",[],import.meta.url)", cursor)) {
|
|
2140
2446
|
replacementEnd = cursor;
|
|
2141
2447
|
break;
|
|
2142
2448
|
}
|
|
2143
2449
|
cursor++;
|
|
2144
2450
|
}
|
|
2145
|
-
if (replacementEnd === -1)
|
|
2451
|
+
if (replacementEnd === -1) {
|
|
2452
|
+
start = nextCode.indexOf(marker, start + marker.length);
|
|
2453
|
+
continue;
|
|
2454
|
+
}
|
|
2146
2455
|
const expression = nextCode.slice(exprStart, replacementEnd);
|
|
2147
2456
|
nextCode = nextCode.slice(0, start) + expression + nextCode.slice(replacementEnd + 20);
|
|
2148
2457
|
start = nextCode.indexOf(marker, start + expression.length);
|
|
@@ -2182,6 +2491,25 @@ var normalizeOptimizeDeps_default = {
|
|
|
2182
2491
|
};
|
|
2183
2492
|
//#endregion
|
|
2184
2493
|
//#region src/index.ts
|
|
2494
|
+
const UNSAFE_JS_SOURCE_CHAR_MAP = {
|
|
2495
|
+
"<": "\\u003C",
|
|
2496
|
+
">": "\\u003E",
|
|
2497
|
+
"/": "\\u002F",
|
|
2498
|
+
"\\": "\\\\",
|
|
2499
|
+
"\b": "\\b",
|
|
2500
|
+
"\f": "\\f",
|
|
2501
|
+
"\n": "\\n",
|
|
2502
|
+
"\r": "\\r",
|
|
2503
|
+
" ": "\\t",
|
|
2504
|
+
"\0": "\\0",
|
|
2505
|
+
"\u2028": "\\u2028",
|
|
2506
|
+
"\u2029": "\\u2029"
|
|
2507
|
+
};
|
|
2508
|
+
function escapeUnsafeJsSourceChars(str) {
|
|
2509
|
+
return str.replace(/[<>/\\\b\f\n\r\t\0\u2028\u2029]/g, (char) => {
|
|
2510
|
+
return UNSAFE_JS_SOURCE_CHAR_MAP[char] ?? char;
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2185
2513
|
/**
|
|
2186
2514
|
* Plugin that runs FIRST to create virtual module files in the config hook.
|
|
2187
2515
|
* This prevents 504 "Outdated Optimize Dep" errors by ensuring files exist
|
|
@@ -2200,13 +2528,14 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
2200
2528
|
VirtualModule.setRoot(root);
|
|
2201
2529
|
VirtualModule.ensureVirtualPackageExists();
|
|
2202
2530
|
initVirtualModules(_command, getRemoteEntryId(options));
|
|
2203
|
-
|
|
2204
|
-
const isRolldown = !!this?.meta?.rolldownVersion;
|
|
2531
|
+
const isRolldown = getIsRolldown(this);
|
|
2205
2532
|
if (remotes && Object.keys(remotes).length > 0) for (const key of Object.keys(remotes)) addUsedRemote(key, key);
|
|
2206
2533
|
if (shared && Object.keys(shared).length > 0) {
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2534
|
+
if (_command === "serve") {
|
|
2535
|
+
config.optimizeDeps = config.optimizeDeps || {};
|
|
2536
|
+
config.optimizeDeps.include = config.optimizeDeps.include || [];
|
|
2537
|
+
config.optimizeDeps.include.push(virtualRuntimeInitStatus.getImportId());
|
|
2538
|
+
}
|
|
2210
2539
|
for (const key of Object.keys(shared)) {
|
|
2211
2540
|
if (key.endsWith("/")) continue;
|
|
2212
2541
|
const shareItem = shared[key];
|
|
@@ -2216,9 +2545,12 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
2216
2545
|
}
|
|
2217
2546
|
getLoadShareModulePath(key, isRolldown);
|
|
2218
2547
|
writeLoadShareModule(key, shareItem, _command, isRolldown);
|
|
2219
|
-
writePreBuildLibPath(key);
|
|
2548
|
+
writePreBuildLibPath(key, shareItem);
|
|
2220
2549
|
addUsedShares(key);
|
|
2221
|
-
|
|
2550
|
+
if (_command === "serve") {
|
|
2551
|
+
if (!isRolldown) config.optimizeDeps.include.push(getLoadShareImportId(key, isRolldown, _command));
|
|
2552
|
+
config.optimizeDeps.include.push(getPreBuildLibImportId(key));
|
|
2553
|
+
}
|
|
2222
2554
|
}
|
|
2223
2555
|
writeLocalSharedImportMap();
|
|
2224
2556
|
}
|
|
@@ -2229,7 +2561,7 @@ function federation(mfUserOptions) {
|
|
|
2229
2561
|
const options = normalizeModuleFederationOptions(mfUserOptions);
|
|
2230
2562
|
const isVinext = hasPackageDependency("vinext");
|
|
2231
2563
|
const { name, remotes, shared, filename, hostInitInjectLocation } = options;
|
|
2232
|
-
if (!name) throw
|
|
2564
|
+
if (!name) throw createModuleFederationError("name is required");
|
|
2233
2565
|
const remoteEntryId = getRemoteEntryId(options);
|
|
2234
2566
|
const virtualExposesId = getVirtualExposesId(options);
|
|
2235
2567
|
let command;
|
|
@@ -2315,7 +2647,16 @@ function federation(mfUserOptions) {
|
|
|
2315
2647
|
}
|
|
2316
2648
|
};
|
|
2317
2649
|
}
|
|
2650
|
+
let warnedAboutCodeSplitting = false;
|
|
2651
|
+
const ensureCodeSplitting = (output) => {
|
|
2652
|
+
if (output?.codeSplitting !== false) return;
|
|
2653
|
+
delete output.codeSplitting;
|
|
2654
|
+
if (warnedAboutCodeSplitting) return;
|
|
2655
|
+
warnedAboutCodeSplitting = true;
|
|
2656
|
+
mfWarn("Ignoring `build.rolldownOptions.output.codeSplitting = false` because module federation requires chunk splitting.");
|
|
2657
|
+
};
|
|
2318
2658
|
const applyManualChunks = (output) => {
|
|
2659
|
+
ensureCodeSplitting(output);
|
|
2319
2660
|
const existingManualChunks = output.manualChunks;
|
|
2320
2661
|
output.manualChunks = function(id) {
|
|
2321
2662
|
if (id.includes(runtimeInitId)) return "runtimeInit";
|
|
@@ -2537,7 +2878,7 @@ function federation(mfUserOptions) {
|
|
|
2537
2878
|
enforce: "post",
|
|
2538
2879
|
_options: options,
|
|
2539
2880
|
config(config, { command: _command }) {
|
|
2540
|
-
const isRolldown =
|
|
2881
|
+
const isRolldown = getIsRolldown(this);
|
|
2541
2882
|
let implementation = options.implementation;
|
|
2542
2883
|
if (isRolldown) implementation = implementation.replace(/\.cjs(\.js)?$/, ".js");
|
|
2543
2884
|
config.resolve.alias.push({
|
|
@@ -2566,7 +2907,7 @@ function federation(mfUserOptions) {
|
|
|
2566
2907
|
const resolvedTarget = options.target ?? (config.build?.ssr ? "node" : "web");
|
|
2567
2908
|
if (!config.define) config.define = {};
|
|
2568
2909
|
if (!("ENV_TARGET" in config.define)) config.define["ENV_TARGET"] = JSON.stringify(resolvedTarget);
|
|
2569
|
-
if (options.target && "ENV_TARGET" in config.define && config.define["ENV_TARGET"] !== JSON.stringify(options.target))
|
|
2910
|
+
if (options.target && "ENV_TARGET" in config.define && config.define["ENV_TARGET"] !== JSON.stringify(options.target)) mfWarn(`ENV_TARGET define (${config.define["ENV_TARGET"]}) differs from target option ("${options.target}"). ENV_TARGET will not be overridden.`);
|
|
2570
2911
|
}
|
|
2571
2912
|
},
|
|
2572
2913
|
...Manifest(),
|
|
@@ -2579,13 +2920,18 @@ function federation(mfUserOptions) {
|
|
|
2579
2920
|
for (const chunk of Object.values(bundle)) {
|
|
2580
2921
|
if (chunk.type !== "chunk") continue;
|
|
2581
2922
|
if (!chunk.code.includes("modulepreload")) continue;
|
|
2582
|
-
const
|
|
2923
|
+
const chunkDir = pathe.default.dirname(chunk.fileName);
|
|
2924
|
+
const prefixToRoot = chunkDir === "." ? "" : `${pathe.default.relative(chunkDir, ".")}/`;
|
|
2925
|
+
const replacementExpr = prefixToRoot ? `${escapeUnsafeJsSourceChars(JSON.stringify(prefixToRoot))}+$1` : "$1";
|
|
2926
|
+
const replacement = `=function($1){return new URL(${replacementExpr},import.meta.url).href}`;
|
|
2583
2927
|
const replaced = chunk.code.replace(/=\(?(\w+)(?:,\w+)?\)?\s*=>\s*["'`][^"'`]*["'`]\s*\+\s*\1/, replacement);
|
|
2584
2928
|
if (replaced !== chunk.code) {
|
|
2585
2929
|
chunk.code = replaced;
|
|
2586
2930
|
continue;
|
|
2587
2931
|
}
|
|
2588
2932
|
chunk.code = chunk.code.replace(/=function\((\w+)(?:,\w+)?\)\{return\s*["'`][^"'`]*["'`]\s*\+\s*\1\s*\}/, replacement);
|
|
2933
|
+
chunk.code = chunk.code.replace(/=function\((\w+)(?:,\w+)?\)\{return new URL\("\.\.\/"\+\1,import\.meta\.url\)\.href\}/, replacement);
|
|
2934
|
+
chunk.code = chunk.code.replace(/new URL\("\.\.\/"\+(\w+),import\.meta\.url\)\.href/g, `new URL(${replacementExpr},import.meta.url).href`);
|
|
2589
2935
|
}
|
|
2590
2936
|
}
|
|
2591
2937
|
}] : []
|