@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.
Files changed (3) hide show
  1. package/lib/index.cjs +429 -83
  2. package/lib/index.mjs +429 -83
  3. package/package.json +7 -5
package/lib/index.mjs CHANGED
@@ -27,38 +27,60 @@ async function mapCodeToCodeWithSourcemap(code) {
27
27
  //#endregion
28
28
  //#region src/utils/htmlEntryUtils.ts
29
29
  function sanitizeDevEntryPath(devEntryPath) {
30
- return devEntryPath.replace(/^[^:]+:([/\\])[/\\]?/, "$1").replace(/\\\\?/g, "/");
30
+ return devEntryPath.replace(/\\\\?/g, "/");
31
31
  }
32
32
  /**
33
- * Inlines the federation init import into existing module script tags to fix
34
- * the race condition (#396) where separate `<script type="module">` tags
35
- * don't guarantee execution order with top-level await.
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 inlineEntryScripts(html, initSrc) {
47
- const src = sanitizeDevEntryPath(initSrc);
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
- hasEntry = true;
56
- return `<script ${attrs.replace(/\s*\bsrc=["'][^"']+["']/i, "")}>await import(${JSON.stringify(src)});await import(${JSON.stringify(originalSrc)});`;
43
+ const proxySrc = createProxySrc(originalSrc);
44
+ return match.replace(srcMatch[0], `src=${JSON.stringify(proxySrc)}`);
57
45
  });
58
- if (hasEntry) return result;
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
52
+ //#region src/utils/logger.ts
53
+ const MODULE_FEDERATION_LOG_PREFIX = "[Module Federation]";
54
+ function formatModuleFederationMessage(message) {
55
+ return `${MODULE_FEDERATION_LOG_PREFIX} ${message}`;
56
+ }
57
+ function createModuleFederationError(message) {
58
+ return new Error(formatModuleFederationMessage(message));
59
+ }
60
+ function toConsoleArgs(message, rest = []) {
61
+ if (typeof message === "string") return [formatModuleFederationMessage(message), ...rest];
62
+ if (message === void 0) return [MODULE_FEDERATION_LOG_PREFIX, ...rest];
63
+ return [
64
+ MODULE_FEDERATION_LOG_PREFIX,
65
+ message,
66
+ ...rest
67
+ ];
68
+ }
69
+ const moduleFederationConsole = {
70
+ log(message, ...rest) {
71
+ console.log(...toConsoleArgs(message, rest));
72
+ },
73
+ warn(message, ...rest) {
74
+ console.warn(...toConsoleArgs(message, rest));
75
+ },
76
+ error(message, ...rest) {
77
+ console.error(...toConsoleArgs(message, rest));
78
+ }
79
+ };
80
+ moduleFederationConsole.log;
81
+ const mfWarn = moduleFederationConsole.warn;
82
+ const mfError = moduleFederationConsole.error;
83
+ //#endregion
62
84
  //#region src/utils/packageUtils.ts
63
85
  const dependencyPresenceCache = /* @__PURE__ */ new Map();
64
86
  let packageDetectionCwd;
@@ -68,6 +90,9 @@ function getDependencyCacheKey(cwd, dependencyName) {
68
90
  function setPackageDetectionCwd(cwd) {
69
91
  packageDetectionCwd = cwd;
70
92
  }
93
+ function getPackageDetectionCwd() {
94
+ return packageDetectionCwd || process.cwd();
95
+ }
71
96
  /**
72
97
  * Escaping rules:
73
98
  * Convert using the format __${mapping}__, where _ and $ are not allowed in npm package names but can be used in variable names.
@@ -82,7 +107,7 @@ function setPackageDetectionCwd(cwd) {
82
107
  * @returns {string} - The encoded file name.
83
108
  */
84
109
  function packageNameEncode(name) {
85
- if (typeof name !== "string") throw new Error("A string package name is required");
110
+ if (typeof name !== "string") throw createModuleFederationError("A string package name is required");
86
111
  return name.replace(/@/g, "_mf_0_").replace(/\//g, "_mf_1_").replace(/-/g, "_mf_2_").replace(/\./g, "_mf_3_");
87
112
  }
88
113
  /**
@@ -91,7 +116,7 @@ function packageNameEncode(name) {
91
116
  * @returns {string} - The decoded package name.
92
117
  */
93
118
  function packageNameDecode(encoded) {
94
- if (typeof encoded !== "string") throw new Error("A string encoded file name is required");
119
+ if (typeof encoded !== "string") throw createModuleFederationError("A string encoded file name is required");
95
120
  return encoded.replace(/_mf_0_/g, "@").replace(/_mf_1_/g, "/").replace(/_mf_2_/g, "-").replace(/_mf_3_/g, ".");
96
121
  }
97
122
  /**
@@ -103,6 +128,13 @@ function removePathFromNpmPackage(packageString) {
103
128
  const match = packageString.match(/^(?:@[^/]+\/)?[^/]+/);
104
129
  return match ? match[0] : packageString;
105
130
  }
131
+ /**
132
+ * Detect whether the current bundler is Rolldown (Vite 8+) by checking
133
+ * for `meta.rolldownVersion` on the plugin hook context.
134
+ */
135
+ function getIsRolldown(ctx) {
136
+ return !!ctx?.meta?.rolldownVersion;
137
+ }
106
138
  function hasPackageDependency(dependencyName, cwd = packageDetectionCwd || process.cwd()) {
107
139
  const cacheKey = getDependencyCacheKey(cwd, dependencyName);
108
140
  const cached = dependencyPresenceCache.get(cacheKey);
@@ -128,6 +160,7 @@ function getFirstHtmlEntryFile(entryFiles) {
128
160
  return entryFiles.find((file) => file.endsWith(".html"));
129
161
  }
130
162
  const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
163
+ const DEV_HTML_PROXY_PREFIX = "virtual:mf-html-entry-proxy?";
131
164
  const getEntryPath = () => typeof entryPath === "function" ? entryPath() : entryPath;
132
165
  let devEntryPath = "";
133
166
  let entryFiles = [];
@@ -151,8 +184,13 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
151
184
  configResolved(config) {
152
185
  viteConfig = config;
153
186
  const resolvedEntryPath = getEntryPath();
154
- devEntryPath = resolvedEntryPath.startsWith("virtual:mf") ? "@id/" + resolvedEntryPath : resolvedEntryPath;
155
- devEntryPath = config.base + devEntryPath.replace(/\\\\?/g, "/").replace(/^[^:]+:([/\\])[/\\]?/, "$1").replace(/^\//, "");
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
+ }
156
194
  },
157
195
  configureServer(server) {
158
196
  server.middlewares.use((req, res, next) => {
@@ -167,7 +205,29 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
167
205
  transformIndexHtml(c) {
168
206
  if (!injectHtml()) return;
169
207
  clientInjected = true;
170
- return inlineEntryScripts(c, devEntryPath);
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
+ `;
171
231
  },
172
232
  transform(code, id) {
173
233
  if (id.includes("node_modules") || inject !== "html" || htmlFilePath) return;
@@ -223,7 +283,7 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
223
283
  if (typeof result === "string") return result;
224
284
  if (result && typeof result === "object") {
225
285
  if ("runtime" in result) {
226
- console.warn("[vite-plugin-federation] renderBuiltUrl returned runtime code for HTML injection. Runtime code cannot be used in <script src=\"\">. Falling back to base path.");
286
+ mfWarn("renderBuiltUrl returned runtime code for HTML injection. Runtime code cannot be used in <script src=\"\">. Falling back to base path.");
227
287
  return viteConfig.base + file;
228
288
  }
229
289
  if (result.relative) return file;
@@ -288,11 +348,11 @@ function checkAliasConflicts(options) {
288
348
  });
289
349
  }
290
350
  if (conflicts.length > 0) {
291
- config.logger.warn("\n[Module Federation] Detected alias conflicts with shared modules:");
351
+ mfWarn("Detected alias conflicts with shared modules:");
292
352
  conflicts.forEach(({ sharedModule, alias, target }) => {
293
- config.logger.warn(` - Shared module "${sharedModule}" is aliased by "${alias}" to "${target}"`);
353
+ mfWarn(`Shared module "${sharedModule}" is aliased by "${alias}" to "${target}"`);
294
354
  });
295
- config.logger.warn(" This may cause runtime errors as the shared module will bypass Module Federation's sharing mechanism.");
355
+ mfWarn("This may cause runtime errors as the shared module will bypass Module Federation's sharing mechanism.");
296
356
  }
297
357
  }
298
358
  };
@@ -321,7 +381,7 @@ function PluginDevProxyModuleTopLevelAwait() {
321
381
  try {
322
382
  ast = this.parse(code, { allowReturnOutsideFunction: true });
323
383
  } catch (e) {
324
- throw new Error(`${id}: ${e}`);
384
+ throw createModuleFederationError(`${id}: ${e}`);
325
385
  }
326
386
  const magicString = new MagicString(code);
327
387
  const walk = await loadWalk();
@@ -449,7 +509,7 @@ const normalizeDevDtsOptions = (dts, context) => {
449
509
  const logDtsError = (error, dtsOptions) => {
450
510
  if (dtsOptions === false) return;
451
511
  if (typeof dtsOptions === "object" && dtsOptions && dtsOptions.displayErrorInTerminal === false) return;
452
- console.error(error);
512
+ mfError(error);
453
513
  };
454
514
  function pluginDts(options) {
455
515
  if (options.dts === false) return [];
@@ -477,7 +537,7 @@ function pluginDts(options) {
477
537
  if (!normalizedDevOptions || !resolvedConfig) return;
478
538
  const devOptions = normalizedDevOptions;
479
539
  if (devOptions.disableDynamicRemoteTypeHints && devOptions.disableHotTypesReload && devOptions.disableLiveReload) return;
480
- if (!options.name) throw new Error("name is required if you want to enable dev server!");
540
+ if (!options.name) throw createModuleFederationError("name is required if you want to enable dev server!");
481
541
  const outputDir = resolveOutputDir(resolvedConfig);
482
542
  const normalizedDtsOptions = normalizeDevDtsOptions(options.dts, resolvedConfig.root);
483
543
  if (typeof normalizedDtsOptions !== "object") return;
@@ -672,11 +732,11 @@ function normalizeShareItem(key, shareItem) {
672
732
  version = __require(path$1.join(process.cwd(), "node_modules", removePathFromNpmPackage(key), "package.json")).version;
673
733
  } catch (e2) {
674
734
  version = searchPackageVersion(key);
675
- if (!version) console.error(e1);
735
+ if (!version) mfError(e1);
676
736
  }
677
737
  }
678
738
  } catch (e) {
679
- console.error(`Unexpected error resolving version for ${key}:`, e);
739
+ mfError(`Unexpected error resolving version for ${key}:`, e);
680
740
  }
681
741
  if (typeof shareItem === "string") return {
682
742
  name: shareItem,
@@ -737,7 +797,7 @@ function getNormalizeShareItem(key) {
737
797
  return options.shared[key] || options.shared[removePathFromNpmPackage(key)] || options.shared[removePathFromNpmPackage(key) + "/"];
738
798
  }
739
799
  function normalizeModuleFederationOptions(options) {
740
- if (options.virtualModuleDir && options.virtualModuleDir.includes("/")) throw new Error(`Invalid virtualModuleDir: "${options.virtualModuleDir}". The virtualModuleDir option cannot contain slashes (/). Please use a single directory name like '__mf__virtual__your_app_name'.`);
800
+ 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'.`);
741
801
  return config = {
742
802
  exposes: normalizeExposes(options.exposes),
743
803
  filename: options.filename || "remoteEntry-[hash]",
@@ -872,7 +932,7 @@ const cacheMap = {};
872
932
  */
873
933
  function assertModuleFound(tag, str = "") {
874
934
  const module = VirtualModule.findModule(tag, str);
875
- if (!module) throw new Error(`Module Federation shared module '${str}' not found. Please ensure it's installed as a dependency in your package.json.`);
935
+ if (!module) throw createModuleFederationError(`Module Federation shared module '${str}' not found. Please ensure it's installed as a dependency in your package.json.`);
876
936
  return module;
877
937
  }
878
938
  var VirtualModule = class {
@@ -933,15 +993,61 @@ var VirtualModule = class {
933
993
  };
934
994
  //#endregion
935
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
+ }
936
1000
  function getVirtualExposesId(options) {
937
1001
  return `virtual:mf-exposes:${`${options.name}__${options.filename}`.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
938
1002
  }
939
1003
  function generateExposes(options) {
940
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
+
941
1046
  export default {
942
1047
  ${Object.keys(options.exposes).map((key) => {
943
1048
  return `
944
1049
  ${JSON.stringify(key)}: async () => {
1050
+ await injectCssAssets(${JSON.stringify(key)})
945
1051
  const importModule = await import(${JSON.stringify(options.exposes[key].import)})
946
1052
  const exportModule = {}
947
1053
  Object.assign(exportModule, importModule)
@@ -1088,36 +1194,167 @@ function generateRemotes(id, command, isRolldown) {
1088
1194
  * 1. __prebuild__: export shareModule (pre-built source code of modules such as vue, react, etc.)
1089
1195
  * 2. __loadShare__: load shareModule (mfRuntime.loadShare('vue'))
1090
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
+ }
1091
1296
  function getPackageNamedExports(pkg) {
1092
1297
  try {
1093
- const mod = createRequire$1(new URL("file://" + process.cwd() + "/package.json"))(pkg);
1298
+ const mod = createRequire$1(new URL(`file://${path.join(getPackageDetectionCwd(), "package.json")}`))(pkg);
1094
1299
  return Object.keys(mod).filter((k) => k !== "default" && k !== "__esModule" && /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(k));
1095
1300
  } catch {
1096
- return [];
1301
+ return getEsmNamedExports(pkg);
1097
1302
  }
1098
1303
  }
1099
1304
  function getLocalProviderImportPath(pkg) {
1100
1305
  try {
1101
- const resolved = createRequire$1(new URL("file://" + process.cwd() + "/package.json")).resolve(pkg);
1306
+ const resolved = createRequire$1(new URL(`file://${path.join(getPackageDetectionCwd(), "package.json")}`)).resolve(pkg);
1102
1307
  return resolved.includes("/node_modules/") || resolved.includes("\\node_modules\\") ? void 0 : resolved;
1103
1308
  } catch {
1104
1309
  return;
1105
1310
  }
1106
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
+ }
1107
1332
  const preBuildCacheMap = {};
1333
+ const preBuildShareItemMap = {};
1108
1334
  const PREBUILD_TAG = "__prebuild__";
1109
- function writePreBuildLibPath(pkg) {
1335
+ function writePreBuildLibPath(pkg, shareItem) {
1110
1336
  if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
1111
- preBuildCacheMap[pkg].writeSync("");
1337
+ preBuildShareItemMap[pkg] = shareItem;
1338
+ preBuildCacheMap[pkg].writeSync("", true);
1112
1339
  }
1113
1340
  function getPreBuildLibImportId(pkg) {
1114
1341
  if (!preBuildCacheMap[pkg]) preBuildCacheMap[pkg] = new VirtualModule(pkg, PREBUILD_TAG);
1115
1342
  return preBuildCacheMap[pkg].getImportId();
1116
1343
  }
1344
+ function getPreBuildShareItem(pkg) {
1345
+ return preBuildShareItemMap[pkg];
1346
+ }
1347
+ function getSharedImportSource(pkg, shareItem) {
1348
+ return getConcreteSharedImportSource(pkg, shareItem) || getPreBuildLibImportId(pkg);
1349
+ }
1117
1350
  const LOAD_SHARE_TAG = "__loadShare__";
1118
1351
  const loadShareCacheMap = {};
1119
- function getLoadShareModulePath(pkg, isRolldown, command) {
1352
+ function getLoadShareImportId(pkg, isRolldown, command) {
1120
1353
  if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, isRolldown || command === "build" ? ".mjs" : ".js");
1354
+ return loadShareCacheMap[pkg].getImportId();
1355
+ }
1356
+ function getLoadShareModulePath(pkg, isRolldown, command) {
1357
+ if (!loadShareCacheMap[pkg]) getLoadShareImportId(pkg, isRolldown, command);
1121
1358
  return loadShareCacheMap[pkg].getPath();
1122
1359
  }
1123
1360
  function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
@@ -1127,22 +1364,25 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
1127
1364
  const { initPromise } = globalThis[globalKey];` : `const {initPromise} = require("${virtualRuntimeInitStatus.getImportId()}")`;
1128
1365
  const awaitOrPlaceholder = useESM ? "await " : "/*mf top-level-await placeholder replacement mf*/";
1129
1366
  const useSsrProviderFallback = hasPackageDependency("vinext") && command === "build" && pkg === "react";
1130
- const providerImportId = getLocalProviderImportPath(pkg) || getPreBuildLibImportId(pkg);
1367
+ const concreteSharedImportSource = getConcreteSharedImportSource(pkg, shareItem);
1368
+ const sharedImportSource = concreteSharedImportSource || getPreBuildLibImportId(pkg);
1369
+ const devImportSource = concreteSharedImportSource || pkg;
1370
+ const providerImportId = getLocalProviderImportPath(pkg) || concreteSharedImportSource || sharedImportSource;
1131
1371
  const namedExports = getPackageNamedExports(pkg);
1132
1372
  let exportLine;
1133
1373
  if (namedExports.length > 0) {
1134
1374
  const destructure = `const { ${namedExports.map((name, i) => `${name}: __mf_${i}`).join(", ")} } = exportModule;`;
1135
1375
  const namedExportLine = `export { ${namedExports.map((name, i) => `__mf_${i} as ${name}`).join(", ")} };`;
1136
- 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(", ")} });`;
1137
- } else exportLine = useESM ? `export default exportModule\n export * from ${JSON.stringify(getPreBuildLibImportId(pkg))}` : "module.exports = exportModule";
1376
+ 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(", ")} });`;
1377
+ } else exportLine = useESM ? `export default exportModule.default ?? exportModule\n export * from ${escapeGeneratedStringLiteral(sharedImportSource)}` : "module.exports = exportModule";
1138
1378
  loadShareCacheMap[pkg].writeSync(`
1139
- import ${JSON.stringify(getPreBuildLibImportId(pkg))};
1140
- ${command !== "build" ? `;() => import(${JSON.stringify(pkg)}).catch(() => {});` : ""}
1379
+ import ${escapeGeneratedStringLiteral(sharedImportSource)};
1380
+ ${command !== "build" ? `;() => import(${escapeGeneratedStringLiteral(devImportSource)}).catch(() => {});` : ""}
1141
1381
  ${importLine}
1142
1382
  ${useSsrProviderFallback ? `const providerModulePromise = typeof window === "undefined"
1143
- ? import(${JSON.stringify(providerImportId)})
1383
+ ? import(${escapeGeneratedStringLiteral(providerImportId)})
1144
1384
  : undefined` : ""}
1145
- const res = initPromise.then(runtime => runtime.loadShare(${JSON.stringify(pkg)}, {
1385
+ const res = initPromise.then(runtime => runtime.loadShare(${escapeGeneratedStringLiteral(pkg)}, {
1146
1386
  customShareInfo: {shareConfig:{
1147
1387
  singleton: ${shareItem.shareConfig.singleton},
1148
1388
  strictVersion: ${shareItem.shareConfig.strictVersion},
@@ -1153,7 +1393,7 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
1153
1393
  ? ((await providerModulePromise)?.default ?? await providerModulePromise)
1154
1394
  : ${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory)))` : `${awaitOrPlaceholder}res.then((factory) => (typeof factory === "function" ? factory() : factory))`}
1155
1395
  ${exportLine}
1156
- `);
1396
+ `, true);
1157
1397
  }
1158
1398
  //#endregion
1159
1399
  //#region src/virtualModules/virtualRemoteEntry.ts
@@ -1186,8 +1426,8 @@ function generateLocalSharedImportMap() {
1186
1426
  const shareItem = getNormalizeShareItem(pkg);
1187
1427
  return `
1188
1428
  ${JSON.stringify(pkg)}: async () => {
1189
- ${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");
1190
- return pkg;` : `let pkg = await import("${getPreBuildLibImportId(pkg)}");
1429
+ ${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");
1430
+ return pkg;` : `let pkg = await import(${JSON.stringify(getSharedImportSource(pkg, shareItem))});
1191
1431
  return pkg;`}
1192
1432
  }
1193
1433
  `;
@@ -1206,7 +1446,7 @@ function generateLocalSharedImportMap() {
1206
1446
  from: ${JSON.stringify(options.name)},
1207
1447
  async get () {
1208
1448
  if (${shareItem.shareConfig.import === false}) {
1209
- throw new Error(\`Shared module '\${${JSON.stringify(key)}}' must be provided by host\`);
1449
+ throw new Error(\`[Module Federation] Shared module '\${${JSON.stringify(key)}}' must be provided by host\`);
1210
1450
  }
1211
1451
  usedShared[${JSON.stringify(key)}].loaded = true
1212
1452
  const {${JSON.stringify(key)}: pkgDynamicImport} = importMap
@@ -1313,14 +1553,14 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1313
1553
  initScope
1314
1554
  }));
1315
1555
  } catch (e) {
1316
- console.error(e)
1556
+ console.error('[Module Federation]', e)
1317
1557
  }
1318
1558
  return initRes
1319
1559
  }
1320
1560
 
1321
1561
  async function getExposes(moduleName) {
1322
1562
  const exposesMap = await getExposesMap()
1323
- if (!(moduleName in exposesMap)) throw new Error(\`Module \${moduleName} does not exist in container.\`)
1563
+ if (!(moduleName in exposesMap)) throw new Error(\`[Module Federation] Module \${moduleName} does not exist in container.\`)
1324
1564
  return (exposesMap[moduleName])().then(res => () => res)
1325
1565
  }
1326
1566
  export {
@@ -1469,6 +1709,18 @@ const processModuleAssets = (bundle, filesMap, moduleMatcher) => {
1469
1709
  }
1470
1710
  };
1471
1711
  /**
1712
+ * Adds global CSS assets to all module exports
1713
+ * @param filesMap - The preload map to update
1714
+ * @param cssAssets - Set of CSS asset filenames to add
1715
+ */
1716
+ const addCssAssetsToAllExports = (filesMap, cssAssets) => {
1717
+ Object.keys(filesMap).forEach((key) => {
1718
+ cssAssets.forEach((cssAsset) => {
1719
+ trackAsset(filesMap, key, cssAsset, false, "css");
1720
+ });
1721
+ });
1722
+ };
1723
+ /**
1472
1724
  * Deduplicates assets in the files map
1473
1725
  * @param filesMap - The preload map to deduplicate
1474
1726
  * @returns New deduplicated preload map
@@ -1737,14 +1989,14 @@ const promise = new Promise((resolve, reject) => {
1737
1989
  });
1738
1990
  function setParseTimeout(timeout) {
1739
1991
  if (!_parseTimeout) _parseTimeout = setTimeout(() => {
1740
- console.warn(`Parse timeout (${timeout}s) - forcing resolve`);
1992
+ mfWarn(`Parse timeout (${timeout}s) - forcing resolve`);
1741
1993
  _resolve(1);
1742
1994
  }, timeout * 1e3);
1743
1995
  }
1744
1996
  function resetIdleTimeout(timeout) {
1745
1997
  clearTimeout(_parseTimeout);
1746
1998
  _parseTimeout = setTimeout(() => {
1747
- console.warn(`moduleParseIdleTimeout: no module activity for ${timeout}s, forcing resolve. Some shared/remote dependencies may be missing. Consider increasing moduleParseIdleTimeout.`);
1999
+ mfWarn(`moduleParseIdleTimeout: no module activity for ${timeout}s, forcing resolve. Some shared/remote dependencies may be missing. Consider increasing moduleParseIdleTimeout.`);
1748
2000
  _resolve(1);
1749
2001
  }, timeout * 1e3);
1750
2002
  }
@@ -1794,12 +2046,13 @@ function pluginModuleParseEnd_default(excludeFn, options) {
1794
2046
  //#region src/plugins/pluginProxyRemoteEntry.ts
1795
2047
  const filter = createFilter();
1796
2048
  function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposesId }) {
1797
- let viteConfig, _command;
2049
+ let viteConfig, _command, root;
1798
2050
  return {
1799
2051
  name: "proxyRemoteEntry",
1800
2052
  enforce: "post",
1801
2053
  configResolved(config) {
1802
2054
  viteConfig = config;
2055
+ root = config.root;
1803
2056
  },
1804
2057
  config(config, { command }) {
1805
2058
  _command = command;
@@ -1854,6 +2107,51 @@ function pluginProxyRemoteEntry_default({ options, remoteEntryId, virtualExposes
1854
2107
  return code;
1855
2108
  }
1856
2109
  })());
2110
+ },
2111
+ generateBundle(_, bundle) {
2112
+ if (_command !== "build") return;
2113
+ const filesMap = {};
2114
+ const exposeEntries = Object.entries(options.exposes);
2115
+ const allCssAssets = options.bundleAllCSS ? collectCssAssets(bundle) : /* @__PURE__ */ new Set();
2116
+ processModuleAssets(bundle, filesMap, (modulePath) => {
2117
+ const absoluteModulePath = path$1.resolve(root, modulePath);
2118
+ return exposeEntries.find(([_, exposeOptions]) => {
2119
+ const exposePath = path$1.resolve(root, exposeOptions.import);
2120
+ if (absoluteModulePath === exposePath) return true;
2121
+ const stripKnownJsExt = (filePath) => {
2122
+ const ext = path$1.extname(filePath);
2123
+ return [
2124
+ ".ts",
2125
+ ".tsx",
2126
+ ".jsx",
2127
+ ".mjs",
2128
+ ".cjs"
2129
+ ].includes(ext) ? path$1.join(path$1.dirname(filePath), path$1.basename(filePath, ext)) : filePath;
2130
+ };
2131
+ return stripKnownJsExt(absoluteModulePath) === stripKnownJsExt(exposePath);
2132
+ })?.[1].import;
2133
+ });
2134
+ if (options.bundleAllCSS) addCssAssetsToAllExports(filesMap, allCssAssets);
2135
+ const ensureRelativeImportPath = (fromFile, toFile) => {
2136
+ let relativePath = path$1.relative(path$1.dirname(fromFile), toFile);
2137
+ if (!relativePath.startsWith(".")) relativePath = `./${relativePath}`;
2138
+ return relativePath;
2139
+ };
2140
+ const placeholderValue = getExposesCssMapPlaceholder();
2141
+ const placeholderPatterns = [
2142
+ JSON.stringify(placeholderValue),
2143
+ `'${placeholderValue}'`,
2144
+ `\`${placeholderValue}\``
2145
+ ];
2146
+ for (const file of Object.values(bundle)) {
2147
+ if (file.type !== "chunk" || !file.code.includes(placeholderValue)) continue;
2148
+ const cssAssetMap = exposeEntries.reduce((acc, [exposeKey, expose]) => {
2149
+ const assets = filesMap[expose.import] || createEmptyAssetMap();
2150
+ acc[exposeKey] = [...assets.css.sync, ...assets.css.async].map((cssAsset) => ensureRelativeImportPath(file.fileName, cssAsset));
2151
+ return acc;
2152
+ }, {});
2153
+ for (const placeholderPattern of placeholderPatterns) file.code = file.code.replace(placeholderPattern, JSON.stringify(cssAssetMap));
2154
+ }
1857
2155
  }
1858
2156
  };
1859
2157
  }
@@ -1865,7 +2163,7 @@ function pluginProxyRemotes_default(options) {
1865
2163
  return {
1866
2164
  name: "proxyRemotes",
1867
2165
  config(config, { command: _command }) {
1868
- const isRolldown = !!this?.meta?.rolldownVersion;
2166
+ const isRolldown = getIsRolldown(this);
1869
2167
  Object.keys(remotes).forEach((key) => {
1870
2168
  const remote = remotes[key];
1871
2169
  config.resolve.alias.push({
@@ -1916,6 +2214,9 @@ var PromiseStore = class {
1916
2214
  };
1917
2215
  //#endregion
1918
2216
  //#region src/plugins/pluginProxySharedModule_preBuild.ts
2217
+ function getPrebuildResolutionSource(pkgName, shareItem) {
2218
+ return getConcreteSharedImportSource(pkgName, shareItem) || pkgName;
2219
+ }
1919
2220
  function proxySharedModule(options) {
1920
2221
  const { shared = {} } = options;
1921
2222
  let _config;
@@ -1937,7 +2238,7 @@ function proxySharedModule(options) {
1937
2238
  config(config, { command }) {
1938
2239
  setPackageDetectionCwd(config.root || process.cwd());
1939
2240
  isVinext = hasPackageDependency("vinext");
1940
- const isRolldown = !!this?.meta?.rolldownVersion;
2241
+ const isRolldown = getIsRolldown(this);
1941
2242
  _command = command;
1942
2243
  config.resolve.alias.push(...Object.keys(shared).filter((key) => !(isVinext && key === "react")).map((key) => {
1943
2244
  const keyBase = key.endsWith("/") ? key.slice(0, -1) : key;
@@ -1954,7 +2255,7 @@ function proxySharedModule(options) {
1954
2255
  if (key.endsWith("/") && source !== key.slice(0, -1)) return;
1955
2256
  const loadSharePath = getLoadShareModulePath(source, isRolldown, command);
1956
2257
  writeLoadShareModule(source, shared[key], command, isRolldown);
1957
- writePreBuildLibPath(source);
2258
+ writePreBuildLibPath(source, shared[key]);
1958
2259
  addUsedShares(source);
1959
2260
  writeLocalSharedImportMap();
1960
2261
  return this.resolve(loadSharePath, importer);
@@ -1965,14 +2266,18 @@ function proxySharedModule(options) {
1965
2266
  return command === "build" ? {
1966
2267
  find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
1967
2268
  replacement: function($1) {
1968
- return assertModuleFound(PREBUILD_TAG, $1).name;
2269
+ const pkgName = assertModuleFound(PREBUILD_TAG, $1).name;
2270
+ return getPrebuildResolutionSource(pkgName, getPreBuildShareItem(pkgName));
1969
2271
  }
1970
2272
  } : {
1971
2273
  find: new RegExp(`(.*${PREBUILD_TAG}.*)`),
1972
2274
  replacement: "$1",
1973
2275
  async customResolver(source, importer) {
1974
2276
  const pkgName = assertModuleFound(PREBUILD_TAG, source).name;
1975
- const result = await this.resolve(pkgName, importer).then((item) => item.id);
2277
+ const importSource = getPrebuildResolutionSource(pkgName, getPreBuildShareItem(pkgName));
2278
+ const resolved = await this.resolve(importSource, importer);
2279
+ if (!resolved?.id) return;
2280
+ const result = resolved.id;
1976
2281
  if (_config && !result.includes(_config.cacheDir)) savePrebuild.set(pkgName, Promise.resolve(result));
1977
2282
  return await this.resolve(await savePrebuild.get(pkgName), importer);
1978
2283
  }
@@ -1989,7 +2294,7 @@ function proxySharedModule(options) {
1989
2294
  return;
1990
2295
  }
1991
2296
  writeLoadShareModule(key, shared[key], _command, isRolldown);
1992
- writePreBuildLibPath(key);
2297
+ writePreBuildLibPath(key, shared[key]);
1993
2298
  addUsedShares(key);
1994
2299
  });
1995
2300
  writeLocalSharedImportMap();
@@ -2017,7 +2322,6 @@ const VarRemoteEntry = () => {
2017
2322
  if (req.url?.replace(/\?.*/, "") === (viteConfig.base + varFilename).replace(/^\/?/, "/")) {
2018
2323
  res.setHeader("Content-Type", "text/javascript");
2019
2324
  res.setHeader("Access-Control-Allow-Origin", "*");
2020
- console.log({ filename });
2021
2325
  res.end(generateVarRemoteEntry(filename));
2022
2326
  } else next();
2023
2327
  });
@@ -2033,9 +2337,9 @@ const VarRemoteEntry = () => {
2033
2337
  },
2034
2338
  async generateBundle(options, bundle) {
2035
2339
  if (!varFilename) return;
2036
- if (!isValidVarName(name)) viteConfig.logger.warn(`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).`);
2340
+ 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).`);
2037
2341
  const remoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
2038
- if (!remoteEntryFile) throw new Error(`Couldn't find a remoteEntry chunk file for ${mfOptions.filename}, can't generate varRemoteEntry file`);
2342
+ if (!remoteEntryFile) throw createModuleFederationError(`Couldn't find a remoteEntry chunk file for ${mfOptions.filename}, can't generate varRemoteEntry file`);
2039
2343
  this.emitFile({
2040
2344
  type: "asset",
2041
2345
  fileName: varFilename,
@@ -2060,7 +2364,7 @@ const VarRemoteEntry = () => {
2060
2364
  function getScriptUrl() {
2061
2365
  const currentScript = document.currentScript;
2062
2366
  if (!currentScript) {
2063
- console.error("[VarRemoteEntry] ${varFilename} script should be called from sync <script> tag (document.currentScript is undefined)")
2367
+ console.error("[Module Federation] ${varFilename} script should be called from sync <script> tag (document.currentScript is undefined)")
2064
2368
  return '/';
2065
2369
  }
2066
2370
  return document.currentScript.src.replace(/\\/[^/]*$/, '/');
@@ -2112,14 +2416,19 @@ function stripEmptyPreloadCalls(code) {
2112
2416
  while (cursor < nextCode.length) {
2113
2417
  const char = nextCode[cursor];
2114
2418
  if (char === "(") depth++;
2115
- else if (char === ")") depth--;
2116
- else if (depth === 0 && nextCode.startsWith(",[],import.meta.url)", cursor)) {
2419
+ else if (char === ")") {
2420
+ depth--;
2421
+ if (depth < 0) break;
2422
+ } else if (depth === 0 && nextCode.startsWith(",[],import.meta.url)", cursor)) {
2117
2423
  replacementEnd = cursor;
2118
2424
  break;
2119
2425
  }
2120
2426
  cursor++;
2121
2427
  }
2122
- if (replacementEnd === -1) break;
2428
+ if (replacementEnd === -1) {
2429
+ start = nextCode.indexOf(marker, start + marker.length);
2430
+ continue;
2431
+ }
2123
2432
  const expression = nextCode.slice(exprStart, replacementEnd);
2124
2433
  nextCode = nextCode.slice(0, start) + expression + nextCode.slice(replacementEnd + 20);
2125
2434
  start = nextCode.indexOf(marker, start + expression.length);
@@ -2159,6 +2468,25 @@ var normalizeOptimizeDeps_default = {
2159
2468
  };
2160
2469
  //#endregion
2161
2470
  //#region src/index.ts
2471
+ const UNSAFE_JS_SOURCE_CHAR_MAP = {
2472
+ "<": "\\u003C",
2473
+ ">": "\\u003E",
2474
+ "/": "\\u002F",
2475
+ "\\": "\\\\",
2476
+ "\b": "\\b",
2477
+ "\f": "\\f",
2478
+ "\n": "\\n",
2479
+ "\r": "\\r",
2480
+ " ": "\\t",
2481
+ "\0": "\\0",
2482
+ "\u2028": "\\u2028",
2483
+ "\u2029": "\\u2029"
2484
+ };
2485
+ function escapeUnsafeJsSourceChars(str) {
2486
+ return str.replace(/[<>/\\\b\f\n\r\t\0\u2028\u2029]/g, (char) => {
2487
+ return UNSAFE_JS_SOURCE_CHAR_MAP[char] ?? char;
2488
+ });
2489
+ }
2162
2490
  /**
2163
2491
  * Plugin that runs FIRST to create virtual module files in the config hook.
2164
2492
  * This prevents 504 "Outdated Optimize Dep" errors by ensuring files exist
@@ -2177,13 +2505,14 @@ function createEarlyVirtualModulesPlugin(options) {
2177
2505
  VirtualModule.setRoot(root);
2178
2506
  VirtualModule.ensureVirtualPackageExists();
2179
2507
  initVirtualModules(_command, getRemoteEntryId(options));
2180
- if (_command !== "serve") return;
2181
- const isRolldown = !!this?.meta?.rolldownVersion;
2508
+ const isRolldown = getIsRolldown(this);
2182
2509
  if (remotes && Object.keys(remotes).length > 0) for (const key of Object.keys(remotes)) addUsedRemote(key, key);
2183
2510
  if (shared && Object.keys(shared).length > 0) {
2184
- config.optimizeDeps = config.optimizeDeps || {};
2185
- config.optimizeDeps.include = config.optimizeDeps.include || [];
2186
- config.optimizeDeps.include.push(virtualRuntimeInitStatus.getImportId());
2511
+ if (_command === "serve") {
2512
+ config.optimizeDeps = config.optimizeDeps || {};
2513
+ config.optimizeDeps.include = config.optimizeDeps.include || [];
2514
+ config.optimizeDeps.include.push(virtualRuntimeInitStatus.getImportId());
2515
+ }
2187
2516
  for (const key of Object.keys(shared)) {
2188
2517
  if (key.endsWith("/")) continue;
2189
2518
  const shareItem = shared[key];
@@ -2193,9 +2522,12 @@ function createEarlyVirtualModulesPlugin(options) {
2193
2522
  }
2194
2523
  getLoadShareModulePath(key, isRolldown);
2195
2524
  writeLoadShareModule(key, shareItem, _command, isRolldown);
2196
- writePreBuildLibPath(key);
2525
+ writePreBuildLibPath(key, shareItem);
2197
2526
  addUsedShares(key);
2198
- config.optimizeDeps.include.push(getPreBuildLibImportId(key));
2527
+ if (_command === "serve") {
2528
+ if (!isRolldown) config.optimizeDeps.include.push(getLoadShareImportId(key, isRolldown, _command));
2529
+ config.optimizeDeps.include.push(getPreBuildLibImportId(key));
2530
+ }
2199
2531
  }
2200
2532
  writeLocalSharedImportMap();
2201
2533
  }
@@ -2206,7 +2538,7 @@ function federation(mfUserOptions) {
2206
2538
  const options = normalizeModuleFederationOptions(mfUserOptions);
2207
2539
  const isVinext = hasPackageDependency("vinext");
2208
2540
  const { name, remotes, shared, filename, hostInitInjectLocation } = options;
2209
- if (!name) throw new Error("name is required");
2541
+ if (!name) throw createModuleFederationError("name is required");
2210
2542
  const remoteEntryId = getRemoteEntryId(options);
2211
2543
  const virtualExposesId = getVirtualExposesId(options);
2212
2544
  let command;
@@ -2292,7 +2624,16 @@ function federation(mfUserOptions) {
2292
2624
  }
2293
2625
  };
2294
2626
  }
2627
+ let warnedAboutCodeSplitting = false;
2628
+ const ensureCodeSplitting = (output) => {
2629
+ if (output?.codeSplitting !== false) return;
2630
+ delete output.codeSplitting;
2631
+ if (warnedAboutCodeSplitting) return;
2632
+ warnedAboutCodeSplitting = true;
2633
+ mfWarn("Ignoring `build.rolldownOptions.output.codeSplitting = false` because module federation requires chunk splitting.");
2634
+ };
2295
2635
  const applyManualChunks = (output) => {
2636
+ ensureCodeSplitting(output);
2296
2637
  const existingManualChunks = output.manualChunks;
2297
2638
  output.manualChunks = function(id) {
2298
2639
  if (id.includes(runtimeInitId)) return "runtimeInit";
@@ -2514,7 +2855,7 @@ function federation(mfUserOptions) {
2514
2855
  enforce: "post",
2515
2856
  _options: options,
2516
2857
  config(config, { command: _command }) {
2517
- const isRolldown = !!this?.meta?.rolldownVersion;
2858
+ const isRolldown = getIsRolldown(this);
2518
2859
  let implementation = options.implementation;
2519
2860
  if (isRolldown) implementation = implementation.replace(/\.cjs(\.js)?$/, ".js");
2520
2861
  config.resolve.alias.push({
@@ -2543,7 +2884,7 @@ function federation(mfUserOptions) {
2543
2884
  const resolvedTarget = options.target ?? (config.build?.ssr ? "node" : "web");
2544
2885
  if (!config.define) config.define = {};
2545
2886
  if (!("ENV_TARGET" in config.define)) config.define["ENV_TARGET"] = JSON.stringify(resolvedTarget);
2546
- if (options.target && "ENV_TARGET" in config.define && config.define["ENV_TARGET"] !== JSON.stringify(options.target)) console.warn(`[module-federation] ENV_TARGET define (${config.define["ENV_TARGET"]}) differs from target option ("${options.target}"). ENV_TARGET will not be overridden.`);
2887
+ 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.`);
2547
2888
  }
2548
2889
  },
2549
2890
  ...Manifest(),
@@ -2556,13 +2897,18 @@ function federation(mfUserOptions) {
2556
2897
  for (const chunk of Object.values(bundle)) {
2557
2898
  if (chunk.type !== "chunk") continue;
2558
2899
  if (!chunk.code.includes("modulepreload")) continue;
2559
- const replacement = "=function($1){return new URL(\"../\"+$1,import.meta.url).href}";
2900
+ const chunkDir = path.dirname(chunk.fileName);
2901
+ const prefixToRoot = chunkDir === "." ? "" : `${path.relative(chunkDir, ".")}/`;
2902
+ const replacementExpr = prefixToRoot ? `${escapeUnsafeJsSourceChars(JSON.stringify(prefixToRoot))}+$1` : "$1";
2903
+ const replacement = `=function($1){return new URL(${replacementExpr},import.meta.url).href}`;
2560
2904
  const replaced = chunk.code.replace(/=\(?(\w+)(?:,\w+)?\)?\s*=>\s*["'`][^"'`]*["'`]\s*\+\s*\1/, replacement);
2561
2905
  if (replaced !== chunk.code) {
2562
2906
  chunk.code = replaced;
2563
2907
  continue;
2564
2908
  }
2565
2909
  chunk.code = chunk.code.replace(/=function\((\w+)(?:,\w+)?\)\{return\s*["'`][^"'`]*["'`]\s*\+\s*\1\s*\}/, replacement);
2910
+ chunk.code = chunk.code.replace(/=function\((\w+)(?:,\w+)?\)\{return new URL\("\.\.\/"\+\1,import\.meta\.url\)\.href\}/, replacement);
2911
+ chunk.code = chunk.code.replace(/new URL\("\.\.\/"\+(\w+),import\.meta\.url\)\.href/g, `new URL(${replacementExpr},import.meta.url).href`);
2566
2912
  }
2567
2913
  }
2568
2914
  }] : []