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