@module-federation/vite 1.23.3 → 1.23.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/index.js +312 -153
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -3807,7 +3807,7 @@ function generateLocalSharedImportMap(options) {
3807
3807
  return pkg;`}
3808
3808
  }
3809
3809
  `;
3810
- }).join(",")}
3810
+ }).filter(Boolean).join(",")}
3811
3811
  }
3812
3812
  const usedShared = {
3813
3813
  ${orderedShares.map((key) => {
@@ -4408,7 +4408,14 @@ function generateRuntimeSharedCacheSeedCode(shareStrategy, options, command = "b
4408
4408
  );
4409
4409
  return;
4410
4410
  }
4411
- if (typeof isWebpackProvider === 'function' && isWebpackProvider(externalProvider)) return;
4411
+ // Leave an unloaded webpack provider to the late bridge, which only takes a
4412
+ // non-singleton of this share's own version; any other version seeds locally.
4413
+ if (
4414
+ typeof isWebpackProvider === 'function' &&
4415
+ isWebpackProvider(externalProvider) &&
4416
+ (share.shareConfig?.singleton ||
4417
+ __mfFindSharedProviderEntry(initialShared[pkg], externalProvider)?.version === share.version)
4418
+ ) return;
4412
4419
  }
4413
4420
  const providerKey = cacheDescriptor.canonical;
4414
4421
  const resolved = await __mfInitializeProviderOnce(providerKey, async () => {
@@ -5784,7 +5791,8 @@ function generateHostAutoInitCode(remoteEntryImport, _command = "build", options
5784
5791
  const cacheDescriptor = __mfGetSharedCacheDescriptor(pkg, share.shareConfig?.singleton, share.version, share.scope);
5785
5792
  if (
5786
5793
  __mfReadSharedCache(__mfModuleCache.share, cacheDescriptor) !== undefined &&
5787
- ${_command === "serve" ? `__mfReadSharedCacheOwner(__mfModuleCache.share, cacheDescriptor) !== undefined` : `(
5794
+ ${_command === "serve" ? `__mfReadSharedCacheOwner(__mfModuleCache.share, cacheDescriptor) !== undefined &&
5795
+ !(share.shareConfig?.singleton && __mfHasAlternativeSharedVersion(pkg, share))` : `(
5788
5796
  (!share.shareConfig?.singleton && __mfReadSharedCacheOwner(__mfModuleCache.share, cacheDescriptor) === ${cacheOwner}) ||
5789
5797
  (share.shareConfig?.singleton && !__mfHasAlternativeSharedVersion(pkg, share))
5790
5798
  )`}
@@ -6496,6 +6504,27 @@ function patchHashEntryFileNames(config, entryName, fileName) {
6496
6504
  patchBundlerOutput(config.build.rolldownOptions);
6497
6505
  Object.values(config.environments ?? {}).forEach((environment) => patchHashEntryFileNames(environment, entryName, fileName));
6498
6506
  }
6507
+ const ROLLDOWN_RUNTIME_GLOBAL = "__rolldown_runtime__";
6508
+ /**
6509
+ * Rolldown's dev runtime lives on `globalThis.__rolldown_runtime__`, and its
6510
+ * module registry is keyed by cwd-relative ids (`src/App.jsx`). A bundledDev
6511
+ * remote loaded into a bundledDev host would share the host's runtime, so the
6512
+ * remote's modules, hot contexts and HMR factories would collide with the
6513
+ * host's. Give each remote its own same-length global (sourcemaps stay valid)
6514
+ * in every chunk and HMR patch it serves.
6515
+ */
6516
+ function renameBundledDevRuntime(req, res, remoteName) {
6517
+ if (!req.url || !stripQueryAndHash(req.url).endsWith(".js")) return;
6518
+ const runtimeGlobal = `__mf_rt_${createHash("sha256").update(remoteName).digest("hex").slice(0, 10)}__`;
6519
+ const end = res.end;
6520
+ res.end = function(chunk, ...args) {
6521
+ if (typeof chunk === "string" || chunk instanceof Uint8Array) {
6522
+ const code = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
6523
+ if (code.includes(ROLLDOWN_RUNTIME_GLOBAL)) chunk = code.replace(/\b__rolldown_runtime__\b/g, runtimeGlobal);
6524
+ }
6525
+ return end.call(this, chunk, ...args);
6526
+ };
6527
+ }
6499
6528
  const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClientInjected, skipTransformFor = [], federationOptions }) => {
6500
6529
  const DEV_HTML_PROXY_PREFIX = "virtual:mf-html-entry-proxy?";
6501
6530
  const ENTRY_BOOTSTRAP_PARAM = "mf-entry-bootstrap";
@@ -6518,6 +6547,9 @@ const addEntry = ({ entryName, entryPath, fileName, inject = "entry", forceClien
6518
6547
  const virtualEntryCode = /* @__PURE__ */ new Map();
6519
6548
  const ignoredHtmlScriptSources = /* @__PURE__ */ new Set();
6520
6549
  let bootstrapDir = "";
6550
+ let isBundledDevRemote = false;
6551
+ let bundledDevRemoteEntryCode;
6552
+ let resolveBundledDevRemoteEntryCode;
6521
6553
  function skipSvelteKitSsrBuild() {
6522
6554
  return (_command === "build" || viteConfig?.command === "build") && viteConfig?.build?.ssr && hasPackageDependency("@sveltejs/kit");
6523
6555
  }
@@ -6616,7 +6648,7 @@ const __mfCurrentScript = document.currentScript;
6616
6648
  : import(src);
6617
6649
  ` : "";
6618
6650
  const importExpression = (src) => useSystemImportFallback ? `__mfImport(${JSON.stringify(src)})` : `import(${JSON.stringify(src)})`;
6619
- const isEncodedVirtualEntry = entrySrc.startsWith(VITE_ENCODED_NULL_BYTE_PREFIX);
6651
+ const isEncodedVirtualEntry = !options?.isBundled && entrySrc.startsWith(VITE_ENCODED_NULL_BYTE_PREFIX);
6620
6652
  const entryImportDeclaration = isEncodedVirtualEntry ? `const __mfEntryUrl = ${JSON.stringify(entrySrc)};
6621
6653
  ` : "";
6622
6654
  const entryImportExpression = isEncodedVirtualEntry ? "import(/* @vite-ignore */ __mfEntryUrl)" : importExpression(entrySrc);
@@ -6638,10 +6670,11 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6638
6670
  const shareItem = getNormalizeShareItem(pkg, federationOptions);
6639
6671
  const isExplicitShare = Object.hasOwn(federationOptions.shared, pkg);
6640
6672
  return shareItem?.shareConfig?.singleton === true && shareItem?.shareConfig?.import !== false && !shareItem?.shareConfig?.treeShaking && (isExplicitShare || typeof shareItem?.shareConfig?.import === "string" || Boolean(getProjectResolvedImportPath(pkg)));
6641
- }).map((pkg) => toViteEncodedId(getLoadShareModulePath(pkg, false, federationOptions))) : [];
6642
- const sharedPreloadBlock = sharedPreloadSources.length > 0 ? `
6643
- const __mfSharedPreloadUrls = ${JSON.stringify(sharedPreloadSources)};
6644
- await Promise.all(__mfSharedPreloadUrls.map((src) => import(/* @vite-ignore */ src).catch((err) => console.warn("[module-federation] shared preload failed:", src, err))));` : "";
6673
+ }).map((pkg) => getLoadShareModulePath(pkg, false, federationOptions)) : [];
6674
+ const sharedPreloadBlock = sharedPreloadSources.length === 0 ? "" : options?.isBundled ? `
6675
+ await Promise.all([${sharedPreloadSources.map((src) => `[${JSON.stringify(src)}, import(${JSON.stringify(src)})]`).join(", ")}].map(([src, load]) => load.catch((err) => console.warn("[module-federation] shared preload failed:", src, err))));` : `
6676
+ const __mfSharedPreloadUrls = ${JSON.stringify(sharedPreloadSources.map(toViteEncodedId))};
6677
+ await Promise.all(__mfSharedPreloadUrls.map((src) => import(/* @vite-ignore */ src).catch((err) => console.warn("[module-federation] shared preload failed:", src, err))));`;
6645
6678
  const remoteCachePrefix = getRuntimeRemoteCachePrefix(federationOptions);
6646
6679
  const preloadBlock = remotePreloads ? `
6647
6680
  const runtime = await initHost();
@@ -6768,19 +6801,6 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6768
6801
  apply: "serve",
6769
6802
  config(_config, { command }) {
6770
6803
  _command = command;
6771
- const isRemoteEntry = entryName === "remoteEntry" && federationOptions !== void 0 && isRemoteContainer(federationOptions);
6772
- if (command === "serve" && _config.experimental?.bundledDev && isRemoteEntry) {
6773
- _config.experimental = {
6774
- ..._config.experimental,
6775
- bundledDev: false
6776
- };
6777
- _config.environments ??= {};
6778
- _config.environments.client ??= {};
6779
- if (_config.environments.client.isBundled !== false) {
6780
- _config.environments.client.isBundled = false;
6781
- mfWarn("Vite bundledDev is disabled for the client environment of a Module Federation remote container so its remoteEntry keeps the standard init/get contract.");
6782
- }
6783
- }
6784
6804
  },
6785
6805
  configResolved(config) {
6786
6806
  viteConfig = config;
@@ -6793,6 +6813,10 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6793
6813
  devEntryPath = config.base + relativePath.replace(/^\//, "");
6794
6814
  }
6795
6815
  skipTransformIds = new Set(skipTransformFor.map(resolveProjectId));
6816
+ isBundledDevRemote = config.command === "serve" && entryName === "remoteEntry" && federationOptions !== void 0 && isRemoteContainer(federationOptions) && (config.environments?.client)?.isBundled === true;
6817
+ if (isBundledDevRemote) bundledDevRemoteEntryCode = new Promise((resolve) => {
6818
+ resolveBundledDevRemoteEntryCode = resolve;
6819
+ });
6796
6820
  },
6797
6821
  configureServer(server) {
6798
6822
  devServer = server;
@@ -6820,7 +6844,18 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6820
6844
  }
6821
6845
  const devFileName = resolveHashPlaceholderFileName(fileName);
6822
6846
  if (devFileName !== fileName && req.url?.startsWith((viteConfig.base + devFileName).replace(/^\/?/, "/"))) req.url = req.url.replace(devFileName, fileName);
6847
+ if (isBundledDevRemote) renameBundledDevRuntime(req, res, federationOptions.name);
6823
6848
  if (req.url && req.url.startsWith((viteConfig.base + fileName).replace(/^\/?/, "/"))) {
6849
+ if (isBundledDevRemote) {
6850
+ const bundledDev = (server.environments?.client)?.bundledDev;
6851
+ Promise.all([bundledDevRemoteEntryCode, bundledDev?.waitForInitialBuildFinish?.()]).then(([code]) => {
6852
+ if (code === void 0) return next();
6853
+ res.setHeader("Content-Type", "text/javascript");
6854
+ res.setHeader("Cache-Control", "no-cache");
6855
+ res.end(code);
6856
+ }, next);
6857
+ return;
6858
+ }
6824
6859
  req.url = devEntryPath;
6825
6860
  req.headers["sec-fetch-dest"] = "script";
6826
6861
  }
@@ -6858,7 +6893,7 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6858
6893
  const initSrc = params.get("init");
6859
6894
  const entrySrc = params.get("entry");
6860
6895
  if (!initSrc || !entrySrc) return;
6861
- const source = getBootstrapSource(initSrc, entrySrc);
6896
+ const source = getBootstrapSource(initSrc, entrySrc, false, { isBundled: this.environment?.config?.isBundled === true });
6862
6897
  return warmupDevEntryGraph(entrySrc).then(() => source);
6863
6898
  },
6864
6899
  transform(code, id) {
@@ -6901,6 +6936,24 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6901
6936
  }
6902
6937
  if (htmlFilePath) addHtmlScriptEntries(htmlFilePath);
6903
6938
  },
6939
+ options(inputOptions) {
6940
+ if (!isBundledDevRemote || !isClientEnvironment(this)) return;
6941
+ const input = inputOptions.input;
6942
+ if (typeof input === "object" && input !== null && !Array.isArray(input)) return {
6943
+ ...inputOptions,
6944
+ input: {
6945
+ ...input,
6946
+ [entryName]: getEntryPath()
6947
+ }
6948
+ };
6949
+ return {
6950
+ ...inputOptions,
6951
+ input: [...input === void 0 ? [] : [input].flat(), getEntryPath()]
6952
+ };
6953
+ },
6954
+ buildEnd(error) {
6955
+ if (error && isBundledDevRemote) resolveBundledDevRemoteEntryCode?.(void 0);
6956
+ },
6904
6957
  async buildStart() {
6905
6958
  if (inject === "entry" && waitsForInit && isClientEnvironment(this)) for (const entry of [...entryFiles]) {
6906
6959
  if (path$1.isAbsolute(entry)) continue;
@@ -6928,6 +6981,15 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
6928
6981
  if (htmlFilePath) addHtmlScriptEntries(htmlFilePath);
6929
6982
  },
6930
6983
  generateBundle(_options, bundle) {
6984
+ if (isBundledDevRemote && _command === "serve") {
6985
+ const remoteEntryChunk = Object.values(bundle).find((output) => output.type === "chunk" && output.isEntry && output.facadeModuleId === getEntryPath());
6986
+ if (remoteEntryChunk?.type === "chunk") {
6987
+ const code = `export { ${remoteEntryChunk.exports.join(", ")} } from ${JSON.stringify(`./${remoteEntryChunk.fileName}`)};\n`;
6988
+ bundledDevRemoteEntryCode = Promise.resolve(code);
6989
+ resolveBundledDevRemoteEntryCode?.(code);
6990
+ }
6991
+ return;
6992
+ }
6931
6993
  if (skipSvelteKitSsrBuild()) return;
6932
6994
  if (entryName === "remoteEntry" && emitFileId && fileName && !viteConfig?.build?.ssr && _options?.format === "es" && viteConfig?.build?.modulePreload !== false) {
6933
6995
  const remoteEntryFile = findRemoteEntryFile(fileName, bundle);
@@ -7062,7 +7124,10 @@ for (const __mfRemoteEntryPrefetchUrl of __mfRemoteEntryPrefetchUrls) {
7062
7124
  virtualEntryCode.set(entrySrc, code);
7063
7125
  entrySrc = toViteEncodedId(entrySrc.slice(1));
7064
7126
  }
7065
- return mapCodeToCodeWithSourcemap(getBootstrapSource(getEntryPath(), entrySrc, false, { skipRemotePreload: _command === "serve" && isNuxtEntryAsyncModule }));
7127
+ return mapCodeToCodeWithSourcemap(getBootstrapSource(getEntryPath(), entrySrc, false, {
7128
+ skipRemotePreload: _command === "serve" && isNuxtEntryAsyncModule,
7129
+ isBundled: _command === "serve" && this.environment?.config?.isBundled === true
7130
+ }));
7066
7131
  }
7067
7132
  }
7068
7133
  }];
@@ -7124,6 +7189,16 @@ function checkAliasConflicts(options) {
7124
7189
  const REACT_REFRESH_PATH = "/@react-refresh";
7125
7190
  const LOCAL_REACT_REFRESH_PATH = "/@mf-react-refresh-local";
7126
7191
  const HOST_REACT_REFRESH_URL = "__MF_REACT_REFRESH_URL__";
7192
+ const HOST_REACT_REFRESH_RUNTIME = "__MF_REACT_REFRESH_RUNTIME__";
7193
+ const LOCAL_REACT_REFRESH_ID = "virtual:mf-react-refresh-local";
7194
+ const REACT_REFRESH_EXPORTS = [
7195
+ "injectIntoGlobalHook",
7196
+ "register",
7197
+ "getRefreshReg",
7198
+ "createSignatureFunctionForTransform",
7199
+ "registerExportsForReactRefresh",
7200
+ "validateRefreshBoundaryAndEnqueueUpdate"
7201
+ ];
7127
7202
  function stripQuery(url) {
7128
7203
  return url?.replace(/\?.*$/, "");
7129
7204
  }
@@ -7149,8 +7224,9 @@ function resolveReactRefreshRuntime(root) {
7149
7224
  */
7150
7225
  const REACT_REFRESH_PROXY_MODULE = [
7151
7226
  `const __remoteUrl = new URL(import.meta.url);`,
7152
- `const __target = window.location.origin === __remoteUrl.origin ? new URL('.${LOCAL_REACT_REFRESH_PATH}', __remoteUrl).href : globalThis.${HOST_REACT_REFRESH_URL} || window.location.origin + '${REACT_REFRESH_PATH}';`,
7153
- `const __rt = await import(__target);`,
7227
+ `const __isHost = window.location.origin !== __remoteUrl.origin;`,
7228
+ `const __target = __isHost ? globalThis.${HOST_REACT_REFRESH_URL} || window.location.origin + '${REACT_REFRESH_PATH}' : new URL('.${LOCAL_REACT_REFRESH_PATH}', __remoteUrl).href;`,
7229
+ `const __rt = (__isHost && globalThis.${HOST_REACT_REFRESH_RUNTIME}) || await import(__target);`,
7154
7230
  `export const injectIntoGlobalHook = __rt.injectIntoGlobalHook;`,
7155
7231
  `export const register = __rt.register;`,
7156
7232
  `export const getRefreshReg = __rt.getRefreshReg;`,
@@ -7160,34 +7236,64 @@ const REACT_REFRESH_PROXY_MODULE = [
7160
7236
  `export const __hmr_import = __rt.__hmr_import;`,
7161
7237
  `export default __rt.default || __rt;`
7162
7238
  ].join("\n");
7239
+ /**
7240
+ * `/@react-refresh` for a bundledDev remote. The bundle cannot fetch the
7241
+ * host's runtime by URL, so it binds lazily to the runtime the host page
7242
+ * publishes on a global and falls back to its own copy when opened directly.
7243
+ * Both share one component registry with the host's React.
7244
+ */
7245
+ const BUNDLED_REACT_REFRESH_MODULE = [
7246
+ `import * as __local from '${LOCAL_REACT_REFRESH_ID}';`,
7247
+ `const __rt = () => globalThis.${HOST_REACT_REFRESH_RUNTIME} || __local;`,
7248
+ ...REACT_REFRESH_EXPORTS.map((name) => `export function ${name}(...args) { return __rt().${name}(...args); }`),
7249
+ `export const __hmr_import = __local.__hmr_import;`,
7250
+ `export const __mfLocalRuntime = __local;`,
7251
+ `export default { injectIntoGlobalHook };`
7252
+ ].join("\n");
7163
7253
  const reactAdapter = {
7164
7254
  name: "react",
7165
7255
  pluginNames: ["vite:react-refresh", "vite:react-swc"],
7166
7256
  host: { transformIndexHtml({ server }) {
7167
7257
  const refreshPath = `${server.config.base.replace(/\/$/, "")}${REACT_REFRESH_PATH}`;
7258
+ const isBundled = server.config.experimental?.bundledDev === true;
7168
7259
  return [{
7169
7260
  tag: "script",
7170
7261
  children: `globalThis.${HOST_REACT_REFRESH_URL} = new URL(${JSON.stringify(refreshPath)}, window.location.origin).href;`,
7171
7262
  injectTo: "head-prepend"
7263
+ }, {
7264
+ tag: "script",
7265
+ attrs: { type: "module" },
7266
+ children: `import * as rt from ${JSON.stringify(isBundled ? REACT_REFRESH_PATH : refreshPath)};\nglobalThis.${HOST_REACT_REFRESH_RUNTIME} ??= rt.__mfLocalRuntime || rt;`,
7267
+ injectTo: "head-prepend"
7172
7268
  }];
7173
7269
  } },
7174
- remote: { configureServer({ server }) {
7175
- let reactRefreshRuntime;
7176
- server.middlewares.use((req, res, next) => {
7177
- const url = stripQuery(req.url);
7178
- if (url?.endsWith(LOCAL_REACT_REFRESH_PATH)) {
7179
- reactRefreshRuntime ??= resolveReactRefreshRuntime(server.config.root);
7270
+ remote: {
7271
+ configureServer({ server }) {
7272
+ let reactRefreshRuntime;
7273
+ server.middlewares.use((req, res, next) => {
7274
+ const url = stripQuery(req.url);
7275
+ if (url?.endsWith(LOCAL_REACT_REFRESH_PATH)) {
7276
+ reactRefreshRuntime ??= resolveReactRefreshRuntime(server.config.root);
7277
+ res.setHeader("Content-Type", "application/javascript; charset=utf-8");
7278
+ res.setHeader("Access-Control-Allow-Origin", "*");
7279
+ res.end(reactRefreshRuntime);
7280
+ return;
7281
+ }
7282
+ if (!url?.endsWith(REACT_REFRESH_PATH)) return next();
7180
7283
  res.setHeader("Content-Type", "application/javascript; charset=utf-8");
7181
7284
  res.setHeader("Access-Control-Allow-Origin", "*");
7182
- res.end(reactRefreshRuntime);
7183
- return;
7184
- }
7185
- if (!url?.endsWith(REACT_REFRESH_PATH)) return next();
7186
- res.setHeader("Content-Type", "application/javascript; charset=utf-8");
7187
- res.setHeader("Access-Control-Allow-Origin", "*");
7188
- res.end(REACT_REFRESH_PROXY_MODULE);
7189
- });
7190
- } }
7285
+ res.end(REACT_REFRESH_PROXY_MODULE);
7286
+ });
7287
+ },
7288
+ resolveId(id) {
7289
+ if (id === LOCAL_REACT_REFRESH_ID) return `\0${LOCAL_REACT_REFRESH_ID}`;
7290
+ },
7291
+ load(id, { root, isBundled }) {
7292
+ if (!isBundled) return;
7293
+ if (id === REACT_REFRESH_PATH) return BUNDLED_REACT_REFRESH_MODULE;
7294
+ if (id === `\0${LOCAL_REACT_REFRESH_ID}`) return resolveReactRefreshRuntime(root);
7295
+ }
7296
+ }
7191
7297
  };
7192
7298
  //#endregion
7193
7299
  //#region src/plugins/hmr/vue.ts
@@ -7574,14 +7680,18 @@ function pluginDevRemoteHmr(options) {
7574
7680
  const isRemote = Object.keys(options.exposes).length > 0;
7575
7681
  let adapters = [];
7576
7682
  let strategy = "full-reload";
7683
+ let root;
7684
+ let devServer;
7577
7685
  return {
7578
7686
  name: "module-federation-dev-remote-hmr",
7579
7687
  apply: "serve",
7580
7688
  configResolved(config) {
7689
+ root = config.root;
7581
7690
  adapters = resolveAdapters(config.plugins);
7582
7691
  strategy = resolveHmrStrategy(options.dev, config.plugins);
7583
7692
  },
7584
7693
  configureServer(server) {
7694
+ devServer = server;
7585
7695
  if (!isRemoteHmrEnabled(options.dev)) return;
7586
7696
  if (isRemote) {
7587
7697
  for (const adapter of adapters) adapter.remote?.configureServer?.({
@@ -7599,6 +7709,27 @@ function pluginDevRemoteHmr(options) {
7599
7709
  if (strategy === "full-reload") setupHostFullReloadRelay(server, options);
7600
7710
  }
7601
7711
  },
7712
+ resolveId(id) {
7713
+ if (!isRemote || !isRemoteHmrEnabled(options.dev)) return;
7714
+ for (const adapter of adapters) {
7715
+ const resolved = adapter.remote?.resolveId?.(id);
7716
+ if (resolved) return resolved;
7717
+ }
7718
+ },
7719
+ load: {
7720
+ order: "pre",
7721
+ handler(id) {
7722
+ if (!isRemote || !isRemoteHmrEnabled(options.dev) || !root) return;
7723
+ const isBundled = this.environment?.config?.isBundled === true;
7724
+ for (const adapter of adapters) {
7725
+ const code = adapter.remote?.load?.(id, {
7726
+ root,
7727
+ isBundled
7728
+ });
7729
+ if (code !== void 0) return code;
7730
+ }
7731
+ }
7732
+ },
7602
7733
  transform: {
7603
7734
  order: "post",
7604
7735
  handler(code, id) {
@@ -7617,8 +7748,9 @@ function pluginDevRemoteHmr(options) {
7617
7748
  order: "pre",
7618
7749
  handler(_html, ctx) {
7619
7750
  if (!isRemoteHmrEnabled(options.dev)) return;
7620
- if (!isHost || !ctx.server) return;
7621
- return collectHostTags(ctx.server, options, adapters);
7751
+ const server = ctx.server ?? devServer;
7752
+ if (!isHost || !server) return;
7753
+ return collectHostTags(server, options, adapters);
7622
7754
  }
7623
7755
  }
7624
7756
  };
@@ -8134,7 +8266,7 @@ function ${helperName}(names) {
8134
8266
  }
8135
8267
  //#endregion
8136
8268
  //#region package.json
8137
- var version$1 = "1.23.3";
8269
+ var version$1 = "1.23.4";
8138
8270
  //#endregion
8139
8271
  //#region src/virtualModules/virtualExposesSSR.ts
8140
8272
  /**
@@ -10806,6 +10938,7 @@ const VarRemoteEntry = (providedOptions) => {
10806
10938
  */
10807
10939
  async generateBundle(_options, bundle) {
10808
10940
  if (!varFilename) return;
10941
+ if (viteConfig?.command === "serve") return;
10809
10942
  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).`);
10810
10943
  const remoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
10811
10944
  if (!remoteEntryFile) throw createModuleFederationError(`Couldn't find a remoteEntry chunk file for ${mfOptions.filename}, can't generate varRemoteEntry file`);
@@ -11429,6 +11562,15 @@ const PRELOAD_HELPER_CHUNK = "vite-preload-helper";
11429
11562
  const PRELOAD_HELPER_TEST = /\0?vite\/preload-helper/;
11430
11563
  const MF_GROUP_PRIORITY = 1e6;
11431
11564
  const USER_GROUP_MAX_PRIORITY = MF_GROUP_PRIORITY - 1;
11565
+ function getBundledDevHtmlPreambleChunk(id, ctx) {
11566
+ let importers;
11567
+ try {
11568
+ importers = ctx.getModuleInfo(id)?.importers;
11569
+ } catch {
11570
+ return null;
11571
+ }
11572
+ return importers?.some((importer) => importer.includes("?html-proxy")) ? "mf-html-preamble" : null;
11573
+ }
11432
11574
  function normalizeVinextRscPreloadHints(code) {
11433
11575
  return code.replace(/(:HL\[[^\]\n]*?,)"stylesheet"/g, "$1\"style\"").replace(/(:HL\[[^\]\n]*?,)\\"stylesheet\\"/g, "$1\\\"style\\\"");
11434
11576
  }
@@ -12100,6 +12242,124 @@ function federation(mfUserOptions) {
12100
12242
  return getSharedExportUsage(pkg, shared[key], key, options);
12101
12243
  });
12102
12244
  };
12245
+ function applyFederationChunking(config, ctx, snapshotOutput) {
12246
+ const runtimeInitId = getRuntimeInitStatusImportId(options);
12247
+ config.build = config.build || {};
12248
+ let warnedAboutCodeSplitting = false;
12249
+ const ensureCodeSplitting = (output) => {
12250
+ if (output?.codeSplitting !== false) return;
12251
+ delete output.codeSplitting;
12252
+ if (warnedAboutCodeSplitting) return;
12253
+ warnedAboutCodeSplitting = true;
12254
+ mfWarn("Ignoring `output.codeSplitting = false` because module federation requires chunk splitting.");
12255
+ };
12256
+ const isFederationGroup = (group) => typeof group === "object" && group !== null && federationGroups.has(group);
12257
+ let warnedAboutGroupPriority = false;
12258
+ const clampUserGroup = (group) => {
12259
+ const candidate = group;
12260
+ if (typeof candidate?.priority !== "number") return group;
12261
+ if (candidate.priority <= USER_GROUP_MAX_PRIORITY) return group;
12262
+ if (!warnedAboutGroupPriority) {
12263
+ warnedAboutGroupPriority = true;
12264
+ mfWarn(`Clamping \`output.codeSplitting.groups\` priority to ${USER_GROUP_MAX_PRIORITY} — module federation groups must keep the highest priority so shared dependency init wrappers stay isolated in their own chunks.`);
12265
+ }
12266
+ return {
12267
+ ...candidate,
12268
+ priority: USER_GROUP_MAX_PRIORITY
12269
+ };
12270
+ };
12271
+ const federationGroupDebugName = supportsCodeSplittingGroupDebugName(ctx) ? { debugName: "module-federation" } : {};
12272
+ let warnedAboutManualChunks = false;
12273
+ let warnedAboutObjectManualChunks = false;
12274
+ const applyManualChunks = (output, useCodeSplitting) => {
12275
+ ensureCodeSplitting(output);
12276
+ const isPatchedByPlugin = typeof output.manualChunks === "function" && patchedManualChunks.has(output.manualChunks);
12277
+ const mfChunkName = function(id) {
12278
+ if (id.includes(runtimeInitId) || id.includes("__mf_v__runtimeInit__mf_v__")) return "runtimeInit";
12279
+ if (isSharedCacheHelpersId(id)) return getSharedChunkName(id);
12280
+ if (id.includes("__loadShare__")) {
12281
+ const pkg = getCachedLoadSharePkg(id);
12282
+ const key = pkg && findSharedKey(pkg, shared);
12283
+ if (key && shared[key].shareConfig.eager === true) return "loadShare-eager";
12284
+ if (key && shared[key].shareConfig.import === false) return null;
12285
+ if (pkg && !id.includes("commonjs-proxy") && isCoalescableLoadShareWrapper(pkg, options, id)) return getSharedChunkName(id);
12286
+ const match = id.match(/([^/\\]+__loadShare__[^/\\]+)/);
12287
+ return match ? match[1] : "loadShare";
12288
+ }
12289
+ return null;
12290
+ };
12291
+ patchedManualChunks.add(mfChunkName);
12292
+ if (!useCodeSplitting) {
12293
+ if (isPatchedByPlugin) return;
12294
+ const userManualChunks = output.manualChunks;
12295
+ if (userManualChunks && typeof userManualChunks !== "function" && !warnedAboutObjectManualChunks) {
12296
+ warnedAboutObjectManualChunks = true;
12297
+ mfWarn("Ignoring the object form of `output.manualChunks` because module federation cannot safely compose with it. Use the function form instead: federation modules are claimed first and your function runs for everything else.");
12298
+ }
12299
+ const mfManualChunks = function(id, ...rest) {
12300
+ if (PRELOAD_HELPER_TEST.test(id)) return PRELOAD_HELPER_CHUNK;
12301
+ const mfChunk = mfChunkName(id);
12302
+ if (mfChunk) return mfChunk;
12303
+ if (typeof userManualChunks === "function") return userManualChunks(id, ...rest) ?? void 0;
12304
+ };
12305
+ patchedManualChunks.add(mfManualChunks);
12306
+ output.manualChunks = mfManualChunks;
12307
+ return;
12308
+ }
12309
+ if (output.manualChunks && !isPatchedByPlugin && !warnedAboutManualChunks) {
12310
+ warnedAboutManualChunks = true;
12311
+ mfWarn("Ignoring `output.manualChunks` for the Rolldown build because module federation manages chunking with `output.codeSplitting.groups`. Move your grouping there — user groups are kept below the federation groups.");
12312
+ }
12313
+ const existingGroups = output.codeSplitting && typeof output.codeSplitting === "object" ? output.codeSplitting.groups : void 0;
12314
+ const userGroups = Array.isArray(existingGroups) ? existingGroups.filter((group) => !isFederationGroup(group)).map(clampUserGroup) : [];
12315
+ const mfPreloadGroup = {
12316
+ name: PRELOAD_HELPER_CHUNK,
12317
+ test: PRELOAD_HELPER_TEST,
12318
+ priority: 1000001
12319
+ };
12320
+ const mfNameGroup = {
12321
+ name: mfChunkName,
12322
+ priority: MF_GROUP_PRIORITY,
12323
+ ...federationGroupDebugName
12324
+ };
12325
+ federationGroups.add(mfPreloadGroup);
12326
+ federationGroups.add(mfNameGroup);
12327
+ const groups = [mfPreloadGroup, mfNameGroup];
12328
+ if (!snapshotOutput) {
12329
+ const htmlPreambleGroup = {
12330
+ name: getBundledDevHtmlPreambleChunk,
12331
+ priority: 1000002
12332
+ };
12333
+ federationGroups.add(htmlPreambleGroup);
12334
+ groups.push(htmlPreambleGroup);
12335
+ }
12336
+ groups.push(...userGroups);
12337
+ output.codeSplitting = {
12338
+ ...output.codeSplitting || {},
12339
+ groups
12340
+ };
12341
+ delete output.manualChunks;
12342
+ };
12343
+ config.build.rollupOptions = config.build.rollupOptions || {};
12344
+ const rollupOutput = config.build.rollupOptions.output;
12345
+ if (Array.isArray(rollupOutput)) rollupOutput.forEach((output) => applyManualChunks(output, false));
12346
+ else applyManualChunks(config.build.rollupOptions.output ||= {}, false);
12347
+ const buildWithRolldown = config.build;
12348
+ buildWithRolldown.rolldownOptions = buildWithRolldown.rolldownOptions || {};
12349
+ const rolldownOutput = buildWithRolldown.rolldownOptions.output;
12350
+ const snapshotRolldownOutput = (output) => ({
12351
+ entryFileNames: output.entryFileNames,
12352
+ chunkFileNames: output.chunkFileNames,
12353
+ assetFileNames: output.assetFileNames
12354
+ });
12355
+ if (Array.isArray(rolldownOutput)) {
12356
+ rolldownOutput.forEach((output) => applyManualChunks(output, true));
12357
+ if (snapshotOutput) desiredRolldownOutput = rolldownOutput.map((output) => snapshotRolldownOutput(output));
12358
+ } else {
12359
+ applyManualChunks(buildWithRolldown.rolldownOptions.output ||= {}, true);
12360
+ if (snapshotOutput) desiredRolldownOutput = [snapshotRolldownOutput(buildWithRolldown.rolldownOptions.output)];
12361
+ }
12362
+ }
12103
12363
  return [
12104
12364
  {
12105
12365
  name: "vite:module-federation-virtual-modules",
@@ -12229,13 +12489,20 @@ function federation(mfUserOptions) {
12229
12489
  getParsePromise: () => moduleParseController.parsePromise
12230
12490
  }),
12231
12491
  pluginLazyConsumeOnlyShares(options),
12492
+ {
12493
+ name: "module-federation-bundled-dev-chunks",
12494
+ apply: "serve",
12495
+ config(config) {
12496
+ if (!config.experimental?.bundledDev) return;
12497
+ applyFederationChunking(config, this, false);
12498
+ }
12499
+ },
12232
12500
  {
12233
12501
  name: "module-federation-esm-shims",
12234
12502
  enforce: "pre",
12235
12503
  apply: "build",
12236
12504
  config(config) {
12237
12505
  isSsrBuild = Boolean(config.build?.ssr);
12238
- const runtimeInitId = getRuntimeInitStatusImportId(options);
12239
12506
  config.build = config.build || {};
12240
12507
  if (config.build.modulePreload !== false) {
12241
12508
  const remoteEntryBasename = path$1.posix.basename(options.filename);
@@ -12257,115 +12524,7 @@ function federation(mfUserOptions) {
12257
12524
  }
12258
12525
  };
12259
12526
  }
12260
- let warnedAboutCodeSplitting = false;
12261
- const ensureCodeSplitting = (output) => {
12262
- if (output?.codeSplitting !== false) return;
12263
- delete output.codeSplitting;
12264
- if (warnedAboutCodeSplitting) return;
12265
- warnedAboutCodeSplitting = true;
12266
- mfWarn("Ignoring `output.codeSplitting = false` because module federation requires chunk splitting.");
12267
- };
12268
- const isFederationGroup = (group) => typeof group === "object" && group !== null && federationGroups.has(group);
12269
- let warnedAboutGroupPriority = false;
12270
- const clampUserGroup = (group) => {
12271
- const candidate = group;
12272
- if (typeof candidate?.priority !== "number") return group;
12273
- if (candidate.priority <= USER_GROUP_MAX_PRIORITY) return group;
12274
- if (!warnedAboutGroupPriority) {
12275
- warnedAboutGroupPriority = true;
12276
- mfWarn(`Clamping \`output.codeSplitting.groups\` priority to ${USER_GROUP_MAX_PRIORITY} — module federation groups must keep the highest priority so shared dependency init wrappers stay isolated in their own chunks.`);
12277
- }
12278
- return {
12279
- ...candidate,
12280
- priority: USER_GROUP_MAX_PRIORITY
12281
- };
12282
- };
12283
- const federationGroupDebugName = supportsCodeSplittingGroupDebugName(this) ? { debugName: "module-federation" } : {};
12284
- let warnedAboutManualChunks = false;
12285
- let warnedAboutObjectManualChunks = false;
12286
- const applyManualChunks = (output, useCodeSplitting) => {
12287
- ensureCodeSplitting(output);
12288
- const isPatchedByPlugin = typeof output.manualChunks === "function" && patchedManualChunks.has(output.manualChunks);
12289
- const mfChunkName = function(id) {
12290
- if (id.includes(runtimeInitId) || id.includes("__mf_v__runtimeInit__mf_v__")) return "runtimeInit";
12291
- if (isSharedCacheHelpersId(id)) return getSharedChunkName(id);
12292
- if (id.includes("__loadShare__")) {
12293
- const pkg = getCachedLoadSharePkg(id);
12294
- const key = pkg && findSharedKey(pkg, shared);
12295
- if (key && shared[key].shareConfig.eager === true) return "loadShare-eager";
12296
- if (key && shared[key].shareConfig.import === false) return null;
12297
- if (pkg && !id.includes("commonjs-proxy") && isCoalescableLoadShareWrapper(pkg, options, id)) return getSharedChunkName(id);
12298
- const match = id.match(/([^/\\]+__loadShare__[^/\\]+)/);
12299
- return match ? match[1] : "loadShare";
12300
- }
12301
- return null;
12302
- };
12303
- patchedManualChunks.add(mfChunkName);
12304
- if (!useCodeSplitting) {
12305
- if (isPatchedByPlugin) return;
12306
- const userManualChunks = output.manualChunks;
12307
- if (userManualChunks && typeof userManualChunks !== "function" && !warnedAboutObjectManualChunks) {
12308
- warnedAboutObjectManualChunks = true;
12309
- mfWarn("Ignoring the object form of `output.manualChunks` because module federation cannot safely compose with it. Use the function form instead: federation modules are claimed first and your function runs for everything else.");
12310
- }
12311
- const mfManualChunks = function(id, ...rest) {
12312
- if (PRELOAD_HELPER_TEST.test(id)) return PRELOAD_HELPER_CHUNK;
12313
- const mfChunk = mfChunkName(id);
12314
- if (mfChunk) return mfChunk;
12315
- if (typeof userManualChunks === "function") return userManualChunks(id, ...rest) ?? void 0;
12316
- };
12317
- patchedManualChunks.add(mfManualChunks);
12318
- output.manualChunks = mfManualChunks;
12319
- return;
12320
- }
12321
- if (output.manualChunks && !isPatchedByPlugin && !warnedAboutManualChunks) {
12322
- warnedAboutManualChunks = true;
12323
- mfWarn("Ignoring `output.manualChunks` for the Rolldown build because module federation manages chunking with `output.codeSplitting.groups`. Move your grouping there — user groups are kept below the federation groups.");
12324
- }
12325
- const existingGroups = output.codeSplitting && typeof output.codeSplitting === "object" ? output.codeSplitting.groups : void 0;
12326
- const userGroups = Array.isArray(existingGroups) ? existingGroups.filter((group) => !isFederationGroup(group)).map(clampUserGroup) : [];
12327
- const mfPreloadGroup = {
12328
- name: PRELOAD_HELPER_CHUNK,
12329
- test: PRELOAD_HELPER_TEST,
12330
- priority: 1000001
12331
- };
12332
- const mfNameGroup = {
12333
- name: mfChunkName,
12334
- priority: MF_GROUP_PRIORITY,
12335
- ...federationGroupDebugName
12336
- };
12337
- federationGroups.add(mfPreloadGroup);
12338
- federationGroups.add(mfNameGroup);
12339
- const groups = [
12340
- mfPreloadGroup,
12341
- mfNameGroup,
12342
- ...userGroups
12343
- ];
12344
- output.codeSplitting = {
12345
- ...output.codeSplitting || {},
12346
- groups
12347
- };
12348
- delete output.manualChunks;
12349
- };
12350
- config.build.rollupOptions = config.build.rollupOptions || {};
12351
- const rollupOutput = config.build.rollupOptions.output;
12352
- if (Array.isArray(rollupOutput)) rollupOutput.forEach((output) => applyManualChunks(output, false));
12353
- else applyManualChunks(config.build.rollupOptions.output ||= {}, false);
12354
- const buildWithRolldown = config.build;
12355
- buildWithRolldown.rolldownOptions = buildWithRolldown.rolldownOptions || {};
12356
- const rolldownOutput = buildWithRolldown.rolldownOptions.output;
12357
- const snapshotRolldownOutput = (output) => ({
12358
- entryFileNames: output.entryFileNames,
12359
- chunkFileNames: output.chunkFileNames,
12360
- assetFileNames: output.assetFileNames
12361
- });
12362
- if (Array.isArray(rolldownOutput)) {
12363
- rolldownOutput.forEach((output) => applyManualChunks(output, true));
12364
- desiredRolldownOutput = rolldownOutput.map((output) => snapshotRolldownOutput(output));
12365
- } else {
12366
- applyManualChunks(buildWithRolldown.rolldownOptions.output ||= {}, true);
12367
- desiredRolldownOutput = [snapshotRolldownOutput(buildWithRolldown.rolldownOptions.output)];
12368
- }
12527
+ applyFederationChunking(config, this, true);
12369
12528
  },
12370
12529
  async buildApp(builder) {
12371
12530
  const desiredOutput = desiredRolldownOutput;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/vite",
3
- "version": "1.23.3",
3
+ "version": "1.23.4",
4
4
  "description": "Vite plugin for Module Federation",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",