@module-federation/vite 1.13.1 → 1.13.2

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 +109 -33
  2. package/lib/index.mjs +109 -33
  3. package/package.json +6 -5
package/lib/index.cjs CHANGED
@@ -81,6 +81,38 @@ function inlineEntryScripts(html, initSrc) {
81
81
  return html.replace("<head>", `<head><script type="module" src=${JSON.stringify(src)}><\/script>`);
82
82
  }
83
83
  //#endregion
84
+ //#region src/utils/logger.ts
85
+ const MODULE_FEDERATION_LOG_PREFIX = "[Module Federation]";
86
+ function formatModuleFederationMessage(message) {
87
+ return `${MODULE_FEDERATION_LOG_PREFIX} ${message}`;
88
+ }
89
+ function createModuleFederationError(message) {
90
+ return new Error(formatModuleFederationMessage(message));
91
+ }
92
+ function toConsoleArgs(message, rest = []) {
93
+ if (typeof message === "string") return [formatModuleFederationMessage(message), ...rest];
94
+ if (message === void 0) return [MODULE_FEDERATION_LOG_PREFIX, ...rest];
95
+ return [
96
+ MODULE_FEDERATION_LOG_PREFIX,
97
+ message,
98
+ ...rest
99
+ ];
100
+ }
101
+ const moduleFederationConsole = {
102
+ log(message, ...rest) {
103
+ console.log(...toConsoleArgs(message, rest));
104
+ },
105
+ warn(message, ...rest) {
106
+ console.warn(...toConsoleArgs(message, rest));
107
+ },
108
+ error(message, ...rest) {
109
+ console.error(...toConsoleArgs(message, rest));
110
+ }
111
+ };
112
+ moduleFederationConsole.log;
113
+ const mfWarn = moduleFederationConsole.warn;
114
+ const mfError = moduleFederationConsole.error;
115
+ //#endregion
84
116
  //#region src/utils/packageUtils.ts
85
117
  const dependencyPresenceCache = /* @__PURE__ */ new Map();
86
118
  let packageDetectionCwd;
@@ -104,7 +136,7 @@ function setPackageDetectionCwd(cwd) {
104
136
  * @returns {string} - The encoded file name.
105
137
  */
106
138
  function packageNameEncode(name) {
107
- if (typeof name !== "string") throw new Error("A string package name is required");
139
+ if (typeof name !== "string") throw createModuleFederationError("A string package name is required");
108
140
  return name.replace(/@/g, "_mf_0_").replace(/\//g, "_mf_1_").replace(/-/g, "_mf_2_").replace(/\./g, "_mf_3_");
109
141
  }
110
142
  /**
@@ -113,7 +145,7 @@ function packageNameEncode(name) {
113
145
  * @returns {string} - The decoded package name.
114
146
  */
115
147
  function packageNameDecode(encoded) {
116
- if (typeof encoded !== "string") throw new Error("A string encoded file name is required");
148
+ if (typeof encoded !== "string") throw createModuleFederationError("A string encoded file name is required");
117
149
  return encoded.replace(/_mf_0_/g, "@").replace(/_mf_1_/g, "/").replace(/_mf_2_/g, "-").replace(/_mf_3_/g, ".");
118
150
  }
119
151
  /**
@@ -125,6 +157,13 @@ function removePathFromNpmPackage(packageString) {
125
157
  const match = packageString.match(/^(?:@[^/]+\/)?[^/]+/);
126
158
  return match ? match[0] : packageString;
127
159
  }
160
+ /**
161
+ * Detect whether the current bundler is Rolldown (Vite 8+) by checking
162
+ * for `meta.rolldownVersion` on the plugin hook context.
163
+ */
164
+ function getIsRolldown(ctx) {
165
+ return !!ctx?.meta?.rolldownVersion;
166
+ }
128
167
  function hasPackageDependency(dependencyName, cwd = packageDetectionCwd || process.cwd()) {
129
168
  const cacheKey = getDependencyCacheKey(cwd, dependencyName);
130
169
  const cached = dependencyPresenceCache.get(cacheKey);
@@ -245,7 +284,7 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
245
284
  if (typeof result === "string") return result;
246
285
  if (result && typeof result === "object") {
247
286
  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.");
287
+ mfWarn("renderBuiltUrl returned runtime code for HTML injection. Runtime code cannot be used in <script src=\"\">. Falling back to base path.");
249
288
  return viteConfig.base + file;
250
289
  }
251
290
  if (result.relative) return file;
@@ -310,11 +349,11 @@ function checkAliasConflicts(options) {
310
349
  });
311
350
  }
312
351
  if (conflicts.length > 0) {
313
- config.logger.warn("\n[Module Federation] Detected alias conflicts with shared modules:");
352
+ mfWarn("Detected alias conflicts with shared modules:");
314
353
  conflicts.forEach(({ sharedModule, alias, target }) => {
315
- config.logger.warn(` - Shared module "${sharedModule}" is aliased by "${alias}" to "${target}"`);
354
+ mfWarn(`Shared module "${sharedModule}" is aliased by "${alias}" to "${target}"`);
316
355
  });
317
- config.logger.warn(" This may cause runtime errors as the shared module will bypass Module Federation's sharing mechanism.");
356
+ mfWarn("This may cause runtime errors as the shared module will bypass Module Federation's sharing mechanism.");
318
357
  }
319
358
  }
320
359
  };
@@ -343,7 +382,7 @@ function PluginDevProxyModuleTopLevelAwait() {
343
382
  try {
344
383
  ast = this.parse(code, { allowReturnOutsideFunction: true });
345
384
  } catch (e) {
346
- throw new Error(`${id}: ${e}`);
385
+ throw createModuleFederationError(`${id}: ${e}`);
347
386
  }
348
387
  const magicString = new magic_string.default(code);
349
388
  const walk = await loadWalk();
@@ -471,7 +510,7 @@ const normalizeDevDtsOptions = (dts, context) => {
471
510
  const logDtsError = (error, dtsOptions) => {
472
511
  if (dtsOptions === false) return;
473
512
  if (typeof dtsOptions === "object" && dtsOptions && dtsOptions.displayErrorInTerminal === false) return;
474
- console.error(error);
513
+ mfError(error);
475
514
  };
476
515
  function pluginDts(options) {
477
516
  if (options.dts === false) return [];
@@ -499,7 +538,7 @@ function pluginDts(options) {
499
538
  if (!normalizedDevOptions || !resolvedConfig) return;
500
539
  const devOptions = normalizedDevOptions;
501
540
  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!");
541
+ if (!options.name) throw createModuleFederationError("name is required if you want to enable dev server!");
503
542
  const outputDir = resolveOutputDir(resolvedConfig);
504
543
  const normalizedDtsOptions = normalizeDevDtsOptions(options.dts, resolvedConfig.root);
505
544
  if (typeof normalizedDtsOptions !== "object") return;
@@ -695,11 +734,11 @@ function normalizeShareItem(key, shareItem) {
695
734
  version = require(localPath).version;
696
735
  } catch (e2) {
697
736
  version = searchPackageVersion(key);
698
- if (!version) console.error(e1);
737
+ if (!version) mfError(e1);
699
738
  }
700
739
  }
701
740
  } catch (e) {
702
- console.error(`Unexpected error resolving version for ${key}:`, e);
741
+ mfError(`Unexpected error resolving version for ${key}:`, e);
703
742
  }
704
743
  if (typeof shareItem === "string") return {
705
744
  name: shareItem,
@@ -760,7 +799,7 @@ function getNormalizeShareItem(key) {
760
799
  return options.shared[key] || options.shared[removePathFromNpmPackage(key)] || options.shared[removePathFromNpmPackage(key) + "/"];
761
800
  }
762
801
  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'.`);
802
+ 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
803
  return config = {
765
804
  exposes: normalizeExposes(options.exposes),
766
805
  filename: options.filename || "remoteEntry-[hash]",
@@ -895,7 +934,7 @@ const cacheMap = {};
895
934
  */
896
935
  function assertModuleFound(tag, str = "") {
897
936
  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.`);
937
+ if (!module) throw createModuleFederationError(`Module Federation shared module '${str}' not found. Please ensure it's installed as a dependency in your package.json.`);
899
938
  return module;
900
939
  }
901
940
  var VirtualModule = class {
@@ -1139,8 +1178,12 @@ function getPreBuildLibImportId(pkg) {
1139
1178
  }
1140
1179
  const LOAD_SHARE_TAG = "__loadShare__";
1141
1180
  const loadShareCacheMap = {};
1142
- function getLoadShareModulePath(pkg, isRolldown, command) {
1181
+ function getLoadShareImportId(pkg, isRolldown, command) {
1143
1182
  if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, isRolldown || command === "build" ? ".mjs" : ".js");
1183
+ return loadShareCacheMap[pkg].getImportId();
1184
+ }
1185
+ function getLoadShareModulePath(pkg, isRolldown, command) {
1186
+ if (!loadShareCacheMap[pkg]) getLoadShareImportId(pkg, isRolldown, command);
1144
1187
  return loadShareCacheMap[pkg].getPath();
1145
1188
  }
1146
1189
  function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
@@ -1156,8 +1199,8 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
1156
1199
  if (namedExports.length > 0) {
1157
1200
  const destructure = `const { ${namedExports.map((name, i) => `${name}: __mf_${i}`).join(", ")} } = exportModule;`;
1158
1201
  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";
1202
+ exportLine = useESM ? `export default exportModule.default ?? exportModule;\n ${destructure}\n ${namedExportLine}` : `module.exports = exportModule;\n ${destructure}\n Object.assign(module.exports, { ${namedExports.map((name, i) => `"${name}": __mf_${i}`).join(", ")} });`;
1203
+ } else exportLine = useESM ? `export default exportModule.default ?? exportModule\n export * from ${JSON.stringify(getPreBuildLibImportId(pkg))}` : "module.exports = exportModule";
1161
1204
  loadShareCacheMap[pkg].writeSync(`
1162
1205
  import ${JSON.stringify(getPreBuildLibImportId(pkg))};
1163
1206
  ${command !== "build" ? `;() => import(${JSON.stringify(pkg)}).catch(() => {});` : ""}
@@ -1209,7 +1252,7 @@ function generateLocalSharedImportMap() {
1209
1252
  const shareItem = getNormalizeShareItem(pkg);
1210
1253
  return `
1211
1254
  ${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");
1255
+ ${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");
1213
1256
  return pkg;` : `let pkg = await import("${getPreBuildLibImportId(pkg)}");
1214
1257
  return pkg;`}
1215
1258
  }
@@ -1229,7 +1272,7 @@ function generateLocalSharedImportMap() {
1229
1272
  from: ${JSON.stringify(options.name)},
1230
1273
  async get () {
1231
1274
  if (${shareItem.shareConfig.import === false}) {
1232
- throw new Error(\`Shared module '\${${JSON.stringify(key)}}' must be provided by host\`);
1275
+ throw new Error(\`[Module Federation] Shared module '\${${JSON.stringify(key)}}' must be provided by host\`);
1233
1276
  }
1234
1277
  usedShared[${JSON.stringify(key)}].loaded = true
1235
1278
  const {${JSON.stringify(key)}: pkgDynamicImport} = importMap
@@ -1336,14 +1379,14 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1336
1379
  initScope
1337
1380
  }));
1338
1381
  } catch (e) {
1339
- console.error(e)
1382
+ console.error('[Module Federation]', e)
1340
1383
  }
1341
1384
  return initRes
1342
1385
  }
1343
1386
 
1344
1387
  async function getExposes(moduleName) {
1345
1388
  const exposesMap = await getExposesMap()
1346
- if (!(moduleName in exposesMap)) throw new Error(\`Module \${moduleName} does not exist in container.\`)
1389
+ if (!(moduleName in exposesMap)) throw new Error(\`[Module Federation] Module \${moduleName} does not exist in container.\`)
1347
1390
  return (exposesMap[moduleName])().then(res => () => res)
1348
1391
  }
1349
1392
  export {
@@ -1760,14 +1803,14 @@ const promise = new Promise((resolve, reject) => {
1760
1803
  });
1761
1804
  function setParseTimeout(timeout) {
1762
1805
  if (!_parseTimeout) _parseTimeout = setTimeout(() => {
1763
- console.warn(`Parse timeout (${timeout}s) - forcing resolve`);
1806
+ mfWarn(`Parse timeout (${timeout}s) - forcing resolve`);
1764
1807
  _resolve(1);
1765
1808
  }, timeout * 1e3);
1766
1809
  }
1767
1810
  function resetIdleTimeout(timeout) {
1768
1811
  clearTimeout(_parseTimeout);
1769
1812
  _parseTimeout = setTimeout(() => {
1770
- console.warn(`moduleParseIdleTimeout: no module activity for ${timeout}s, forcing resolve. Some shared/remote dependencies may be missing. Consider increasing moduleParseIdleTimeout.`);
1813
+ mfWarn(`moduleParseIdleTimeout: no module activity for ${timeout}s, forcing resolve. Some shared/remote dependencies may be missing. Consider increasing moduleParseIdleTimeout.`);
1771
1814
  _resolve(1);
1772
1815
  }, timeout * 1e3);
1773
1816
  }
@@ -1888,7 +1931,7 @@ function pluginProxyRemotes_default(options) {
1888
1931
  return {
1889
1932
  name: "proxyRemotes",
1890
1933
  config(config, { command: _command }) {
1891
- const isRolldown = !!this?.meta?.rolldownVersion;
1934
+ const isRolldown = getIsRolldown(this);
1892
1935
  Object.keys(remotes).forEach((key) => {
1893
1936
  const remote = remotes[key];
1894
1937
  config.resolve.alias.push({
@@ -1960,7 +2003,7 @@ function proxySharedModule(options) {
1960
2003
  config(config, { command }) {
1961
2004
  setPackageDetectionCwd(config.root || process.cwd());
1962
2005
  isVinext = hasPackageDependency("vinext");
1963
- const isRolldown = !!this?.meta?.rolldownVersion;
2006
+ const isRolldown = getIsRolldown(this);
1964
2007
  _command = command;
1965
2008
  config.resolve.alias.push(...Object.keys(shared).filter((key) => !(isVinext && key === "react")).map((key) => {
1966
2009
  const keyBase = key.endsWith("/") ? key.slice(0, -1) : key;
@@ -2040,7 +2083,6 @@ const VarRemoteEntry = () => {
2040
2083
  if (req.url?.replace(/\?.*/, "") === (viteConfig.base + varFilename).replace(/^\/?/, "/")) {
2041
2084
  res.setHeader("Content-Type", "text/javascript");
2042
2085
  res.setHeader("Access-Control-Allow-Origin", "*");
2043
- console.log({ filename });
2044
2086
  res.end(generateVarRemoteEntry(filename));
2045
2087
  } else next();
2046
2088
  });
@@ -2056,9 +2098,9 @@ const VarRemoteEntry = () => {
2056
2098
  },
2057
2099
  async generateBundle(options, bundle) {
2058
2100
  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).`);
2101
+ 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
2102
  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`);
2103
+ if (!remoteEntryFile) throw createModuleFederationError(`Couldn't find a remoteEntry chunk file for ${mfOptions.filename}, can't generate varRemoteEntry file`);
2062
2104
  this.emitFile({
2063
2105
  type: "asset",
2064
2106
  fileName: varFilename,
@@ -2083,7 +2125,7 @@ const VarRemoteEntry = () => {
2083
2125
  function getScriptUrl() {
2084
2126
  const currentScript = document.currentScript;
2085
2127
  if (!currentScript) {
2086
- console.error("[VarRemoteEntry] ${varFilename} script should be called from sync <script> tag (document.currentScript is undefined)")
2128
+ console.error("[Module Federation] ${varFilename} script should be called from sync <script> tag (document.currentScript is undefined)")
2087
2129
  return '/';
2088
2130
  }
2089
2131
  return document.currentScript.src.replace(/\\/[^/]*$/, '/');
@@ -2182,6 +2224,25 @@ var normalizeOptimizeDeps_default = {
2182
2224
  };
2183
2225
  //#endregion
2184
2226
  //#region src/index.ts
2227
+ const UNSAFE_JS_SOURCE_CHAR_MAP = {
2228
+ "<": "\\u003C",
2229
+ ">": "\\u003E",
2230
+ "/": "\\u002F",
2231
+ "\\": "\\\\",
2232
+ "\b": "\\b",
2233
+ "\f": "\\f",
2234
+ "\n": "\\n",
2235
+ "\r": "\\r",
2236
+ " ": "\\t",
2237
+ "\0": "\\0",
2238
+ "\u2028": "\\u2028",
2239
+ "\u2029": "\\u2029"
2240
+ };
2241
+ function escapeUnsafeJsSourceChars(str) {
2242
+ return str.replace(/[<>/\\\b\f\n\r\t\0\u2028\u2029]/g, (char) => {
2243
+ return UNSAFE_JS_SOURCE_CHAR_MAP[char] ?? char;
2244
+ });
2245
+ }
2185
2246
  /**
2186
2247
  * Plugin that runs FIRST to create virtual module files in the config hook.
2187
2248
  * This prevents 504 "Outdated Optimize Dep" errors by ensuring files exist
@@ -2201,7 +2262,7 @@ function createEarlyVirtualModulesPlugin(options) {
2201
2262
  VirtualModule.ensureVirtualPackageExists();
2202
2263
  initVirtualModules(_command, getRemoteEntryId(options));
2203
2264
  if (_command !== "serve") return;
2204
- const isRolldown = !!this?.meta?.rolldownVersion;
2265
+ const isRolldown = getIsRolldown(this);
2205
2266
  if (remotes && Object.keys(remotes).length > 0) for (const key of Object.keys(remotes)) addUsedRemote(key, key);
2206
2267
  if (shared && Object.keys(shared).length > 0) {
2207
2268
  config.optimizeDeps = config.optimizeDeps || {};
@@ -2218,6 +2279,7 @@ function createEarlyVirtualModulesPlugin(options) {
2218
2279
  writeLoadShareModule(key, shareItem, _command, isRolldown);
2219
2280
  writePreBuildLibPath(key);
2220
2281
  addUsedShares(key);
2282
+ config.optimizeDeps.include.push(getLoadShareImportId(key, isRolldown, _command));
2221
2283
  config.optimizeDeps.include.push(getPreBuildLibImportId(key));
2222
2284
  }
2223
2285
  writeLocalSharedImportMap();
@@ -2229,7 +2291,7 @@ function federation(mfUserOptions) {
2229
2291
  const options = normalizeModuleFederationOptions(mfUserOptions);
2230
2292
  const isVinext = hasPackageDependency("vinext");
2231
2293
  const { name, remotes, shared, filename, hostInitInjectLocation } = options;
2232
- if (!name) throw new Error("name is required");
2294
+ if (!name) throw createModuleFederationError("name is required");
2233
2295
  const remoteEntryId = getRemoteEntryId(options);
2234
2296
  const virtualExposesId = getVirtualExposesId(options);
2235
2297
  let command;
@@ -2315,7 +2377,16 @@ function federation(mfUserOptions) {
2315
2377
  }
2316
2378
  };
2317
2379
  }
2380
+ let warnedAboutCodeSplitting = false;
2381
+ const ensureCodeSplitting = (output) => {
2382
+ if (output?.codeSplitting !== false) return;
2383
+ delete output.codeSplitting;
2384
+ if (warnedAboutCodeSplitting) return;
2385
+ warnedAboutCodeSplitting = true;
2386
+ mfWarn("Ignoring `build.rolldownOptions.output.codeSplitting = false` because module federation requires chunk splitting.");
2387
+ };
2318
2388
  const applyManualChunks = (output) => {
2389
+ ensureCodeSplitting(output);
2319
2390
  const existingManualChunks = output.manualChunks;
2320
2391
  output.manualChunks = function(id) {
2321
2392
  if (id.includes(runtimeInitId)) return "runtimeInit";
@@ -2537,7 +2608,7 @@ function federation(mfUserOptions) {
2537
2608
  enforce: "post",
2538
2609
  _options: options,
2539
2610
  config(config, { command: _command }) {
2540
- const isRolldown = !!this?.meta?.rolldownVersion;
2611
+ const isRolldown = getIsRolldown(this);
2541
2612
  let implementation = options.implementation;
2542
2613
  if (isRolldown) implementation = implementation.replace(/\.cjs(\.js)?$/, ".js");
2543
2614
  config.resolve.alias.push({
@@ -2566,7 +2637,7 @@ function federation(mfUserOptions) {
2566
2637
  const resolvedTarget = options.target ?? (config.build?.ssr ? "node" : "web");
2567
2638
  if (!config.define) config.define = {};
2568
2639
  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.`);
2640
+ 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
2641
  }
2571
2642
  },
2572
2643
  ...Manifest(),
@@ -2579,13 +2650,18 @@ function federation(mfUserOptions) {
2579
2650
  for (const chunk of Object.values(bundle)) {
2580
2651
  if (chunk.type !== "chunk") continue;
2581
2652
  if (!chunk.code.includes("modulepreload")) continue;
2582
- const replacement = "=function($1){return new URL(\"../\"+$1,import.meta.url).href}";
2653
+ const chunkDir = pathe.default.dirname(chunk.fileName);
2654
+ const prefixToRoot = chunkDir === "." ? "" : `${pathe.default.relative(chunkDir, ".")}/`;
2655
+ const replacementExpr = prefixToRoot ? `${escapeUnsafeJsSourceChars(JSON.stringify(prefixToRoot))}+$1` : "$1";
2656
+ const replacement = `=function($1){return new URL(${replacementExpr},import.meta.url).href}`;
2583
2657
  const replaced = chunk.code.replace(/=\(?(\w+)(?:,\w+)?\)?\s*=>\s*["'`][^"'`]*["'`]\s*\+\s*\1/, replacement);
2584
2658
  if (replaced !== chunk.code) {
2585
2659
  chunk.code = replaced;
2586
2660
  continue;
2587
2661
  }
2588
2662
  chunk.code = chunk.code.replace(/=function\((\w+)(?:,\w+)?\)\{return\s*["'`][^"'`]*["'`]\s*\+\s*\1\s*\}/, replacement);
2663
+ chunk.code = chunk.code.replace(/=function\((\w+)(?:,\w+)?\)\{return new URL\("\.\.\/"\+\1,import\.meta\.url\)\.href\}/, replacement);
2664
+ chunk.code = chunk.code.replace(/new URL\("\.\.\/"\+(\w+),import\.meta\.url\)\.href/g, `new URL(${replacementExpr},import.meta.url).href`);
2589
2665
  }
2590
2666
  }
2591
2667
  }] : []
package/lib/index.mjs CHANGED
@@ -59,6 +59,38 @@ function inlineEntryScripts(html, initSrc) {
59
59
  return html.replace("<head>", `<head><script type="module" src=${JSON.stringify(src)}><\/script>`);
60
60
  }
61
61
  //#endregion
62
+ //#region src/utils/logger.ts
63
+ const MODULE_FEDERATION_LOG_PREFIX = "[Module Federation]";
64
+ function formatModuleFederationMessage(message) {
65
+ return `${MODULE_FEDERATION_LOG_PREFIX} ${message}`;
66
+ }
67
+ function createModuleFederationError(message) {
68
+ return new Error(formatModuleFederationMessage(message));
69
+ }
70
+ function toConsoleArgs(message, rest = []) {
71
+ if (typeof message === "string") return [formatModuleFederationMessage(message), ...rest];
72
+ if (message === void 0) return [MODULE_FEDERATION_LOG_PREFIX, ...rest];
73
+ return [
74
+ MODULE_FEDERATION_LOG_PREFIX,
75
+ message,
76
+ ...rest
77
+ ];
78
+ }
79
+ const moduleFederationConsole = {
80
+ log(message, ...rest) {
81
+ console.log(...toConsoleArgs(message, rest));
82
+ },
83
+ warn(message, ...rest) {
84
+ console.warn(...toConsoleArgs(message, rest));
85
+ },
86
+ error(message, ...rest) {
87
+ console.error(...toConsoleArgs(message, rest));
88
+ }
89
+ };
90
+ moduleFederationConsole.log;
91
+ const mfWarn = moduleFederationConsole.warn;
92
+ const mfError = moduleFederationConsole.error;
93
+ //#endregion
62
94
  //#region src/utils/packageUtils.ts
63
95
  const dependencyPresenceCache = /* @__PURE__ */ new Map();
64
96
  let packageDetectionCwd;
@@ -82,7 +114,7 @@ function setPackageDetectionCwd(cwd) {
82
114
  * @returns {string} - The encoded file name.
83
115
  */
84
116
  function packageNameEncode(name) {
85
- if (typeof name !== "string") throw new Error("A string package name is required");
117
+ if (typeof name !== "string") throw createModuleFederationError("A string package name is required");
86
118
  return name.replace(/@/g, "_mf_0_").replace(/\//g, "_mf_1_").replace(/-/g, "_mf_2_").replace(/\./g, "_mf_3_");
87
119
  }
88
120
  /**
@@ -91,7 +123,7 @@ function packageNameEncode(name) {
91
123
  * @returns {string} - The decoded package name.
92
124
  */
93
125
  function packageNameDecode(encoded) {
94
- if (typeof encoded !== "string") throw new Error("A string encoded file name is required");
126
+ if (typeof encoded !== "string") throw createModuleFederationError("A string encoded file name is required");
95
127
  return encoded.replace(/_mf_0_/g, "@").replace(/_mf_1_/g, "/").replace(/_mf_2_/g, "-").replace(/_mf_3_/g, ".");
96
128
  }
97
129
  /**
@@ -103,6 +135,13 @@ function removePathFromNpmPackage(packageString) {
103
135
  const match = packageString.match(/^(?:@[^/]+\/)?[^/]+/);
104
136
  return match ? match[0] : packageString;
105
137
  }
138
+ /**
139
+ * Detect whether the current bundler is Rolldown (Vite 8+) by checking
140
+ * for `meta.rolldownVersion` on the plugin hook context.
141
+ */
142
+ function getIsRolldown(ctx) {
143
+ return !!ctx?.meta?.rolldownVersion;
144
+ }
106
145
  function hasPackageDependency(dependencyName, cwd = packageDetectionCwd || process.cwd()) {
107
146
  const cacheKey = getDependencyCacheKey(cwd, dependencyName);
108
147
  const cached = dependencyPresenceCache.get(cacheKey);
@@ -223,7 +262,7 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry" }) => {
223
262
  if (typeof result === "string") return result;
224
263
  if (result && typeof result === "object") {
225
264
  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.");
265
+ mfWarn("renderBuiltUrl returned runtime code for HTML injection. Runtime code cannot be used in <script src=\"\">. Falling back to base path.");
227
266
  return viteConfig.base + file;
228
267
  }
229
268
  if (result.relative) return file;
@@ -288,11 +327,11 @@ function checkAliasConflicts(options) {
288
327
  });
289
328
  }
290
329
  if (conflicts.length > 0) {
291
- config.logger.warn("\n[Module Federation] Detected alias conflicts with shared modules:");
330
+ mfWarn("Detected alias conflicts with shared modules:");
292
331
  conflicts.forEach(({ sharedModule, alias, target }) => {
293
- config.logger.warn(` - Shared module "${sharedModule}" is aliased by "${alias}" to "${target}"`);
332
+ mfWarn(`Shared module "${sharedModule}" is aliased by "${alias}" to "${target}"`);
294
333
  });
295
- config.logger.warn(" This may cause runtime errors as the shared module will bypass Module Federation's sharing mechanism.");
334
+ mfWarn("This may cause runtime errors as the shared module will bypass Module Federation's sharing mechanism.");
296
335
  }
297
336
  }
298
337
  };
@@ -321,7 +360,7 @@ function PluginDevProxyModuleTopLevelAwait() {
321
360
  try {
322
361
  ast = this.parse(code, { allowReturnOutsideFunction: true });
323
362
  } catch (e) {
324
- throw new Error(`${id}: ${e}`);
363
+ throw createModuleFederationError(`${id}: ${e}`);
325
364
  }
326
365
  const magicString = new MagicString(code);
327
366
  const walk = await loadWalk();
@@ -449,7 +488,7 @@ const normalizeDevDtsOptions = (dts, context) => {
449
488
  const logDtsError = (error, dtsOptions) => {
450
489
  if (dtsOptions === false) return;
451
490
  if (typeof dtsOptions === "object" && dtsOptions && dtsOptions.displayErrorInTerminal === false) return;
452
- console.error(error);
491
+ mfError(error);
453
492
  };
454
493
  function pluginDts(options) {
455
494
  if (options.dts === false) return [];
@@ -477,7 +516,7 @@ function pluginDts(options) {
477
516
  if (!normalizedDevOptions || !resolvedConfig) return;
478
517
  const devOptions = normalizedDevOptions;
479
518
  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!");
519
+ if (!options.name) throw createModuleFederationError("name is required if you want to enable dev server!");
481
520
  const outputDir = resolveOutputDir(resolvedConfig);
482
521
  const normalizedDtsOptions = normalizeDevDtsOptions(options.dts, resolvedConfig.root);
483
522
  if (typeof normalizedDtsOptions !== "object") return;
@@ -672,11 +711,11 @@ function normalizeShareItem(key, shareItem) {
672
711
  version = __require(path$1.join(process.cwd(), "node_modules", removePathFromNpmPackage(key), "package.json")).version;
673
712
  } catch (e2) {
674
713
  version = searchPackageVersion(key);
675
- if (!version) console.error(e1);
714
+ if (!version) mfError(e1);
676
715
  }
677
716
  }
678
717
  } catch (e) {
679
- console.error(`Unexpected error resolving version for ${key}:`, e);
718
+ mfError(`Unexpected error resolving version for ${key}:`, e);
680
719
  }
681
720
  if (typeof shareItem === "string") return {
682
721
  name: shareItem,
@@ -737,7 +776,7 @@ function getNormalizeShareItem(key) {
737
776
  return options.shared[key] || options.shared[removePathFromNpmPackage(key)] || options.shared[removePathFromNpmPackage(key) + "/"];
738
777
  }
739
778
  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'.`);
779
+ 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
780
  return config = {
742
781
  exposes: normalizeExposes(options.exposes),
743
782
  filename: options.filename || "remoteEntry-[hash]",
@@ -872,7 +911,7 @@ const cacheMap = {};
872
911
  */
873
912
  function assertModuleFound(tag, str = "") {
874
913
  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.`);
914
+ if (!module) throw createModuleFederationError(`Module Federation shared module '${str}' not found. Please ensure it's installed as a dependency in your package.json.`);
876
915
  return module;
877
916
  }
878
917
  var VirtualModule = class {
@@ -1116,8 +1155,12 @@ function getPreBuildLibImportId(pkg) {
1116
1155
  }
1117
1156
  const LOAD_SHARE_TAG = "__loadShare__";
1118
1157
  const loadShareCacheMap = {};
1119
- function getLoadShareModulePath(pkg, isRolldown, command) {
1158
+ function getLoadShareImportId(pkg, isRolldown, command) {
1120
1159
  if (!loadShareCacheMap[pkg]) loadShareCacheMap[pkg] = new VirtualModule(pkg, LOAD_SHARE_TAG, isRolldown || command === "build" ? ".mjs" : ".js");
1160
+ return loadShareCacheMap[pkg].getImportId();
1161
+ }
1162
+ function getLoadShareModulePath(pkg, isRolldown, command) {
1163
+ if (!loadShareCacheMap[pkg]) getLoadShareImportId(pkg, isRolldown, command);
1121
1164
  return loadShareCacheMap[pkg].getPath();
1122
1165
  }
1123
1166
  function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
@@ -1133,8 +1176,8 @@ function writeLoadShareModule(pkg, shareItem, command, isRolldown) {
1133
1176
  if (namedExports.length > 0) {
1134
1177
  const destructure = `const { ${namedExports.map((name, i) => `${name}: __mf_${i}`).join(", ")} } = exportModule;`;
1135
1178
  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";
1179
+ exportLine = useESM ? `export default exportModule.default ?? exportModule;\n ${destructure}\n ${namedExportLine}` : `module.exports = exportModule;\n ${destructure}\n Object.assign(module.exports, { ${namedExports.map((name, i) => `"${name}": __mf_${i}`).join(", ")} });`;
1180
+ } else exportLine = useESM ? `export default exportModule.default ?? exportModule\n export * from ${JSON.stringify(getPreBuildLibImportId(pkg))}` : "module.exports = exportModule";
1138
1181
  loadShareCacheMap[pkg].writeSync(`
1139
1182
  import ${JSON.stringify(getPreBuildLibImportId(pkg))};
1140
1183
  ${command !== "build" ? `;() => import(${JSON.stringify(pkg)}).catch(() => {});` : ""}
@@ -1186,7 +1229,7 @@ function generateLocalSharedImportMap() {
1186
1229
  const shareItem = getNormalizeShareItem(pkg);
1187
1230
  return `
1188
1231
  ${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");
1232
+ ${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");
1190
1233
  return pkg;` : `let pkg = await import("${getPreBuildLibImportId(pkg)}");
1191
1234
  return pkg;`}
1192
1235
  }
@@ -1206,7 +1249,7 @@ function generateLocalSharedImportMap() {
1206
1249
  from: ${JSON.stringify(options.name)},
1207
1250
  async get () {
1208
1251
  if (${shareItem.shareConfig.import === false}) {
1209
- throw new Error(\`Shared module '\${${JSON.stringify(key)}}' must be provided by host\`);
1252
+ throw new Error(\`[Module Federation] Shared module '\${${JSON.stringify(key)}}' must be provided by host\`);
1210
1253
  }
1211
1254
  usedShared[${JSON.stringify(key)}].loaded = true
1212
1255
  const {${JSON.stringify(key)}: pkgDynamicImport} = importMap
@@ -1313,14 +1356,14 @@ function generateRemoteEntry(options, virtualExposesId = getVirtualExposesId(opt
1313
1356
  initScope
1314
1357
  }));
1315
1358
  } catch (e) {
1316
- console.error(e)
1359
+ console.error('[Module Federation]', e)
1317
1360
  }
1318
1361
  return initRes
1319
1362
  }
1320
1363
 
1321
1364
  async function getExposes(moduleName) {
1322
1365
  const exposesMap = await getExposesMap()
1323
- if (!(moduleName in exposesMap)) throw new Error(\`Module \${moduleName} does not exist in container.\`)
1366
+ if (!(moduleName in exposesMap)) throw new Error(\`[Module Federation] Module \${moduleName} does not exist in container.\`)
1324
1367
  return (exposesMap[moduleName])().then(res => () => res)
1325
1368
  }
1326
1369
  export {
@@ -1737,14 +1780,14 @@ const promise = new Promise((resolve, reject) => {
1737
1780
  });
1738
1781
  function setParseTimeout(timeout) {
1739
1782
  if (!_parseTimeout) _parseTimeout = setTimeout(() => {
1740
- console.warn(`Parse timeout (${timeout}s) - forcing resolve`);
1783
+ mfWarn(`Parse timeout (${timeout}s) - forcing resolve`);
1741
1784
  _resolve(1);
1742
1785
  }, timeout * 1e3);
1743
1786
  }
1744
1787
  function resetIdleTimeout(timeout) {
1745
1788
  clearTimeout(_parseTimeout);
1746
1789
  _parseTimeout = setTimeout(() => {
1747
- console.warn(`moduleParseIdleTimeout: no module activity for ${timeout}s, forcing resolve. Some shared/remote dependencies may be missing. Consider increasing moduleParseIdleTimeout.`);
1790
+ mfWarn(`moduleParseIdleTimeout: no module activity for ${timeout}s, forcing resolve. Some shared/remote dependencies may be missing. Consider increasing moduleParseIdleTimeout.`);
1748
1791
  _resolve(1);
1749
1792
  }, timeout * 1e3);
1750
1793
  }
@@ -1865,7 +1908,7 @@ function pluginProxyRemotes_default(options) {
1865
1908
  return {
1866
1909
  name: "proxyRemotes",
1867
1910
  config(config, { command: _command }) {
1868
- const isRolldown = !!this?.meta?.rolldownVersion;
1911
+ const isRolldown = getIsRolldown(this);
1869
1912
  Object.keys(remotes).forEach((key) => {
1870
1913
  const remote = remotes[key];
1871
1914
  config.resolve.alias.push({
@@ -1937,7 +1980,7 @@ function proxySharedModule(options) {
1937
1980
  config(config, { command }) {
1938
1981
  setPackageDetectionCwd(config.root || process.cwd());
1939
1982
  isVinext = hasPackageDependency("vinext");
1940
- const isRolldown = !!this?.meta?.rolldownVersion;
1983
+ const isRolldown = getIsRolldown(this);
1941
1984
  _command = command;
1942
1985
  config.resolve.alias.push(...Object.keys(shared).filter((key) => !(isVinext && key === "react")).map((key) => {
1943
1986
  const keyBase = key.endsWith("/") ? key.slice(0, -1) : key;
@@ -2017,7 +2060,6 @@ const VarRemoteEntry = () => {
2017
2060
  if (req.url?.replace(/\?.*/, "") === (viteConfig.base + varFilename).replace(/^\/?/, "/")) {
2018
2061
  res.setHeader("Content-Type", "text/javascript");
2019
2062
  res.setHeader("Access-Control-Allow-Origin", "*");
2020
- console.log({ filename });
2021
2063
  res.end(generateVarRemoteEntry(filename));
2022
2064
  } else next();
2023
2065
  });
@@ -2033,9 +2075,9 @@ const VarRemoteEntry = () => {
2033
2075
  },
2034
2076
  async generateBundle(options, bundle) {
2035
2077
  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).`);
2078
+ 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
2079
  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`);
2080
+ if (!remoteEntryFile) throw createModuleFederationError(`Couldn't find a remoteEntry chunk file for ${mfOptions.filename}, can't generate varRemoteEntry file`);
2039
2081
  this.emitFile({
2040
2082
  type: "asset",
2041
2083
  fileName: varFilename,
@@ -2060,7 +2102,7 @@ const VarRemoteEntry = () => {
2060
2102
  function getScriptUrl() {
2061
2103
  const currentScript = document.currentScript;
2062
2104
  if (!currentScript) {
2063
- console.error("[VarRemoteEntry] ${varFilename} script should be called from sync <script> tag (document.currentScript is undefined)")
2105
+ console.error("[Module Federation] ${varFilename} script should be called from sync <script> tag (document.currentScript is undefined)")
2064
2106
  return '/';
2065
2107
  }
2066
2108
  return document.currentScript.src.replace(/\\/[^/]*$/, '/');
@@ -2159,6 +2201,25 @@ var normalizeOptimizeDeps_default = {
2159
2201
  };
2160
2202
  //#endregion
2161
2203
  //#region src/index.ts
2204
+ const UNSAFE_JS_SOURCE_CHAR_MAP = {
2205
+ "<": "\\u003C",
2206
+ ">": "\\u003E",
2207
+ "/": "\\u002F",
2208
+ "\\": "\\\\",
2209
+ "\b": "\\b",
2210
+ "\f": "\\f",
2211
+ "\n": "\\n",
2212
+ "\r": "\\r",
2213
+ " ": "\\t",
2214
+ "\0": "\\0",
2215
+ "\u2028": "\\u2028",
2216
+ "\u2029": "\\u2029"
2217
+ };
2218
+ function escapeUnsafeJsSourceChars(str) {
2219
+ return str.replace(/[<>/\\\b\f\n\r\t\0\u2028\u2029]/g, (char) => {
2220
+ return UNSAFE_JS_SOURCE_CHAR_MAP[char] ?? char;
2221
+ });
2222
+ }
2162
2223
  /**
2163
2224
  * Plugin that runs FIRST to create virtual module files in the config hook.
2164
2225
  * This prevents 504 "Outdated Optimize Dep" errors by ensuring files exist
@@ -2178,7 +2239,7 @@ function createEarlyVirtualModulesPlugin(options) {
2178
2239
  VirtualModule.ensureVirtualPackageExists();
2179
2240
  initVirtualModules(_command, getRemoteEntryId(options));
2180
2241
  if (_command !== "serve") return;
2181
- const isRolldown = !!this?.meta?.rolldownVersion;
2242
+ const isRolldown = getIsRolldown(this);
2182
2243
  if (remotes && Object.keys(remotes).length > 0) for (const key of Object.keys(remotes)) addUsedRemote(key, key);
2183
2244
  if (shared && Object.keys(shared).length > 0) {
2184
2245
  config.optimizeDeps = config.optimizeDeps || {};
@@ -2195,6 +2256,7 @@ function createEarlyVirtualModulesPlugin(options) {
2195
2256
  writeLoadShareModule(key, shareItem, _command, isRolldown);
2196
2257
  writePreBuildLibPath(key);
2197
2258
  addUsedShares(key);
2259
+ config.optimizeDeps.include.push(getLoadShareImportId(key, isRolldown, _command));
2198
2260
  config.optimizeDeps.include.push(getPreBuildLibImportId(key));
2199
2261
  }
2200
2262
  writeLocalSharedImportMap();
@@ -2206,7 +2268,7 @@ function federation(mfUserOptions) {
2206
2268
  const options = normalizeModuleFederationOptions(mfUserOptions);
2207
2269
  const isVinext = hasPackageDependency("vinext");
2208
2270
  const { name, remotes, shared, filename, hostInitInjectLocation } = options;
2209
- if (!name) throw new Error("name is required");
2271
+ if (!name) throw createModuleFederationError("name is required");
2210
2272
  const remoteEntryId = getRemoteEntryId(options);
2211
2273
  const virtualExposesId = getVirtualExposesId(options);
2212
2274
  let command;
@@ -2292,7 +2354,16 @@ function federation(mfUserOptions) {
2292
2354
  }
2293
2355
  };
2294
2356
  }
2357
+ let warnedAboutCodeSplitting = false;
2358
+ const ensureCodeSplitting = (output) => {
2359
+ if (output?.codeSplitting !== false) return;
2360
+ delete output.codeSplitting;
2361
+ if (warnedAboutCodeSplitting) return;
2362
+ warnedAboutCodeSplitting = true;
2363
+ mfWarn("Ignoring `build.rolldownOptions.output.codeSplitting = false` because module federation requires chunk splitting.");
2364
+ };
2295
2365
  const applyManualChunks = (output) => {
2366
+ ensureCodeSplitting(output);
2296
2367
  const existingManualChunks = output.manualChunks;
2297
2368
  output.manualChunks = function(id) {
2298
2369
  if (id.includes(runtimeInitId)) return "runtimeInit";
@@ -2514,7 +2585,7 @@ function federation(mfUserOptions) {
2514
2585
  enforce: "post",
2515
2586
  _options: options,
2516
2587
  config(config, { command: _command }) {
2517
- const isRolldown = !!this?.meta?.rolldownVersion;
2588
+ const isRolldown = getIsRolldown(this);
2518
2589
  let implementation = options.implementation;
2519
2590
  if (isRolldown) implementation = implementation.replace(/\.cjs(\.js)?$/, ".js");
2520
2591
  config.resolve.alias.push({
@@ -2543,7 +2614,7 @@ function federation(mfUserOptions) {
2543
2614
  const resolvedTarget = options.target ?? (config.build?.ssr ? "node" : "web");
2544
2615
  if (!config.define) config.define = {};
2545
2616
  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.`);
2617
+ 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
2618
  }
2548
2619
  },
2549
2620
  ...Manifest(),
@@ -2556,13 +2627,18 @@ function federation(mfUserOptions) {
2556
2627
  for (const chunk of Object.values(bundle)) {
2557
2628
  if (chunk.type !== "chunk") continue;
2558
2629
  if (!chunk.code.includes("modulepreload")) continue;
2559
- const replacement = "=function($1){return new URL(\"../\"+$1,import.meta.url).href}";
2630
+ const chunkDir = path.dirname(chunk.fileName);
2631
+ const prefixToRoot = chunkDir === "." ? "" : `${path.relative(chunkDir, ".")}/`;
2632
+ const replacementExpr = prefixToRoot ? `${escapeUnsafeJsSourceChars(JSON.stringify(prefixToRoot))}+$1` : "$1";
2633
+ const replacement = `=function($1){return new URL(${replacementExpr},import.meta.url).href}`;
2560
2634
  const replaced = chunk.code.replace(/=\(?(\w+)(?:,\w+)?\)?\s*=>\s*["'`][^"'`]*["'`]\s*\+\s*\1/, replacement);
2561
2635
  if (replaced !== chunk.code) {
2562
2636
  chunk.code = replaced;
2563
2637
  continue;
2564
2638
  }
2565
2639
  chunk.code = chunk.code.replace(/=function\((\w+)(?:,\w+)?\)\{return\s*["'`][^"'`]*["'`]\s*\+\s*\1\s*\}/, replacement);
2640
+ chunk.code = chunk.code.replace(/=function\((\w+)(?:,\w+)?\)\{return new URL\("\.\.\/"\+\1,import\.meta\.url\)\.href\}/, replacement);
2641
+ chunk.code = chunk.code.replace(/new URL\("\.\.\/"\+(\w+),import\.meta\.url\)\.href/g, `new URL(${replacementExpr},import.meta.url).href`);
2566
2642
  }
2567
2643
  }
2568
2644
  }] : []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/vite",
3
- "version": "1.13.1",
3
+ "version": "1.13.2",
4
4
  "description": "Vite plugin for Module Federation",
5
5
  "type": "module",
6
6
  "main": "./lib/index.cjs",
@@ -30,8 +30,9 @@
30
30
  "dev-rv": "pnpm clean && pnpm -filter 'examples-rust-vite*' run dev",
31
31
  "preview-rv": "pnpm clean && pnpm -filter 'examples-rust-vite*' run preview",
32
32
  "dev-vv": "pnpm clean && pnpm -filter 'examples-vite-vite*' run dev",
33
- "dev-nv": "pnpm clean && pnpm -filter 'examples-nuxt-vite-host' -filter 'examples-vite-vite-remote' run dev",
34
33
  "preview-vv": "pnpm clean && pnpm -filter 'examples-vite-vite*' --parallel run preview",
34
+ "mixed-vv:1": "pnpm clean && pnpm -filter 'examples-vite-vite*' run mixed:1",
35
+ "mixed-vv:2": "pnpm clean && pnpm -filter 'examples-vite-vite*' run mixed:2",
35
36
  "multi-example": "pnpm clean && pnpm --filter \"multi-example-*\" --parallel run start",
36
37
  "test": "vitest run --dir src",
37
38
  "test:integration": "vitest run integration",
@@ -66,9 +67,9 @@
66
67
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
67
68
  },
68
69
  "dependencies": {
69
- "@module-federation/dts-plugin": "2.2.2",
70
- "@module-federation/runtime": "2.2.2",
71
- "@module-federation/sdk": "2.2.2",
70
+ "@module-federation/dts-plugin": "2.2.3",
71
+ "@module-federation/runtime": "2.2.3",
72
+ "@module-federation/sdk": "2.2.3",
72
73
  "@rollup/pluginutils": "^5.3.0",
73
74
  "defu": "^6.1.4",
74
75
  "estree-walker": "^3.0.3",