@module-federation/vite 1.20.1 → 1.20.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.
@@ -0,0 +1,119 @@
1
+ //#region src/utils/pathNormalization.ts
2
+ const COMMON_SHARED_SUBPATHS = {
3
+ react: [
4
+ "react/jsx-runtime",
5
+ "react/jsx-dev-runtime",
6
+ "react/compiler-runtime"
7
+ ],
8
+ "react-dom": [
9
+ "react-dom/client",
10
+ "react-dom/server",
11
+ "react-dom/server.browser"
12
+ ],
13
+ "solid-js": [
14
+ "solid-js/web",
15
+ "solid-js/store",
16
+ "solid-js/html",
17
+ "solid-js/h"
18
+ ],
19
+ zustand: ["zustand/vanilla", "zustand/react"]
20
+ };
21
+ const VITE_DEFAULT_ASSET_TYPES = [
22
+ "apng",
23
+ "bmp",
24
+ "png",
25
+ "jpe?g",
26
+ "jfif",
27
+ "pjpeg",
28
+ "pjp",
29
+ "gif",
30
+ "svg",
31
+ "ico",
32
+ "webp",
33
+ "avif",
34
+ "cur",
35
+ "jxl",
36
+ "mp4",
37
+ "webm",
38
+ "ogg",
39
+ "mp3",
40
+ "wav",
41
+ "flac",
42
+ "aac",
43
+ "opus",
44
+ "mov",
45
+ "m4a",
46
+ "vtt",
47
+ "woff2?",
48
+ "eot",
49
+ "ttf",
50
+ "otf",
51
+ "webmanifest",
52
+ "pdf",
53
+ "txt"
54
+ ];
55
+ const ASSET_LIKE_IMPORT_RE = new RegExp(`\\.(${[...[
56
+ "css",
57
+ "scss",
58
+ "sass",
59
+ "less",
60
+ "styl",
61
+ "stylus"
62
+ ], ...VITE_DEFAULT_ASSET_TYPES].join("|")})(?:[?#].*)?$`, "i");
63
+ function isAssetLikeImport(source) {
64
+ return ASSET_LIKE_IMPORT_RE.test(source);
65
+ }
66
+ const VITE_OPTIMIZABLE_ENTRY_RE = /\.[cm]?[jt]s$/;
67
+ function isViteOptimizableEntry(resolvedPath) {
68
+ return VITE_OPTIMIZABLE_ENTRY_RE.test(resolvedPath);
69
+ }
70
+ function removeTrailingSlash(value) {
71
+ return value.endsWith("/") ? value.slice(0, -1) : value;
72
+ }
73
+ function ensureTrailingSlash(value) {
74
+ return `${removeTrailingSlash(value)}/`;
75
+ }
76
+ function getBasePath(base) {
77
+ return removeTrailingSlash(base || "/");
78
+ }
79
+ function isNuxtClientBase(base) {
80
+ return getBasePath(base).endsWith("/_nuxt");
81
+ }
82
+ function normalizeNodeModulePath(source) {
83
+ const queryIndex = source.indexOf("?");
84
+ return (queryIndex === -1 ? source : source.slice(0, queryIndex)).replace(/\\/g, "/");
85
+ }
86
+ function isNodeModulePath(source) {
87
+ return source.includes("/node_modules/") || source.includes("\\node_modules\\");
88
+ }
89
+ function filterId(id) {
90
+ return typeof id === "string" && !id.includes("\0");
91
+ }
92
+ function getMatchingNodeModuleSubpath(source, candidates) {
93
+ const normalized = normalizeNodeModulePath(source);
94
+ return [...candidates].sort((a, b) => b.length - a.length).find((candidate) => normalized.includes(`/node_modules/${candidate}/`) || normalized.includes(`/node_modules/${candidate}.`));
95
+ }
96
+ function getCommonSharedSubpaths(sharedKey) {
97
+ return COMMON_SHARED_SUBPATHS[removeTrailingSlash(sharedKey)] || [];
98
+ }
99
+ function getCommonSharedSubpathFromNodeModulePath(source, sharedKey) {
100
+ return getMatchingNodeModuleSubpath(source, getCommonSharedSubpaths(removeTrailingSlash(sharedKey)));
101
+ }
102
+ /**
103
+ * Resolves the public path for remote entries
104
+ * @param options - Module Federation options
105
+ * @param viteBase - Vite's base config value
106
+ * @param originalBase - Original base config before any transformations
107
+ * @returns The resolved public path
108
+ */
109
+ function resolvePublicPath(options, viteBase, originalBase) {
110
+ if (options.publicPath && options.publicPath !== "auto") return options.publicPath;
111
+ if (!originalBase) return "auto";
112
+ if (viteBase) {
113
+ if (viteBase === "./") return "auto";
114
+ return ensureTrailingSlash(viteBase);
115
+ }
116
+ return "auto";
117
+ }
118
+ //#endregion
119
+ export { getMatchingNodeModuleSubpath as a, isNuxtClientBase as c, resolvePublicPath as d, getCommonSharedSubpaths as i, isViteOptimizableEntry as l, getBasePath as n, isAssetLikeImport as o, getCommonSharedSubpathFromNodeModulePath as r, isNodeModulePath as s, filterId as t, normalizeNodeModulePath as u };
@@ -1,3 +1,4 @@
1
+ import { t as EXTERNAL_URL_RE } from "./buildPaths-BkaQHrd2.js";
1
2
  //#region src/utils/fetchWithTimeout.ts
2
3
  const DEFAULT_SSR_FETCH_TIMEOUT_MS = 1e4;
3
4
  const DEFAULT_SSR_FETCH_MAX_BYTES = 10 * 1024 * 1024;
@@ -116,11 +117,10 @@ async function readResponseTextBounded(res, maxBytes = DEFAULT_SSR_FETCH_MAX_BYT
116
117
  * module source through Vite's plugin pipeline, avoiding serialisation which
117
118
  * cannot faithfully represent React components or closures.
118
119
  *
119
- * Dev mode on Vite < 8 is NOT supported `ModuleRunner` and
120
- * `FetchableDevEnvironment` are Vite 8+ APIs. If you need dev-mode SSR on
121
- * an older Vite version, implement an alternative loader in `loadSSRRemoteEntry`
122
- * for the `isDevSsrEntry` branch and expose a corresponding server endpoint
123
- * from `pluginSSRRemoteEntry.configureServer`.
120
+ * Dev mode on Vite < 8 is NOT supported by this integration because the
121
+ * cross-process `fetchModule` proxy uses Vite 8's environment APIs.
122
+ * `ModuleRunner` itself is available in earlier Vite versions, but an older
123
+ * remote needs a different transport and server endpoint.
124
124
  *
125
125
  * Exported as a plain factory function so it can be serialised into the
126
126
  * generated runtimePlugins list in virtualRemotes.ts.
@@ -135,17 +135,21 @@ async function nodeImport(id) {
135
135
  }
136
136
  const isNodeServer = () => typeof globalThis.process?.versions?.node === "string";
137
137
  const runnerCache = /* @__PURE__ */ new Map();
138
+ function getSortedRecordEntries(record) {
139
+ return Object.entries(record).sort(([left], [right]) => left.localeCompare(right));
140
+ }
138
141
  /**
139
- * Load `vite/module-runner`. Returns null on Vite < 8 where the subpath doesn't
140
- * exist.
142
+ * Load `vite/module-runner`. Returns null when the installed Vite does not
143
+ * expose the module-runner entry point.
141
144
  */
142
145
  async function getModuleRunnerModule() {
146
+ const moduleRunnerId = ["vite", "module-runner"].join("/");
143
147
  try {
144
148
  const { createRequire } = await nodeImport("module");
145
- return createRequire(import.meta.url)("vite/module-runner");
149
+ return createRequire(import.meta.url)(moduleRunnerId);
146
150
  } catch {}
147
151
  try {
148
- return await import("vite/module-runner");
152
+ return await nodeImport(moduleRunnerId);
149
153
  } catch {
150
154
  return null;
151
155
  }
@@ -155,11 +159,33 @@ async function getModuleRunnerModule() {
155
159
  * `/__mf_runner__` endpoint. Each HTTP POST carries a `fetchModule` invoke
156
160
  * payload; the remote responds with the transformed module source as JSON.
157
161
  *
158
- * This is Vite 8+ only older versions don't expose `vite/module-runner` or
159
- * the `/__mf_runner__` proxy endpoint.
162
+ * The cross-process transport is Vite 8+ only because older versions do not
163
+ * expose the `/__mf_runner__` environment proxy used here.
160
164
  */
161
- async function getOrCreateRunner(remoteOrigin, fetchTimeoutMs, fetchMaxBytes) {
162
- const cacheKey = `${fetchTimeoutMs}::${fetchMaxBytes}::${remoteOrigin}`;
165
+ function getRunnerCacheKey(remoteOrigin, resolvedShared, fetchTimeoutMs, fetchMaxBytes) {
166
+ return JSON.stringify([
167
+ remoteOrigin,
168
+ fetchTimeoutMs,
169
+ fetchMaxBytes,
170
+ getSortedRecordEntries(resolvedShared)
171
+ ]);
172
+ }
173
+ async function resolveSharedExternal(id, resolvedShared) {
174
+ if (typeof id !== "string") return null;
175
+ const resolved = resolvedShared[id];
176
+ if (!resolved) return null;
177
+ if (EXTERNAL_URL_RE.test(resolved)) return {
178
+ externalize: resolved,
179
+ type: "module"
180
+ };
181
+ const { pathToFileURL } = await _url();
182
+ return {
183
+ externalize: pathToFileURL(resolved).href,
184
+ type: "module"
185
+ };
186
+ }
187
+ async function getOrCreateRunner(remoteOrigin, resolvedShared, fetchTimeoutMs, fetchMaxBytes) {
188
+ const cacheKey = getRunnerCacheKey(remoteOrigin, resolvedShared, fetchTimeoutMs, fetchMaxBytes);
163
189
  if (runnerCache.has(cacheKey)) return runnerCache.get(cacheKey);
164
190
  const promise = (async () => {
165
191
  const viteRunner = await getModuleRunnerModule();
@@ -170,6 +196,10 @@ async function getOrCreateRunner(remoteOrigin, fetchTimeoutMs, fetchMaxBytes) {
170
196
  return new ModuleRunner({
171
197
  hmr: false,
172
198
  transport: { async invoke(payload) {
199
+ if (payload.data.name === "fetchModule") {
200
+ const sharedExternal = await resolveSharedExternal(payload.data.data[0], resolvedShared);
201
+ if (sharedExternal) return { result: sharedExternal };
202
+ }
173
203
  const text = await readResponseTextBounded(await fetchWithTimeout(runnerEndpoint, {
174
204
  method: "POST",
175
205
  headers: { "Content-Type": "application/json" },
@@ -189,6 +219,7 @@ const _path = () => nodeImport("path");
189
219
  const _fs = () => nodeImport("fs");
190
220
  const _crypto = () => nodeImport("crypto");
191
221
  const _module = () => nodeImport("module");
222
+ const _url = () => nodeImport("url");
192
223
  /**
193
224
  * Version key for a resolved SSR entry. Derived from the remote's manifest
194
225
  * content so a redeploy at the same URL produces a different key, which in
@@ -448,7 +479,7 @@ function revalidate(remoteEntryUrl) {
448
479
  const tempFileCache = /* @__PURE__ */ new Map();
449
480
  const tempFilePathCache = /* @__PURE__ */ new Map();
450
481
  function getSsrTransformContextKey(resolvedShared, shareScopeName) {
451
- return JSON.stringify([shareScopeName, Object.entries(resolvedShared).sort(([left], [right]) => left.localeCompare(right))]);
482
+ return JSON.stringify([shareScopeName, getSortedRecordEntries(resolvedShared)]);
452
483
  }
453
484
  let ssrCacheDirPromise;
454
485
  async function getSSRCacheDir() {
@@ -572,7 +603,7 @@ async function importTempModule(filePath, versionKey) {
572
603
  }
573
604
  let warnedVmUnavailable = false;
574
605
  async function tryVmStrategy(ssrEntry, options) {
575
- const { loadViaVmStrategy, isVmStrategyAvailable } = await import("./ssrVmStrategy-7HAPa-Vc.js");
606
+ const { loadViaVmStrategy, isVmStrategyAvailable } = await import("./ssrVmStrategy-BkEp3YIv.js");
576
607
  if (!await isVmStrategyAvailable()) {
577
608
  if (!warnedVmUnavailable) {
578
609
  warnedVmUnavailable = true;
@@ -604,7 +635,7 @@ async function loadSSRRemoteEntry(ssrEntry, options) {
604
635
  const urlObj = new URL(url);
605
636
  if (urlObj.pathname.includes("/__mf_ssr__/")) {
606
637
  const remoteOrigin = urlObj.origin;
607
- const runner = await getOrCreateRunner(remoteOrigin, options.fetchTimeoutMs, options.fetchMaxBytes);
638
+ const runner = await getOrCreateRunner(remoteOrigin, resolvedShared, options.fetchTimeoutMs, options.fetchMaxBytes);
608
639
  if (!runner) {
609
640
  if (process.env.NODE_ENV !== "production") return null;
610
641
  } else try {
@@ -1,4 +1,5 @@
1
- import { c as readResponseTextBounded, n as neutralizeBrowserPreloadHelpers, s as fetchWithTimeout, t as SsrEntryHttpError } from "./ssrEntryLoader-Bw423jj_.js";
1
+ import { i as getCommonSharedSubpaths } from "./pathNormalization-CLDIcf9-.js";
2
+ import { c as readResponseTextBounded, n as neutralizeBrowserPreloadHelpers, s as fetchWithTimeout, t as SsrEntryHttpError } from "./ssrEntryLoader-7v0Do_g5.js";
2
3
  //#region src/utils/ssrVmStrategy.ts
3
4
  /**
4
5
  * vm.SourceTextModule strategy for loading remote SSR entries.
@@ -39,6 +40,22 @@ async function getVmApi() {
39
40
  async function isVmStrategyAvailable() {
40
41
  return await getVmApi() !== null;
41
42
  }
43
+ function findVmSharedKey(specifier, shared) {
44
+ if (!shared) return;
45
+ const keys = Object.keys(shared);
46
+ if (Object.prototype.hasOwnProperty.call(shared, specifier)) return specifier;
47
+ const vueKey = keys.find((key) => key.endsWith("/") ? key.slice(0, -1) === "vue" : key === "vue");
48
+ if (vueKey && (specifier === "vue/dist/vue.esm-bundler.js" || specifier === "vue/dist/vue.runtime.esm-bundler.js")) return vueKey;
49
+ const commonSubpathKey = keys.find((key) => {
50
+ return getCommonSharedSubpaths(key.endsWith("/") ? key.slice(0, -1) : key).includes(specifier);
51
+ });
52
+ if (commonSubpathKey) return commonSubpathKey;
53
+ return keys.find((key) => {
54
+ if (!key.endsWith("/")) return false;
55
+ const keyBase = key.slice(0, -1);
56
+ return specifier === keyBase || specifier.startsWith(`${keyBase}/`);
57
+ });
58
+ }
42
59
  function getFederationInstances() {
43
60
  return globalThis.__FEDERATION__?.__INSTANCES__ ?? [];
44
61
  }
@@ -51,9 +68,11 @@ async function loadBareModule(specifier, options) {
51
68
  const instances = owner ? [owner] : getFederationInstances();
52
69
  for (const instance of instances) {
53
70
  if (typeof instance?.loadShare !== "function") continue;
54
- const shared = instance.options?.shared?.[specifier];
55
- if (!shared) continue;
56
- if (!(Array.isArray(shared.scope) ? shared.scope : [shared.scope ?? "default"]).includes(options.shareScopeName)) continue;
71
+ const shared = instance.options?.shared;
72
+ const sharedKey = findVmSharedKey(specifier, shared);
73
+ const shareConfig = sharedKey ? shared?.[sharedKey] : void 0;
74
+ if (!shareConfig) continue;
75
+ if (!(Array.isArray(shareConfig.scope) ? shareConfig.scope : [shareConfig.scope ?? "default"]).includes(options.shareScopeName)) continue;
57
76
  try {
58
77
  const factory = await instance.loadShare(specifier);
59
78
  if (typeof factory === "function") {
@@ -17,11 +17,10 @@
17
17
  * module source through Vite's plugin pipeline, avoiding serialisation which
18
18
  * cannot faithfully represent React components or closures.
19
19
  *
20
- * Dev mode on Vite < 8 is NOT supported `ModuleRunner` and
21
- * `FetchableDevEnvironment` are Vite 8+ APIs. If you need dev-mode SSR on
22
- * an older Vite version, implement an alternative loader in `loadSSRRemoteEntry`
23
- * for the `isDevSsrEntry` branch and expose a corresponding server endpoint
24
- * from `pluginSSRRemoteEntry.configureServer`.
20
+ * Dev mode on Vite < 8 is NOT supported by this integration because the
21
+ * cross-process `fetchModule` proxy uses Vite 8's environment APIs.
22
+ * `ModuleRunner` itself is available in earlier Vite versions, but an older
23
+ * remote needs a different transport and server endpoint.
25
24
  *
26
25
  * Exported as a plain factory function so it can be serialised into the
27
26
  * generated runtimePlugins list in virtualRemotes.ts.
@@ -1,2 +1,2 @@
1
- import { i as ssrEntryLoaderPlugin, n as neutralizeBrowserPreloadHelpers, r as revalidate, t as SsrEntryHttpError } from "../ssrEntryLoader-Bw423jj_.js";
1
+ import { i as ssrEntryLoaderPlugin, n as neutralizeBrowserPreloadHelpers, r as revalidate, t as SsrEntryHttpError } from "../ssrEntryLoader-7v0Do_g5.js";
2
2
  export { SsrEntryHttpError, ssrEntryLoaderPlugin as default, neutralizeBrowserPreloadHelpers, revalidate };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/vite",
3
- "version": "1.20.1",
3
+ "version": "1.20.3",
4
4
  "description": "Vite plugin for Module Federation",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -90,7 +90,7 @@
90
90
  "rollup": "4.62.3",
91
91
  "tsdown": "0.22.14",
92
92
  "typescript": "7.0.2",
93
- "vite": "8.1.5",
94
- "vitest": "4.0.18"
93
+ "vite": "8.2.0",
94
+ "vitest": "4.1.10"
95
95
  }
96
- }
96
+ }