@module-federation/vite 1.17.0 → 1.17.1

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.
@@ -1,491 +1,2 @@
1
- //#region src/utils/ssrEntryLoader.ts
2
- /**
3
- * MF runtime plugin that intercepts the `loadEntry` lifecycle hook on the
4
- * server and loads the SSR-compatible remote entry instead of the browser one.
5
- *
6
- * This completely replaces the need for any `@module-federation/sdk` patches.
7
- * The `loadEntry` hook is emitted by `runtime-core` before it falls through to
8
- * `loadScriptNode` — if the hook returns a value, the runtime uses it directly.
9
- *
10
- * Strategy:
11
- * - In Node (detected through process.versions.node), fetch the remote's mf-manifest.json
12
- * to discover the ssrRemoteEntry URL and its type.
13
- * - ESM entry: use a dynamic `import()` — the SSR entry has no browser
14
- * globals and all shared packages are external.
15
- * - Dev mode (Vite 8+ only): use `ModuleRunner` with an HTTP transport backed
16
- * by the remote's `/__mf_runner__` endpoint. This fetches fully-transformed
17
- * module source through Vite's plugin pipeline, avoiding serialisation which
18
- * cannot faithfully represent React components or closures.
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`.
25
- *
26
- * Exported as a plain factory function so it can be serialised into the
27
- * generated runtimePlugins list in virtualRemotes.ts.
28
- */
29
- const importCache = /* @__PURE__ */ new Map();
30
- async function nodeImport(id) {
31
- if (!importCache.has(id)) importCache.set(id, import(
32
- /* @vite-ignore */
33
- id
34
- ));
35
- return importCache.get(id);
36
- }
37
- const isNodeServer = () => typeof globalThis.process?.versions?.node === "string";
38
- const runnerCache = /* @__PURE__ */ new Map();
39
- /**
40
- * Import `vite/module-runner` dynamically. Returns null on Vite < 8 where the
41
- * subpath doesn't exist. Uses a plain dynamic import (not nodeImport) so that
42
- * Vitest can intercept it with vi.mock in tests.
43
- */
44
- async function getModuleRunnerModule() {
45
- try {
46
- return await import("vite/module-runner");
47
- } catch {
48
- return null;
49
- }
50
- }
51
- /**
52
- * Create a ModuleRunner that fetches modules from a remote Vite dev server's
53
- * `/__mf_runner__` endpoint. Each HTTP POST carries a `fetchModule` invoke
54
- * payload; the remote responds with the transformed module source as JSON.
55
- *
56
- * This is Vite 8+ only — older versions don't expose `vite/module-runner` or
57
- * the `/__mf_runner__` proxy endpoint.
58
- */
59
- async function getOrCreateRunner(remoteOrigin) {
60
- if (runnerCache.has(remoteOrigin)) return runnerCache.get(remoteOrigin);
61
- const promise = (async () => {
62
- const viteRunner = await getModuleRunnerModule();
63
- if (!viteRunner) return null;
64
- const { ModuleRunner, ESModulesEvaluator } = viteRunner;
65
- const runnerEndpoint = `${remoteOrigin}/__mf_runner__`;
66
- try {
67
- return new ModuleRunner({
68
- hmr: false,
69
- transport: { async invoke(payload) {
70
- return await (await fetch(runnerEndpoint, {
71
- method: "POST",
72
- headers: { "Content-Type": "application/json" },
73
- body: JSON.stringify(payload)
74
- })).json();
75
- } }
76
- }, new ESModulesEvaluator());
77
- } catch {
78
- return null;
79
- }
80
- })();
81
- runnerCache.set(remoteOrigin, promise);
82
- return promise;
83
- }
84
- const _path = () => nodeImport("path");
85
- const _fs = () => nodeImport("fs");
86
- const _crypto = () => nodeImport("crypto");
87
- const _module = () => nodeImport("module");
88
- /**
89
- * Version key for a resolved SSR entry. Derived from the remote's manifest
90
- * content so a redeploy at the same URL produces a different key, which in
91
- * turn produces different temp-file names — busting both our caches and
92
- * Node's ESM module cache. Convention-resolved entries (no manifest) get a
93
- * stable placeholder key and cannot be revalidated automatically.
94
- */
95
- const UNVERSIONED = "unversioned";
96
- function hashString(value) {
97
- let hash = 2166136261;
98
- for (let i = 0; i < value.length; i++) {
99
- hash ^= value.charCodeAt(i);
100
- hash = Math.imul(hash, 16777619);
101
- }
102
- return (hash >>> 0).toString(16).padStart(8, "0");
103
- }
104
- function computeManifestVersionKey(manifest) {
105
- const buildVersion = manifest.metaData?.buildInfo?.buildVersion;
106
- const contentHash = hashString(JSON.stringify(manifest));
107
- return buildVersion ? `${buildVersion}-${contentHash}` : contentHash;
108
- }
109
- const ssrEntryCache = /* @__PURE__ */ new Map();
110
- const manifestFetchCache = /* @__PURE__ */ new Map();
111
- var SsrEntryHttpError = class extends Error {
112
- constructor(url, status, statusText, bodyPreview) {
113
- super(`Failed to fetch SSR module "${url}": ${status} ${statusText}` + (bodyPreview ? `\npreview: ${bodyPreview}` : ""));
114
- this.url = url;
115
- this.status = status;
116
- this.statusText = statusText;
117
- this.bodyPreview = bodyPreview;
118
- this.name = "SsrEntryHttpError";
119
- }
120
- };
121
- function getBodyPreview(body) {
122
- return body.slice(0, 240).replace(/\s+/g, " ").trim();
123
- }
124
- function isSsrEntryHttpError(error) {
125
- return error instanceof SsrEntryHttpError;
126
- }
127
- async function fetchManifest(manifestUrl) {
128
- try {
129
- const res = await fetch(manifestUrl);
130
- if (!res.ok) return null;
131
- return await res.json();
132
- } catch {
133
- return null;
134
- }
135
- }
136
- async function fetchManifestCached(manifestUrl) {
137
- if (!manifestFetchCache.has(manifestUrl)) manifestFetchCache.set(manifestUrl, fetchManifest(manifestUrl));
138
- return manifestFetchCache.get(manifestUrl);
139
- }
140
- /** True when the host configured a manifest URL as the remote entry (any .json name). */
141
- function isManifestEntry(remoteEntryUrl) {
142
- try {
143
- const { pathname } = new URL(remoteEntryUrl);
144
- return /\.json$/i.test(pathname);
145
- } catch {
146
- return /\.json(?:[?#]|$)/i.test(remoteEntryUrl);
147
- }
148
- }
149
- function isSsrEntry(remoteEntryUrl) {
150
- return /\.ssr\.js(?:[?#].*)?$/.test(remoteEntryUrl);
151
- }
152
- function getManifestUrl(remoteEntryUrl) {
153
- if (isManifestEntry(remoteEntryUrl)) return remoteEntryUrl;
154
- return remoteEntryUrl.replace(/\/[^/]+$/, "/mf-manifest.json");
155
- }
156
- function getEntryFilename(entryUrl) {
157
- return entryUrl.split("/").pop()?.replace(/[?#].*$/, "").replace(/\.[^.]+$/, "") ?? "remoteEntry";
158
- }
159
- function resolveEntryAssetUrl(entry, manifestUrl) {
160
- const base = manifestUrl.replace(/\/[^/]+$/, "/");
161
- return new URL(`${entry.path || ""}${entry.name}`, base).href;
162
- }
163
- function resolveSSREntryUrl(manifest, manifestUrl) {
164
- const meta = manifest?.metaData;
165
- if (!meta?.ssrRemoteEntry?.name) return null;
166
- const base = manifestUrl.replace(/\/[^/]+$/, "/");
167
- const entryPath = (meta.ssrRemoteEntry.path || "") + meta.ssrRemoteEntry.name;
168
- return {
169
- url: new URL(entryPath, base).href,
170
- type: meta.ssrRemoteEntry.type || "module",
171
- versionKey: computeManifestVersionKey(manifest)
172
- };
173
- }
174
- /**
175
- * Derive the SSR entry URL by convention when no manifest is available.
176
- * remoteEntry.js → remoteEntry.ssr.js
177
- * remoteEntry.js → /__mf_ssr__/remoteEntry.ssr.js (dev middleware)
178
- * Returns the first URL that responds with a 200.
179
- */
180
- async function headCheckSsrEntry(candidate) {
181
- try {
182
- const res = await fetch(candidate.url, { method: "HEAD" });
183
- const ct = res.headers.get("content-type") ?? "";
184
- if (res.ok && !ct.includes("text/html")) return candidate;
185
- } catch {}
186
- return null;
187
- }
188
- function resolveAssetBaseUrl(entryUrl, manifest, manifestUrl) {
189
- const remoteEntry = manifest?.metaData?.remoteEntry;
190
- if (remoteEntry?.name) return resolveEntryAssetUrl(remoteEntry, manifestUrl);
191
- if (!isManifestEntry(entryUrl)) return entryUrl;
192
- return new URL("remoteEntry.js", manifestUrl.replace(/\/[^/]+$/, "/")).href;
193
- }
194
- async function buildEntryContext(entryUrl) {
195
- const manifestUrl = getManifestUrl(entryUrl);
196
- const manifest = await fetchManifestCached(manifestUrl);
197
- const assetBaseUrl = resolveAssetBaseUrl(entryUrl, manifest, manifestUrl);
198
- return {
199
- entryUrl,
200
- manifestUrl,
201
- manifest,
202
- assetBaseUrl,
203
- filename: getEntryFilename(assetBaseUrl),
204
- remoteOrigin: assetBaseUrl.replace(/\/[^/]+$/, "")
205
- };
206
- }
207
- function buildSsrEntryCandidates(ctx, options = {}) {
208
- const { assetBaseUrl, filename, remoteOrigin } = ctx;
209
- const base = assetBaseUrl.replace(/\.[^.]+$/, "");
210
- const candidates = [];
211
- if (!options.skipServerBuild) candidates.push({
212
- url: `${remoteOrigin}/__mf_server__/${filename}.ssr.js`,
213
- type: "module",
214
- versionKey: UNVERSIONED
215
- });
216
- candidates.push({
217
- url: `${base}.ssr.js`,
218
- type: "module",
219
- versionKey: UNVERSIONED
220
- }, {
221
- url: `${remoteOrigin}/__mf_ssr__/${filename}.ssr.js`,
222
- type: "module",
223
- versionKey: UNVERSIONED
224
- });
225
- return candidates;
226
- }
227
- async function resolveFirstReachableCandidate(candidates) {
228
- for (const candidate of candidates) {
229
- const hit = await headCheckSsrEntry(candidate);
230
- if (hit) return hit;
231
- }
232
- return null;
233
- }
234
- async function resolveSSREntryImpl(remoteEntryUrl) {
235
- if (isSsrEntry(remoteEntryUrl)) return {
236
- url: remoteEntryUrl,
237
- type: "module",
238
- versionKey: UNVERSIONED
239
- };
240
- if (!isManifestEntry(remoteEntryUrl)) {
241
- const filename = getEntryFilename(remoteEntryUrl);
242
- const fromServerBuild = await headCheckSsrEntry({
243
- url: `${remoteEntryUrl.replace(/\/[^/]+$/, "")}/__mf_server__/${filename}.ssr.js`,
244
- type: "module",
245
- versionKey: UNVERSIONED
246
- });
247
- if (fromServerBuild) return fromServerBuild;
248
- }
249
- const ctx = await buildEntryContext(remoteEntryUrl);
250
- if (ctx.manifest) {
251
- const fromManifest = resolveSSREntryUrl(ctx.manifest, ctx.manifestUrl);
252
- if (fromManifest) return fromManifest;
253
- }
254
- return resolveFirstReachableCandidate(buildSsrEntryCandidates(ctx, { skipServerBuild: !isManifestEntry(remoteEntryUrl) }));
255
- }
256
- function setSsrEntryCache(remoteEntryUrl) {
257
- const record = {
258
- promise: resolveSSREntryImpl(remoteEntryUrl),
259
- resolvedAt: Date.now()
260
- };
261
- ssrEntryCache.set(remoteEntryUrl, record);
262
- return record;
263
- }
264
- async function getSSREntry(remoteEntryUrl, maxAgeMs) {
265
- const cached = ssrEntryCache.get(remoteEntryUrl);
266
- if (!cached) return setSsrEntryCache(remoteEntryUrl).promise;
267
- if (!(typeof maxAgeMs === "number" && maxAgeMs >= 0 && Date.now() - cached.resolvedAt >= maxAgeMs)) return cached.promise;
268
- const previous = await cached.promise.catch(() => null);
269
- manifestFetchCache.delete(getManifestUrl(remoteEntryUrl));
270
- const record = setSsrEntryCache(remoteEntryUrl);
271
- const next = await record.promise.catch(() => null);
272
- if (previous && next && previous.versionKey !== next.versionKey) dropRemoteCaches(remoteEntryUrl);
273
- return record.promise;
274
- }
275
- /**
276
- * Drop per-remote caches after a version change so old artifacts stop being
277
- * reused. Temp-file cache keys hold SSR entry/chunk URLs (not the browser
278
- * entry URL), so scope the invalidation by origin.
279
- */
280
- function dropRemoteCaches(remoteEntryUrl) {
281
- let origin;
282
- try {
283
- origin = new URL(remoteEntryUrl).origin;
284
- } catch {
285
- return;
286
- }
287
- for (const key of tempFileCache.keys()) if (key.slice(key.indexOf("::") + 2).startsWith(origin)) tempFileCache.delete(key);
288
- }
289
- /**
290
- * Drop the loader's caches so the next `loadEntry` re-resolves and re-fetches
291
- * remote SSR entries. Pass a remote entry URL to scope the invalidation to one
292
- * remote; call with no arguments to invalidate everything.
293
- *
294
- * Note: the MF runtime keeps its own container/module caches per federation
295
- * instance. This function best-effort clears the module caches of all global
296
- * federation instances so re-renders load fresh remote modules, but hosts that
297
- * hold direct references to previously loaded modules keep those references.
298
- */
299
- function revalidate(remoteEntryUrl) {
300
- if (remoteEntryUrl) {
301
- ssrEntryCache.delete(remoteEntryUrl);
302
- manifestFetchCache.delete(getManifestUrl(remoteEntryUrl));
303
- dropRemoteCaches(remoteEntryUrl);
304
- } else {
305
- ssrEntryCache.clear();
306
- manifestFetchCache.clear();
307
- tempFileCache.clear();
308
- }
309
- const federation = globalThis.__FEDERATION__;
310
- for (const instance of federation?.__INSTANCES__ ?? []) try {
311
- instance?.moduleCache?.clear?.();
312
- } catch {}
313
- }
314
- const tempFileCache = /* @__PURE__ */ new Map();
315
- let ssrCacheDirPromise;
316
- async function getSSRCacheDir() {
317
- if (!ssrCacheDirPromise) ssrCacheDirPromise = (async () => {
318
- const { join } = await _path();
319
- const { rmSync } = await _fs();
320
- const dir = join(process.cwd(), "node_modules", ".ssr-cache");
321
- process.once("exit", () => {
322
- try {
323
- rmSync(dir, {
324
- recursive: true,
325
- force: true
326
- });
327
- } catch {}
328
- });
329
- return dir;
330
- })();
331
- return ssrCacheDirPromise;
332
- }
333
- /**
334
- * Neutralize browser-only preload machinery in Vite/Rolldown output so the
335
- * code can evaluate in Node. Shared by the temp-file and vm strategies.
336
- */
337
- function neutralizeBrowserPreloadHelpers(code) {
338
- code = code.replace(/import\s*\{([^}]*)\}\s*from\s*["'][^"']*preload-helper[^"']*["'];?/g, (_m, bindings) => {
339
- return bindings.split(",").map((b) => {
340
- const parts = b.trim().split(/\s+as\s+/);
341
- return (parts[1] ?? parts[0]).trim();
342
- }).filter(Boolean).map((l) => `const ${l} = (fn) => fn();`).join("\n");
343
- });
344
- code = code.replace(/__vite__mapDeps\([^)]+\)/g, "[]");
345
- code = code.replace(/\b([A-Za-z_$][\w$]*)\s*\(\s*\(\s*\)\s*=>\s*import\(([^)]*)\)\s*,\s*\[\]\s*\)/g, "import($2)");
346
- return code;
347
- }
348
- function transformSsrCode(code, base, sharedPkgMap) {
349
- code = code.replace(/((?:from|export\s*\*\s*from)\s*)(["'`])(\.\.?\/[^"'`\s][^"'`]*)["'`]/g, (_m, prefix, _q, specifier) => `${prefix}"${new URL(specifier, base).href}"`);
350
- code = code.replace(/(import\s*)(["'`])(\.\.?\/[^"'`\s][^"'`]*)["'`]/g, (_m, prefix, _q, specifier) => `${prefix}"${new URL(specifier, base).href}"`);
351
- code = code.replace(/(import\s*\(\s*)(["'`])(\.\.?\/[^"'`\s][^"'`]*)["'`](\s*\))/g, (_m, prefix, _q, specifier, suffix) => `${prefix}"${new URL(specifier, base).href}"${suffix}`);
352
- if (sharedPkgMap && sharedPkgMap.size > 0) code = code.replace(/(?:from|import\s*\()\s*(["'`])([^"'`./][^"'`]*)["'`]/g, (m, _q, specifier) => {
353
- const resolved = sharedPkgMap.get(specifier);
354
- return resolved ? m.replace(specifier, `file://${resolved}`) : m;
355
- });
356
- return neutralizeBrowserPreloadHelpers(code);
357
- }
358
- function isVitePreloadHelperSpecifier(specifier) {
359
- return specifier.includes("preload-helper");
360
- }
361
- /**
362
- * Fetch an HTTP ESM module, transform it, write it to a temp .js file and
363
- * return the file path. Recursively does the same for HTTP transitive imports
364
- * so that `import('file:///...temp.js')` can resolve them.
365
- *
366
- * `versionKey` participates in both the cache key and the temp file name, so
367
- * a remote redeploy (new manifest → new key) produces new files and bypasses
368
- * Node's ESM module cache instead of serving the stale build.
369
- */
370
- async function fetchEsmToTempFile(url, tmpDir, visited, sharedPkgMap, versionKey = UNVERSIONED) {
371
- const cacheKey = `${versionKey}::${url}`;
372
- if (visited.has(url)) return visited.get(url);
373
- if (tempFileCache.has(cacheKey)) return tempFileCache.get(cacheKey);
374
- const promise = (async () => {
375
- const res = await fetch(url);
376
- let code = await res.text();
377
- if (!res.ok) throw new SsrEntryHttpError(url, res.status, res.statusText, getBodyPreview(code));
378
- const base = url.replace(/\/[^/]*$/, "/");
379
- const relImports = [];
380
- const relRegex = /(?:from|export\s*\*\s*from|import\s*(?:\(|\s))\s*["'`]([^"'`\s]+)["'`]/g;
381
- let m;
382
- while ((m = relRegex.exec(code)) !== null) if ((m[1].startsWith("./") || m[1].startsWith("../")) && !isVitePreloadHelperSpecifier(m[1])) relImports.push(new URL(m[1], base).href);
383
- const subMap = /* @__PURE__ */ new Map();
384
- await Promise.all([...new Set(relImports)].filter((u) => u.startsWith("http://") || u.startsWith("https://")).map(async (u) => {
385
- const tmpPath = await fetchEsmToTempFile(u, tmpDir, visited, sharedPkgMap, versionKey);
386
- subMap.set(u, `file://${tmpPath}`);
387
- }));
388
- code = transformSsrCode(code, base, sharedPkgMap);
389
- for (const [httpUrl, fileUrl] of subMap) code = code.split(httpUrl).join(fileUrl);
390
- const { createHash } = await _crypto();
391
- const { join } = await _path();
392
- const { writeFileSync } = await _fs();
393
- const tmpFile = join(tmpDir, `${createHash("sha1").update(cacheKey).digest("hex").slice(0, 12)}.js`);
394
- writeFileSync(tmpFile, code, "utf8");
395
- visited.set(url, tmpFile);
396
- return tmpFile;
397
- })();
398
- tempFileCache.set(cacheKey, promise);
399
- return promise;
400
- }
401
- async function importTempModule(filePath, versionKey) {
402
- return await import(`${filePath}?v=${encodeURIComponent(versionKey)}`);
403
- }
404
- let warnedVmUnavailable = false;
405
- async function tryVmStrategy(ssrEntry, options) {
406
- const { loadViaVmStrategy, isVmStrategyAvailable } = await import("../ssrVmStrategy-DtpfkCw1.js");
407
- if (!await isVmStrategyAvailable()) {
408
- if (!warnedVmUnavailable) {
409
- warnedVmUnavailable = true;
410
- console.warn("[mf-vite:ssr-entry-loader] strategy \"vm\" requires vm.SourceTextModule (run Node with --experimental-vm-modules); falling back to the temp-file strategy.");
411
- }
412
- return null;
413
- }
414
- return await loadViaVmStrategy(ssrEntry.url, {
415
- resolvedShared: options.resolvedShared,
416
- shareScopeName: options.shareScopeName,
417
- versionKey: ssrEntry.versionKey
418
- });
419
- }
420
- async function loadSSRRemoteEntry(ssrEntry, options) {
421
- const { url, type, versionKey } = ssrEntry;
422
- const { resolvedShared } = options;
423
- if (type === "commonjs-module" || type === "commonjs") {
424
- const { createRequire } = await _module();
425
- const req = createRequire(import.meta.url);
426
- try {
427
- return req(url);
428
- } catch {}
429
- }
430
- if (url.startsWith("http://") || url.startsWith("https://")) {
431
- const urlObj = new URL(url);
432
- if (urlObj.pathname.includes("/__mf_ssr__/")) {
433
- const remoteOrigin = urlObj.origin;
434
- const runner = await getOrCreateRunner(remoteOrigin);
435
- if (!runner) {
436
- if (process.env.NODE_ENV !== "production") return null;
437
- } else try {
438
- const mod = await runner.import(urlObj.pathname);
439
- if (mod && typeof mod === "object" && "init" in mod) return mod;
440
- if (process.env.NODE_ENV !== "production") return null;
441
- } catch {
442
- if (process.env.NODE_ENV !== "production") return null;
443
- }
444
- }
445
- if (options.strategy === "vm") try {
446
- const fromVm = await tryVmStrategy(ssrEntry, options);
447
- if (fromVm) return fromVm;
448
- } catch (error) {
449
- if (isSsrEntryHttpError(error)) throw error;
450
- }
451
- const { mkdirSync } = await _fs();
452
- const cacheDir = await getSSRCacheDir();
453
- mkdirSync(cacheDir, { recursive: true });
454
- const sharedPkgMap = new Map(Object.entries(resolvedShared));
455
- try {
456
- return await importTempModule(await fetchEsmToTempFile(url, cacheDir, /* @__PURE__ */ new Map(), sharedPkgMap, versionKey), versionKey);
457
- } catch (error) {
458
- if (isSsrEntryHttpError(error)) throw error;
459
- return null;
460
- }
461
- }
462
- try {
463
- return await import(
464
- /* @vite-ignore */
465
- url
466
- );
467
- } catch {
468
- return null;
469
- }
470
- }
471
- function ssrEntryLoaderPlugin(options = {}) {
472
- const resolved = {
473
- resolvedShared: options.resolvedShared ?? {},
474
- strategy: options.strategy ?? "temp-file",
475
- shareScopeName: options.shareScopeName ?? "default",
476
- maxAgeMs: options.maxAgeMs
477
- };
478
- return {
479
- name: "mf-vite:ssr-entry-loader",
480
- async loadEntry({ remoteInfo }) {
481
- if (!isNodeServer()) return;
482
- const ssrEntry = await getSSREntry(remoteInfo.entry, resolved.maxAgeMs);
483
- if (!ssrEntry) return;
484
- const mod = await loadSSRRemoteEntry(ssrEntry, resolved);
485
- if (!mod) return;
486
- return mod;
487
- }
488
- };
489
- }
490
- //#endregion
1
+ import { i as ssrEntryLoaderPlugin, n as neutralizeBrowserPreloadHelpers, r as revalidate, t as SsrEntryHttpError } from "../ssrEntryLoader-D_sUES94.js";
491
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.17.0",
3
+ "version": "1.17.1",
4
4
  "description": "Vite plugin for Module Federation",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",