@module-federation/vite 1.13.2 → 1.13.4
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 +353 -53
- package/lib/index.mjs +353 -53
- package/package.json +2 -1
package/lib/index.cjs
CHANGED
|
@@ -49,35 +49,25 @@ 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
|
|
@@ -122,6 +112,9 @@ function getDependencyCacheKey(cwd, dependencyName) {
|
|
|
122
112
|
function setPackageDetectionCwd(cwd) {
|
|
123
113
|
packageDetectionCwd = cwd;
|
|
124
114
|
}
|
|
115
|
+
function getPackageDetectionCwd() {
|
|
116
|
+
return packageDetectionCwd || process.cwd();
|
|
117
|
+
}
|
|
125
118
|
/**
|
|
126
119
|
* Escaping rules:
|
|
127
120
|
* Convert using the format __${mapping}__, where _ and $ are not allowed in npm package names but can be used in variable names.
|
|
@@ -189,6 +182,7 @@ function getFirstHtmlEntryFile(entryFiles) {
|
|
|
189
182
|
return entryFiles.find((file) => file.endsWith(".html"));
|
|
190
183
|
}
|
|
191
184
|
const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
185
|
+
const DEV_HTML_PROXY_PREFIX = "virtual:mf-html-entry-proxy?";
|
|
192
186
|
const getEntryPath = () => typeof entryPath === "function" ? entryPath() : entryPath;
|
|
193
187
|
let devEntryPath = "";
|
|
194
188
|
let entryFiles = [];
|
|
@@ -212,8 +206,13 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
212
206
|
configResolved(config) {
|
|
213
207
|
viteConfig = config;
|
|
214
208
|
const resolvedEntryPath = getEntryPath();
|
|
215
|
-
|
|
216
|
-
|
|
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
|
+
}
|
|
217
216
|
},
|
|
218
217
|
configureServer(server) {
|
|
219
218
|
server.middlewares.use((req, res, next) => {
|
|
@@ -228,7 +227,29 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
228
227
|
transformIndexHtml(c) {
|
|
229
228
|
if (!injectHtml()) return;
|
|
230
229
|
clientInjected = true;
|
|
231
|
-
|
|
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
|
+
`;
|
|
232
253
|
},
|
|
233
254
|
transform(code, id) {
|
|
234
255
|
if (id.includes("node_modules") || inject !== "html" || htmlFilePath) return;
|
|
@@ -725,7 +746,7 @@ function inferVersionFromRequiredVersion(requiredVersion) {
|
|
|
725
746
|
}
|
|
726
747
|
function normalizeShareItem(key, shareItem) {
|
|
727
748
|
let version;
|
|
728
|
-
try {
|
|
749
|
+
if (!(typeof shareItem === "object" && shareItem.import === false)) try {
|
|
729
750
|
try {
|
|
730
751
|
version = require(pathe.join(removePathFromNpmPackage(key), "package.json")).version;
|
|
731
752
|
} catch (e1) {
|
|
@@ -995,15 +1016,61 @@ var VirtualModule = class {
|
|
|
995
1016
|
};
|
|
996
1017
|
//#endregion
|
|
997
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
|
+
}
|
|
998
1023
|
function getVirtualExposesId(options) {
|
|
999
1024
|
return `virtual:mf-exposes:${`${options.name}__${options.filename}`.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
|
|
1000
1025
|
}
|
|
1001
1026
|
function generateExposes(options) {
|
|
1002
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
|
+
|
|
1003
1069
|
export default {
|
|
1004
1070
|
${Object.keys(options.exposes).map((key) => {
|
|
1005
1071
|
return `
|
|
1006
1072
|
${JSON.stringify(key)}: async () => {
|
|
1073
|
+
await injectCssAssets(${JSON.stringify(key)})
|
|
1007
1074
|
const importModule = await import(${JSON.stringify(options.exposes[key].import)})
|
|
1008
1075
|
const exportModule = {}
|
|
1009
1076
|
Object.assign(exportModule, importModule)
|
|
@@ -1150,32 +1217,159 @@ function generateRemotes(id, command, isRolldown) {
|
|
|
1150
1217
|
* 1. __prebuild__: export shareModule (pre-built source code of modules such as vue, react, etc.)
|
|
1151
1218
|
* 2. __loadShare__: load shareModule (mfRuntime.loadShare('vue'))
|
|
1152
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
|
+
}
|
|
1153
1319
|
function getPackageNamedExports(pkg) {
|
|
1154
1320
|
try {
|
|
1155
|
-
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);
|
|
1156
1322
|
return Object.keys(mod).filter((k) => k !== "default" && k !== "__esModule" && /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(k));
|
|
1157
1323
|
} catch {
|
|
1158
|
-
return
|
|
1324
|
+
return getEsmNamedExports(pkg);
|
|
1159
1325
|
}
|
|
1160
1326
|
}
|
|
1161
1327
|
function getLocalProviderImportPath(pkg) {
|
|
1162
1328
|
try {
|
|
1163
|
-
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);
|
|
1164
1330
|
return resolved.includes("/node_modules/") || resolved.includes("\\node_modules\\") ? void 0 : resolved;
|
|
1165
1331
|
} catch {
|
|
1166
1332
|
return;
|
|
1167
1333
|
}
|
|
1168
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
|
+
}
|
|
1169
1355
|
const preBuildCacheMap = {};
|
|
1356
|
+
const preBuildShareItemMap = {};
|
|
1170
1357
|
const PREBUILD_TAG = "__prebuild__";
|
|
1171
|
-
function writePreBuildLibPath(pkg) {
|
|
1358
|
+
function writePreBuildLibPath(pkg, shareItem) {
|
|
1172
1359
|
if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
|
|
1173
|
-
|
|
1360
|
+
preBuildShareItemMap[pkg] = shareItem;
|
|
1361
|
+
preBuildCacheMap[pkg].writeSync("", true);
|
|
1174
1362
|
}
|
|
1175
1363
|
function getPreBuildLibImportId(pkg) {
|
|
1176
1364
|
if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
|
|
1177
1365
|
return preBuildCacheMap[pkg].getImportId();
|
|
1178
1366
|
}
|
|
1367
|
+
function getPreBuildShareItem(pkg) {
|
|
1368
|
+
return preBuildShareItemMap[pkg];
|
|
1369
|
+
}
|
|
1370
|
+
function getSharedImportSource(pkg, shareItem) {
|
|
1371
|
+
return getConcreteSharedImportSource(pkg, shareItem) || getPreBuildLibImportId(pkg);
|
|
1372
|
+
}
|
|
1179
1373
|
const LOAD_SHARE_TAG = "__loadShare__";
|
|
1180
1374
|
const loadShareCacheMap = {};
|
|
1181
1375
|
function getLoadShareImportId(pkg, isRolldown, command) {
|
|
@@ -1192,23 +1386,48 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
|
1192
1386
|
const importLine = command === "build" ? getRuntimeInitPromiseBootstrapCode() : useESM ? `${getRuntimeInitBootstrapCode()}
|
|
1193
1387
|
const { initPromise } = globalThis[globalKey];` : `const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")`;
|
|
1194
1388
|
const awaitOrPlaceholder = useESM ? "await " : "/*mf top-level-await placeholder replacement mf*/";
|
|
1389
|
+
if (shareItem.shareConfig.import === false) {
|
|
1390
|
+
const namedExports = useESM ? getPackageNamedExports(pkg) : [];
|
|
1391
|
+
let exportLine;
|
|
1392
|
+
if (useESM && namedExports.length > 0) exportLine = `export default exportModule.default ?? exportModule;\n ${`const { ${namedExports.map((name, i) => `${name}: __mf_${i}`).join(", ")} } = exportModule;`}\n ${`export { ${namedExports.map((name, i) => `__mf_${i} as ${name}`).join(", ")} };`}`;
|
|
1393
|
+
else {
|
|
1394
|
+
if (useESM) mfWarn(`Shared dependency "${pkg}" has import: false but is not installed locally.\n Named imports (e.g. import { ... } from '${pkg}') will not work in production builds.\n Install it as a devDependency to enable named export detection.`);
|
|
1395
|
+
exportLine = useESM ? "export default exportModule.default ?? exportModule" : "module.exports = exportModule";
|
|
1396
|
+
}
|
|
1397
|
+
loadShareCacheMap[pkg].writeSync(`
|
|
1398
|
+
${importLine}
|
|
1399
|
+
const res = initPromise.then(runtime => runtime.loadShare(${escapeGeneratedStringLiteral(pkg)}, {
|
|
1400
|
+
customShareInfo: {shareConfig:{
|
|
1401
|
+
singleton: ${shareItem.shareConfig.singleton},
|
|
1402
|
+
strictVersion: ${shareItem.shareConfig.strictVersion},
|
|
1403
|
+
requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)}
|
|
1404
|
+
}}
|
|
1405
|
+
}))
|
|
1406
|
+
const exportModule = ${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory))
|
|
1407
|
+
${exportLine}
|
|
1408
|
+
`, true);
|
|
1409
|
+
return;
|
|
1410
|
+
}
|
|
1195
1411
|
const useSsrProviderFallback = hasPackageDependency("vinext") && command === "build" && pkg === "react";
|
|
1196
|
-
const
|
|
1412
|
+
const concreteSharedImportSource = getConcreteSharedImportSource(pkg, shareItem);
|
|
1413
|
+
const sharedImportSource = concreteSharedImportSource || getPreBuildLibImportId(pkg);
|
|
1414
|
+
const devImportSource = concreteSharedImportSource || pkg;
|
|
1415
|
+
const providerImportId = getLocalProviderImportPath(pkg) || concreteSharedImportSource || sharedImportSource;
|
|
1197
1416
|
const namedExports = getPackageNamedExports(pkg);
|
|
1198
1417
|
let exportLine;
|
|
1199
1418
|
if (namedExports.length > 0) {
|
|
1200
1419
|
const destructure = `const { ${namedExports.map((name, i) => `${name}: __mf_${i}`).join(", ")} } = exportModule;`;
|
|
1201
1420
|
const namedExportLine = `export { ${namedExports.map((name, i) => `__mf_${i} as ${name}`).join(", ")} };`;
|
|
1202
1421
|
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(", ")} });`;
|
|
1203
|
-
} else exportLine = useESM ? `export default exportModule.default ?? exportModule\n export * from ${
|
|
1422
|
+
} else exportLine = useESM ? `export default exportModule.default ?? exportModule\n export * from ${escapeGeneratedStringLiteral(sharedImportSource)}` : "module.exports = exportModule";
|
|
1204
1423
|
loadShareCacheMap[pkg].writeSync(`
|
|
1205
|
-
import ${
|
|
1206
|
-
${command !== "build" ? `;() => import(${
|
|
1424
|
+
import ${escapeGeneratedStringLiteral(sharedImportSource)};
|
|
1425
|
+
${command !== "build" ? `;() => import(${escapeGeneratedStringLiteral(devImportSource)}).catch(() => {});` : ""}
|
|
1207
1426
|
${importLine}
|
|
1208
1427
|
${useSsrProviderFallback ? `const providerModulePromise = typeof window === "undefined"
|
|
1209
|
-
? import(${
|
|
1428
|
+
? import(${escapeGeneratedStringLiteral(providerImportId)})
|
|
1210
1429
|
: undefined` : ""}
|
|
1211
|
-
const res = initPromise.then(runtime => runtime.loadShare(${
|
|
1430
|
+
const res = initPromise.then(runtime => runtime.loadShare(${escapeGeneratedStringLiteral(pkg)}, {
|
|
1212
1431
|
customShareInfo: {shareConfig:{
|
|
1213
1432
|
singleton: ${shareItem.shareConfig.singleton},
|
|
1214
1433
|
strictVersion: ${shareItem.shareConfig.strictVersion},
|
|
@@ -1219,7 +1438,7 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
|
1219
1438
|
? ((await providerModulePromise)?.default ?? await providerModulePromise)
|
|
1220
1439
|
: ${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory)))` : `${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory))`}
|
|
1221
1440
|
${exportLine}
|
|
1222
|
-
|
|
1441
|
+
`, true);
|
|
1223
1442
|
}
|
|
1224
1443
|
//#endregion
|
|
1225
1444
|
//#region src/virtualModules/virtualRemoteEntry.ts
|
|
@@ -1253,7 +1472,7 @@ function generateLocalSharedImportMap() {
|
|
|
1253
1472
|
return `
|
|
1254
1473
|
${JSON.stringify(pkg)}: async () => {
|
|
1255
1474
|
${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");
|
|
1256
|
-
return pkg;` : `let pkg = await import(
|
|
1475
|
+
return pkg;` : `let pkg = await import(${JSON.stringify(getSharedImportSource(pkg, shareItem))});
|
|
1257
1476
|
return pkg;`}
|
|
1258
1477
|
}
|
|
1259
1478
|
`;
|
|
@@ -1336,6 +1555,14 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1336
1555
|
];
|
|
1337
1556
|
});
|
|
1338
1557
|
return `
|
|
1558
|
+
// Shim Vue HMR runtime for dev-compiled components loaded by a non-Vite host.
|
|
1559
|
+
// When a remote is served by a Vite dev server, Vue's SFC compiler injects HMR
|
|
1560
|
+
// hooks that reference __VUE_HMR_RUNTIME__. This global only exists on pages
|
|
1561
|
+
// served by Vite's client runtime. When a production host loads the remote,
|
|
1562
|
+
// the HMR calls would throw. This no-op shim prevents that.
|
|
1563
|
+
if (typeof __VUE_HMR_RUNTIME__ === 'undefined') {
|
|
1564
|
+
globalThis.__VUE_HMR_RUNTIME__ = { createRecord() {}, rerender() {}, reload() {} };
|
|
1565
|
+
}
|
|
1339
1566
|
import {init as runtimeInit, loadRemote} from "@module-federation/runtime";
|
|
1340
1567
|
${pluginImportNames.map((item) => item[1]).join("\n")}
|
|
1341
1568
|
${command === "build" ? getRuntimeInitResolveBootstrapCode() : getRuntimeInitBootstrapCode() + "\n const { initResolve } = globalThis[globalKey];"}
|
|
@@ -1535,6 +1762,18 @@ const processModuleAssets = (bundle, filesMap, moduleMatcher) => {
|
|
|
1535
1762
|
}
|
|
1536
1763
|
};
|
|
1537
1764
|
/**
|
|
1765
|
+
* Adds global CSS assets to all module exports
|
|
1766
|
+
* @param filesMap - The preload map to update
|
|
1767
|
+
* @param cssAssets - Set of CSS asset filenames to add
|
|
1768
|
+
*/
|
|
1769
|
+
const addCssAssetsToAllExports = (filesMap, cssAssets) => {
|
|
1770
|
+
Object.keys(filesMap).forEach((key) => {
|
|
1771
|
+
cssAssets.forEach((cssAsset) => {
|
|
1772
|
+
trackAsset(filesMap, key, cssAsset, false, "css");
|
|
1773
|
+
});
|
|
1774
|
+
});
|
|
1775
|
+
};
|
|
1776
|
+
/**
|
|
1538
1777
|
* Deduplicates assets in the files map
|
|
1539
1778
|
* @param filesMap - The preload map to deduplicate
|
|
1540
1779
|
* @returns New deduplicated preload map
|
|
@@ -1860,12 +2099,13 @@ function pluginModuleParseEnd_default(excludeFn, options) {
|
|
|
1860
2099
|
//#region src/plugins/pluginProxyRemoteEntry.ts
|
|
1861
2100
|
const filter = (0, _rollup_pluginutils.createFilter)();
|
|
1862
2101
|
function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposesId }) {
|
|
1863
|
-
let viteConfig, _command;
|
|
2102
|
+
let viteConfig, _command, root;
|
|
1864
2103
|
return {
|
|
1865
2104
|
name: "proxyRemoteEntry",
|
|
1866
2105
|
enforce: "post",
|
|
1867
2106
|
configResolved(config) {
|
|
1868
2107
|
viteConfig = config;
|
|
2108
|
+
root = config.root;
|
|
1869
2109
|
},
|
|
1870
2110
|
config(config, { command }) {
|
|
1871
2111
|
_command = command;
|
|
@@ -1920,6 +2160,51 @@ function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposes
|
|
|
1920
2160
|
return code;
|
|
1921
2161
|
}
|
|
1922
2162
|
})());
|
|
2163
|
+
},
|
|
2164
|
+
generateBundle(_, bundle) {
|
|
2165
|
+
if (_command !== "build") return;
|
|
2166
|
+
const filesMap = {};
|
|
2167
|
+
const exposeEntries = Object.entries(options.exposes);
|
|
2168
|
+
const allCssAssets = options.bundleAllCSS ? collectCssAssets(bundle) : /* @__PURE__ */ new Set();
|
|
2169
|
+
processModuleAssets(bundle, filesMap, (modulePath) => {
|
|
2170
|
+
const absoluteModulePath = pathe.resolve(root, modulePath);
|
|
2171
|
+
return exposeEntries.find(([_, exposeOptions]) => {
|
|
2172
|
+
const exposePath = pathe.resolve(root, exposeOptions.import);
|
|
2173
|
+
if (absoluteModulePath === exposePath) return true;
|
|
2174
|
+
const stripKnownJsExt = (filePath) => {
|
|
2175
|
+
const ext = pathe.extname(filePath);
|
|
2176
|
+
return [
|
|
2177
|
+
".ts",
|
|
2178
|
+
".tsx",
|
|
2179
|
+
".jsx",
|
|
2180
|
+
".mjs",
|
|
2181
|
+
".cjs"
|
|
2182
|
+
].includes(ext) ? pathe.join(pathe.dirname(filePath), pathe.basename(filePath, ext)) : filePath;
|
|
2183
|
+
};
|
|
2184
|
+
return stripKnownJsExt(absoluteModulePath) === stripKnownJsExt(exposePath);
|
|
2185
|
+
})?.[1].import;
|
|
2186
|
+
});
|
|
2187
|
+
if (options.bundleAllCSS) addCssAssetsToAllExports(filesMap, allCssAssets);
|
|
2188
|
+
const ensureRelativeImportPath = (fromFile, toFile) => {
|
|
2189
|
+
let relativePath = pathe.relative(pathe.dirname(fromFile), toFile);
|
|
2190
|
+
if (!relativePath.startsWith(".")) relativePath = `./${relativePath}`;
|
|
2191
|
+
return relativePath;
|
|
2192
|
+
};
|
|
2193
|
+
const placeholderValue = getExposesCssMapPlaceholder();
|
|
2194
|
+
const placeholderPatterns = [
|
|
2195
|
+
JSON.stringify(placeholderValue),
|
|
2196
|
+
`'${placeholderValue}'`,
|
|
2197
|
+
`\`${placeholderValue}\``
|
|
2198
|
+
];
|
|
2199
|
+
for (const file of Object.values(bundle)) {
|
|
2200
|
+
if (file.type !== "chunk" || !file.code.includes(placeholderValue)) continue;
|
|
2201
|
+
const cssAssetMap = exposeEntries.reduce((acc, [exposeKey, expose]) => {
|
|
2202
|
+
const assets = filesMap[expose.import] || createEmptyAssetMap();
|
|
2203
|
+
acc[exposeKey] = [...assets.css.sync, ...assets.css.async].map((cssAsset) => ensureRelativeImportPath(file.fileName, cssAsset));
|
|
2204
|
+
return acc;
|
|
2205
|
+
}, {});
|
|
2206
|
+
for (const placeholderPattern of placeholderPatterns) file.code = file.code.replace(placeholderPattern, JSON.stringify(cssAssetMap));
|
|
2207
|
+
}
|
|
1923
2208
|
}
|
|
1924
2209
|
};
|
|
1925
2210
|
}
|
|
@@ -1982,6 +2267,9 @@ var PromiseStore = class {
|
|
|
1982
2267
|
};
|
|
1983
2268
|
//#endregion
|
|
1984
2269
|
//#region src/plugins/pluginProxySharedModule_preBuild.ts
|
|
2270
|
+
function getPrebuildResolutionSource(pkgName, shareItem) {
|
|
2271
|
+
return getConcreteSharedImportSource(pkgName, shareItem) || pkgName;
|
|
2272
|
+
}
|
|
1985
2273
|
function proxySharedModule(options) {
|
|
1986
2274
|
const { shared = {} } = options;
|
|
1987
2275
|
let _config;
|
|
@@ -2020,7 +2308,7 @@ function proxySharedModule(options) {
|
|
|
2020
2308
|
if (key.endsWith("/") && source !== key.slice(0, -1)) return;
|
|
2021
2309
|
const loadSharePath = getLoadShareModulePath(source, isRolldown, command);
|
|
2022
2310
|
writeLoadShareModule(source, shared[key], command, isRolldown);
|
|
2023
|
-
writePreBuildLibPath(source);
|
|
2311
|
+
if (shared[key].shareConfig.import !== false) writePreBuildLibPath(source, shared[key]);
|
|
2024
2312
|
addUsedShares(source);
|
|
2025
2313
|
writeLocalSharedImportMap();
|
|
2026
2314
|
return this.resolve(loadSharePath, importer);
|
|
@@ -2031,14 +2319,18 @@ function proxySharedModule(options) {
|
|
|
2031
2319
|
return command === "build" ? {
|
|
2032
2320
|
find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
|
|
2033
2321
|
replacement: function($1) {
|
|
2034
|
-
|
|
2322
|
+
const pkgName = assertModuleFound(PREBUILD_TAG, $1).name;
|
|
2323
|
+
return getPrebuildResolutionSource(pkgName, getPreBuildShareItem(pkgName));
|
|
2035
2324
|
}
|
|
2036
2325
|
} : {
|
|
2037
2326
|
find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
|
|
2038
2327
|
replacement: "$1",
|
|
2039
2328
|
async customResolver(source, importer) {
|
|
2040
2329
|
const pkgName = assertModuleFound(PREBUILD_TAG, source).name;
|
|
2041
|
-
const
|
|
2330
|
+
const importSource = getPrebuildResolutionSource(pkgName, getPreBuildShareItem(pkgName));
|
|
2331
|
+
const resolved = await this.resolve(importSource, importer);
|
|
2332
|
+
if (!resolved?.id) return;
|
|
2333
|
+
const result = resolved.id;
|
|
2042
2334
|
if (_config && !result.includes(_config.cacheDir)) savePrebuild.set(pkgName, Promise.resolve(result));
|
|
2043
2335
|
return await this.resolve(await savePrebuild.get(pkgName), importer);
|
|
2044
2336
|
}
|
|
@@ -2055,7 +2347,7 @@ function proxySharedModule(options) {
|
|
|
2055
2347
|
return;
|
|
2056
2348
|
}
|
|
2057
2349
|
writeLoadShareModule(key, shared[key], _command, isRolldown);
|
|
2058
|
-
writePreBuildLibPath(key);
|
|
2350
|
+
if (shared[key].shareConfig.import !== false) writePreBuildLibPath(key, shared[key]);
|
|
2059
2351
|
addUsedShares(key);
|
|
2060
2352
|
});
|
|
2061
2353
|
writeLocalSharedImportMap();
|
|
@@ -2177,14 +2469,19 @@ function stripEmptyPreloadCalls(code) {
|
|
|
2177
2469
|
while (cursor < nextCode.length) {
|
|
2178
2470
|
const char = nextCode[cursor];
|
|
2179
2471
|
if (char === "(") depth++;
|
|
2180
|
-
else if (char === ")")
|
|
2181
|
-
|
|
2472
|
+
else if (char === ")") {
|
|
2473
|
+
depth--;
|
|
2474
|
+
if (depth < 0) break;
|
|
2475
|
+
} else if (depth === 0 && nextCode.startsWith(",[],import.meta.url)", cursor)) {
|
|
2182
2476
|
replacementEnd = cursor;
|
|
2183
2477
|
break;
|
|
2184
2478
|
}
|
|
2185
2479
|
cursor++;
|
|
2186
2480
|
}
|
|
2187
|
-
if (replacementEnd === -1)
|
|
2481
|
+
if (replacementEnd === -1) {
|
|
2482
|
+
start = nextCode.indexOf(marker, start + marker.length);
|
|
2483
|
+
continue;
|
|
2484
|
+
}
|
|
2188
2485
|
const expression = nextCode.slice(exprStart, replacementEnd);
|
|
2189
2486
|
nextCode = nextCode.slice(0, start) + expression + nextCode.slice(replacementEnd + 20);
|
|
2190
2487
|
start = nextCode.indexOf(marker, start + expression.length);
|
|
@@ -2261,13 +2558,14 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
2261
2558
|
VirtualModule.setRoot(root);
|
|
2262
2559
|
VirtualModule.ensureVirtualPackageExists();
|
|
2263
2560
|
initVirtualModules(_command, getRemoteEntryId(options));
|
|
2264
|
-
if (_command !== "serve") return;
|
|
2265
2561
|
const isRolldown = getIsRolldown(this);
|
|
2266
2562
|
if (remotes && Object.keys(remotes).length > 0) for (const key of Object.keys(remotes)) addUsedRemote(key, key);
|
|
2267
2563
|
if (shared && Object.keys(shared).length > 0) {
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2564
|
+
if (_command === "serve") {
|
|
2565
|
+
config.optimizeDeps = config.optimizeDeps || {};
|
|
2566
|
+
config.optimizeDeps.include = config.optimizeDeps.include || [];
|
|
2567
|
+
config.optimizeDeps.include.push(virtualRuntimeInitStatus.getImportId());
|
|
2568
|
+
}
|
|
2271
2569
|
for (const key of Object.keys(shared)) {
|
|
2272
2570
|
if (key.endsWith("/")) continue;
|
|
2273
2571
|
const shareItem = shared[key];
|
|
@@ -2277,10 +2575,12 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
2277
2575
|
}
|
|
2278
2576
|
getLoadShareModulePath(key, isRolldown);
|
|
2279
2577
|
writeLoadShareModule(key, shareItem, _command, isRolldown);
|
|
2280
|
-
writePreBuildLibPath(key);
|
|
2578
|
+
if (shareItem.shareConfig?.import !== false) writePreBuildLibPath(key, shareItem);
|
|
2281
2579
|
addUsedShares(key);
|
|
2282
|
-
|
|
2283
|
-
|
|
2580
|
+
if (_command === "serve" && shareItem.shareConfig?.import !== false) {
|
|
2581
|
+
if (!isRolldown) config.optimizeDeps.include.push(getLoadShareImportId(key, isRolldown, _command));
|
|
2582
|
+
config.optimizeDeps.include.push(getPreBuildLibImportId(key));
|
|
2583
|
+
}
|
|
2284
2584
|
}
|
|
2285
2585
|
writeLocalSharedImportMap();
|
|
2286
2586
|
}
|
package/lib/index.mjs
CHANGED
|
@@ -27,35 +27,25 @@ async function mapCodeToCodeWithSourcemap(code) {
|
|
|
27
27
|
//#endregion
|
|
28
28
|
//#region src/utils/htmlEntryUtils.ts
|
|
29
29
|
function sanitizeDevEntryPath(devEntryPath) {
|
|
30
|
-
return devEntryPath.replace(
|
|
30
|
+
return devEntryPath.replace(/\\\\?/g, "/");
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* If no entry scripts are found, falls back to injecting a separate script tag.
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* // Before (two separate scripts, race condition):
|
|
41
|
-
* // <script type="module" src="/__mf__virtual/hostAutoInit.js"><\/script>
|
|
42
|
-
* // <script type="module" src="/src/main.js"><\/script>
|
|
43
|
-
* // After (single inline script, sequential execution):
|
|
44
|
-
* // <script type="module">await import("/__mf__virtual/hostAutoInit.js");await import("/src/main.js");<\/script>
|
|
33
|
+
* Rewrites entry module script tags to point at an external wrapper module.
|
|
34
|
+
* The wrapper can then sequence federation init before the app entry without
|
|
35
|
+
* relying on CSP-breaking inline `<script type="module">`.
|
|
45
36
|
*/
|
|
46
|
-
function
|
|
47
|
-
|
|
48
|
-
const scriptTagRegex = /<script\s+([^>]*\btype=["']module["'][^>]*\bsrc=["'][^"']+["'][^>]*)>/gi;
|
|
49
|
-
let hasEntry = false;
|
|
50
|
-
const result = html.replace(scriptTagRegex, (match, attrs) => {
|
|
37
|
+
function rewriteEntryScripts(html, createProxySrc) {
|
|
38
|
+
return html.replace(/<script\s+([^>]*\btype=["']module["'][^>]*\bsrc=["'][^"']+["'][^>]*)>/gi, (match, attrs) => {
|
|
51
39
|
const srcMatch = attrs.match(/\bsrc=["']([^"']+)["']/i);
|
|
52
40
|
if (!srcMatch) return match;
|
|
53
41
|
const originalSrc = srcMatch[1];
|
|
54
42
|
if (originalSrc.includes("@vite/client")) return match;
|
|
55
|
-
|
|
56
|
-
return
|
|
43
|
+
const proxySrc = createProxySrc(originalSrc);
|
|
44
|
+
return match.replace(srcMatch[0], `src=${JSON.stringify(proxySrc)}`);
|
|
57
45
|
});
|
|
58
|
-
|
|
46
|
+
}
|
|
47
|
+
function injectEntryScript(html, initSrc) {
|
|
48
|
+
const src = sanitizeDevEntryPath(initSrc);
|
|
59
49
|
return html.replace("<head>", `<head><script type="module" src=${JSON.stringify(src)}><\/script>`);
|
|
60
50
|
}
|
|
61
51
|
//#endregion
|
|
@@ -100,6 +90,9 @@ function getDependencyCacheKey(cwd, dependencyName) {
|
|
|
100
90
|
function setPackageDetectionCwd(cwd) {
|
|
101
91
|
packageDetectionCwd = cwd;
|
|
102
92
|
}
|
|
93
|
+
function getPackageDetectionCwd() {
|
|
94
|
+
return packageDetectionCwd || process.cwd();
|
|
95
|
+
}
|
|
103
96
|
/**
|
|
104
97
|
* Escaping rules:
|
|
105
98
|
* Convert using the format __${mapping}__, where _ and $ are not allowed in npm package names but can be used in variable names.
|
|
@@ -167,6 +160,7 @@ function getFirstHtmlEntryFile(entryFiles) {
|
|
|
167
160
|
return entryFiles.find((file) => file.endsWith(".html"));
|
|
168
161
|
}
|
|
169
162
|
const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
163
|
+
const DEV_HTML_PROXY_PREFIX = "virtual:mf-html-entry-proxy?";
|
|
170
164
|
const getEntryPath = () => typeof entryPath === "function" ? entryPath() : entryPath;
|
|
171
165
|
let devEntryPath = "";
|
|
172
166
|
let entryFiles = [];
|
|
@@ -190,8 +184,13 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
190
184
|
configResolved(config) {
|
|
191
185
|
viteConfig = config;
|
|
192
186
|
const resolvedEntryPath = getEntryPath();
|
|
193
|
-
|
|
194
|
-
|
|
187
|
+
if (resolvedEntryPath.startsWith("virtual:mf")) devEntryPath = config.base + "@id/" + resolvedEntryPath;
|
|
188
|
+
else {
|
|
189
|
+
const normalized = resolvedEntryPath.replace(/\\\\?/g, "/");
|
|
190
|
+
const root = config.root.replace(/\\\\?/g, "/").replace(/\/$/, "");
|
|
191
|
+
const relativePath = normalized.startsWith(root + "/") ? normalized.slice(root.length) : "/" + normalized.replace(/^[A-Za-z]:[\\/]/, "");
|
|
192
|
+
devEntryPath = config.base + relativePath.replace(/^\//, "");
|
|
193
|
+
}
|
|
195
194
|
},
|
|
196
195
|
configureServer(server) {
|
|
197
196
|
server.middlewares.use((req, res, next) => {
|
|
@@ -206,7 +205,29 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
|
|
|
206
205
|
transformIndexHtml(c) {
|
|
207
206
|
if (!injectHtml()) return;
|
|
208
207
|
clientInjected = true;
|
|
209
|
-
|
|
208
|
+
const html = rewriteEntryScripts(c, (originalSrc) => {
|
|
209
|
+
const query = new URLSearchParams({
|
|
210
|
+
init: sanitizeDevEntryPath(devEntryPath),
|
|
211
|
+
entry: originalSrc
|
|
212
|
+
}).toString();
|
|
213
|
+
return `${viteConfig.base}@id/${DEV_HTML_PROXY_PREFIX}${query}`;
|
|
214
|
+
});
|
|
215
|
+
return html === c ? injectEntryScript(c, devEntryPath) : html;
|
|
216
|
+
},
|
|
217
|
+
resolveId(id) {
|
|
218
|
+
if (id.startsWith(DEV_HTML_PROXY_PREFIX)) return id;
|
|
219
|
+
},
|
|
220
|
+
load(id) {
|
|
221
|
+
if (!id.startsWith(DEV_HTML_PROXY_PREFIX)) return;
|
|
222
|
+
const params = new URLSearchParams(id.slice(28));
|
|
223
|
+
const initSrc = params.get("init");
|
|
224
|
+
const entrySrc = params.get("entry");
|
|
225
|
+
if (!initSrc || !entrySrc) return;
|
|
226
|
+
return `
|
|
227
|
+
const baseUrl = document.baseURI || window.location.href;
|
|
228
|
+
await import(new URL(${JSON.stringify(initSrc)}, baseUrl).href);
|
|
229
|
+
await import(new URL(${JSON.stringify(entrySrc)}, baseUrl).href);
|
|
230
|
+
`;
|
|
210
231
|
},
|
|
211
232
|
transform(code, id) {
|
|
212
233
|
if (id.includes("node_modules") || inject !== "html" || htmlFilePath) return;
|
|
@@ -703,7 +724,7 @@ function inferVersionFromRequiredVersion(requiredVersion) {
|
|
|
703
724
|
}
|
|
704
725
|
function normalizeShareItem(key, shareItem) {
|
|
705
726
|
let version;
|
|
706
|
-
try {
|
|
727
|
+
if (!(typeof shareItem === "object" && shareItem.import === false)) try {
|
|
707
728
|
try {
|
|
708
729
|
version = __require(path$1.join(removePathFromNpmPackage(key), "package.json")).version;
|
|
709
730
|
} catch (e1) {
|
|
@@ -972,15 +993,61 @@ var VirtualModule = class {
|
|
|
972
993
|
};
|
|
973
994
|
//#endregion
|
|
974
995
|
//#region src/virtualModules/virtualExposes.ts
|
|
996
|
+
const EXPOSES_CSS_MAP_PLACEHOLDER = "__MF_EXPOSES_CSS_MAP__";
|
|
997
|
+
function getExposesCssMapPlaceholder() {
|
|
998
|
+
return EXPOSES_CSS_MAP_PLACEHOLDER;
|
|
999
|
+
}
|
|
975
1000
|
function getVirtualExposesId(options) {
|
|
976
1001
|
return `virtual:mf-exposes:${`${options.name}__${options.filename}`.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
|
|
977
1002
|
}
|
|
978
1003
|
function generateExposes(options) {
|
|
979
1004
|
return `
|
|
1005
|
+
const cssAssetMap = ${JSON.stringify(options.bundleAllCSS ? EXPOSES_CSS_MAP_PLACEHOLDER : {})};
|
|
1006
|
+
const injectedCssHrefs = new Set();
|
|
1007
|
+
|
|
1008
|
+
async function injectCssAssets(exposeKey) {
|
|
1009
|
+
if (typeof document === "undefined") {
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// Replaced at build time with expose -> css asset paths.
|
|
1014
|
+
const cssAssets = cssAssetMap[exposeKey] || [];
|
|
1015
|
+
|
|
1016
|
+
await Promise.all(
|
|
1017
|
+
cssAssets.map((cssAsset) => {
|
|
1018
|
+
const href = new URL(cssAsset, import.meta.url).href;
|
|
1019
|
+
|
|
1020
|
+
// Same expose can be resolved multiple times in one page.
|
|
1021
|
+
if (injectedCssHrefs.has(href)) {
|
|
1022
|
+
return Promise.resolve();
|
|
1023
|
+
}
|
|
1024
|
+
injectedCssHrefs.add(href);
|
|
1025
|
+
|
|
1026
|
+
const existingLink = document.querySelector(
|
|
1027
|
+
\`link[rel="stylesheet"][data-mf-href="\${href}"]\`
|
|
1028
|
+
);
|
|
1029
|
+
if (existingLink) {
|
|
1030
|
+
return Promise.resolve();
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
return new Promise((resolve, reject) => {
|
|
1034
|
+
const link = document.createElement("link");
|
|
1035
|
+
link.rel = "stylesheet";
|
|
1036
|
+
link.href = href;
|
|
1037
|
+
link.setAttribute("data-mf-href", href);
|
|
1038
|
+
link.onload = () => resolve();
|
|
1039
|
+
link.onerror = () => reject(new Error(\`[Module Federation] Failed to load CSS asset: \${href}\`));
|
|
1040
|
+
document.head.appendChild(link);
|
|
1041
|
+
});
|
|
1042
|
+
})
|
|
1043
|
+
);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
980
1046
|
export default {
|
|
981
1047
|
${Object.keys(options.exposes).map((key) => {
|
|
982
1048
|
return `
|
|
983
1049
|
${JSON.stringify(key)}: async () => {
|
|
1050
|
+
await injectCssAssets(${JSON.stringify(key)})
|
|
984
1051
|
const importModule = await import(${JSON.stringify(options.exposes[key].import)})
|
|
985
1052
|
const exportModule = {}
|
|
986
1053
|
Object.assign(exportModule, importModule)
|
|
@@ -1127,32 +1194,159 @@ function generateRemotes(id, command, isRolldown) {
|
|
|
1127
1194
|
* 1. __prebuild__: export shareModule (pre-built source code of modules such as vue, react, etc.)
|
|
1128
1195
|
* 2. __loadShare__: load shareModule (mfRuntime.loadShare('vue'))
|
|
1129
1196
|
*/
|
|
1197
|
+
function escapeGeneratedStringLiteral(value) {
|
|
1198
|
+
return JSON.stringify(value).replace(/[<>\u2028\u2029]/g, (char) => {
|
|
1199
|
+
switch (char) {
|
|
1200
|
+
case "<": return "\\u003C";
|
|
1201
|
+
case ">": return "\\u003E";
|
|
1202
|
+
case "\u2028": return "\\u2028";
|
|
1203
|
+
case "\u2029": return "\\u2029";
|
|
1204
|
+
default: return char;
|
|
1205
|
+
}
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1208
|
+
const localRequire = createRequire$1(import.meta.url);
|
|
1209
|
+
function resolvePackageEntryFromProjectRoot(pkg) {
|
|
1210
|
+
try {
|
|
1211
|
+
return createRequire$1(new URL(`file://${path.join(getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
|
|
1212
|
+
} catch {
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
function getInstalledPackageJsonPath(pkg) {
|
|
1217
|
+
try {
|
|
1218
|
+
const packageName = removePathFromNpmPackage(pkg);
|
|
1219
|
+
const projectRequire = createRequire$1(new URL(`file://${path.join(getPackageDetectionCwd(), "package.json")}`));
|
|
1220
|
+
let resolvedPath;
|
|
1221
|
+
try {
|
|
1222
|
+
resolvedPath = projectRequire.resolve(pkg);
|
|
1223
|
+
} catch {
|
|
1224
|
+
resolvedPath = projectRequire.resolve(packageName);
|
|
1225
|
+
}
|
|
1226
|
+
let currentDir = path.dirname(resolvedPath);
|
|
1227
|
+
const rootDir = path.parse(currentDir).root;
|
|
1228
|
+
while (currentDir !== rootDir) {
|
|
1229
|
+
const packageJsonPath = path.join(currentDir, "package.json");
|
|
1230
|
+
if (existsSync(packageJsonPath)) {
|
|
1231
|
+
if (JSON.parse(readFileSync(packageJsonPath, "utf-8")).name === packageName) return packageJsonPath;
|
|
1232
|
+
}
|
|
1233
|
+
currentDir = path.dirname(currentDir);
|
|
1234
|
+
}
|
|
1235
|
+
const rootPackageJsonPath = path.join(rootDir, "package.json");
|
|
1236
|
+
if (existsSync(rootPackageJsonPath)) {
|
|
1237
|
+
if (JSON.parse(readFileSync(rootPackageJsonPath, "utf-8")).name === packageName) return rootPackageJsonPath;
|
|
1238
|
+
}
|
|
1239
|
+
} catch {
|
|
1240
|
+
const packageName = removePathFromNpmPackage(pkg);
|
|
1241
|
+
let currentDir = getPackageDetectionCwd();
|
|
1242
|
+
const rootDir = path.parse(currentDir).root;
|
|
1243
|
+
while (currentDir !== rootDir) {
|
|
1244
|
+
const packageJsonPath = path.join(currentDir, "node_modules", packageName, "package.json");
|
|
1245
|
+
if (existsSync(packageJsonPath)) return packageJsonPath;
|
|
1246
|
+
currentDir = path.dirname(currentDir);
|
|
1247
|
+
}
|
|
1248
|
+
const rootPackageJsonPath = path.join(rootDir, "node_modules", packageName, "package.json");
|
|
1249
|
+
return existsSync(rootPackageJsonPath) ? rootPackageJsonPath : void 0;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
function resolveImportTarget(exportsField) {
|
|
1253
|
+
if (typeof exportsField === "string") return exportsField;
|
|
1254
|
+
if (!exportsField || typeof exportsField !== "object") return void 0;
|
|
1255
|
+
const record = exportsField;
|
|
1256
|
+
for (const condition of [
|
|
1257
|
+
"import",
|
|
1258
|
+
"module",
|
|
1259
|
+
"default"
|
|
1260
|
+
]) {
|
|
1261
|
+
const target = resolveImportTarget(record[condition]);
|
|
1262
|
+
if (target) return target;
|
|
1263
|
+
}
|
|
1264
|
+
for (const target of Object.values(record)) {
|
|
1265
|
+
const resolved = resolveImportTarget(target);
|
|
1266
|
+
if (resolved) return resolved;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
function getPackageEsmEntryPath(pkg) {
|
|
1270
|
+
try {
|
|
1271
|
+
const resolvedEntryPath = resolvePackageEntryFromProjectRoot(pkg);
|
|
1272
|
+
const packageJsonPath = getInstalledPackageJsonPath(pkg);
|
|
1273
|
+
if (!packageJsonPath) return resolvedEntryPath;
|
|
1274
|
+
const packageName = removePathFromNpmPackage(pkg);
|
|
1275
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
1276
|
+
const subpath = pkg === packageName ? "." : `.${pkg.slice(packageName.length)}`;
|
|
1277
|
+
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;
|
|
1278
|
+
if (!target) return resolvedEntryPath;
|
|
1279
|
+
return path.resolve(path.dirname(packageJsonPath), target);
|
|
1280
|
+
} catch {
|
|
1281
|
+
return resolvePackageEntryFromProjectRoot(pkg);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
function getEsmNamedExports(pkg) {
|
|
1285
|
+
try {
|
|
1286
|
+
const entryPath = getPackageEsmEntryPath(pkg);
|
|
1287
|
+
if (!entryPath) return [];
|
|
1288
|
+
const { initSync, parse } = localRequire("es-module-lexer");
|
|
1289
|
+
initSync();
|
|
1290
|
+
const [, exports] = parse(readFileSync(entryPath, "utf-8"), entryPath);
|
|
1291
|
+
return exports.map((item) => item.n).filter((name) => !!name && name !== "default" && name !== "__esModule" && /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name));
|
|
1292
|
+
} catch {
|
|
1293
|
+
return [];
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1130
1296
|
function getPackageNamedExports(pkg) {
|
|
1131
1297
|
try {
|
|
1132
|
-
const mod = createRequire$1(new URL(
|
|
1298
|
+
const mod = createRequire$1(new URL(`file://${path.join(getPackageDetectionCwd(), "package.json")}`))(pkg);
|
|
1133
1299
|
return Object.keys(mod).filter((k) => k !== "default" && k !== "__esModule" && /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(k));
|
|
1134
1300
|
} catch {
|
|
1135
|
-
return
|
|
1301
|
+
return getEsmNamedExports(pkg);
|
|
1136
1302
|
}
|
|
1137
1303
|
}
|
|
1138
1304
|
function getLocalProviderImportPath(pkg) {
|
|
1139
1305
|
try {
|
|
1140
|
-
const resolved = createRequire$1(new URL(
|
|
1306
|
+
const resolved = createRequire$1(new URL(`file://${path.join(getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
|
|
1141
1307
|
return resolved.includes("/node_modules/") || resolved.includes("\\node_modules\\") ? void 0 : resolved;
|
|
1142
1308
|
} catch {
|
|
1143
1309
|
return;
|
|
1144
1310
|
}
|
|
1145
1311
|
}
|
|
1312
|
+
function tryResolveImportFromPackageRoot(pkg, root) {
|
|
1313
|
+
try {
|
|
1314
|
+
return createRequire$1(new URL(`file://${path.join(root, "package.json")}`)).resolve(pkg);
|
|
1315
|
+
} catch {
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
function getConcreteSharedImportSource(pkg, shareItem) {
|
|
1320
|
+
const configuredImport = shareItem?.shareConfig.import;
|
|
1321
|
+
if (typeof configuredImport === "string") return configuredImport;
|
|
1322
|
+
const projectRoot = getPackageDetectionCwd();
|
|
1323
|
+
if (tryResolveImportFromPackageRoot(pkg, projectRoot)) return;
|
|
1324
|
+
let currentDir = path.dirname(projectRoot);
|
|
1325
|
+
while (currentDir !== path.dirname(currentDir)) {
|
|
1326
|
+
const resolved = tryResolveImportFromPackageRoot(pkg, currentDir);
|
|
1327
|
+
if (resolved) return resolved;
|
|
1328
|
+
currentDir = path.dirname(currentDir);
|
|
1329
|
+
}
|
|
1330
|
+
return tryResolveImportFromPackageRoot(pkg, currentDir);
|
|
1331
|
+
}
|
|
1146
1332
|
const preBuildCacheMap = {};
|
|
1333
|
+
const preBuildShareItemMap = {};
|
|
1147
1334
|
const PREBUILD_TAG = "__prebuild__";
|
|
1148
|
-
function writePreBuildLibPath(pkg) {
|
|
1335
|
+
function writePreBuildLibPath(pkg, shareItem) {
|
|
1149
1336
|
if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
|
|
1150
|
-
|
|
1337
|
+
preBuildShareItemMap[pkg] = shareItem;
|
|
1338
|
+
preBuildCacheMap[pkg].writeSync("", true);
|
|
1151
1339
|
}
|
|
1152
1340
|
function getPreBuildLibImportId(pkg) {
|
|
1153
1341
|
if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
|
|
1154
1342
|
return preBuildCacheMap[pkg].getImportId();
|
|
1155
1343
|
}
|
|
1344
|
+
function getPreBuildShareItem(pkg) {
|
|
1345
|
+
return preBuildShareItemMap[pkg];
|
|
1346
|
+
}
|
|
1347
|
+
function getSharedImportSource(pkg, shareItem) {
|
|
1348
|
+
return getConcreteSharedImportSource(pkg, shareItem) || getPreBuildLibImportId(pkg);
|
|
1349
|
+
}
|
|
1156
1350
|
const LOAD_SHARE_TAG = "__loadShare__";
|
|
1157
1351
|
const loadShareCacheMap = {};
|
|
1158
1352
|
function getLoadShareImportId(pkg, isRolldown, command) {
|
|
@@ -1169,23 +1363,48 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
|
1169
1363
|
const importLine = command === "build" ? getRuntimeInitPromiseBootstrapCode() : useESM ? `${getRuntimeInitBootstrapCode()}
|
|
1170
1364
|
const { initPromise } = globalThis[globalKey];` : `const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")`;
|
|
1171
1365
|
const awaitOrPlaceholder = useESM ? "await " : "/*mf top-level-await placeholder replacement mf*/";
|
|
1366
|
+
if (shareItem.shareConfig.import === false) {
|
|
1367
|
+
const namedExports = useESM ? getPackageNamedExports(pkg) : [];
|
|
1368
|
+
let exportLine;
|
|
1369
|
+
if (useESM && namedExports.length > 0) exportLine = `export default exportModule.default ?? exportModule;\n ${`const { ${namedExports.map((name, i) => `${name}: __mf_${i}`).join(", ")} } = exportModule;`}\n ${`export { ${namedExports.map((name, i) => `__mf_${i} as ${name}`).join(", ")} };`}`;
|
|
1370
|
+
else {
|
|
1371
|
+
if (useESM) mfWarn(`Shared dependency "${pkg}" has import: false but is not installed locally.\n Named imports (e.g. import { ... } from '${pkg}') will not work in production builds.\n Install it as a devDependency to enable named export detection.`);
|
|
1372
|
+
exportLine = useESM ? "export default exportModule.default ?? exportModule" : "module.exports = exportModule";
|
|
1373
|
+
}
|
|
1374
|
+
loadShareCacheMap[pkg].writeSync(`
|
|
1375
|
+
${importLine}
|
|
1376
|
+
const res = initPromise.then(runtime => runtime.loadShare(${escapeGeneratedStringLiteral(pkg)}, {
|
|
1377
|
+
customShareInfo: {shareConfig:{
|
|
1378
|
+
singleton: ${shareItem.shareConfig.singleton},
|
|
1379
|
+
strictVersion: ${shareItem.shareConfig.strictVersion},
|
|
1380
|
+
requiredVersion: ${JSON.stringify(shareItem.shareConfig.requiredVersion)}
|
|
1381
|
+
}}
|
|
1382
|
+
}))
|
|
1383
|
+
const exportModule = ${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory))
|
|
1384
|
+
${exportLine}
|
|
1385
|
+
`, true);
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1172
1388
|
const useSsrProviderFallback = hasPackageDependency("vinext") && command === "build" && pkg === "react";
|
|
1173
|
-
const
|
|
1389
|
+
const concreteSharedImportSource = getConcreteSharedImportSource(pkg, shareItem);
|
|
1390
|
+
const sharedImportSource = concreteSharedImportSource || getPreBuildLibImportId(pkg);
|
|
1391
|
+
const devImportSource = concreteSharedImportSource || pkg;
|
|
1392
|
+
const providerImportId = getLocalProviderImportPath(pkg) || concreteSharedImportSource || sharedImportSource;
|
|
1174
1393
|
const namedExports = getPackageNamedExports(pkg);
|
|
1175
1394
|
let exportLine;
|
|
1176
1395
|
if (namedExports.length > 0) {
|
|
1177
1396
|
const destructure = `const { ${namedExports.map((name, i) => `${name}: __mf_${i}`).join(", ")} } = exportModule;`;
|
|
1178
1397
|
const namedExportLine = `export { ${namedExports.map((name, i) => `__mf_${i} as ${name}`).join(", ")} };`;
|
|
1179
1398
|
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(", ")} });`;
|
|
1180
|
-
} else exportLine = useESM ? `export default exportModule.default ?? exportModule\n export * from ${
|
|
1399
|
+
} else exportLine = useESM ? `export default exportModule.default ?? exportModule\n export * from ${escapeGeneratedStringLiteral(sharedImportSource)}` : "module.exports = exportModule";
|
|
1181
1400
|
loadShareCacheMap[pkg].writeSync(`
|
|
1182
|
-
import ${
|
|
1183
|
-
${command !== "build" ? `;() => import(${
|
|
1401
|
+
import ${escapeGeneratedStringLiteral(sharedImportSource)};
|
|
1402
|
+
${command !== "build" ? `;() => import(${escapeGeneratedStringLiteral(devImportSource)}).catch(() => {});` : ""}
|
|
1184
1403
|
${importLine}
|
|
1185
1404
|
${useSsrProviderFallback ? `const providerModulePromise = typeof window === "undefined"
|
|
1186
|
-
? import(${
|
|
1405
|
+
? import(${escapeGeneratedStringLiteral(providerImportId)})
|
|
1187
1406
|
: undefined` : ""}
|
|
1188
|
-
const res = initPromise.then(runtime => runtime.loadShare(${
|
|
1407
|
+
const res = initPromise.then(runtime => runtime.loadShare(${escapeGeneratedStringLiteral(pkg)}, {
|
|
1189
1408
|
customShareInfo: {shareConfig:{
|
|
1190
1409
|
singleton: ${shareItem.shareConfig.singleton},
|
|
1191
1410
|
strictVersion: ${shareItem.shareConfig.strictVersion},
|
|
@@ -1196,7 +1415,7 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
|
|
|
1196
1415
|
? ((await providerModulePromise)?.default ?? await providerModulePromise)
|
|
1197
1416
|
: ${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory)))` : `${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory))`}
|
|
1198
1417
|
${exportLine}
|
|
1199
|
-
|
|
1418
|
+
`, true);
|
|
1200
1419
|
}
|
|
1201
1420
|
//#endregion
|
|
1202
1421
|
//#region src/virtualModules/virtualRemoteEntry.ts
|
|
@@ -1230,7 +1449,7 @@ function generateLocalSharedImportMap() {
|
|
|
1230
1449
|
return `
|
|
1231
1450
|
${JSON.stringify(pkg)}: async () => {
|
|
1232
1451
|
${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");
|
|
1233
|
-
return pkg;` : `let pkg = await import(
|
|
1452
|
+
return pkg;` : `let pkg = await import(${JSON.stringify(getSharedImportSource(pkg, shareItem))});
|
|
1234
1453
|
return pkg;`}
|
|
1235
1454
|
}
|
|
1236
1455
|
`;
|
|
@@ -1313,6 +1532,14 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
|
|
|
1313
1532
|
];
|
|
1314
1533
|
});
|
|
1315
1534
|
return `
|
|
1535
|
+
// Shim Vue HMR runtime for dev-compiled components loaded by a non-Vite host.
|
|
1536
|
+
// When a remote is served by a Vite dev server, Vue's SFC compiler injects HMR
|
|
1537
|
+
// hooks that reference __VUE_HMR_RUNTIME__. This global only exists on pages
|
|
1538
|
+
// served by Vite's client runtime. When a production host loads the remote,
|
|
1539
|
+
// the HMR calls would throw. This no-op shim prevents that.
|
|
1540
|
+
if (typeof __VUE_HMR_RUNTIME__ === 'undefined') {
|
|
1541
|
+
globalThis.__VUE_HMR_RUNTIME__ = { createRecord() {}, rerender() {}, reload() {} };
|
|
1542
|
+
}
|
|
1316
1543
|
import {init as runtimeInit, loadRemote} from "@module-federation/runtime";
|
|
1317
1544
|
${pluginImportNames.map((item) => item[1]).join("\n")}
|
|
1318
1545
|
${command === "build" ? getRuntimeInitResolveBootstrapCode() : getRuntimeInitBootstrapCode() + "\n const { initResolve } = globalThis[globalKey];"}
|
|
@@ -1512,6 +1739,18 @@ const processModuleAssets = (bundle, filesMap, moduleMatcher) => {
|
|
|
1512
1739
|
}
|
|
1513
1740
|
};
|
|
1514
1741
|
/**
|
|
1742
|
+
* Adds global CSS assets to all module exports
|
|
1743
|
+
* @param filesMap - The preload map to update
|
|
1744
|
+
* @param cssAssets - Set of CSS asset filenames to add
|
|
1745
|
+
*/
|
|
1746
|
+
const addCssAssetsToAllExports = (filesMap, cssAssets) => {
|
|
1747
|
+
Object.keys(filesMap).forEach((key) => {
|
|
1748
|
+
cssAssets.forEach((cssAsset) => {
|
|
1749
|
+
trackAsset(filesMap, key, cssAsset, false, "css");
|
|
1750
|
+
});
|
|
1751
|
+
});
|
|
1752
|
+
};
|
|
1753
|
+
/**
|
|
1515
1754
|
* Deduplicates assets in the files map
|
|
1516
1755
|
* @param filesMap - The preload map to deduplicate
|
|
1517
1756
|
* @returns New deduplicated preload map
|
|
@@ -1837,12 +2076,13 @@ function pluginModuleParseEnd_default(excludeFn, options) {
|
|
|
1837
2076
|
//#region src/plugins/pluginProxyRemoteEntry.ts
|
|
1838
2077
|
const filter = createFilter();
|
|
1839
2078
|
function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposesId }) {
|
|
1840
|
-
let viteConfig, _command;
|
|
2079
|
+
let viteConfig, _command, root;
|
|
1841
2080
|
return {
|
|
1842
2081
|
name: "proxyRemoteEntry",
|
|
1843
2082
|
enforce: "post",
|
|
1844
2083
|
configResolved(config) {
|
|
1845
2084
|
viteConfig = config;
|
|
2085
|
+
root = config.root;
|
|
1846
2086
|
},
|
|
1847
2087
|
config(config, { command }) {
|
|
1848
2088
|
_command = command;
|
|
@@ -1897,6 +2137,51 @@ function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposes
|
|
|
1897
2137
|
return code;
|
|
1898
2138
|
}
|
|
1899
2139
|
})());
|
|
2140
|
+
},
|
|
2141
|
+
generateBundle(_, bundle) {
|
|
2142
|
+
if (_command !== "build") return;
|
|
2143
|
+
const filesMap = {};
|
|
2144
|
+
const exposeEntries = Object.entries(options.exposes);
|
|
2145
|
+
const allCssAssets = options.bundleAllCSS ? collectCssAssets(bundle) : /* @__PURE__ */ new Set();
|
|
2146
|
+
processModuleAssets(bundle, filesMap, (modulePath) => {
|
|
2147
|
+
const absoluteModulePath = path$1.resolve(root, modulePath);
|
|
2148
|
+
return exposeEntries.find(([_, exposeOptions]) => {
|
|
2149
|
+
const exposePath = path$1.resolve(root, exposeOptions.import);
|
|
2150
|
+
if (absoluteModulePath === exposePath) return true;
|
|
2151
|
+
const stripKnownJsExt = (filePath) => {
|
|
2152
|
+
const ext = path$1.extname(filePath);
|
|
2153
|
+
return [
|
|
2154
|
+
".ts",
|
|
2155
|
+
".tsx",
|
|
2156
|
+
".jsx",
|
|
2157
|
+
".mjs",
|
|
2158
|
+
".cjs"
|
|
2159
|
+
].includes(ext) ? path$1.join(path$1.dirname(filePath), path$1.basename(filePath, ext)) : filePath;
|
|
2160
|
+
};
|
|
2161
|
+
return stripKnownJsExt(absoluteModulePath) === stripKnownJsExt(exposePath);
|
|
2162
|
+
})?.[1].import;
|
|
2163
|
+
});
|
|
2164
|
+
if (options.bundleAllCSS) addCssAssetsToAllExports(filesMap, allCssAssets);
|
|
2165
|
+
const ensureRelativeImportPath = (fromFile, toFile) => {
|
|
2166
|
+
let relativePath = path$1.relative(path$1.dirname(fromFile), toFile);
|
|
2167
|
+
if (!relativePath.startsWith(".")) relativePath = `./${relativePath}`;
|
|
2168
|
+
return relativePath;
|
|
2169
|
+
};
|
|
2170
|
+
const placeholderValue = getExposesCssMapPlaceholder();
|
|
2171
|
+
const placeholderPatterns = [
|
|
2172
|
+
JSON.stringify(placeholderValue),
|
|
2173
|
+
`'${placeholderValue}'`,
|
|
2174
|
+
`\`${placeholderValue}\``
|
|
2175
|
+
];
|
|
2176
|
+
for (const file of Object.values(bundle)) {
|
|
2177
|
+
if (file.type !== "chunk" || !file.code.includes(placeholderValue)) continue;
|
|
2178
|
+
const cssAssetMap = exposeEntries.reduce((acc, [exposeKey, expose]) => {
|
|
2179
|
+
const assets = filesMap[expose.import] || createEmptyAssetMap();
|
|
2180
|
+
acc[exposeKey] = [...assets.css.sync, ...assets.css.async].map((cssAsset) => ensureRelativeImportPath(file.fileName, cssAsset));
|
|
2181
|
+
return acc;
|
|
2182
|
+
}, {});
|
|
2183
|
+
for (const placeholderPattern of placeholderPatterns) file.code = file.code.replace(placeholderPattern, JSON.stringify(cssAssetMap));
|
|
2184
|
+
}
|
|
1900
2185
|
}
|
|
1901
2186
|
};
|
|
1902
2187
|
}
|
|
@@ -1959,6 +2244,9 @@ var PromiseStore = class {
|
|
|
1959
2244
|
};
|
|
1960
2245
|
//#endregion
|
|
1961
2246
|
//#region src/plugins/pluginProxySharedModule_preBuild.ts
|
|
2247
|
+
function getPrebuildResolutionSource(pkgName, shareItem) {
|
|
2248
|
+
return getConcreteSharedImportSource(pkgName, shareItem) || pkgName;
|
|
2249
|
+
}
|
|
1962
2250
|
function proxySharedModule(options) {
|
|
1963
2251
|
const { shared = {} } = options;
|
|
1964
2252
|
let _config;
|
|
@@ -1997,7 +2285,7 @@ function proxySharedModule(options) {
|
|
|
1997
2285
|
if (key.endsWith("/") && source !== key.slice(0, -1)) return;
|
|
1998
2286
|
const loadSharePath = getLoadShareModulePath(source, isRolldown, command);
|
|
1999
2287
|
writeLoadShareModule(source, shared[key], command, isRolldown);
|
|
2000
|
-
writePreBuildLibPath(source);
|
|
2288
|
+
if (shared[key].shareConfig.import !== false) writePreBuildLibPath(source, shared[key]);
|
|
2001
2289
|
addUsedShares(source);
|
|
2002
2290
|
writeLocalSharedImportMap();
|
|
2003
2291
|
return this.resolve(loadSharePath, importer);
|
|
@@ -2008,14 +2296,18 @@ function proxySharedModule(options) {
|
|
|
2008
2296
|
return command === "build" ? {
|
|
2009
2297
|
find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
|
|
2010
2298
|
replacement: function($1) {
|
|
2011
|
-
|
|
2299
|
+
const pkgName = assertModuleFound(PREBUILD_TAG, $1).name;
|
|
2300
|
+
return getPrebuildResolutionSource(pkgName, getPreBuildShareItem(pkgName));
|
|
2012
2301
|
}
|
|
2013
2302
|
} : {
|
|
2014
2303
|
find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
|
|
2015
2304
|
replacement: "$1",
|
|
2016
2305
|
async customResolver(source, importer) {
|
|
2017
2306
|
const pkgName = assertModuleFound(PREBUILD_TAG, source).name;
|
|
2018
|
-
const
|
|
2307
|
+
const importSource = getPrebuildResolutionSource(pkgName, getPreBuildShareItem(pkgName));
|
|
2308
|
+
const resolved = await this.resolve(importSource, importer);
|
|
2309
|
+
if (!resolved?.id) return;
|
|
2310
|
+
const result = resolved.id;
|
|
2019
2311
|
if (_config && !result.includes(_config.cacheDir)) savePrebuild.set(pkgName, Promise.resolve(result));
|
|
2020
2312
|
return await this.resolve(await savePrebuild.get(pkgName), importer);
|
|
2021
2313
|
}
|
|
@@ -2032,7 +2324,7 @@ function proxySharedModule(options) {
|
|
|
2032
2324
|
return;
|
|
2033
2325
|
}
|
|
2034
2326
|
writeLoadShareModule(key, shared[key], _command, isRolldown);
|
|
2035
|
-
writePreBuildLibPath(key);
|
|
2327
|
+
if (shared[key].shareConfig.import !== false) writePreBuildLibPath(key, shared[key]);
|
|
2036
2328
|
addUsedShares(key);
|
|
2037
2329
|
});
|
|
2038
2330
|
writeLocalSharedImportMap();
|
|
@@ -2154,14 +2446,19 @@ function stripEmptyPreloadCalls(code) {
|
|
|
2154
2446
|
while (cursor < nextCode.length) {
|
|
2155
2447
|
const char = nextCode[cursor];
|
|
2156
2448
|
if (char === "(") depth++;
|
|
2157
|
-
else if (char === ")")
|
|
2158
|
-
|
|
2449
|
+
else if (char === ")") {
|
|
2450
|
+
depth--;
|
|
2451
|
+
if (depth < 0) break;
|
|
2452
|
+
} else if (depth === 0 && nextCode.startsWith(",[],import.meta.url)", cursor)) {
|
|
2159
2453
|
replacementEnd = cursor;
|
|
2160
2454
|
break;
|
|
2161
2455
|
}
|
|
2162
2456
|
cursor++;
|
|
2163
2457
|
}
|
|
2164
|
-
if (replacementEnd === -1)
|
|
2458
|
+
if (replacementEnd === -1) {
|
|
2459
|
+
start = nextCode.indexOf(marker, start + marker.length);
|
|
2460
|
+
continue;
|
|
2461
|
+
}
|
|
2165
2462
|
const expression = nextCode.slice(exprStart, replacementEnd);
|
|
2166
2463
|
nextCode = nextCode.slice(0, start) + expression + nextCode.slice(replacementEnd + 20);
|
|
2167
2464
|
start = nextCode.indexOf(marker, start + expression.length);
|
|
@@ -2238,13 +2535,14 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
2238
2535
|
VirtualModule.setRoot(root);
|
|
2239
2536
|
VirtualModule.ensureVirtualPackageExists();
|
|
2240
2537
|
initVirtualModules(_command, getRemoteEntryId(options));
|
|
2241
|
-
if (_command !== "serve") return;
|
|
2242
2538
|
const isRolldown = getIsRolldown(this);
|
|
2243
2539
|
if (remotes && Object.keys(remotes).length > 0) for (const key of Object.keys(remotes)) addUsedRemote(key, key);
|
|
2244
2540
|
if (shared && Object.keys(shared).length > 0) {
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2541
|
+
if (_command === "serve") {
|
|
2542
|
+
config.optimizeDeps = config.optimizeDeps || {};
|
|
2543
|
+
config.optimizeDeps.include = config.optimizeDeps.include || [];
|
|
2544
|
+
config.optimizeDeps.include.push(virtualRuntimeInitStatus.getImportId());
|
|
2545
|
+
}
|
|
2248
2546
|
for (const key of Object.keys(shared)) {
|
|
2249
2547
|
if (key.endsWith("/")) continue;
|
|
2250
2548
|
const shareItem = shared[key];
|
|
@@ -2254,10 +2552,12 @@ function createEarlyVirtualModulesPlugin(options) {
|
|
|
2254
2552
|
}
|
|
2255
2553
|
getLoadShareModulePath(key, isRolldown);
|
|
2256
2554
|
writeLoadShareModule(key, shareItem, _command, isRolldown);
|
|
2257
|
-
writePreBuildLibPath(key);
|
|
2555
|
+
if (shareItem.shareConfig?.import !== false) writePreBuildLibPath(key, shareItem);
|
|
2258
2556
|
addUsedShares(key);
|
|
2259
|
-
|
|
2260
|
-
|
|
2557
|
+
if (_command === "serve" && shareItem.shareConfig?.import !== false) {
|
|
2558
|
+
if (!isRolldown) config.optimizeDeps.include.push(getLoadShareImportId(key, isRolldown, _command));
|
|
2559
|
+
config.optimizeDeps.include.push(getPreBuildLibImportId(key));
|
|
2560
|
+
}
|
|
2261
2561
|
}
|
|
2262
2562
|
writeLocalSharedImportMap();
|
|
2263
2563
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@module-federation/vite",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.4",
|
|
4
4
|
"description": "Vite plugin for Module Federation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.cjs",
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
"@module-federation/sdk": "2.2.3",
|
|
73
73
|
"@rollup/pluginutils": "^5.3.0",
|
|
74
74
|
"defu": "^6.1.4",
|
|
75
|
+
"es-module-lexer": "^1.7.0",
|
|
75
76
|
"estree-walker": "^3.0.3",
|
|
76
77
|
"magic-string": "^0.30.21",
|
|
77
78
|
"pathe": "^2.0.3"
|