From db13cf65919103f86ca548dc0ec3995b5a635efa Mon Sep 17 00:00:00 2001 From: Giorgio Boa <35845425+gioboa@users.noreply.github.com> Date: Mon, 3 Aug 2026 08:33:15 +0200 Subject: [PATCH 01/32] fix(retry-plugin): fix ESM remote entry retry (#4877) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Néstor --- .changeset/icy-llamas-tell.md | 6 + .../3005-runtime-host/cypress/e2e/app.cy.ts | 19 +++ .../3005-runtime-host/package.json | 1 + .../3005-runtime-host/src/App.tsx | 5 + .../3005-runtime-host/src/EsmRetryDemo.tsx | 48 ++++++++ .../3005-runtime-host/webpack.config.js | 30 +++++ packages/retry-plugin/__tests__/retry.spec.ts | 72 ++++++++++++ packages/retry-plugin/src/index.ts | 7 +- packages/runtime-core/__tests__/load.spec.ts | 108 ++++++++++++++++++ packages/runtime-core/src/utils/load.ts | 56 ++++++++- pnpm-lock.yaml | 3 + 11 files changed, 348 insertions(+), 7 deletions(-) create mode 100644 .changeset/icy-llamas-tell.md create mode 100644 apps/runtime-demo/3005-runtime-host/src/EsmRetryDemo.tsx diff --git a/.changeset/icy-llamas-tell.md b/.changeset/icy-llamas-tell.md new file mode 100644 index 00000000000..64834ff0e00 --- /dev/null +++ b/.changeset/icy-llamas-tell.md @@ -0,0 +1,6 @@ +--- +'@module-federation/runtime-core': patch +'@module-federation/retry-plugin': patch +--- + +Fix retry-plugin recovery for ESM and module remote entry load failures, including default cache-busting retries. diff --git a/apps/runtime-demo/3005-runtime-host/cypress/e2e/app.cy.ts b/apps/runtime-demo/3005-runtime-host/cypress/e2e/app.cy.ts index f37b336bb8a..24b8c378504 100644 --- a/apps/runtime-demo/3005-runtime-host/cypress/e2e/app.cy.ts +++ b/apps/runtime-demo/3005-runtime-host/cypress/e2e/app.cy.ts @@ -123,6 +123,25 @@ describe('3005-runtime-host/', () => { }); }); + describe('ESM remote retry', () => { + it('re-requests a failed module entry with the default retry config', () => { + const requestUrls: string[] = []; + cy.intercept('GET', '**/esm-retry-fixture/remoteEntry.js*', (request) => { + requestUrls.push(request.url); + }); + cy.visit('/esm-retry'); + + cy.get('[data-testid="esm-retry-load"]').click(); + cy.get('[data-testid="esm-retry-status"]') + .should('contain', 'ESM retry recovered') + .then(() => { + expect(requestUrls).to.have.length(2); + expect(requestUrls[0]).not.to.contain('retryCount'); + expect(requestUrls[1]).to.contain('retryCount=1'); + }); + }); + }); + describe('observability demo fixture', () => { beforeEach(() => { cy.visit('/observability'); diff --git a/apps/runtime-demo/3005-runtime-host/package.json b/apps/runtime-demo/3005-runtime-host/package.json index 91cad0cc326..337b7928198 100644 --- a/apps/runtime-demo/3005-runtime-host/package.json +++ b/apps/runtime-demo/3005-runtime-host/package.json @@ -5,6 +5,7 @@ "devDependencies": { "@module-federation/core": "workspace:*", "@module-federation/observability-plugin": "workspace:*", + "@module-federation/retry-plugin": "workspace:*", "@module-federation/runtime": "workspace:*", "@module-federation/typescript": "workspace:*", "@module-federation/enhanced": "workspace:*", diff --git a/apps/runtime-demo/3005-runtime-host/src/App.tsx b/apps/runtime-demo/3005-runtime-host/src/App.tsx index 5b3bcd1bc0e..347dd8b04ef 100644 --- a/apps/runtime-demo/3005-runtime-host/src/App.tsx +++ b/apps/runtime-demo/3005-runtime-host/src/App.tsx @@ -8,6 +8,7 @@ import { } from 'react-router-dom'; import ObservabilityDemo from './ObservabilityDemo'; import ObservabilityShowcase from './ObservabilityShowcase'; +import EsmRetryDemo from './EsmRetryDemo'; import Root from './Root'; import Remote1 from './Remote1'; import Remote2 from './Remote2'; @@ -37,6 +38,9 @@ const AppRoutes = () => {
  • observability showcase
  • +
  • + ESM retry +
  • ) : null} @@ -49,6 +53,7 @@ const AppRoutes = () => { path="/observability-showcase/*" element={} /> + } /> ); diff --git a/apps/runtime-demo/3005-runtime-host/src/EsmRetryDemo.tsx b/apps/runtime-demo/3005-runtime-host/src/EsmRetryDemo.tsx new file mode 100644 index 00000000000..9a11454afbe --- /dev/null +++ b/apps/runtime-demo/3005-runtime-host/src/EsmRetryDemo.tsx @@ -0,0 +1,48 @@ +import React, { useCallback, useState } from 'react'; +import { RetryPlugin } from '@module-federation/retry-plugin'; +import { createInstance } from '@module-federation/runtime'; + +type RetryRemote = { + default: string; +}; + +const EsmRetryDemo = () => { + const [status, setStatus] = useState('idle'); + + const loadRemote = useCallback(async () => { + setStatus('loading'); + await fetch('/esm-retry-fixture/reset', { method: 'POST' }); + + const runtime = createInstance({ + name: `esm_retry_host_${Date.now()}`, + remotes: [ + { + name: 'esm_retry_remote', + entry: 'http://127.0.0.1:3005/esm-retry-fixture/remoteEntry.js', + type: 'module', + }, + ], + plugins: [RetryPlugin({ retryTimes: 1, retryDelay: 0 })], + }); + + try { + const remote = await runtime.loadRemote( + 'esm_retry_remote/message', + ); + setStatus(remote?.default ?? 'missing result'); + } catch (error) { + setStatus(error instanceof Error ? error.message : String(error)); + } + }, []); + + return ( +
    + +

    {status}

    +
    + ); +}; + +export default EsmRetryDemo; diff --git a/apps/runtime-demo/3005-runtime-host/webpack.config.js b/apps/runtime-demo/3005-runtime-host/webpack.config.js index 18d57b4adb8..f1fd4395d11 100644 --- a/apps/runtime-demo/3005-runtime-host/webpack.config.js +++ b/apps/runtime-demo/3005-runtime-host/webpack.config.js @@ -173,6 +173,7 @@ module.exports = (_env, argv = {}) => { response.setHeader('Content-Type', 'application/javascript'); response.end(body); }; + let esmRetryRequestCount = 0; const createManifest = ({ name, globalName, publicPath }) => ({ id: name, name, @@ -219,6 +220,35 @@ module.exports = (_env, argv = {}) => { ], }); + devServer.app.post('/esm-retry-fixture/reset', (_request, response) => { + esmRetryRequestCount = 0; + response.statusCode = 204; + response.end(); + }); + devServer.app.get( + '/esm-retry-fixture/remoteEntry.js', + (_request, response) => { + esmRetryRequestCount += 1; + response.setHeader('Cache-Control', 'no-store'); + + if (esmRetryRequestCount === 1) { + response.statusCode = 503; + response.end('ESM remote unavailable'); + return; + } + + sendJs( + response, + [ + 'export function init() {}', + 'export function get() {', + " return Promise.resolve(function() { return { default: 'ESM retry recovered' }; });", + '}', + ].join('\n'), + ); + }, + ); + devServer.app.get( '/observability-fixtures/missing-fields/mf-manifest.json', (_request, response) => { diff --git a/packages/retry-plugin/__tests__/retry.spec.ts b/packages/retry-plugin/__tests__/retry.spec.ts index 9eb78f2b5ed..5b701ccbbdd 100644 --- a/packages/retry-plugin/__tests__/retry.spec.ts +++ b/packages/retry-plugin/__tests__/retry.spec.ts @@ -1,5 +1,6 @@ import { describe, it, expect, beforeEach, afterEach, rs } from '@rstest/core'; import { fetchRetry } from '../src/fetch-retry'; +import { RetryPlugin } from '../src'; import { scriptRetry } from '../src/script-retry'; import { ERROR_ABANDONED, RUNTIME_008 } from '../src/constant'; @@ -21,6 +22,77 @@ describe('Retry Plugin', () => { rs.useRealTimers(); }); + describe('RetryPlugin', () => { + const createLoadEntryErrorArgs = ( + type: 'global' | 'esm' | 'module', + getRemoteEntry: ReturnType, + ) => + ({ + getRemoteEntry, + origin: {}, + remoteInfo: { + name: 'remote', + entry: 'https://example.com/remoteEntry.js', + type, + }, + remoteEntryExports: undefined, + globalLoading: {}, + uniqueKey: 'remote', + }) as any; + + it.each(['esm', 'module'] as const)( + 'adds a retry query by default for %s remote entries', + async (type) => { + const getRemoteEntry = rs.fn(async ({ getEntryUrl }) => ({ + url: getEntryUrl('https://example.com/remoteEntry.js'), + })); + const plugin = RetryPlugin({ retryTimes: 1, retryDelay: 0 }); + + const result = await plugin.loadEntryError!( + createLoadEntryErrorArgs(type, getRemoteEntry), + ); + + expect(result).toEqual({ + url: 'https://example.com/remoteEntry.js?retryCount=1', + }); + }, + ); + + it('does not add a retry query by default for global remote entries', async () => { + const getRemoteEntry = rs.fn(async ({ getEntryUrl }) => ({ + url: getEntryUrl('https://example.com/remoteEntry.js'), + })); + const plugin = RetryPlugin({ retryTimes: 1, retryDelay: 0 }); + + const result = await plugin.loadEntryError!( + createLoadEntryErrorArgs('global', getRemoteEntry), + ); + + expect(result).toEqual({ + url: 'https://example.com/remoteEntry.js', + }); + }); + + it('respects addQuery false for module remote entries', async () => { + const getRemoteEntry = rs.fn(async ({ getEntryUrl }) => ({ + url: getEntryUrl('https://example.com/remoteEntry.js'), + })); + const plugin = RetryPlugin({ + retryTimes: 1, + retryDelay: 0, + addQuery: false, + }); + + const result = await plugin.loadEntryError!( + createLoadEntryErrorArgs('module', getRemoteEntry), + ); + + expect(result).toEqual({ + url: 'https://example.com/remoteEntry.js', + }); + }); + }); + describe('fetchRetry', () => { it('should retry on fetch failure', async () => { const mockResponse = { diff --git a/packages/retry-plugin/src/index.ts b/packages/retry-plugin/src/index.ts index 1a5c9851a81..063641230b7 100644 --- a/packages/retry-plugin/src/index.ts +++ b/packages/retry-plugin/src/index.ts @@ -63,6 +63,11 @@ const RetryPlugin = ( globalLoading, uniqueKey, }: LoadEntryErrorArgs) { + const retryAddQuery = + addQuery === undefined && + (remoteInfo.type === 'esm' || remoteInfo.type === 'module') + ? true + : addQuery; const beforeExecuteRetry = () => { delete globalLoading[uniqueKey]; }; @@ -72,7 +77,7 @@ const RetryPlugin = ( retryTimes, retryDelay, domains, - addQuery, + addQuery: retryAddQuery, onRetry, onSuccess, onError, diff --git a/packages/runtime-core/__tests__/load.spec.ts b/packages/runtime-core/__tests__/load.spec.ts index f2ca8a439ba..042bbc1e392 100644 --- a/packages/runtime-core/__tests__/load.spec.ts +++ b/packages/runtime-core/__tests__/load.spec.ts @@ -23,6 +23,8 @@ mockStaticServer({ }); const createMF = () => new ModuleFederation({ name: 'test-host', remotes: [] }); +const createDataUrlEntry = (code: string) => + `data:text/javascript;charset=utf-8,${encodeURIComponent(code)}`; describe('getRemoteEntry - script load error discrimination', () => { beforeEach(() => { @@ -97,6 +99,112 @@ describe('getRemoteEntry - script load error discrimination', () => { ); }); + it('module entry load failure can recover through loadEntryError with getEntryUrl', async () => { + const entry = createDataUrlEntry( + `throw new TypeError('Failed to fetch dynamically imported module: http://localhost:4999/remoteEntry.js');`, + ); + const fallbackEntry = createDataUrlEntry(` + export function get() {} + export function init() {} + `); + const origin = createMF(); + const remoteInfo = getRemoteInfo({ name: 'remote', entry, type: 'module' }); + const getEntryUrl = rs.fn(() => fallbackEntry); + const loadEntryError = rs.fn( + async ({ getRemoteEntry, globalLoading, uniqueKey }) => { + delete globalLoading[uniqueKey]; + return getRemoteEntry({ + origin, + remoteInfo, + getEntryUrl, + }); + }, + ); + const afterLoadEntry = rs.fn(); + + origin.registerPlugins([ + { + name: 'module-entry-retry-test', + loadEntryError, + afterLoadEntry, + }, + ]); + + const result = await getRemoteEntry({ origin, remoteInfo }); + + expect(loadEntryError).toHaveBeenCalledTimes(1); + expect(getEntryUrl).toHaveBeenCalledWith(entry); + expect(result).toEqual( + expect.objectContaining({ + get: expect.any(Function), + init: expect.any(Function), + }), + ); + expect(afterLoadEntry).toHaveBeenCalledWith( + expect.objectContaining({ + remoteInfo, + remoteEntryExports: result, + recovered: true, + }), + ); + }); + + it('module entry load failure is reported as RUNTIME_008 when unrecovered', async () => { + const entry = createDataUrlEntry( + `throw new TypeError('Failed to fetch dynamically imported module: http://localhost:4999/remoteEntry.js');`, + ); + const origin = createMF(); + const remoteInfo = getRemoteInfo({ name: 'remote', entry, type: 'module' }); + + const err = await getRemoteEntry({ origin, remoteInfo }).catch((e) => e); + + expect(err.message).toContain(RUNTIME_008); + expect(err.message).toContain( + 'Failed to fetch dynamically imported module', + ); + }); + + it('module entry execution errors are not retried through loadEntryError', async () => { + const entry = createDataUrlEntry( + `throw new Error('remote entry execution failed');`, + ); + const origin = createMF(); + const remoteInfo = getRemoteInfo({ name: 'remote', entry, type: 'module' }); + const loadEntryError = rs.fn(); + + origin.registerPlugins([ + { + name: 'module-entry-execution-error-test', + loadEntryError, + }, + ]); + + const err = await getRemoteEntry({ origin, remoteInfo }).catch((e) => e); + + expect(err.message).toContain('remote entry execution failed'); + expect(loadEntryError).not.toHaveBeenCalled(); + }); + + it('module entry TypeError execution errors are not reported as RUNTIME_008', async () => { + const entry = createDataUrlEntry(`throw new TypeError('Load failed');`); + const origin = createMF(); + const remoteInfo = getRemoteInfo({ name: 'remote', entry, type: 'module' }); + const loadEntryError = rs.fn(); + + origin.registerPlugins([ + { + name: 'module-entry-type-error-test', + loadEntryError, + }, + ]); + + const err = await getRemoteEntry({ origin, remoteInfo }).catch((e) => e); + + expect(err.message).toContain('Load failed'); + expect(err.message).not.toContain(RUNTIME_008); + expect(loadEntryError).not.toHaveBeenCalled(); + }); + it('remote container init failure is reported as RUNTIME_015 with the original error', async () => { const entry = `${BASE}/init-error.js`; const mf = new ModuleFederation({ diff --git a/packages/runtime-core/src/utils/load.ts b/packages/runtime-core/src/utils/load.ts index 7bcc7c3ded6..a624f9a109f 100644 --- a/packages/runtime-core/src/utils/load.ts +++ b/packages/runtime-core/src/utils/load.ts @@ -24,6 +24,22 @@ import { declare const ENV_TARGET: 'web' | 'node'; const importCallback = '.then(callbacks[0]).catch(callbacks[1])'; +const esmRemoteEntryLoadErrorMessages = [ + 'Failed to fetch dynamically imported module', + 'Importing a module script failed', + 'error loading dynamically imported module', +]; + +function isEsmRemoteEntryLoadError(err: unknown): boolean { + if (!(err instanceof TypeError)) { + return false; + } + + return esmRemoteEntryLoadErrorMessages.some((loadErrorMessage) => + err.message.includes(loadErrorMessage), + ); +} + export function isEsmRemoteType(type: RemoteInfo['type']): boolean { return type === 'esm' || type === 'module'; } @@ -31,29 +47,57 @@ export function isEsmRemoteType(type: RemoteInfo['type']): boolean { async function loadEsmEntry({ entry, remoteEntryExports, + name, + getEntryUrl, }: { entry: string; remoteEntryExports: RemoteEntryExports | undefined; + name: string; + getEntryUrl?: (url: string) => string; }): Promise { return new Promise((resolve, reject) => { + const rejectEntry = (loadError: unknown) => { + if (isEsmRemoteEntryLoadError(loadError)) { + const originalMsg = + loadError instanceof Error ? loadError.message : String(loadError); + try { + error( + RUNTIME_008, + runtimeDescMap, + { + remoteName: name, + resourceUrl: url, + }, + originalMsg, + ); + } catch (runtimeError) { + reject(runtimeError); + return; + } + } + + reject(loadError); + }; + + const url = getEntryUrl ? getEntryUrl(entry) : entry; try { if (!remoteEntryExports) { if (typeof FEDERATION_ALLOW_NEW_FUNCTION !== 'undefined') { - new Function('callbacks', `import("${entry}")${importCallback}`)([ + new Function('callbacks', `import("${url}")${importCallback}`)([ resolve, - reject, + rejectEntry, ]); } else { - import(/* webpackIgnore: true */ /* @vite-ignore */ entry) + import(/* webpackIgnore: true */ /* @vite-ignore */ url) .then(resolve) - .catch(reject); + .catch(rejectEntry); } } else { resolve(remoteEntryExports); } } catch (e) { const msg = e instanceof Error ? e.message : String(e); - error(`Failed to load ESM entry from "${entry}". ${msg}`); + error(`Failed to load ESM entry from "${url}". ${msg}`); } }); } @@ -205,7 +249,7 @@ async function loadEntryDom({ }) { const { entry, entryGlobalName: globalName, name, type } = remoteInfo; if (isEsmRemoteType(type)) { - return loadEsmEntry({ entry, remoteEntryExports }); + return loadEsmEntry({ entry, remoteEntryExports, name, getEntryUrl }); } if (type === 'system') { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4b15ef49a5c..4b552b5ebbb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2463,6 +2463,9 @@ importers: '@module-federation/observability-plugin': specifier: workspace:* version: link:../../../packages/observability-plugin + '@module-federation/retry-plugin': + specifier: workspace:* + version: link:../../../packages/retry-plugin '@module-federation/runtime': specifier: workspace:* version: link:../../../packages/runtime From 45b01e11331750814ad2eac96468792754883fa5 Mon Sep 17 00:00:00 2001 From: Giorgio Boa <35845425+gioboa@users.noreply.github.com> Date: Mon, 3 Aug 2026 13:35:57 +0200 Subject: [PATCH 02/32] docs: add ESM retry cache-busting defaults (#4951) --- .../docs/en/plugin/plugins/retry-plugin.mdx | 14 +++++++++++++- .../docs/zh/plugin/plugins/retry-plugin.mdx | 14 +++++++++++++- packages/retry-plugin/README.md | 7 ++++++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/apps/website-new/docs/en/plugin/plugins/retry-plugin.mdx b/apps/website-new/docs/en/plugin/plugins/retry-plugin.mdx index 620725e1e74..b5b4edc69bd 100644 --- a/apps/website-new/docs/en/plugin/plugins/retry-plugin.mdx +++ b/apps/website-new/docs/en/plugin/plugins/retry-plugin.mdx @@ -133,7 +133,9 @@ const mf = createInstance({ **addQuery** - Type: `boolean | ((context: { times: number; originalQuery: string }) => string)` - Optional -- Whether to append a query parameter when retrying, default is false +- Whether to append a query parameter when retrying +- Defaults to cache-busting for `esm` and `module` remote entry retries because browsers cache failed dynamic imports by URL. Other retry paths do not add a query parameter by default +- Set `addQuery: false` to opt out of the default ESM/module remote entry cache-busting - If a function is provided, it receives retry count and the original query string, and should return the new query string **fetchOptions** @@ -199,6 +201,16 @@ Order of attempts: Use `addQuery` to add query parameters during retries to avoid cache interference: +For remote entries with type `esm` or `module`, the plugin adds `retryCount` by default so each dynamic import retry uses a new URL. This default does not affect manifest, fetch, or classic script retries. Disable it explicitly if needed: + +```javascript +const retryPlugin = RetryPlugin({ + addQuery: false, +}); +``` + +To enable cache-busting for every retry path: + ```javascript const retryPlugin = RetryPlugin({ addQuery: true, // adds ?retryCount=1, ?retryCount=2, etc. diff --git a/apps/website-new/docs/zh/plugin/plugins/retry-plugin.mdx b/apps/website-new/docs/zh/plugin/plugins/retry-plugin.mdx index c923c68bb9f..9667737ad74 100644 --- a/apps/website-new/docs/zh/plugin/plugins/retry-plugin.mdx +++ b/apps/website-new/docs/zh/plugin/plugins/retry-plugin.mdx @@ -133,7 +133,9 @@ const mf = createInstance({ **addQuery** - 类型:`boolean | ((context: { times: number; originalQuery: string }) => string)` - 可选 -- 是否在重试时添加查询参数,默认为 false +- 是否在重试时添加查询参数 +- `esm` 和 `module` 类型的远程入口重试默认会添加缓存破坏参数,因为浏览器会按 URL 缓存失败的动态导入。其他重试路径默认不添加查询参数 +- 可设置 `addQuery: false` 关闭 ESM/module 远程入口的默认缓存破坏行为 - 当为函数时,接收重试次数和原始查询字符串,返回新的查询字符串 **fetchOptions** @@ -199,6 +201,16 @@ const retryPlugin = RetryPlugin({ 通过 `addQuery` 参数可以在重试时添加查询参数,避免浏览器缓存影响: +对于 `esm` 或 `module` 类型的远程入口,插件默认添加 `retryCount`,确保每次动态导入重试使用新的 URL。此默认行为不会影响 manifest、fetch 或传统 script 重试。如需关闭: + +```javascript +const retryPlugin = RetryPlugin({ + addQuery: false, +}); +``` + +如需为所有重试路径启用缓存破坏: + ```javascript const retryPlugin = RetryPlugin({ addQuery: true, // 添加 ?retryCount=1, ?retryCount=2 等 diff --git a/packages/retry-plugin/README.md b/packages/retry-plugin/README.md index 7f6fb3a3eb0..4bf18d8401a 100644 --- a/packages/retry-plugin/README.md +++ b/packages/retry-plugin/README.md @@ -100,7 +100,7 @@ export default () => | `successTimes` | `number` | `0` | Number of successful requests required | | `domains` | `string[]` | `[]` | Alternative domains for script resources | | `manifestDomains` | `string[]` | `[]` | Alternative domains for manifest files | -| `addQuery` | `boolean \| function` | `false` | Add query parameters for cache busting | +| `addQuery` | `boolean \| function` | See below | Add query parameters for cache busting | | `fetchOptions` | `RequestInit` | `{}` | Additional fetch options | | `onRetry` | `function` | `undefined` | Callback when retry occurs | | `onSuccess` | `function` | `undefined` | Callback when request succeeds | @@ -108,6 +108,11 @@ export default () => ### addQuery Function +When omitted, `addQuery` defaults to `true` only for `esm` and `module` remote +entry retries. This gives failed dynamic imports a new URL because browsers cache +their failures by URL. Manifest, fetch, and classic script retries still default +to no query parameter. Set `addQuery: false` to disable the ESM/module default. + ```ts addQuery: ({ times, originalQuery }) => { // Add retry count and timestamp for cache busting From 179caf45b2a9bd5c89ccd39f15994fd8638a0cdf Mon Sep 17 00:00:00 2001 From: Petr Glaser <12586960+BleedingDev@users.noreply.github.com> Date: Wed, 5 Aug 2026 00:01:49 +0200 Subject: [PATCH 03/32] fix(bridge-react): dedupe SSR stylesheet assets (#4852) Co-authored-by: Hanric Co-authored-by: ScriptedAlchemy --- .changeset/clean-bridge-css-hydration.md | 5 + .../HydratedStylesheetAssets.spec.tsx | 196 ++++++++++++++++++ .../__tests__/createLazyComponent.spec.tsx | 177 +++++++++++++--- .../src/lazy/HydratedStylesheetAssets.tsx | 189 +++++++++++++++++ .../src/lazy/createLazyComponent.tsx | 77 ++++--- 5 files changed, 586 insertions(+), 58 deletions(-) create mode 100644 .changeset/clean-bridge-css-hydration.md create mode 100644 packages/bridge/bridge-react/__tests__/HydratedStylesheetAssets.spec.tsx create mode 100644 packages/bridge/bridge-react/src/lazy/HydratedStylesheetAssets.tsx diff --git a/.changeset/clean-bridge-css-hydration.md b/.changeset/clean-bridge-css-hydration.md new file mode 100644 index 00000000000..f61b9757d3a --- /dev/null +++ b/.changeset/clean-bridge-css-hydration.md @@ -0,0 +1,5 @@ +--- +"@module-federation/bridge-react": patch +--- + +Prevent duplicate bridge React stylesheets during hydration while preserving public SSR asset output and stylesheet ownership across document and shadow roots. diff --git a/packages/bridge/bridge-react/__tests__/HydratedStylesheetAssets.spec.tsx b/packages/bridge/bridge-react/__tests__/HydratedStylesheetAssets.spec.tsx new file mode 100644 index 00000000000..5b625130f7d --- /dev/null +++ b/packages/bridge/bridge-react/__tests__/HydratedStylesheetAssets.spec.tsx @@ -0,0 +1,196 @@ +import { act, render, waitFor } from '@testing-library/react'; +import { hydrateRoot } from 'react-dom/client'; +import { renderToString } from 'react-dom/server'; +import { HydratedStylesheetAssets } from '../src/lazy/HydratedStylesheetAssets'; + +const href = 'https://cdn.example.com/remote.css'; + +describe('HydratedStylesheetAssets', () => { + beforeEach(() => { + document.head.innerHTML = ''; + document.body.innerHTML = ''; + }); + + it('hydrates the server link without a warning before suppressing a head duplicate', async () => { + document.head.innerHTML = ``; + const container = document.createElement('div'); + container.innerHTML = renderToString( + , + ); + document.body.append(container); + expect(container.querySelector('link')?.href).toBe(href); + + const onRecoverableError = jest.fn(); + let root: ReturnType; + await act(async () => { + root = hydrateRoot( + container, + , + { onRecoverableError }, + ); + }); + + await waitFor(() => expect(container.querySelector('link')).toBeNull()); + expect(onRecoverableError).not.toHaveBeenCalled(); + await act(async () => root!.unmount()); + }); + + it('keeps a matching stylesheet inside a shadow root', async () => { + document.head.innerHTML = ``; + const shadowRoot = document.body + .appendChild(document.createElement('div')) + .attachShadow({ mode: 'open' }); + const container = shadowRoot.appendChild(document.createElement('div')); + + render(, { container }); + + await waitFor(() => + expect(container.querySelector('link')?.href).toBe(href), + ); + }); + + it('uses the owner document base URI and ignores the parent document head', async () => { + document.head.innerHTML = ''; + const childDocument = document.implementation.createHTMLDocument('child'); + const base = childDocument.createElement('base'); + base.href = 'https://child.example.com/assets/'; + childDocument.head.append(base); + const container = childDocument.body.appendChild( + childDocument.createElement('div'), + ); + + render(, { + container, + baseElement: childDocument.body, + }); + + await waitFor(() => + expect(container.querySelector('link')?.href).toBe( + 'https://child.example.com/assets/remote.css', + ), + ); + + const childOwner = childDocument.createElement('link'); + childOwner.rel = 'stylesheet'; + childOwner.href = './remote.css'; + childDocument.head.append(childOwner); + await waitFor(() => expect(container.querySelector('link')).toBeNull()); + }); + + it('suppresses a late head owner and restores the link when it is removed', async () => { + const { container, rerender } = render( + , + ); + expect(container.querySelector('link')?.href).toBe(href); + + const owner = document.createElement('link'); + owner.rel = 'stylesheet'; + owner.href = href; + document.head.append(owner); + await waitFor(() => expect(container.querySelector('link')).toBeNull()); + + rerender(); + owner.remove(); + await waitFor(() => + expect(container.querySelector('link')?.href).toBe(href), + ); + }); + + it('keeps observing while another stylesheet group remains mounted', async () => { + const first = render(); + const second = render(); + const owner = document.createElement('link'); + owner.rel = 'stylesheet'; + owner.href = href; + document.head.append(owner); + + await waitFor(() => { + expect(first.container.querySelector('link')).toBeNull(); + expect(second.container.querySelector('link')).toBeNull(); + }); + + first.unmount(); + owner.remove(); + await waitFor(() => + expect(second.container.querySelector('link')?.href).toBe(href), + ); + }); + + it('disconnects the document observer after the last group unmounts', async () => { + const disconnect = jest.spyOn(MutationObserver.prototype, 'disconnect'); + try { + const rendered = render(); + await waitFor(() => + expect(rendered.container.querySelector('link')?.href).toBe(href), + ); + const callsBeforeUnmount = disconnect.mock.calls.length; + + rendered.unmount(); + + expect(disconnect.mock.calls.length).toBeGreaterThan(callsBeforeUnmount); + } finally { + disconnect.mockRestore(); + } + }); + + it('tracks changes that make a head owner active or inactive', async () => { + const owner = document.createElement('link'); + owner.rel = 'stylesheet'; + owner.href = href; + document.head.append(owner); + const { container } = render(); + await waitFor(() => expect(container.querySelector('link')).toBeNull()); + + owner.setAttribute('disabled', ''); + await waitFor(() => + expect(container.querySelector('link')?.href).toBe(href), + ); + + owner.removeAttribute('disabled'); + await waitFor(() => expect(container.querySelector('link')).toBeNull()); + + owner.type = 'text/plain'; + await waitFor(() => + expect(container.querySelector('link')?.href).toBe(href), + ); + + owner.type = 'text/css; charset=utf-8'; + await waitFor(() => expect(container.querySelector('link')).toBeNull()); + + owner.href = 'https://cdn.example.com/other.css'; + await waitFor(() => + expect(container.querySelector('link')?.href).toBe(href), + ); + }); + + it.each<[string, (link: HTMLLinkElement) => void]>([ + ['unsupported type', (link) => (link.type = 'text/plain')], + ['non-screen media', (link) => (link.media = 'print')], + ['alternate relation', (link) => (link.rel = 'alternate stylesheet')], + ['disabled state', (link) => link.setAttribute('disabled', '')], + ])('keeps the link for an inactive head stylesheet: %s', async (_, setup) => { + const inactive = document.createElement('link'); + inactive.rel = 'stylesheet'; + inactive.href = href; + setup(inactive); + document.head.append(inactive); + + const { container } = render(); + + await waitFor(() => + expect(container.querySelector('link')?.href).toBe(href), + ); + }); + + it('keeps React-owned stylesheets rendered in the document head', async () => { + render(, { + container: document.head, + }); + + await waitFor(() => + expect( + document.head.querySelectorAll(`link[href="${href}"]`), + ).toHaveLength(1), + ); + }); +}); diff --git a/packages/bridge/bridge-react/__tests__/createLazyComponent.spec.tsx b/packages/bridge/bridge-react/__tests__/createLazyComponent.spec.tsx index 9969cd0ca08..c351e3c2740 100644 --- a/packages/bridge/bridge-react/__tests__/createLazyComponent.spec.tsx +++ b/packages/bridge/bridge-react/__tests__/createLazyComponent.spec.tsx @@ -1,5 +1,6 @@ import React, { Suspense } from 'react'; import { render, screen, waitFor } from '@testing-library/react'; +import { renderToString } from 'react-dom/server'; import { createLazyComponent, collectSSRAssets, @@ -20,6 +21,22 @@ const MockComponent = () =>
    Mock Component
    ; const LoadingComponent = () =>
    Loading...
    ; const ErrorComponent = () =>
    Error!
    ; +const renderAssetsToFragment = (assets: React.ReactNode[]) => { + const template = document.createElement('template'); + template.innerHTML = renderToString(<>{assets}); + return template.content; +}; + +const getStylesheetHrefs = (root: ParentNode) => + Array.from( + root.querySelectorAll('link[rel="stylesheet"]'), + ).map((link) => link.href); + +const getScriptSrcs = (root: ParentNode) => + Array.from(root.querySelectorAll('script[src]')).map( + (script) => script.src, + ); + describe('createLazyComponent', () => { let mockInstance: any; @@ -124,13 +141,96 @@ describe('createLazyComponent', () => { ).toBeInTheDocument(); }); }); + + it('should suppress automatic SSR stylesheets owned by document head', async () => { + const previousFederationSSR = globalThis.FEDERATION_SSR; + let unmount: (() => void) | undefined; + globalThis.FEDERATION_SSR = true; + document.head.innerHTML = + ''; + mockFetchData.mockResolvedValue(undefined); + mockGetLoadedRemoteInfos.mockReturnValue({ + name: 'remoteApp', + alias: 'remote', + expose: './Component', + version: '1.0.0', + snapshot: { + modules: [ + { + modulePath: './Component', + assets: { + css: { sync: ['main.css'], async: [] }, + js: { sync: [], async: [] }, + }, + }, + ], + publicPath: 'http://localhost:3001/', + remoteEntry: 'remoteEntry.js', + }, + entryGlobalName: 'remoteApp', + }); + + const LazyComponent = createLazyComponent({ + loader: jest.fn().mockResolvedValue({ + default: MockComponent, + [Symbol.for('mf_module_id')]: 'remoteApp/Component', + }), + instance: mockInstance, + loading: , + fallback: , + injectLink: true, + }); + + try { + const rendered = render(); + const { container } = rendered; + unmount = rendered.unmount; + + await waitFor(() => { + expect(screen.getByText('Mock Component')).toBeInTheDocument(); + expect(getStylesheetHrefs(container)).toEqual([]); + }); + expect(getStylesheetHrefs(document.head)).toEqual([ + 'http://localhost:3001/main.css', + ]); + } finally { + unmount?.(); + globalThis.FEDERATION_SSR = previousFederationSSR; + document.head.innerHTML = ''; + } + }); }); describe('collectSSRAssets', () => { let mockInstance: any; + const mockRemoteAssets = ({ + css, + js = { sync: [], async: [] }, + }: { + css: { sync: string[]; async: string[] }; + js?: { sync: string[]; async: string[] }; + }) => { + mockGetLoadedRemoteInfos.mockReturnValue({ + name: 'remoteApp', + expose: './Component', + snapshot: { + publicPath: 'http://localhost:3001/', + remoteEntry: 'remoteEntry.js', + modules: [ + { + modulePath: './Component', + assets: { css, js }, + }, + ], + }, + }); + }; + beforeEach(() => { jest.clearAllMocks(); + document.head.innerHTML = ''; + document.body.innerHTML = ''; mockInstance = { name: 'host-app', options: { version: '1.0.0' }, @@ -156,22 +256,12 @@ describe('collectSSRAssets', () => { }); it('should collect CSS and JS assets for SSR', () => { - mockGetLoadedRemoteInfos.mockReturnValue({ - name: 'remoteApp', - expose: './Component', - snapshot: { - publicPath: 'http://localhost:3001/', - remoteEntry: 'remoteEntry.js', - modules: [ - { - modulePath: './Component', - assets: { - css: { sync: ['main.css'], async: ['extra.css'] }, - js: { sync: ['main.js'], async: [] }, - }, - }, - ], + mockRemoteAssets({ + css: { + sync: ['main.css'], + async: ['extra.css', 'main.css'], }, + js: { sync: ['main.js'], async: [] }, }); const assets = collectSSRAssets({ @@ -184,26 +274,63 @@ describe('collectSSRAssets', () => { expect(assets).toHaveLength(4); // 2 links, 2 scripts const links = assets.filter( - (asset) => (asset as React.ReactElement).type === 'link', + (asset): asset is React.ReactElement => + React.isValidElement(asset) && asset.type === 'link', ); const scripts = assets.filter( - (asset) => (asset as React.ReactElement).type === 'script', + (asset): asset is React.ReactElement => + React.isValidElement(asset) && asset.type === 'script', ); expect(links).toHaveLength(2); - expect((links[0] as React.ReactElement).props.href).toBe( + expect(links.map((link) => link.props.href)).toEqual([ 'http://localhost:3001/extra.css', - ); - expect((links[1] as React.ReactElement).props.href).toBe( 'http://localhost:3001/main.css', - ); - + ]); expect(scripts).toHaveLength(2); - expect((scripts[0] as React.ReactElement).props.src).toBe( + expect(scripts.map((script) => script.props.src)).toEqual([ 'http://localhost:3001/remoteEntry.js', - ); - expect((scripts[1] as React.ReactElement).props.src).toBe( 'http://localhost:3001/main.js', + ]); + + const fragment = renderAssetsToFragment(assets); + + expect(getStylesheetHrefs(fragment)).toEqual([ + 'http://localhost:3001/extra.css', + 'http://localhost:3001/main.css', + ]); + expect(getScriptSrcs(fragment)).toEqual([ + 'http://localhost:3001/remoteEntry.js', + 'http://localhost:3001/main.js', + ]); + }); + + it('should preserve stylesheet nodes when inserting an earlier asset', () => { + mockRemoteAssets({ + css: { sync: ['main.css'], async: [] }, + }); + + const options = { + id: 'remoteApp/Component', + instance: mockInstance, + injectLink: true, + }; + const { container, rerender } = render(<>{collectSSRAssets(options)}); + const originalMainLink = container.querySelector( + 'link[href="http://localhost:3001/main.css"]', ); + + mockRemoteAssets({ + css: { sync: ['main.css'], async: ['extra.css'] }, + }); + rerender(<>{collectSSRAssets(options)}); + + expect(getStylesheetHrefs(container)).toEqual([ + 'http://localhost:3001/extra.css', + 'http://localhost:3001/main.css', + ]); + expect( + container.querySelector('link[href="http://localhost:3001/main.css"]'), + ).toBe(originalMainLink); }); }); diff --git a/packages/bridge/bridge-react/src/lazy/HydratedStylesheetAssets.tsx b/packages/bridge/bridge-react/src/lazy/HydratedStylesheetAssets.tsx new file mode 100644 index 00000000000..aec9647e50d --- /dev/null +++ b/packages/bridge/bridge-react/src/lazy/HydratedStylesheetAssets.tsx @@ -0,0 +1,189 @@ +import React, { useEffect, useRef, useState } from 'react'; + +type StylesheetSubscriber = (hrefs: ReadonlySet) => void; + +type HeadStylesheetStore = { + document: Document; + head: HTMLHeadElement | null; + hrefs: ReadonlySet; + observer: MutationObserver; + subscribers: Set; +}; + +const EMPTY_HREFS = new Set(); +const stylesheetStores = new WeakMap(); + +function isActiveStylesheet(link: HTMLLinkElement) { + const rel = link.rel.toLowerCase().split(/\s+/u); + const media = link.media.trim().toLowerCase(); + const type = link.type.trim().toLowerCase().split(';', 1)[0].trim(); + + return ( + rel.includes('stylesheet') && + !rel.includes('alternate') && + !link.disabled && + !link.hasAttribute('disabled') && + (!media || media === 'all') && + (!type || type === 'text/css') + ); +} + +function collectHeadStylesheetHrefs(document: Document) { + const hrefs = new Set(); + document.head + ?.querySelectorAll('link[href]') + .forEach((link) => { + if (isActiveStylesheet(link)) { + hrefs.add(link.href); + } + }); + return hrefs; +} + +function haveSameHrefs( + current: ReadonlySet, + next: ReadonlySet, +) { + if (current.size !== next.size) { + return false; + } + for (const href of current) { + if (!next.has(href)) { + return false; + } + } + return true; +} + +function observeHead(store: HeadStylesheetStore) { + store.observer.disconnect(); + const { document, head, observer } = store; + + if (head) { + observer.observe(head, { + attributes: true, + attributeFilter: ['disabled', 'href', 'media', 'rel', 'type'], + childList: true, + subtree: true, + }); + } + + if (document.documentElement) { + observer.observe(document.documentElement, { childList: true }); + } +} + +function refreshHeadStylesheets(store: HeadStylesheetStore) { + if (!store.subscribers.size) { + return; + } + + const head = store.document.head; + if (head !== store.head) { + store.head = head; + observeHead(store); + } + + const hrefs = collectHeadStylesheetHrefs(store.document); + if (haveSameHrefs(store.hrefs, hrefs)) { + return; + } + + store.hrefs = hrefs; + store.subscribers.forEach((subscriber) => subscriber(hrefs)); +} + +function getStylesheetStore(document: Document) { + const current = stylesheetStores.get(document); + if (current) { + return current; + } + + const MutationObserver = + document.defaultView?.MutationObserver ?? globalThis.MutationObserver; + let store: HeadStylesheetStore; + const observer = new MutationObserver(() => refreshHeadStylesheets(store)); + store = { + document, + head: document.head, + hrefs: collectHeadStylesheetHrefs(document), + observer, + subscribers: new Set(), + }; + observeHead(store); + stylesheetStores.set(document, store); + return store; +} + +function subscribeToHeadStylesheets( + document: Document, + subscriber: StylesheetSubscriber, +) { + const store = getStylesheetStore(document); + let subscribed = true; + store.subscribers.add(subscriber); + subscriber(store.hrefs); + + return () => { + if (!subscribed) { + return; + } + subscribed = false; + store.subscribers.delete(subscriber); + if (!store.subscribers.size) { + store.observer.disconnect(); + if (stylesheetStores.get(document) === store) { + stylesheetStores.delete(document); + } + } + }; +} + +function resolveHref(href: string, document: Document) { + try { + return new URL(href, document.baseURI).href; + } catch { + return href; + } +} + +export function HydratedStylesheetAssets({ hrefs }: { hrefs: string[] }) { + const firstLinkRef = useRef(null); + const ownerDocumentRef = useRef(null); + const [headHrefs, setHeadHrefs] = useState>(EMPTY_HREFS); + + useEffect(() => { + const link = firstLinkRef.current; + if (!link) { + return; + } + + const ownerDocument = link.ownerDocument; + ownerDocumentRef.current = ownerDocument; + if ( + link.getRootNode() !== ownerDocument || + ownerDocument.head?.contains(link) + ) { + return; + } + + return subscribeToHeadStylesheets(ownerDocument, setHeadHrefs); + }, []); + + return ( + <> + {hrefs.map((href, index) => + ownerDocumentRef.current && + headHrefs.has(resolveHref(href, ownerDocumentRef.current)) ? null : ( + + ), + )} + + ); +} diff --git a/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx index 7be87d4b021..c7a561268d4 100644 --- a/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx +++ b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx @@ -3,6 +3,7 @@ import type { BasicProviderModuleInfo } from '@module-federation/sdk'; import React, { ReactNode, useState, useEffect } from 'react'; import type { ErrorInfo } from './AwaitDataFetch'; import type { DataFetchParams, NoSSRRemoteInfo } from './types'; +import { HydratedStylesheetAssets } from './HydratedStylesheetAssets'; import logger from './logger'; import { @@ -49,6 +50,11 @@ export type CreateLazyComponentOptions = { type ReactKey = { key?: React.Key | null }; +type SSRAssetDescriptors = { + scriptSrcs: string[]; + stylesheetHrefs: string[]; +}; + function getTargetModuleInfo( id: string, instance?: ModuleFederation, @@ -98,61 +104,62 @@ function getTargetModuleInfo( }; } -export function collectSSRAssets(options: IProps) { +function collectSSRAssetDescriptors(options: IProps): SSRAssetDescriptors { const { id, injectLink = true, injectScript = false, } = typeof options === 'string' ? { id: options } : options; - const links: React.ReactNode[] = []; - const scripts: React.ReactNode[] = []; + const stylesheetHrefs: string[] = []; + const scriptSrcs: string[] = []; const instance = options.instance; if (!instance || (!injectLink && !injectScript)) { - return [...scripts, ...links]; + return { scriptSrcs, stylesheetHrefs }; } const moduleAndPublicPath = getTargetModuleInfo(id, instance); if (!moduleAndPublicPath) { - return [...scripts, ...links]; + return { scriptSrcs, stylesheetHrefs }; } const { module: targetModule, publicPath, remoteEntry } = moduleAndPublicPath; if (injectLink) { + const seenStylesheetHrefs = new Set(); [...targetModule.assets.css.sync, ...targetModule.assets.css.async] .sort() - .forEach((file, index) => { - links.push( - , - ); + .forEach((file) => { + const href = `${publicPath}${file}`; + if (seenStylesheetHrefs.has(href)) { + return; + } + seenStylesheetHrefs.add(href); + stylesheetHrefs.push(href); }); } if (injectScript) { - scripts.push( - + + diff --git a/apps/bridge-ssr-demo/host-vue/src/entry.client.ts b/apps/bridge-ssr-demo/host-vue/src/entry.client.ts new file mode 100644 index 00000000000..e83cec85dfa --- /dev/null +++ b/apps/bridge-ssr-demo/host-vue/src/entry.client.ts @@ -0,0 +1,13 @@ +import { createSSRApp } from 'vue'; +import { createRouter, createWebHistory } from 'vue-router'; +import App from './App.vue'; +import { readHostSSRContext } from './ssrContext'; + +const router = createRouter({ + history: createWebHistory(), + routes: [{ path: '/:pathMatch(.*)*', component: App }], +}); +const app = createSSRApp(App, { ssrContext: readHostSSRContext() }); +app.use(router); +await router.isReady(); +app.mount('#root'); diff --git a/apps/bridge-ssr-demo/host-vue/src/entry.server.ts b/apps/bridge-ssr-demo/host-vue/src/entry.server.ts new file mode 100644 index 00000000000..5da8cd99a98 --- /dev/null +++ b/apps/bridge-ssr-demo/host-vue/src/entry.server.ts @@ -0,0 +1,29 @@ +import { createSSRApp } from 'vue'; +import { renderToString } from '@vue/server-renderer'; +import { createMemoryHistory, createRouter } from 'vue-router'; +import App from './App.vue'; +import { + prepareSSRContext, + type PrepareSSRContextOptions, +} from './prepareSSRContext'; + +async function createHostApp(url: string, options: PrepareSSRContextOptions) { + const ssrContext = await prepareSSRContext(url, options); + const router = createRouter({ + history: createMemoryHistory(), + routes: [{ path: '/:pathMatch(.*)*', component: App }], + }); + await router.push(url); + await router.isReady(); + const app = createSSRApp(App, { ssrContext }); + app.use(router); + return { app, ssrContext }; +} + +export async function render( + url: string, + options: PrepareSSRContextOptions = {}, +) { + const { app, ssrContext } = await createHostApp(url, options); + return { html: await renderToString(app), ssrContext }; +} diff --git a/apps/bridge-ssr-demo/host-vue/src/env.d.ts b/apps/bridge-ssr-demo/host-vue/src/env.d.ts new file mode 100644 index 00000000000..c736914276c --- /dev/null +++ b/apps/bridge-ssr-demo/host-vue/src/env.d.ts @@ -0,0 +1,4 @@ +/// + +declare module 'bridge_ssr_react/export-app'; +declare module 'bridge_ssr_vue/export-app'; diff --git a/apps/bridge-ssr-demo/host-vue/src/index.html b/apps/bridge-ssr-demo/host-vue/src/index.html new file mode 100644 index 00000000000..edf442c4adf --- /dev/null +++ b/apps/bridge-ssr-demo/host-vue/src/index.html @@ -0,0 +1,11 @@ + + + + + + Bridge SSR Vue Host + + +
    + + diff --git a/apps/bridge-ssr-demo/host-vue/src/prepareSSRContext.ts b/apps/bridge-ssr-demo/host-vue/src/prepareSSRContext.ts new file mode 100644 index 00000000000..97af22acd50 --- /dev/null +++ b/apps/bridge-ssr-demo/host-vue/src/prepareSSRContext.ts @@ -0,0 +1,51 @@ +import { getInstance } from '@module-federation/runtime'; +import { renderRemoteBridge } from '@module-federation/bridge-shared'; +import { normalizeBridgeRequestUrl } from '../../host/src/lib/normalizeRequestUrl.mjs'; +import type { HostSSRContext } from './ssrContext'; + +export type PrepareSSRContextOptions = { signal?: AbortSignal }; + +export async function prepareSSRContext( + url: string, + options: PrepareSSRContextOptions = {}, +): Promise { + const requestUrl = normalizeBridgeRequestUrl(url); + const parsed = new URL(requestUrl, 'http://bridge-ssr.local'); + const context: HostSSRContext = { url: requestUrl }; + const instance = getInstance(); + if (!instance) + throw new Error('Module Federation runtime is not initialized'); + const request = new Request(parsed, { signal: options.signal }); + + const renderReact = ( + instanceId: string, + basename: string, + name: string, + age: number, + ) => + renderRemoteBridge({ + loader: () => + instance.loadRemote>( + 'bridge_ssr_react/export-app', + ), + moduleName: 'bridge_ssr_react', + instanceId, + request, + props: { basename, name, age }, + }); + + if (parsed.pathname.startsWith('/react-pair')) { + context.reactPair = await Promise.all([ + renderReact('react-pair-left', '/react-pair', 'Left', 1), + renderReact('react-pair-right', '/react-pair', 'Right', 2), + ]); + } else if (parsed.pathname.startsWith('/react-remote')) { + context.reactRemote = await renderReact( + 'react-primary', + '/react-remote', + 'Ming', + 12, + ); + } + return context; +} diff --git a/apps/bridge-ssr-demo/host-vue/src/remoteApps.ts b/apps/bridge-ssr-demo/host-vue/src/remoteApps.ts new file mode 100644 index 00000000000..0ffa9858501 --- /dev/null +++ b/apps/bridge-ssr-demo/host-vue/src/remoteApps.ts @@ -0,0 +1,5 @@ +import { createRemoteAppComponent } from '@module-federation/bridge-vue3'; + +export const RemoteReactApp = createRemoteAppComponent({ + loader: () => import('bridge_ssr_react/export-app'), +}); diff --git a/apps/bridge-ssr-demo/host-vue/src/ssrContext.ts b/apps/bridge-ssr-demo/host-vue/src/ssrContext.ts new file mode 100644 index 00000000000..52d784a2610 --- /dev/null +++ b/apps/bridge-ssr-demo/host-vue/src/ssrContext.ts @@ -0,0 +1,19 @@ +import type { BridgeSSRResult } from '@module-federation/bridge-shared'; + +export type HostSSRContext = { + url: string; + reactRemote?: BridgeSSRResult; + reactPair?: [BridgeSSRResult, BridgeSSRResult]; +}; + +export const HOST_SSR_CONTEXT_SCRIPT_ID = 'bridge-ssr-host-context'; + +export function readHostSSRContext() { + const script = document.getElementById(HOST_SSR_CONTEXT_SCRIPT_ID); + if (!script?.textContent) return undefined; + try { + return JSON.parse(script.textContent) as HostSSRContext; + } catch { + return undefined; + } +} diff --git a/apps/bridge-ssr-demo/host-vue/tsconfig.json b/apps/bridge-ssr-demo/host-vue/tsconfig.json new file mode 100644 index 00000000000..8a26c51abfb --- /dev/null +++ b/apps/bridge-ssr-demo/host-vue/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "skipLibCheck": true, + "allowJs": true, + "types": ["node"] + }, + "include": ["src", "rsbuild.config.ts", "playwright.config.ts"] +} diff --git a/apps/bridge-ssr-demo/host/e2e/bridge-ssr-browser.spec.ts b/apps/bridge-ssr-demo/host/e2e/bridge-ssr-browser.spec.ts new file mode 100644 index 00000000000..113abff34e3 --- /dev/null +++ b/apps/bridge-ssr-demo/host/e2e/bridge-ssr-browser.spec.ts @@ -0,0 +1,97 @@ +import { expect, test } from './fixtures'; + +const direction = (projectName: string) => + projectName.startsWith('vue-host') + ? { + route: '/react-remote', + detail: '/react-remote/detail', + homeHeading: 'React Remote Home', + detailHeading: 'React Remote Detail', + counter: '.react-remote-counter', + detailLink: '.react-remote-detail-link', + hostLink: '.host-react-remote-link', + } + : { + route: '/vue-remote', + detail: '/vue-remote/detail', + homeHeading: 'Vue Remote Home', + detailHeading: 'Vue Remote Detail', + counter: '.vue-remote-counter', + detailLink: '.vue-remote-detail-link', + hostLink: '.host-vue-remote-link', + }; + +test('hydrates the direct SSR island and remains interactive', async ({ + page, +}, testInfo) => { + const remote = direction(testInfo.project.name); + await page.goto(remote.route); + await expect( + page.getByRole('heading', { name: remote.homeHeading }), + ).toBeVisible(); + const mount = page.locator('[data-mf-bridge-ssr="true"]'); + await expect(mount).toHaveCount(1); + const counter = page.locator(remote.counter); + await counter.click(); + await expect(counter).toHaveText(/Count: 1/); +}); + +test('server-renders a deep route and remote navigation updates the URL', async ({ + page, +}, testInfo) => { + const remote = direction(testInfo.project.name); + await page.goto(remote.detail); + await expect( + page.getByRole('heading', { name: remote.detailHeading }), + ).toBeVisible(); + await page.goto(remote.route); + await page.locator(remote.detailLink).click(); + await expect(page).toHaveURL(new RegExp(`${remote.detail}$`)); + await expect( + page.getByRole('heading', { name: remote.detailHeading }), + ).toBeVisible(); +}); + +test('host navigation enters, leaves, and returns through CSR without reload', async ({ + page, +}, testInfo) => { + const remote = direction(testInfo.project.name); + await page.goto('/'); + await page.evaluate(() => { + ( + window as Window & { __navigationSentinel?: string } + ).__navigationSentinel = 'alive'; + }); + await page.locator(remote.hostLink).first().click(); + await expect( + page.getByRole('heading', { name: remote.homeHeading }), + ).toBeVisible(); + await page.getByRole('link', { name: 'Home' }).first().click(); + await expect(page).toHaveURL(/\/$/); + await page.locator(remote.hostLink).first().click(); + await expect( + page.getByRole('heading', { name: remote.homeHeading }), + ).toBeVisible(); + await expect + .poll(() => page.evaluate(() => (window as any).__navigationSentinel)) + .toBe('alive'); +}); + +test('two instances of one React remote hydrate independently', async ({ + page, +}, testInfo) => { + test.skip(!testInfo.project.name.startsWith('vue-host')); + await page.goto('/react-pair'); + const mounts = page.locator('[data-mf-bridge-ssr="true"]'); + await expect(mounts).toHaveCount(2); + const ids = await mounts.evaluateAll((nodes) => + nodes.map((node) => node.getAttribute('data-mf-bridge-instance')), + ); + expect(new Set(ids).size).toBe(2); + const counters = page.locator('.react-remote-counter'); + await counters.nth(0).click(); + await expect(counters.nth(0)).toHaveText('Count: 1'); + await expect(counters.nth(1)).toHaveText('Count: 0'); + await expect(page.getByText('name: Left, age: 1')).toBeVisible(); + await expect(page.getByText('name: Right, age: 2')).toBeVisible(); +}); diff --git a/apps/bridge-ssr-demo/host/e2e/bridge-ssr-nojs.spec.ts b/apps/bridge-ssr-demo/host/e2e/bridge-ssr-nojs.spec.ts new file mode 100644 index 00000000000..5628de49bbd --- /dev/null +++ b/apps/bridge-ssr-demo/host/e2e/bridge-ssr-nojs.spec.ts @@ -0,0 +1,19 @@ +import { expect, test } from '@playwright/test'; + +test('raw response contains the cross-framework remote route', async ({ + page, + request, +}, testInfo) => { + const vueHost = testInfo.project.name.startsWith('vue-host'); + const route = vueHost ? '/react-remote/detail' : '/vue-remote/detail'; + const heading = vueHost ? 'React Remote Detail' : 'Vue Remote Detail'; + const response = await request.get(route); + const html = await response.text(); + expect(response.ok()).toBeTruthy(); + expect(html).toContain(heading); + expect(html).toContain('data-mf-bridge-ssr="true"'); + expect(html).toContain('bridge-ssr-host-context'); + + await page.goto(route); + await expect(page.getByRole('heading', { name: heading })).toBeVisible(); +}); diff --git a/apps/bridge-ssr-demo/host/e2e/fixtures.ts b/apps/bridge-ssr-demo/host/e2e/fixtures.ts new file mode 100644 index 00000000000..5fe4e8bfd83 --- /dev/null +++ b/apps/bridge-ssr-demo/host/e2e/fixtures.ts @@ -0,0 +1,24 @@ +import { expect, test as base } from '@playwright/test'; + +export const test = base.extend({ + page: async ({ page }, use) => { + const browserErrors: string[] = []; + page.on('console', (message) => { + const text = message.text(); + if ( + message.type() === 'error' || + (message.type() === 'warning' && + /hydration|hydrate|did not match|mount|mismatch|recoverable/i.test( + text, + )) + ) { + browserErrors.push(text); + } + }); + page.on('pageerror', (error) => browserErrors.push(error.message)); + await use(page); + expect(browserErrors, 'unexpected browser errors').toEqual([]); + }, +}); + +export { expect }; diff --git a/apps/bridge-ssr-demo/host/package.json b/apps/bridge-ssr-demo/host/package.json new file mode 100644 index 00000000000..195929df962 --- /dev/null +++ b/apps/bridge-ssr-demo/host/package.json @@ -0,0 +1,35 @@ +{ + "name": "bridge-ssr-host", + "private": true, + "version": "0.0.1", + "scripts": { + "dev": "NODE_OPTIONS=--experimental-vm-modules node ./server.mjs", + "build": "rsbuild build", + "preview": "rsbuild preview", + "serve": "pnpm run dev", + "serve:production": "NODE_OPTIONS=--experimental-vm-modules BRIDGE_SSR_MODE=production node ./server.mjs", + "e2e:ssr": "node ../../../scripts/ensure-playwright.js && playwright test", + "e2e:ssr:ci": "node ../../../scripts/ensure-playwright.js && playwright test --reporter=line" + }, + "dependencies": { + "@module-federation/bridge-react": "workspace:*", + "@module-federation/bridge-shared": "workspace:*", + "@module-federation/enhanced": "workspace:*", + "express": "^4.21.2", + "react": "~18.3.1", + "react-dom": "~18.3.1", + "react-router-dom": "6.30.2", + "vue": "^3.5.30", + "vue-router": "4.4.5" + }, + "devDependencies": { + "@module-federation/rsbuild-plugin": "workspace:*", + "@rsbuild/core": "1.7.3", + "@rsbuild/plugin-react": "^1.4.5", + "@types/express": "^4.17.21", + "@types/react": "~18.2.0", + "@types/react-dom": "~18.3.0", + "@playwright/test": "1.57.0", + "typescript": "~5.0.4" + } +} diff --git a/apps/bridge-ssr-demo/host/playwright.config.ts b/apps/bridge-ssr-demo/host/playwright.config.ts new file mode 100644 index 00000000000..2d5ba9852f6 --- /dev/null +++ b/apps/bridge-ssr-demo/host/playwright.config.ts @@ -0,0 +1,25 @@ +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + testDir: './e2e', + timeout: 60_000, + fullyParallel: false, + retries: process.env.CI ? 2 : 0, + workers: 1, + use: { + baseURL: process.env.BRIDGE_SSR_BASE_URL ?? 'http://localhost:2300', + trace: 'on-first-retry', + ...devices['Desktop Chrome'], + }, + projects: [ + { + name: 'react-host-nojs', + testMatch: /bridge-ssr-nojs\.spec\.ts/, + use: { javaScriptEnabled: false }, + }, + { + name: 'react-host-browser', + testMatch: /bridge-ssr-browser\.spec\.ts/, + }, + ], +}); diff --git a/apps/bridge-ssr-demo/host/public/.gitkeep b/apps/bridge-ssr-demo/host/public/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apps/bridge-ssr-demo/host/rsbuild.config.ts b/apps/bridge-ssr-demo/host/rsbuild.config.ts new file mode 100644 index 00000000000..4778e56b240 --- /dev/null +++ b/apps/bridge-ssr-demo/host/rsbuild.config.ts @@ -0,0 +1,109 @@ +import { pluginModuleFederation } from '@module-federation/rsbuild-plugin'; +import { defineConfig } from '@rsbuild/core'; +import { pluginReact } from '@rsbuild/plugin-react'; +import path from 'path'; +import { + bridgeSsrHostUrl, + bridgeSsrRemotePort, + bridgeSsrServerManifestPath, +} from '../shared/devHost'; + +const vueRemoteOrigin = bridgeSsrHostUrl(bridgeSsrRemotePort('vue')); + +const clientRuntimePlugins = [ + require.resolve('@module-federation/bridge-react/plugin'), +]; + +const ssrRuntimePlugins = [ + require.resolve('@module-federation/bridge-react/plugin'), +]; + +const shared = { + react: { singleton: true, eager: true }, + 'react-dom': { singleton: true, eager: true }, + vue: { singleton: true, eager: true }, + 'vue-router': { singleton: true, eager: true }, +}; + +const ssrShared = { + react: { singleton: true, eager: true }, + 'react-dom': { singleton: true, eager: true }, + vue: { singleton: true, eager: true }, + 'vue-router': { singleton: true, eager: true }, +}; + +const webRemotes = { + bridge_ssr_vue: `bridge_ssr_vue@${vueRemoteOrigin}/mf-manifest.json`, +}; + +const ssrRemotes = { + bridge_ssr_vue: `bridge_ssr_vue@${vueRemoteOrigin}/${bridgeSsrServerManifestPath}`, +}; + +export default defineConfig({ + performance: { buildCache: false }, + resolve: { + alias: { + react: path.resolve(__dirname, 'node_modules/react'), + 'react-dom': path.resolve(__dirname, 'node_modules/react-dom'), + }, + }, + server: { + port: 2300, + cors: true, + middlewareMode: true, + }, + environments: { + client: { + source: { + entry: { + index: './src/entry.client.tsx', + }, + }, + html: { + template: './src/index.html', + }, + output: { + distPath: { + root: 'dist', + }, + }, + }, + ssr: { + source: { + entry: { + index: './src/entry.server.tsx', + }, + }, + output: { + target: 'node', + distPath: { + root: 'dist/ssr', + }, + }, + }, + }, + plugins: [ + pluginReact(), + pluginModuleFederation( + { + name: 'bridge_ssr_host', + shareStrategy: 'loaded-first', + remotes: webRemotes, + shared, + runtimePlugins: clientRuntimePlugins, + }, + { environment: 'client' }, + ), + pluginModuleFederation( + { + name: 'bridge_ssr_host', + shareStrategy: 'loaded-first', + remotes: ssrRemotes, + shared: ssrShared, + runtimePlugins: ssrRuntimePlugins, + }, + { target: 'node', environment: 'ssr' }, + ), + ], +}); diff --git a/apps/bridge-ssr-demo/host/server.mjs b/apps/bridge-ssr-demo/host/server.mjs new file mode 100644 index 00000000000..f52a629c0a1 --- /dev/null +++ b/apps/bridge-ssr-demo/host/server.mjs @@ -0,0 +1,11 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { startBridgeHost } from '../shared/createHostServer.mjs'; + +const rootDir = path.dirname(fileURLToPath(import.meta.url)); +startBridgeHost({ rootDir, port: 2300, label: 'bridge-ssr-react-host' }).catch( + (error) => { + console.error('[bridge-ssr-react-host] failed:', error); + process.exitCode = 1; + }, +); diff --git a/apps/bridge-ssr-demo/host/src/App.tsx b/apps/bridge-ssr-demo/host/src/App.tsx new file mode 100644 index 00000000000..4f552b830f2 --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/App.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { Link, Route, Routes } from 'react-router-dom'; +import { RemoteVueApp } from './lib/remoteApps'; +import { VUE_REMOTE_BASENAME, VUE_REMOTE_MODULE } from './lib/remoteRoutes'; +import type { HostSSRContext } from './lib/ssrContext'; +import { useHostSsrContext } from './lib/useHostSsrContext'; + +type AppProps = { + ssrContext?: HostSSRContext; +}; + +const Layout = ({ children }: { children: React.ReactNode }) => ( +
    + + {children} +
    +); + +const Home = () => ( +
    +

    Bridge SSR Host

    +

    + Direct visits are server-rendered. In-app navigation is instant on the + client — federated remotes load and hydrate through the bridge without a + document reload (Nuxt-style takeover). +

    +
      +
    • + + Vue Remote (federated SSR on direct visit) + +
    • +
    +
    +); + +const VueRemotePage = ({ ssrContext }: { ssrContext?: HostSSRContext }) => ( +
    +

    Vue Remote

    + +
    +); + +const AppRoutes = ({ ssrContext }: { ssrContext?: HostSSRContext }) => ( + + } /> + } + /> + +); + +const App = ({ ssrContext: initialSsrContext }: AppProps) => { + const { ssrContext } = useHostSsrContext(initialSsrContext); + + return ( + + + + ); +}; + +export default App; diff --git a/apps/bridge-ssr-demo/host/src/bootstrap.tsx b/apps/bridge-ssr-demo/host/src/bootstrap.tsx new file mode 100644 index 00000000000..9e2c30be810 --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/bootstrap.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { BrowserRouter } from 'react-router-dom'; +import App from './App'; + +const root = ReactDOM.createRoot(document.getElementById('root')!); +root.render( + + + + + , +); diff --git a/apps/bridge-ssr-demo/host/src/entry.client.tsx b/apps/bridge-ssr-demo/host/src/entry.client.tsx new file mode 100644 index 00000000000..c006d63a909 --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/entry.client.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { hydrateRoot } from 'react-dom/client'; +import { BrowserRouter } from 'react-router-dom'; +import App from './App'; +import { readHostSSRContextFromDocument } from './lib/hostSsrContext'; + +async function bootstrap() { + const ssrContext = readHostSSRContextFromDocument(); + hydrateRoot( + document.getElementById('root')!, + + + , + ); +} + +const bootstrapPromise = bootstrap(); +( + window as Window & { __BRIDGE_SSR_BOOTSTRAP__?: Promise } +).__BRIDGE_SSR_BOOTSTRAP__ = bootstrapPromise; + +void bootstrapPromise; diff --git a/apps/bridge-ssr-demo/host/src/entry.server.tsx b/apps/bridge-ssr-demo/host/src/entry.server.tsx new file mode 100644 index 00000000000..3ffb09399c3 --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/entry.server.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { renderToString } from 'react-dom/server'; +import { StaticRouter } from 'react-router-dom/server'; +import App from './App'; +import { + prepareSSRContext, + type PrepareSSRContextOptions, +} from './lib/prepareSSRContext'; + +export { prepareSSRContext as getSSRContext }; + +function createHostTree( + url: string, + ssrContext: Awaited>, +) { + return ( + + + + ); +} + +/** String rendering remains available to focused tests and non-streaming consumers. */ +export async function render( + url: string, + options: PrepareSSRContextOptions = {}, +) { + const ssrContext = await prepareSSRContext(url, options); + return { + html: renderToString(createHostTree(url, ssrContext)), + ssrContext, + }; +} diff --git a/apps/bridge-ssr-demo/host/src/env.d.ts b/apps/bridge-ssr-demo/host/src/env.d.ts new file mode 100644 index 00000000000..69f2a7d3d5c --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/env.d.ts @@ -0,0 +1,23 @@ +/// + +declare module 'bridge_ssr_react/export-app' { + const provider: () => { + render: (info: Record) => void | Promise; + destroy: (info: { dom: HTMLElement }) => void; + renderToString?: ( + info: Record, + ) => Promise<{ html: string; state?: Record }>; + }; + export default provider; +} + +declare module 'bridge_ssr_vue/export-app' { + const provider: () => { + render: (info: Record) => void | Promise; + destroy: (info: { dom: HTMLElement }) => void; + renderToString?: ( + info: Record, + ) => Promise<{ html: string; state?: Record }>; + }; + export default provider; +} diff --git a/apps/bridge-ssr-demo/host/src/index.html b/apps/bridge-ssr-demo/host/src/index.html new file mode 100644 index 00000000000..e983dbe344a --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/index.html @@ -0,0 +1,11 @@ + + + + + + Bridge SSR Host + + +
    + + diff --git a/apps/bridge-ssr-demo/host/src/index.tsx b/apps/bridge-ssr-demo/host/src/index.tsx new file mode 100644 index 00000000000..b93c7a0268a --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/index.tsx @@ -0,0 +1 @@ +import('./bootstrap'); diff --git a/apps/bridge-ssr-demo/host/src/lib/hostSsrContext.ts b/apps/bridge-ssr-demo/host/src/lib/hostSsrContext.ts new file mode 100644 index 00000000000..a789b87cf7f --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/lib/hostSsrContext.ts @@ -0,0 +1,21 @@ +import type { HostSSRContext } from './ssrContext'; + +// Kept in sync with server.mjs, which injects the script server-side. +export const HOST_SSR_CONTEXT_SCRIPT_ID = 'bridge-ssr-host-context'; + +export function readHostSSRContextFromDocument(): HostSSRContext | undefined { + if (typeof document === 'undefined') { + return undefined; + } + + const script = document.getElementById(HOST_SSR_CONTEXT_SCRIPT_ID); + if (!script?.textContent) { + return undefined; + } + + try { + return JSON.parse(script.textContent) as HostSSRContext; + } catch { + return undefined; + } +} diff --git a/apps/bridge-ssr-demo/host/src/lib/normalizeRequestUrl.d.mts b/apps/bridge-ssr-demo/host/src/lib/normalizeRequestUrl.d.mts new file mode 100644 index 00000000000..40a1f869740 --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/lib/normalizeRequestUrl.d.mts @@ -0,0 +1,4 @@ +export function normalizeBridgeRequestUrl( + url: string, + fallback?: string, +): string; diff --git a/apps/bridge-ssr-demo/host/src/lib/normalizeRequestUrl.mjs b/apps/bridge-ssr-demo/host/src/lib/normalizeRequestUrl.mjs new file mode 100644 index 00000000000..41e6660fcce --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/lib/normalizeRequestUrl.mjs @@ -0,0 +1,30 @@ +/** + * Restrict request URLs to same-origin pathnames with search for SSR routing. + * + * Single source of truth shared by the Express server (`server.mjs`) and the + * bundled host code (`prepareSSRContext.ts`). + * + * @param {string} url + * @param {string} [fallback] + * @returns {string} + */ +export function normalizeBridgeRequestUrl(url, fallback = '/') { + if (!url || typeof url !== 'string') { + return fallback; + } + + const trimmed = url.trim(); + if ( + /^[a-zA-Z][a-zA-Z\d+.-]*:\/\//.test(trimmed) || + trimmed.startsWith('//') + ) { + return fallback; + } + + const withoutHash = trimmed.split('#')[0] ?? ''; + const pathname = withoutHash.startsWith('/') + ? withoutHash + : `/${withoutHash}`; + + return pathname || fallback; +} diff --git a/apps/bridge-ssr-demo/host/src/lib/prepareSSRContext.ts b/apps/bridge-ssr-demo/host/src/lib/prepareSSRContext.ts new file mode 100644 index 00000000000..5d227b1cf5a --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/lib/prepareSSRContext.ts @@ -0,0 +1,35 @@ +import { getInstance } from '@module-federation/runtime'; +import { renderRemoteBridge } from '@module-federation/bridge-shared'; +import type { HostSSRContext } from './ssrContext'; +import { normalizeBridgeRequestUrl } from './normalizeRequestUrl.mjs'; +import { VUE_REMOTE_BASENAME, VUE_REMOTE_MODULE } from './remoteRoutes'; + +export type PrepareSSRContextOptions = { signal?: AbortSignal }; + +export async function prepareSSRContext( + url: string, + options: PrepareSSRContextOptions = {}, +): Promise { + const requestUrl = normalizeBridgeRequestUrl(url); + const pathname = new URL(requestUrl, 'http://bridge-ssr.local').pathname; + const context: HostSSRContext = { url: requestUrl }; + if (!pathname.startsWith(VUE_REMOTE_BASENAME)) return context; + + const instance = getInstance(); + if (!instance) + throw new Error('Module Federation runtime is not initialized'); + const request = new Request(`http://bridge-ssr.local${requestUrl}`, { + signal: options.signal, + }); + context.vueRemote = await renderRemoteBridge({ + loader: () => + instance.loadRemote>( + `${VUE_REMOTE_MODULE}/export-app`, + ), + moduleName: VUE_REMOTE_MODULE, + instanceId: 'vue-primary', + request, + props: { basename: VUE_REMOTE_BASENAME, test: 'vue-ssr' }, + }); + return context; +} diff --git a/apps/bridge-ssr-demo/host/src/lib/remoteApps.tsx b/apps/bridge-ssr-demo/host/src/lib/remoteApps.tsx new file mode 100644 index 00000000000..ce3705b4393 --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/lib/remoteApps.tsx @@ -0,0 +1,11 @@ +import { createRemoteAppComponent } from '@module-federation/bridge-react'; + +export const vueRemoteLoader = () => import('bridge_ssr_vue/export-app'); + +export const RemoteVueApp = createRemoteAppComponent({ + loader: vueRemoteLoader, + loading:
    Loading Vue remote...
    , + fallback: ({ error }: { error: Error }) => ( +
    Vue remote error: {error.message}
    + ), +}); diff --git a/apps/bridge-ssr-demo/host/src/lib/remoteRoutes.ts b/apps/bridge-ssr-demo/host/src/lib/remoteRoutes.ts new file mode 100644 index 00000000000..6d97b207d9c --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/lib/remoteRoutes.ts @@ -0,0 +1,31 @@ +import type { HostSSRContext } from './ssrContext'; + +export const VUE_REMOTE_BASENAME = '/vue-remote'; +export const VUE_REMOTE_MODULE = 'bridge_ssr_vue'; + +export function isVueRemotePath(pathname: string) { + return pathname.startsWith(VUE_REMOTE_BASENAME); +} + +/** + * Keep SSR payload only when it matches the active URL and remote route. + * Client navigations without a document reload use CSR (no remote SSR fields). + */ +export function resolveHostSsrContextForLocation( + locationUrl: string, + pathname: string, + seed?: HostSSRContext, +): HostSSRContext { + const context: HostSSRContext = { url: locationUrl }; + const seedPath = seed?.url?.split('?')[0]?.split('#')[0]; + + if (!seed || seedPath !== pathname) { + return context; + } + + if (isVueRemotePath(pathname) && seed.vueRemote) { + context.vueRemote = seed.vueRemote; + } + + return context; +} diff --git a/apps/bridge-ssr-demo/host/src/lib/ssrContext.ts b/apps/bridge-ssr-demo/host/src/lib/ssrContext.ts new file mode 100644 index 00000000000..e2f18d057bf --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/lib/ssrContext.ts @@ -0,0 +1,6 @@ +import type { BridgeSSRResult } from '@module-federation/bridge-shared'; + +export type HostSSRContext = { + url: string; + vueRemote?: BridgeSSRResult; +}; diff --git a/apps/bridge-ssr-demo/host/src/lib/useHostSsrContext.ts b/apps/bridge-ssr-demo/host/src/lib/useHostSsrContext.ts new file mode 100644 index 00000000000..89873221f46 --- /dev/null +++ b/apps/bridge-ssr-demo/host/src/lib/useHostSsrContext.ts @@ -0,0 +1,39 @@ +import { useMemo } from 'react'; +import { useLocation } from 'react-router-dom'; +import { readHostSSRContextFromDocument } from './hostSsrContext'; +import { resolveHostSsrContextForLocation } from './remoteRoutes'; +import type { HostSSRContext } from './ssrContext'; + +function getLocationUrl(pathname: string, search: string) { + return `${pathname}${search}`; +} + +/** + * Nuxt-style SSR takeover: + * - Direct visit / hard refresh: use SSR payload embedded in the document (or passed from server render). + * - Client-side navigations: no document reload; remotes mount via federated CSR + bridge hydrate. + */ +export function useHostSsrContext(initialContext?: HostSSRContext) { + const location = useLocation(); + const locationUrl = getLocationUrl(location.pathname, location.search); + const documentContext = useMemo(() => readHostSSRContextFromDocument(), []); + + const seedContext = + initialContext?.url?.split('?')[0]?.split('#')[0] === location.pathname + ? initialContext + : documentContext?.url?.split('?')[0]?.split('#')[0] === location.pathname + ? documentContext + : undefined; + + const ssrContext = useMemo( + () => + resolveHostSsrContextForLocation( + locationUrl, + location.pathname, + seedContext, + ), + [location.pathname, locationUrl, seedContext], + ); + + return { ssrContext }; +} diff --git a/apps/bridge-ssr-demo/host/tsconfig.json b/apps/bridge-ssr-demo/host/tsconfig.json new file mode 100644 index 00000000000..3519d14e252 --- /dev/null +++ b/apps/bridge-ssr-demo/host/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "lib": ["DOM", "ES2020"], + "module": "ESNext", + "jsx": "react-jsx", + "strict": true, + "skipLibCheck": true, + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true + }, + "include": ["src"] +} diff --git a/apps/bridge-ssr-demo/remote-react/package.json b/apps/bridge-ssr-demo/remote-react/package.json new file mode 100644 index 00000000000..9b2c14adaac --- /dev/null +++ b/apps/bridge-ssr-demo/remote-react/package.json @@ -0,0 +1,26 @@ +{ + "name": "bridge-ssr-remote-react", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "rsbuild dev", + "build": "rsbuild build", + "preview": "rsbuild preview", + "serve": "pnpm run dev" + }, + "dependencies": { + "@module-federation/bridge-react": "workspace:*", + "react": "~18.3.1", + "react-dom": "~18.3.1", + "react-router-dom": "6.30.2" + }, + "devDependencies": { + "@module-federation/rsbuild-plugin": "workspace:*", + "@rsbuild/core": "1.7.3", + "@rsbuild/plugin-react": "^1.4.5", + "@types/react": "~18.2.0", + "@types/react-dom": "~18.3.0", + "typescript": "~5.0.4" + } +} diff --git a/apps/bridge-ssr-demo/remote-react/rsbuild.config.ts b/apps/bridge-ssr-demo/remote-react/rsbuild.config.ts new file mode 100644 index 00000000000..81bb920a46d --- /dev/null +++ b/apps/bridge-ssr-demo/remote-react/rsbuild.config.ts @@ -0,0 +1,124 @@ +import { pluginModuleFederation } from '@module-federation/rsbuild-plugin'; +import { defineConfig } from '@rsbuild/core'; +import { pluginReact } from '@rsbuild/plugin-react'; +import path from 'path'; +import { createBridgeRouterAlias } from '../shared/routerAlias'; +import { pluginServeSsrDist } from '../shared/pluginServeSsrDist'; +import { bridgeSsrHostUrl } from '../shared/devHost'; + +const remoteOrigin = bridgeSsrHostUrl(2301); + +const runtimePlugins = [ + require.resolve('@module-federation/bridge-react/plugin'), +]; + +const shared = { + react: { singleton: true }, + 'react-dom': { singleton: true }, +}; + +const mfOptions = { + name: 'bridge_ssr_react', + runtimePlugins, + exposes: { + './export-app': './src/export-app.tsx', + }, + shared, + dts: false, + getPublicPath: `return '${remoteOrigin}/'`, +}; + +const ssrMfOptions = { + ...mfOptions, + exposes: { + './export-app': './src/export-app.server.tsx', + }, + // The server remote owns a matching React + renderer pair. Sharing either + // with the host would reintroduce cross-version renderer coupling. + shared: {}, + getPublicPath: `return '${remoteOrigin}/ssr/'`, +}; + +export default defineConfig({ + performance: { buildCache: false }, + resolve: { + alias: { + react: path.resolve(__dirname, 'node_modules/react'), + 'react-dom': path.resolve(__dirname, 'node_modules/react-dom'), + }, + }, + server: { + port: 2301, + cors: true, + }, + dev: { + assetPrefix: remoteOrigin, + writeToDisk: true, + }, + tools: { + rspack: (config) => { + delete config.optimization?.splitChunks; + }, + }, + environments: { + web: { + source: { + entry: { + index: './src/index.tsx', + }, + }, + output: { + distPath: { + root: 'dist', + }, + }, + tools: { + rspack: (config) => { + config.resolve ??= {}; + config.resolve.alias = { + ...(config.resolve.alias as Record), + ...createBridgeRouterAlias( + path.resolve(__dirname, 'node_modules/react-router-dom'), + ), + }; + }, + }, + }, + ssr: { + source: { + entry: { + index: './src/ssr-env.ts', + }, + }, + output: { + target: 'node', + distPath: { + root: 'dist/ssr', + }, + emitAssets: true, + }, + tools: { + rspack: (config) => { + config.output ??= {}; + config.output.publicPath = `${remoteOrigin}/ssr/`; + config.resolve ??= {}; + config.resolve.alias = { + ...(config.resolve.alias as Record), + ...createBridgeRouterAlias( + path.resolve(__dirname, 'node_modules/react-router-dom'), + ), + }; + }, + }, + }, + }, + plugins: [ + pluginReact(), + pluginServeSsrDist(__dirname), + pluginModuleFederation(mfOptions, { environment: 'web' }), + pluginModuleFederation(ssrMfOptions, { + target: 'node', + environment: 'ssr', + }), + ], +}); diff --git a/apps/bridge-ssr-demo/remote-react/src/App.tsx b/apps/bridge-ssr-demo/remote-react/src/App.tsx new file mode 100644 index 00000000000..cdf4bf13d2f --- /dev/null +++ b/apps/bridge-ssr-demo/remote-react/src/App.tsx @@ -0,0 +1,72 @@ +import React, { useId, useState } from 'react'; +import { BrowserRouter, Link, Route, Routes } from 'react-router-dom'; + +function Home({ name, age }: { name?: string; age?: number }) { + const [count, setCount] = useState(0); + const fieldId = useId(); + return ( +
    +

    React Remote Home

    +

    + name: {name}, age: {age} +

    + + + +
    + ); +} + +function Detail() { + return ( +
    +

    React Remote Detail

    +

    SSR detail page content

    +
    + ); +} + +export type ReactRemoteProps = { + name?: string; + age?: number; + basename?: string; +}; + +const ReactRemoteRouteTree = (props: ReactRemoteProps) => { + return ( + <> + + + } /> + } /> + + + ); +}; + +const App = (props: ReactRemoteProps) => ( + + + +); + +export default App; diff --git a/apps/bridge-ssr-demo/remote-react/src/bootstrap.tsx b/apps/bridge-ssr-demo/remote-react/src/bootstrap.tsx new file mode 100644 index 00000000000..032f8ba0220 --- /dev/null +++ b/apps/bridge-ssr-demo/remote-react/src/bootstrap.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; + +const root = ReactDOM.createRoot(document.getElementById('root')!); +root.render( + + + , +); diff --git a/apps/bridge-ssr-demo/remote-react/src/env.d.ts b/apps/bridge-ssr-demo/remote-react/src/env.d.ts new file mode 100644 index 00000000000..b0ac762b091 --- /dev/null +++ b/apps/bridge-ssr-demo/remote-react/src/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/apps/bridge-ssr-demo/remote-react/src/export-app.server.tsx b/apps/bridge-ssr-demo/remote-react/src/export-app.server.tsx new file mode 100644 index 00000000000..c9f10b62515 --- /dev/null +++ b/apps/bridge-ssr-demo/remote-react/src/export-app.server.tsx @@ -0,0 +1,26 @@ +import App, { type ReactRemoteProps } from './App'; +import { createBridgeComponent } from '@module-federation/bridge-react/v18'; + +export default createBridgeComponent({ + rootComponent: App, + ssr: { + prepare(context) { + const props = context.props as ReactRemoteProps; + const applicationProps: ReactRemoteProps = { + ...(typeof props.name === 'string' ? { name: props.name } : {}), + ...(typeof props.age === 'number' ? { age: props.age } : {}), + ...(typeof props.basename === 'string' + ? { basename: props.basename } + : {}), + }; + return { + props: applicationProps, + dehydratedState: { + name: props.name ?? null, + age: props.age ?? null, + basename: props.basename ?? null, + }, + }; + }, + }, +}); diff --git a/apps/bridge-ssr-demo/remote-react/src/export-app.tsx b/apps/bridge-ssr-demo/remote-react/src/export-app.tsx new file mode 100644 index 00000000000..13fb3e1d3f2 --- /dev/null +++ b/apps/bridge-ssr-demo/remote-react/src/export-app.tsx @@ -0,0 +1,20 @@ +import App, { type ReactRemoteProps } from './App'; +import { createBridgeComponent } from '@module-federation/bridge-react/v18'; + +export default createBridgeComponent({ + rootComponent: App, + ssr: { + hydrate(state) { + if (!state || Array.isArray(state) || typeof state !== 'object') + return {}; + const props = state as Record; + return { + ...(typeof props.name === 'string' ? { name: props.name } : {}), + ...(typeof props.age === 'number' ? { age: props.age } : {}), + ...(typeof props.basename === 'string' + ? { basename: props.basename } + : {}), + } satisfies ReactRemoteProps; + }, + }, +}); diff --git a/apps/bridge-ssr-demo/remote-react/src/index.tsx b/apps/bridge-ssr-demo/remote-react/src/index.tsx new file mode 100644 index 00000000000..b93c7a0268a --- /dev/null +++ b/apps/bridge-ssr-demo/remote-react/src/index.tsx @@ -0,0 +1 @@ +import('./bootstrap'); diff --git a/apps/bridge-ssr-demo/remote-react/src/ssr-env.ts b/apps/bridge-ssr-demo/remote-react/src/ssr-env.ts new file mode 100644 index 00000000000..31b8b869cc5 --- /dev/null +++ b/apps/bridge-ssr-demo/remote-react/src/ssr-env.ts @@ -0,0 +1,6 @@ +/** + * Node MF environment entry for the React remote. + * Rsbuild builds this to dist/ssr/ for the host to consume via + * bridge_ssr_react@/ssr/mf-manifest.json at request time. + */ +export {}; diff --git a/apps/bridge-ssr-demo/remote-react/tsconfig.json b/apps/bridge-ssr-demo/remote-react/tsconfig.json new file mode 100644 index 00000000000..3519d14e252 --- /dev/null +++ b/apps/bridge-ssr-demo/remote-react/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "lib": ["DOM", "ES2020"], + "module": "ESNext", + "jsx": "react-jsx", + "strict": true, + "skipLibCheck": true, + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true + }, + "include": ["src"] +} diff --git a/apps/bridge-ssr-demo/remote-vue/package.json b/apps/bridge-ssr-demo/remote-vue/package.json new file mode 100644 index 00000000000..16d0d021a78 --- /dev/null +++ b/apps/bridge-ssr-demo/remote-vue/package.json @@ -0,0 +1,29 @@ +{ + "name": "bridge-ssr-remote-vue", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "rsbuild dev", + "build": "rsbuild build", + "build:vite": "pnpm run build:vite:web && pnpm run build:vite:ssr", + "build:vite:web": "vite build --config vite.config.mts", + "build:vite:ssr": "BRIDGE_VITE_SSR=true vite build --config vite.config.mts && cp dist-vite/ssr/remoteEntry.js dist-vite/ssr/remoteEntry.ssr.js", + "preview": "rsbuild preview" + }, + "dependencies": { + "@module-federation/bridge-vue3": "workspace:*", + "@vue/server-renderer": "^3.5.30", + "vue": "^3.5.30", + "vue-router": "4.4.5" + }, + "devDependencies": { + "@module-federation/rsbuild-plugin": "workspace:*", + "@module-federation/vite": "1.16.16", + "@rsbuild/core": "1.7.3", + "@rsbuild/plugin-vue": "^1.2.6", + "@vitejs/plugin-vue": "^5.0.4", + "typescript": "~5.0.4", + "vite": "^5.4.21" + } +} diff --git a/apps/bridge-ssr-demo/remote-vue/rsbuild.config.ts b/apps/bridge-ssr-demo/remote-vue/rsbuild.config.ts new file mode 100644 index 00000000000..86c3bedfefd --- /dev/null +++ b/apps/bridge-ssr-demo/remote-vue/rsbuild.config.ts @@ -0,0 +1,93 @@ +import { defineConfig } from '@rsbuild/core'; +import { pluginVue } from '@rsbuild/plugin-vue'; +import { pluginModuleFederation } from '@module-federation/rsbuild-plugin'; +import { pluginServeSsrDist } from '../shared/pluginServeSsrDist'; +import { bridgeSsrHostUrl } from '../shared/devHost'; + +const remoteOrigin = bridgeSsrHostUrl(2302); + +const mfOptions = { + name: 'bridge_ssr_vue', + exposes: { + './export-app': './src/export-app.ts', + }, + shared: { + vue: { singleton: true }, + 'vue-router': { singleton: true }, + }, + dts: false, + getPublicPath: `return '${remoteOrigin}/'`, +}; + +const ssrMfOptions = { + ...mfOptions, + exposes: { + './export-app': './src/export-app.server.ts', + }, + // Keep the Vue app and its renderer request-local to the remote server graph. + shared: {}, + getPublicPath: `return '${remoteOrigin}/ssr/'`, +}; + +export default defineConfig({ + performance: { buildCache: false }, + server: { + port: 2302, + cors: true, + }, + dev: { + assetPrefix: remoteOrigin, + writeToDisk: true, + }, + tools: { + rspack: (config) => { + delete config.optimization?.splitChunks; + }, + }, + environments: { + web: { + source: { + entry: { + index: './src/standalone.ts', + }, + }, + html: { + template: './src/index.html', + }, + output: { + distPath: { + root: 'dist', + }, + }, + }, + ssr: { + source: { + entry: { + index: './src/ssr-env.ts', + }, + }, + output: { + target: 'node', + distPath: { + root: 'dist/ssr', + }, + emitAssets: true, + }, + tools: { + rspack: (config) => { + config.output ??= {}; + config.output.publicPath = `${remoteOrigin}/ssr/`; + }, + }, + }, + }, + plugins: [ + pluginVue(), + pluginServeSsrDist(__dirname), + pluginModuleFederation(mfOptions, { environment: 'web' }), + pluginModuleFederation(ssrMfOptions, { + target: 'node', + environment: 'ssr', + }), + ], +}); diff --git a/apps/bridge-ssr-demo/remote-vue/src/RemoteVueApplication.vue b/apps/bridge-ssr-demo/remote-vue/src/RemoteVueApplication.vue new file mode 100644 index 00000000000..e653b29596f --- /dev/null +++ b/apps/bridge-ssr-demo/remote-vue/src/RemoteVueApplication.vue @@ -0,0 +1,20 @@ + + + diff --git a/apps/bridge-ssr-demo/remote-vue/src/export-app.server.ts b/apps/bridge-ssr-demo/remote-vue/src/export-app.server.ts new file mode 100644 index 00000000000..c90e02a653d --- /dev/null +++ b/apps/bridge-ssr-demo/remote-vue/src/export-app.server.ts @@ -0,0 +1,32 @@ +import App from './RemoteVueApplication.vue'; +import { createBridgeComponent } from '@module-federation/bridge-vue3'; +import { createMemoryHistory, createRouter } from 'vue-router'; +import Home from './pages/Home.vue'; +import Detail from './pages/Detail.vue'; + +export default createBridgeComponent({ + rootComponent: App, + appOptions: () => ({ + router: createRouter({ + history: createMemoryHistory(), + routes: [ + { path: '/', component: Home }, + { path: '/detail', component: Detail }, + ], + }), + }), + ssr: { + prepare(context) { + const props = context.props as { test?: string; basename?: string }; + return { + props: { + ...(typeof props.test === 'string' ? { test: props.test } : {}), + ...(typeof props.basename === 'string' + ? { basename: props.basename } + : {}), + }, + dehydratedState: { test: props.test ?? null }, + }; + }, + }, +}); diff --git a/apps/bridge-ssr-demo/remote-vue/src/export-app.ts b/apps/bridge-ssr-demo/remote-vue/src/export-app.ts new file mode 100644 index 00000000000..fcb14c40b0c --- /dev/null +++ b/apps/bridge-ssr-demo/remote-vue/src/export-app.ts @@ -0,0 +1,26 @@ +import App from './RemoteVueApplication.vue'; +import { createBridgeComponent } from '@module-federation/bridge-vue3'; +import { createRouter, createWebHistory } from 'vue-router'; +import Home from './pages/Home.vue'; +import Detail from './pages/Detail.vue'; + +export default createBridgeComponent({ + rootComponent: App, + appOptions: () => ({ + router: createRouter({ + history: createWebHistory(), + routes: [ + { path: '/', component: Home }, + { path: '/detail', component: Detail }, + ], + }), + }), + ssr: { + hydrate(state) { + if (!state || Array.isArray(state) || typeof state !== 'object') + return {}; + const test = (state as Record).test; + return typeof test === 'string' ? { test } : {}; + }, + }, +}); diff --git a/apps/bridge-ssr-demo/remote-vue/src/index.html b/apps/bridge-ssr-demo/remote-vue/src/index.html new file mode 100644 index 00000000000..c7fe0adc4c3 --- /dev/null +++ b/apps/bridge-ssr-demo/remote-vue/src/index.html @@ -0,0 +1,11 @@ + + + + + + Bridge SSR Vue Remote + + +
    + + diff --git a/apps/bridge-ssr-demo/remote-vue/src/pages/Detail.vue b/apps/bridge-ssr-demo/remote-vue/src/pages/Detail.vue new file mode 100644 index 00000000000..2e05e520e52 --- /dev/null +++ b/apps/bridge-ssr-demo/remote-vue/src/pages/Detail.vue @@ -0,0 +1,6 @@ + diff --git a/apps/bridge-ssr-demo/remote-vue/src/pages/Home.vue b/apps/bridge-ssr-demo/remote-vue/src/pages/Home.vue new file mode 100644 index 00000000000..8373d64d00d --- /dev/null +++ b/apps/bridge-ssr-demo/remote-vue/src/pages/Home.vue @@ -0,0 +1,16 @@ + + + diff --git a/apps/bridge-ssr-demo/remote-vue/src/ssr-env.ts b/apps/bridge-ssr-demo/remote-vue/src/ssr-env.ts new file mode 100644 index 00000000000..ffee3d7483a --- /dev/null +++ b/apps/bridge-ssr-demo/remote-vue/src/ssr-env.ts @@ -0,0 +1,6 @@ +/** + * Node MF environment entry for the Vue remote. + * Rsbuild builds this to dist/ssr/ for the host to consume via + * bridge_ssr_vue@/ssr/mf-manifest.json at request time. + */ +export {}; diff --git a/apps/bridge-ssr-demo/remote-vue/src/standalone.ts b/apps/bridge-ssr-demo/remote-vue/src/standalone.ts new file mode 100644 index 00000000000..4f6adaaeb2d --- /dev/null +++ b/apps/bridge-ssr-demo/remote-vue/src/standalone.ts @@ -0,0 +1,15 @@ +import { createApp } from 'vue'; +import App from './RemoteVueApplication.vue'; +import { createRouter, createWebHistory } from 'vue-router'; +import Home from './pages/Home.vue'; +import Detail from './pages/Detail.vue'; + +const router = createRouter({ + history: createWebHistory(), + routes: [ + { path: '/', component: Home }, + { path: '/detail', component: Detail }, + ], +}); + +createApp(App).use(router).mount('#root'); diff --git a/apps/bridge-ssr-demo/remote-vue/tsconfig.json b/apps/bridge-ssr-demo/remote-vue/tsconfig.json new file mode 100644 index 00000000000..ac97d6272cc --- /dev/null +++ b/apps/bridge-ssr-demo/remote-vue/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "jsx": "preserve", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src", "rsbuild.config.ts"] +} diff --git a/apps/bridge-ssr-demo/remote-vue/vite.config.mts b/apps/bridge-ssr-demo/remote-vue/vite.config.mts new file mode 100644 index 00000000000..3e7ba50bbd4 --- /dev/null +++ b/apps/bridge-ssr-demo/remote-vue/vite.config.mts @@ -0,0 +1,51 @@ +import { federation } from '@module-federation/vite'; +import vue from '@vitejs/plugin-vue'; +import { defineConfig } from 'vite'; +import path from 'node:path'; +import { bridgeSsrHostUrl } from '../shared/devHost'; + +const isSSR = process.env.BRIDGE_VITE_SSR === 'true'; +const remoteOrigin = bridgeSsrHostUrl(2402); + +export default defineConfig({ + plugins: [ + vue(), + federation({ + name: 'bridge_ssr_vue', + filename: 'remoteEntry.js', + exposes: { + './export-app': isSSR + ? './src/export-app.server.ts' + : './src/export-app.ts', + }, + shared: isSSR + ? {} + : { + vue: { singleton: true }, + 'vue-router': { singleton: true }, + }, + manifest: true, + dts: false, + target: isSSR ? 'node' : 'web', + getPublicPath: `return '${remoteOrigin}${isSSR ? '/ssr' : ''}/'`, + }), + ], + server: { + origin: remoteOrigin, + port: 2402, + }, + build: { + outDir: isSSR ? 'dist-vite/ssr' : 'dist-vite', + emptyOutDir: !isSSR, + target: isSSR ? 'node20' : 'es2020', + ssr: isSSR ? './src/ssr-env.ts' : undefined, + rollupOptions: isSSR + ? undefined + : { + input: path.resolve(__dirname, 'src/standalone.ts'), + }, + }, + ssr: { + noExternal: true, + }, +}); diff --git a/apps/bridge-ssr-demo/shared/createHostServer.mjs b/apps/bridge-ssr-demo/shared/createHostServer.mjs new file mode 100644 index 00000000000..57aec8ba0b5 --- /dev/null +++ b/apps/bridge-ssr-demo/shared/createHostServer.mjs @@ -0,0 +1,106 @@ +import express from 'express'; +import { createRsbuild, loadConfig } from '@rsbuild/core'; +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { serializeBridgeJSON } from '@module-federation/bridge-shared/dist/index.es.js'; + +const shouldRender = (url) => { + if (url.startsWith('/@') || url.startsWith('/__rsbuild')) return false; + const pathname = url.split('?')[0]; + return !pathname.includes('.') || pathname.endsWith('.html'); +}; + +function assembleDocument(template, html, ssrContext) { + const marker = ''; + if (!template.includes(marker)) { + throw new Error(`Bridge SSR host template is missing ${marker}`); + } + const payload = ``; + return template.replace(marker, html).replace('', `${payload}`); +} + +function registerSSRRoute(app, getBundle, getTemplate, label) { + app.get('*', async (req, res, next) => { + if (!shouldRender(req.originalUrl)) return next(); + const controller = new AbortController(); + const disconnect = () => controller.abort(new Error('Client disconnected')); + req.once('aborted', disconnect); + try { + const [bundle, template] = await Promise.all([ + getBundle(), + getTemplate(), + ]); + const rendered = await bundle.render(req.originalUrl, { + signal: controller.signal, + }); + if (controller.signal.aborted) return; + res + .status(200) + .type('html') + .set('Cache-Control', 'no-store') + .send(assembleDocument(template, rendered.html, rendered.ssrContext)); + } catch (error) { + if (!controller.signal.aborted) { + console.error(`[${label}] SSR request failed`, error, error?.cause); + next(error); + } + } finally { + req.off('aborted', disconnect); + } + }); +} + +export async function startBridgeHost({ rootDir, port, label }) { + const host = + process.env.HOST ?? process.env.BRIDGE_SSR_DEV_HOST ?? 'localhost'; + const app = express(); + if (process.env.BRIDGE_SSR_MODE === 'production') { + const dist = path.join(rootDir, 'dist'); + const template = await readFile(path.join(dist, 'index.html'), 'utf8'); + const imported = await import( + `${pathToFileURL(path.join(dist, 'ssr', 'index.js')).href}?${Date.now()}` + ); + registerSSRRoute( + app, + async () => imported.default ?? imported, + async () => template, + label, + ); + app.use(express.static(dist)); + } else { + const { content } = await loadConfig({ cwd: rootDir }); + const rsbuild = await createRsbuild({ + cwd: rootDir, + rsbuildConfig: content, + }); + const server = await rsbuild.createDevServer(); + let bundlePromise; + const getBundle = () => { + bundlePromise ??= server.environments.ssr + .loadBundle('index') + .catch((error) => { + bundlePromise = undefined; + throw error; + }); + return bundlePromise; + }; + registerSSRRoute( + app, + getBundle, + () => server.environments.client.getTransformedHtml('index'), + label, + ); + app.use(server.middlewares); + const httpServer = app.listen(port, host, async () => { + await server.afterListen(); + console.log(`[${label}] ready at http://${host}:${port}`); + }); + server.connectWebSocket({ server: httpServer }); + return; + } + + app.listen(port, host, () => { + console.log(`[${label}] production ready at http://${host}:${port}`); + }); +} diff --git a/apps/bridge-ssr-demo/shared/devHost.ts b/apps/bridge-ssr-demo/shared/devHost.ts new file mode 100644 index 00000000000..b5aefe9ca6f --- /dev/null +++ b/apps/bridge-ssr-demo/shared/devHost.ts @@ -0,0 +1,17 @@ +export const BRIDGE_SSR_DEV_HOST = + process.env.BRIDGE_SSR_DEV_HOST ?? 'localhost'; + +export const BRIDGE_SSR_REMOTE_BUNDLER = + process.env.BRIDGE_SSR_REMOTE_BUNDLER === 'vite' ? 'vite' : 'rsbuild'; + +export const bridgeSsrRemotePort = (framework: 'react' | 'vue') => { + if (BRIDGE_SSR_REMOTE_BUNDLER === 'vite') { + return framework === 'react' ? 2401 : 2402; + } + return framework === 'react' ? 2301 : 2302; +}; + +export const bridgeSsrServerManifestPath = 'ssr/mf-manifest.json'; + +export const bridgeSsrHostUrl = (port: number) => + `http://${BRIDGE_SSR_DEV_HOST}:${port}`; diff --git a/apps/bridge-ssr-demo/shared/package.json b/apps/bridge-ssr-demo/shared/package.json new file mode 100644 index 00000000000..99cc4bbc4db --- /dev/null +++ b/apps/bridge-ssr-demo/shared/package.json @@ -0,0 +1,11 @@ +{ + "name": "bridge-ssr-demo-shared", + "private": true, + "version": "0.0.1", + "type": "module", + "dependencies": { + "@module-federation/bridge-shared": "workspace:*", + "@rsbuild/core": "1.7.3", + "express": "^4.21.2" + } +} diff --git a/apps/bridge-ssr-demo/shared/pluginServeSsrDist.ts b/apps/bridge-ssr-demo/shared/pluginServeSsrDist.ts new file mode 100644 index 00000000000..fa6c1f40146 --- /dev/null +++ b/apps/bridge-ssr-demo/shared/pluginServeSsrDist.ts @@ -0,0 +1,63 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import type { RsbuildPlugin } from '@rsbuild/core'; + +function getContentType(filePath: string) { + if (filePath.endsWith('.json')) { + return 'application/json'; + } + if (filePath.endsWith('.js')) { + return 'application/javascript'; + } + if (filePath.endsWith('.map')) { + return 'application/json'; + } + return 'application/octet-stream'; +} + +export function pluginServeSsrDist(rootDir = process.cwd()): RsbuildPlugin { + const ssrDir = path.join(rootDir, 'dist', 'ssr'); + + return { + name: 'plugin-serve-ssr-dist', + setup(api) { + api.modifyRsbuildConfig((config) => { + config.dev ??= {}; + const previous = config.dev.setupMiddlewares; + + config.dev.setupMiddlewares = (middlewares, server) => { + if (typeof previous === 'function') { + previous(middlewares, server); + } else if (Array.isArray(previous)) { + previous.forEach((setup) => setup(middlewares, server)); + } + + middlewares.unshift((req, res, next) => { + const url = req.url?.split('?')[0] ?? ''; + if (!url.startsWith('/ssr/')) { + next(); + return; + } + + const relativePath = decodeURIComponent(url.slice('/ssr/'.length)); + const filePath = path.join(ssrDir, relativePath); + + if ( + !filePath.startsWith(ssrDir) || + !fs.existsSync(filePath) || + fs.statSync(filePath).isDirectory() + ) { + next(); + return; + } + + res.statusCode = 200; + res.setHeader('Content-Type', getContentType(filePath)); + res.setHeader('Access-Control-Allow-Origin', '*'); + fs.createReadStream(filePath).pipe(res); + }); + }; + }); + }, + }; +} diff --git a/apps/bridge-ssr-demo/shared/routerAlias.ts b/apps/bridge-ssr-demo/shared/routerAlias.ts new file mode 100644 index 00000000000..6ce885d8c98 --- /dev/null +++ b/apps/bridge-ssr-demo/shared/routerAlias.ts @@ -0,0 +1,14 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const directory = path.dirname(fileURLToPath(import.meta.url)); + +export function createBridgeRouterAlias(reactRouterDomPath: string) { + return { + 'react-router-dom$': path.resolve( + directory, + '../../../packages/bridge/bridge-react/dist/router-v6.es.js', + ), + 'react-router-dom/dist/index.js': reactRouterDomPath, + }; +} diff --git a/apps/bridge-ssr-demo/shared/serveDist.mjs b/apps/bridge-ssr-demo/shared/serveDist.mjs new file mode 100644 index 00000000000..292ec4f14fa --- /dev/null +++ b/apps/bridge-ssr-demo/shared/serveDist.mjs @@ -0,0 +1,19 @@ +import express from 'express'; +import path from 'node:path'; + +const [distDir, portValue] = process.argv.slice(2); +const port = Number(portValue); + +if (!distDir || !Number.isInteger(port)) { + throw new Error('Usage: serveDist.mjs '); +} + +const app = express(); +app.use((_req, res, next) => { + res.setHeader('Access-Control-Allow-Origin', '*'); + next(); +}); +app.use(express.static(path.resolve(distDir))); +app.listen(port, process.env.HOST ?? 'localhost', () => { + console.log(`[bridge-ssr-static] serving ${distDir} on port ${port}`); +}); diff --git a/apps/website-new/docs/en/guide/bridge/_meta.json b/apps/website-new/docs/en/guide/bridge/_meta.json index b7f300763b2..9703deaca9e 100644 --- a/apps/website-new/docs/en/guide/bridge/_meta.json +++ b/apps/website-new/docs/en/guide/bridge/_meta.json @@ -10,5 +10,10 @@ "label": "React", "collapsible": true, "collapsed": true + }, + { + "type": "file", + "name": "ssr", + "label": "Server rendering" } ] diff --git a/apps/website-new/docs/en/guide/bridge/ssr.mdx b/apps/website-new/docs/en/guide/bridge/ssr.mdx new file mode 100644 index 00000000000..bc78c0d62c0 --- /dev/null +++ b/apps/website-new/docs/en/guide/bridge/ssr.mdx @@ -0,0 +1,55 @@ +# Server rendering Bridge applications + +Bridge SSR V1 lets a federated application provider return a buffered HTML island on the server and hydrate that same island through the existing client lifecycle. + +## Supported scope + +- React 18 with declarative React Router v6 +- Vue 3 with Vue Router 4 +- Full host-passed `{ html, dehydratedState, moduleName, instanceId, protocolVersion }` payloads +- Multiple instances of the same remote through document-unique instance IDs + +React data routers and other React or Router versions keep their existing client-rendering support but are not supported for SSR in V1. + +## Remote provider + +Set `ssr: true` when no request preparation is needed. If preparation is required, map the same federated export key to separate browser and Node source files. The browser file supplies `hydrate`; the Node file supplies `prepare`. This keeps server renderers and request-only code out of browser chunks. + +```ts +// export-app.server.ts +export default createBridgeComponent({ + rootComponent: App, + ssr: { + prepare({ props }) { + return { + props, + dehydratedState: { initialValue: props.initialValue }, + }; + }, + }, +}); +``` + +The React Node entry owns `react-dom/server`; the Vue Node entry owns `@vue/server-renderer`. Framework elements, routers, application instances, and renderers never cross `@module-federation/bridge-shared`. + +## Host rendering + +Use `renderRemoteBridge` with an intentional, sanitized standard `Request`, stable module name, document-unique instance ID, and explicit props: + +```ts +const result = await renderRemoteBridge({ + loader: () => federationInstance.loadRemote('catalog/export-app'), + moduleName: 'catalog', + instanceId: 'catalog-sidebar', + request, + props: { basename: '/catalog' }, +}); +``` + +Carry the complete result in the host application's normal SSR payload and pass it to `createRemoteAppComponent` as `ssr`. Serialize payloads with `serializeBridgeJSON`, which validates JSON-only data and escapes executable HTML sequences. The adapters hydrate only when the payload identity matches the instance-scoped SSR mount marker; otherwise they use the unchanged CSR path. V1 does not scan the document or use a hydration registry. + +`renderRemoteBridge` rejects provider-load, unsupported-contract, identity, and rendering failures with contextual errors. Response policy remains host-owned. + +## Not included in V1 + +Assets/CSP/head management, status and header conflict policy, timeouts and fallbacks, DOM-reference payload recovery, React data routers, additional React/Router versions, Nuxt or Modern.js adapters, portals/Teleports, streaming, backpressure, and benchmarks are follow-up work. diff --git a/package.json b/package.json index 31ffc62b07a..1a161808bd5 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,9 @@ "e2e:treeshake:frontend": "pnpm exec turbo run e2e --filter=@module-federation/treeshake-frontend", "e2e:modern:ssr": "node tools/scripts/run-modern-e2e.mjs --mode=manifest", "e2e:router": "node tools/scripts/run-router-e2e.mjs --mode=dev", + "e2e:bridge:ssr": "node tools/scripts/run-bridge-ssr-e2e.mjs", + "e2e:bridge:ssr:production": "BRIDGE_SSR_MODE=production node tools/scripts/run-bridge-ssr-e2e.mjs", + "e2e:bridge:ssr:vite-smoke": "BRIDGE_SSR_REMOTE_BUNDLER=vite node tools/scripts/run-bridge-ssr-e2e.mjs", "e2e:shared-tree-shaking:runtime-infer": "npx kill-port --port 3001,3002 && pnpm exec turbo run test:e2e --filter=shared-tree-shaking-no-server-host && lsof -ti tcp:3001,3002 | xargs kill", "e2e:shared-tree-shaking:server-calc": "npx kill-port --port 3001,3002,3003 && pnpm exec turbo run test:e2e --filter=shared-tree-shaking-with-server-host && lsof -ti tcp:3001,3002,3003 | xargs kill", "e2e:devtools:dev": "npx kill-port 3009 3010 3011 3012 3013 4001 && pnpm run app:manifest:dev & echo \"done\" && npx wait-on tcp:3009 tcp:3010 tcp:3011 tcp:3012 tcp:3013 && sleep 10 && pnpm exec turbo run test:e2e --filter=@module-federation/devtools", diff --git a/packages/bridge/bridge-react/package.json b/packages/bridge/bridge-react/package.json index 99f973a9b48..0ab31d075ec 100644 --- a/packages/bridge/bridge-react/package.json +++ b/packages/bridge/bridge-react/package.json @@ -32,6 +32,14 @@ }, "./v18": { "types": "./dist/v18.d.ts", + "browser": { + "import": "./dist/v18.es.js", + "require": "./dist/v18.cjs.js" + }, + "node": { + "import": "./dist/v18.server.es.js", + "require": "./dist/v18.server.cjs.js" + }, "import": "./dist/v18.es.js", "require": "./dist/v18.cjs.js" }, @@ -189,6 +197,7 @@ "vite": "^5.4.21", "@module-federation/runtime": "workspace:*", "@module-federation/runtime-core": "workspace:*", - "hono": "4.12.34" + "hono": "4.12.34", + "jsdom": "20.0.3" } } diff --git a/packages/bridge/bridge-react/src/provider/versions/bridge-base.spec.tsx b/packages/bridge/bridge-react/src/provider/versions/bridge-base.spec.tsx new file mode 100644 index 00000000000..4bb011e6b19 --- /dev/null +++ b/packages/bridge/bridge-react/src/provider/versions/bridge-base.spec.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { describe, expect, it, rs } from '@rstest/core'; +import { getBridgeSSRContainerAttrs } from '@module-federation/bridge-shared'; +import { createBaseBridgeComponent } from './bridge-base'; + +const Root = () =>
    remote
    ; + +describe('React Bridge hydration selection', () => { + it('hydrates only a matching host-passed SSR mount', async () => { + const hydrateRoot = rs.fn(() => ({ render: rs.fn(), unmount: rs.fn() })); + const createRoot = rs.fn(() => ({ render: rs.fn(), unmount: rs.fn() })); + const dom = document.createElement('div'); + for (const [name, value] of Object.entries( + getBridgeSSRContainerAttrs({ moduleName: 'remote', instanceId: 'one' }), + )) + dom.setAttribute(name, value); + dom.innerHTML = '
    remote
    '; + const provider = createBaseBridgeComponent({ + rootComponent: Root, + createRoot, + hydrateRoot, + ssr: true, + })(); + await provider.render({ dom, moduleName: 'remote', instanceId: 'one' }); + expect(hydrateRoot).toHaveBeenCalledOnce(); + expect(createRoot).not.toHaveBeenCalled(); + }); + + it('keeps the existing CSR path without a payload marker', async () => { + const root = { render: rs.fn(), unmount: rs.fn() }; + const createRoot = rs.fn(() => root); + const hydrate = rs.fn(() => ({ restored: true })); + const provider = createBaseBridgeComponent({ + rootComponent: Root, + createRoot, + hydrateRoot: rs.fn(), + ssr: { hydrate }, + })(); + await provider.render({ + dom: document.createElement('div'), + moduleName: 'remote', + }); + expect(createRoot).toHaveBeenCalledOnce(); + expect(root.render).toHaveBeenCalledOnce(); + expect(hydrate).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/bridge/bridge-react/src/provider/versions/bridge-base.tsx b/packages/bridge/bridge-react/src/provider/versions/bridge-base.tsx index 174dbf0f3f8..8af2c4491ea 100644 --- a/packages/bridge/bridge-react/src/provider/versions/bridge-base.tsx +++ b/packages/bridge/bridge-react/src/provider/versions/bridge-base.tsx @@ -2,23 +2,24 @@ * Base bridge component implementation * This file contains bridge component logic shared across all React versions */ -import * as React from 'react'; import type { - ProviderParams, ProviderFnParams, RootType, DestroyParams, RenderParams, CreateRootOptions, - ErrorFallbackProps, } from '../../types'; -import { ErrorBoundary } from '../../error-boundary'; -import { RouterContext } from '../context'; import { LoggerInstance } from '../../utils'; import { federationRuntime } from '../plugin'; +import { + hasBridgeSSRMarkup, + type BridgeJSONValue, +} from '@module-federation/bridge-shared'; +import { createBridgeReactElement, omitHostFallback } from './bridge-render'; export function createBaseBridgeComponent({ createRoot, + hydrateRoot, defaultRootOptions, ...bridgeInfo }: ProviderFnParams) { @@ -30,60 +31,14 @@ export function createBaseBridgeComponent({ instance, ); - const RawComponent = (info: { propsInfo: T; appInfo: ProviderParams }) => { - const { appInfo, propsInfo, ...restProps } = info; - const { moduleName, memoryRoute, basename = '/' } = appInfo; - return ( - - - - ); - }; - - const DefaultFallback = ({ error }: ErrorFallbackProps) => ( -
    -

    Something went wrong:

    -
    -          {error instanceof Error ? error.message : String(error)}
    -        
    -
    - ); - - const omitHostFallback =

    >(props: P) => { - const nextProps = { ...props }; - delete nextProps.fallback; - return nextProps; - }; - - const BridgeWrapper = ({ - basename, - moduleName, - memoryRoute, - propsInfo, - }: { - basename?: string; - moduleName?: string; - memoryRoute?: any; - propsInfo: T; - }) => ( - - - - ); + const hydrateState = + bridgeInfo.ssr && typeof bridgeInfo.ssr === 'object' + ? bridgeInfo.ssr.hydrate + : undefined; return { async render(info: RenderParams) { + if (info.signal?.aborted) return; LoggerInstance.debug(`createBridgeComponent render Info`, info); const { moduleName, @@ -91,38 +46,71 @@ export function createBaseBridgeComponent({ basename, memoryRoute, rootOptions, + instanceId, + ssrState, ...propsInfo } = info; const mergedRootOptions: CreateRootOptions | undefined = { ...defaultRootOptions, ...(rootOptions as CreateRootOptions), + ...(instanceId + ? { identifierPrefix: `mf-${encodeURIComponent(instanceId)}-` } + : {}), }; + const isFirstRender = !rootMap.has(dom); + const shouldHydrate = + isFirstRender && + hasBridgeSSRMarkup(dom, { + moduleName, + instanceId, + }); + const hydratedProps = + shouldHydrate && hydrateState + ? hydrateState(ssrState as BridgeJSONValue | undefined) + : {}; + const beforeBridgeRenderRes = instance?.bridgeHook?.lifecycle?.beforeBridgeRender?.emit(info) || {}; - const rootComponentWithErrorBoundary = ( - ), - basename, - ...(beforeBridgeRenderRes as any)?.extraProps, - } as T - } - /> - ); + const rootComponentWithErrorBoundary = createBridgeReactElement({ + rootComponent: bridgeInfo.rootComponent, + basename, + moduleName, + memoryRoute, + propsInfo: { + ...hydratedProps, + ...omitHostFallback(propsInfo as Record), + basename, + ...(beforeBridgeRenderRes as any)?.extraProps, + } as T, + }); if (bridgeInfo.render) { + const renderer = shouldHydrate + ? bridgeInfo.hydrate + : bridgeInfo.render; + if (!renderer) { + throw new Error( + 'A custom Bridge renderer must provide hydrate when SSR is enabled', + ); + } await Promise.resolve( - bridgeInfo.render(rootComponentWithErrorBoundary, dom), + renderer(rootComponentWithErrorBoundary, dom), ).then((root: RootType) => rootMap.set(dom, root)); } else { let root = rootMap.get(dom); + let didHydrate = false; + if (shouldHydrate && hydrateRoot) { + root = hydrateRoot!( + dom, + rootComponentWithErrorBoundary, + mergedRootOptions, + ); + rootMap.set(dom, root as RootType); + didHydrate = true; + } // Do not call createRoot multiple times if (!root && createRoot) { root = createRoot(dom, mergedRootOptions); @@ -130,7 +118,7 @@ export function createBaseBridgeComponent({ } if (root && 'render' in root) { - root.render(rootComponentWithErrorBoundary); + if (!didHydrate) root.render(rootComponentWithErrorBoundary); } } instance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit(info) || {}; diff --git a/packages/bridge/bridge-react/src/provider/versions/bridge-render.tsx b/packages/bridge/bridge-react/src/provider/versions/bridge-render.tsx new file mode 100644 index 00000000000..1747425d787 --- /dev/null +++ b/packages/bridge/bridge-react/src/provider/versions/bridge-render.tsx @@ -0,0 +1,54 @@ +import * as React from 'react'; +import { ErrorBoundary } from '../../error-boundary'; +import type { + ErrorFallbackProps, + ProviderFnParams, + ProviderParams, +} from '../../types'; +import { RouterContext } from '../context'; + +export function omitHostFallback

    >(props: P) { + const next = { ...props }; + delete next.fallback; + return next; +} + +export function createBridgeReactElement({ + rootComponent: RootComponent, + basename, + moduleName, + memoryRoute, + ssrLocation, + propsInfo, +}: { + rootComponent: ProviderFnParams['rootComponent']; + basename?: string; + moduleName?: string; + memoryRoute?: ProviderParams['memoryRoute']; + ssrLocation?: string; + propsInfo: T; +}) { + const DefaultFallback = ({ error }: ErrorFallbackProps) => ( +

    +

    Something went wrong:

    +
    +        {error instanceof Error ? error.message : String(error)}
    +      
    +
    + ); + + return ( + + + + + + ); +} diff --git a/packages/bridge/bridge-react/src/provider/versions/bridge-server.tsx b/packages/bridge/bridge-react/src/provider/versions/bridge-server.tsx new file mode 100644 index 00000000000..ab3839cdcbb --- /dev/null +++ b/packages/bridge/bridge-react/src/provider/versions/bridge-server.tsx @@ -0,0 +1,68 @@ +import { + BRIDGE_SSR_PROTOCOL_VERSION, + type BridgeSSRPrepareResult, + type BridgeSSRResult, + type BridgeServerRenderContext, +} from '@module-federation/bridge-shared'; +import type { ProviderFnParams, ProviderParams } from '../../types'; +import { createBaseBridgeComponent } from './bridge-base'; +import { createBridgeReactElement, omitHostFallback } from './bridge-render'; + +export function createServerBridgeComponent( + bridgeInfo: ProviderFnParams & { + serverRenderer: ( + element: React.ReactElement, + options: { identifierPrefix: string }, + ) => string | Promise; + }, +) { + const { serverRenderer, ...clientInfo } = bridgeInfo; + const createClientProvider = createBaseBridgeComponent(clientInfo); + + return () => { + const provider = createClientProvider() as ReturnType< + typeof createClientProvider + > & { + renderServer?: ( + context: BridgeServerRenderContext, + ) => Promise; + }; + if (!bridgeInfo.ssr) return provider; + + provider.renderServer = async (context) => { + if (context.signal.aborted) throw context.signal.reason; + const config = + typeof bridgeInfo.ssr === 'object' ? bridgeInfo.ssr : undefined; + const preparedValue = await config?.prepare?.(context); + const prepared = (preparedValue || {}) as BridgeSSRPrepareResult; + const renderInfo = (prepared.props ?? context.props) as T & + ProviderParams; + const { basename, memoryRoute, ...applicationProps } = renderInfo; + delete (applicationProps as Record).moduleName; + const url = new URL(context.request.url); + const element = createBridgeReactElement({ + rootComponent: bridgeInfo.rootComponent, + basename, + moduleName: context.moduleName, + memoryRoute, + ssrLocation: `${url.pathname}${url.search}`, + propsInfo: { + ...omitHostFallback(applicationProps as Record), + basename, + } as T, + }); + const html = await serverRenderer(element, { + identifierPrefix: `mf-${encodeURIComponent(context.instanceId)}-`, + }); + if (context.signal.aborted) throw context.signal.reason; + return { + protocolVersion: BRIDGE_SSR_PROTOCOL_VERSION, + moduleName: context.moduleName, + instanceId: context.instanceId, + html, + dehydratedState: prepared.dehydratedState, + }; + }; + return provider; + }; +} diff --git a/packages/bridge/bridge-react/src/provider/versions/server-renderer.ts b/packages/bridge/bridge-react/src/provider/versions/server-renderer.ts new file mode 100644 index 00000000000..de5bd538e08 --- /dev/null +++ b/packages/bridge/bridge-react/src/provider/versions/server-renderer.ts @@ -0,0 +1,8 @@ +import { renderToString } from 'react-dom/server'; + +export function renderBridgeReactToString( + element: React.ReactElement, + options: { identifierPrefix: string }, +) { + return renderToString(element, options); +} diff --git a/packages/bridge/bridge-react/src/provider/versions/v18.server.ts b/packages/bridge/bridge-react/src/provider/versions/v18.server.ts new file mode 100644 index 00000000000..56fdf46abea --- /dev/null +++ b/packages/bridge/bridge-react/src/provider/versions/v18.server.ts @@ -0,0 +1,17 @@ +import type { ProviderFnParams } from '../../types'; +import { createReact18Root, hydrateReact18Root } from './v18'; +import { createServerBridgeComponent } from './bridge-server'; +import { renderBridgeReactToString } from './server-renderer'; + +export function createBridgeComponent( + bridgeInfo: Omit, 'createRoot' | 'hydrateRoot'>, +) { + return createServerBridgeComponent({ + ...bridgeInfo, + createRoot: createReact18Root, + hydrateRoot: hydrateReact18Root, + serverRenderer: renderBridgeReactToString, + }); +} + +export type { CreateRootOptions, Root } from './v18'; diff --git a/packages/bridge/bridge-react/src/provider/versions/v18.ts b/packages/bridge/bridge-react/src/provider/versions/v18.ts index 31436fde6cd..937a50fdb51 100644 --- a/packages/bridge/bridge-react/src/provider/versions/v18.ts +++ b/packages/bridge/bridge-react/src/provider/versions/v18.ts @@ -36,10 +36,11 @@ export function hydrateReact18Root( } export function createBridgeComponent( - bridgeInfo: Omit, 'createRoot'>, + bridgeInfo: Omit, 'createRoot' | 'hydrateRoot'>, ) { const fullBridgeInfo = { createRoot: createReact18Root, + hydrateRoot: hydrateReact18Root, ...bridgeInfo, } as unknown as ProviderFnParams; diff --git a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx index 44b6887f43c..ed6f85bd968 100644 --- a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx +++ b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx @@ -6,9 +6,11 @@ import React, { useEffect, useRef, useState, forwardRef } from 'react'; import { LoggerInstance, getRootDomDefaultClassName } from '../utils'; import { federationRuntime } from '../provider/plugin'; import { RemoteComponentProps, RemoteAppParams } from '../types'; +import type { RemoteAppSSRProps } from '../types'; +import { getBridgeSSRContainerAttrs } from '@module-federation/bridge-shared'; export const RemoteAppWrapper = forwardRef(function ( - props: RemoteAppParams & RemoteComponentProps, + props: RemoteAppParams & RemoteComponentProps & RemoteAppSSRProps, ref, ) { const { @@ -20,8 +22,12 @@ export const RemoteAppWrapper = forwardRef(function ( style, fallback, loading, + ssr, + instanceId: suppliedInstanceId, ...resProps } = props; + const instanceId = suppliedInstanceId || ssr?.instanceId; + const hasSSRPayload = Boolean(ssr && instanceId); const instance = federationRuntime.instance; const rootRef: React.MutableRefObject = @@ -85,6 +91,8 @@ export const RemoteAppWrapper = forwardRef(function ( basename, memoryRoute, fallback, + instanceId, + ssrState: ssr?.dehydratedState, ...resProps, }; renderDom.current = rootRef.current; @@ -101,8 +109,21 @@ export const RemoteAppWrapper = forwardRef(function ( // bridge-remote-root const rootComponentClassName = `${getRootDomDefaultClassName(moduleName)} ${className || ''}`; return ( -
    - {loading} +
    + {hasSSRPayload ? null : loading}
    ); }); diff --git a/packages/bridge/bridge-react/src/remote/createHelpers.tsx b/packages/bridge/bridge-react/src/remote/createHelpers.tsx index b0580acacde..65e4eacb2fc 100644 --- a/packages/bridge/bridge-react/src/remote/createHelpers.tsx +++ b/packages/bridge/bridge-react/src/remote/createHelpers.tsx @@ -100,15 +100,28 @@ export function createRemoteAppComponentFactory( >(info: LazyRemoteComponentInfo) { const LazyComponent = createLazyRemoteComponent(info); return forwardRef((props, ref) => { + const ssrResult = (props as any).ssr; + const content = + typeof window === 'undefined' && ssrResult ? ( + ({ render() {}, destroy() {} })} + exportName={info.export || 'default'} + fallback={info.fallback} + loading={info.loading} + ref={ref} + /> + ) : ( + + ); return ( } > - - - + {content} ); }); diff --git a/packages/bridge/bridge-react/src/router/static.tsx b/packages/bridge/bridge-react/src/router/static.tsx new file mode 100644 index 00000000000..10bb00308fb --- /dev/null +++ b/packages/bridge/bridge-react/src/router/static.tsx @@ -0,0 +1,52 @@ +import React from 'react'; + +function parsePath(value: string) { + const url = new URL(value, 'http://bridge.invalid'); + return { + pathname: url.pathname, + search: url.search, + hash: url.hash, + state: null, + key: 'default', + }; +} + +const navigator = { + createHref: (value: any) => + typeof value === 'string' + ? value + : `${value.pathname || '/'}${value.search || ''}${value.hash || ''}`, + encodeLocation: (value: any) => + typeof value === 'string' ? parsePath(value) : value, + push: () => { + throw new Error('Cannot navigate while server rendering a Bridge remote'); + }, + replace: () => { + throw new Error('Cannot navigate while server rendering a Bridge remote'); + }, + go: () => undefined, +}; + +export function BridgeStaticRouter({ + Router, + basename, + location, + children, +}: { + Router: React.ComponentType; + basename?: string; + location: string; + children?: React.ReactNode; +}) { + return ( + + {children} + + ); +} diff --git a/packages/bridge/bridge-react/src/router/v6.tsx b/packages/bridge/bridge-react/src/router/v6.tsx index c0b2025a5a3..52897ecdc6e 100644 --- a/packages/bridge/bridge-react/src/router/v6.tsx +++ b/packages/bridge/bridge-react/src/router/v6.tsx @@ -3,6 +3,7 @@ import React, { useContext } from 'react'; import * as ReactRouterDom from 'react-router-dom/dist/index.js'; import { RouterContext } from '../provider/context'; import { LoggerInstance } from '../utils'; +import { BridgeStaticRouter } from './static'; function WraperRouter( props: @@ -18,6 +19,17 @@ function WraperRouter( WraperRouterProps: props, }); + if (routerContextProps?.ssrLocation) { + return ( + + {props.children} + + ); + } if (routerContextProps?.memoryRoute) { return ( ; + instanceId?: string; + ssrState?: BridgeJSONValue; + signal?: AbortSignal; [key: string]: unknown; } @@ -90,10 +103,19 @@ export interface ProviderFnParams { App: React.ReactElement, id?: HTMLElement | string, ) => RootType | Promise; + hydrate?: ( + App: React.ReactElement, + id?: HTMLElement | string, + ) => RootType | Promise; createRoot?: ( container: Element | DocumentFragment, options?: CreateRootOptions, ) => Root; + hydrateRoot?: ( + container: Element | DocumentFragment, + initialChildren: React.ReactNode, + options?: CreateRootOptions, + ) => Root; /** * Default options to pass to createRoot for React 18 and 19 * These options will be used when creating a root unless overridden by rootOptions in render params @@ -104,6 +126,7 @@ export interface ProviderFnParams { * } */ defaultRootOptions?: CreateRootOptions; + ssr?: BridgeSSRConfig; } /** @@ -135,11 +158,19 @@ export interface RemoteComponentParams< */ export interface RemoteModule { provider: () => { - render: (info: RenderFnParams) => void; + render: (info: RenderFnParams) => void | Promise; destroy: (info: { dom: any }) => void; + renderServer?: ( + context: BridgeServerRenderContext, + ) => Promise; }; } +export type RemoteAppSSRProps = { + ssr?: BridgeSSRResult; + instanceId?: string; +}; + /** * Parameters for a remote app component */ diff --git a/packages/bridge/bridge-react/src/v18.server.ts b/packages/bridge/bridge-react/src/v18.server.ts new file mode 100644 index 00000000000..72b84752cb4 --- /dev/null +++ b/packages/bridge/bridge-react/src/v18.server.ts @@ -0,0 +1,9 @@ +export { createBridgeComponent } from './provider/versions/v18.server'; +export type { CreateRootOptions, Root } from './provider/versions/v18.server'; +export type { + ProviderParams, + ProviderFnParams, + RootType, + DestroyParams, + RenderParams, +} from './types'; diff --git a/packages/bridge/bridge-react/src/v18.ts b/packages/bridge/bridge-react/src/v18.ts index 626628602f2..0b21ad5f54a 100644 --- a/packages/bridge/bridge-react/src/v18.ts +++ b/packages/bridge/bridge-react/src/v18.ts @@ -6,4 +6,5 @@ export type { RootType, DestroyParams, RenderParams, + RemoteAppSSRProps, } from './types'; diff --git a/packages/bridge/bridge-react/vite.config.ts b/packages/bridge/bridge-react/vite.config.ts index e703d5ea572..bbb8f7b4115 100644 --- a/packages/bridge/bridge-react/vite.config.ts +++ b/packages/bridge/bridge-react/vite.config.ts @@ -16,6 +16,7 @@ export default defineConfig({ 'router-v6': path.resolve(__dirname, 'src/router/v6.tsx'), 'router-v7': path.resolve(__dirname, 'src/router/v7.tsx'), v18: path.resolve(__dirname, 'src/v18.ts'), + 'v18.server': path.resolve(__dirname, 'src/v18.server.ts'), v19: path.resolve(__dirname, 'src/v19.ts'), 'lazy-load-component-plugin': path.resolve( __dirname, diff --git a/packages/bridge/bridge-shared/package.json b/packages/bridge/bridge-shared/package.json index bf7700751f2..aa7201c88a4 100644 --- a/packages/bridge/bridge-shared/package.json +++ b/packages/bridge/bridge-shared/package.json @@ -22,6 +22,7 @@ "scripts": { "dev": "vite", "build": "vite build && tsc -p tsconfig.json", + "test": "vitest run", "preview": "vite preview" }, "devDependencies": { @@ -31,6 +32,7 @@ "@vitejs/plugin-vue-jsx": "^4.0.0", "typescript": "7.0.2", "vite": "^5.4.21", + "vitest": "1.6.0", "vue-tsc": "^2.0.6" } } diff --git a/packages/bridge/bridge-shared/src/index.ts b/packages/bridge/bridge-shared/src/index.ts index 825eade3082..4c4886467f5 100644 --- a/packages/bridge/bridge-shared/src/index.ts +++ b/packages/bridge/bridge-shared/src/index.ts @@ -1,2 +1,26 @@ export type { RenderFnParams, ProviderParams } from './type'; +export { BRIDGE_SSR_PROTOCOL_VERSION, BridgeSSRError } from './type'; +export type { + BridgeJSONValue, + BridgeProviderAPI, + BridgeServerRenderContext, + BridgeSSRConfig, + BridgeSSRPrepareResult, + BridgeSSRResult, +} from './type'; export { dispatchPopstateEnv } from './env'; +export { + MF_BRIDGE_INSTANCE_ATTR, + MF_BRIDGE_MODULE_ATTR, + MF_BRIDGE_SSR_ATTR, + MF_BRIDGE_VERSION_ATTR, + assertBridgeJSONValue, + assertBridgeSSRIdentity, + assertBridgeSSRResult, + getBridgeSSRContainerAttrs, + hasBridgeSSRMarkup, + serializeBridgeJSON, + serializeBridgeSSRResult, +} from './ssr'; +export { renderRemoteBridge } from './renderRemoteBridge'; +export type { RenderRemoteBridgeOptions } from './renderRemoteBridge'; diff --git a/packages/bridge/bridge-shared/src/renderRemoteBridge.ts b/packages/bridge/bridge-shared/src/renderRemoteBridge.ts new file mode 100644 index 00000000000..556ad8ba6b8 --- /dev/null +++ b/packages/bridge/bridge-shared/src/renderRemoteBridge.ts @@ -0,0 +1,92 @@ +import { assertBridgeSSRIdentity, assertBridgeSSRResult } from './ssr'; +import { + BridgeSSRError, + type BridgeServerRenderContext, + type BridgeSSRResult, +} from './type'; + +export type RenderRemoteBridgeOptions

    > = { + loader: () => Promise>; + export?: string; + moduleName: string; + instanceId: string; + request: Request; + props?: P; +}; + +export async function renderRemoteBridge

    >( + options: RenderRemoteBridgeOptions

    , +): Promise { + if (typeof window !== 'undefined' || typeof document !== 'undefined') { + throw new BridgeSSRError( + 'renderRemoteBridge can only be called in a server environment', + ); + } + if (!(options.request instanceof Request)) { + throw new BridgeSSRError('Bridge SSR requires a standard Request'); + } + assertBridgeSSRIdentity(options); + if (options.request.signal.aborted) { + throw new BridgeSSRError( + `Bridge SSR request for ${options.moduleName} was aborted`, + options.request.signal.reason, + ); + } + + let remoteModule: Record; + try { + remoteModule = await options.loader(); + } catch (error) { + throw new BridgeSSRError( + `Unable to load Bridge remote ${options.moduleName}`, + error, + ); + } + + const exportName = options.export ?? 'default'; + const factory = remoteModule[exportName]; + if (typeof factory !== 'function') { + throw new BridgeSSRError( + `Bridge remote ${options.moduleName} does not export ${exportName}`, + ); + } + + const provider = factory() as { + renderServer?: ( + context: BridgeServerRenderContext

    , + ) => Promise; + }; + if (typeof provider?.renderServer !== 'function') { + throw new BridgeSSRError( + `Bridge remote ${options.moduleName} does not support server rendering`, + ); + } + + let result: BridgeSSRResult; + try { + result = await provider.renderServer({ + moduleName: options.moduleName, + instanceId: options.instanceId, + request: options.request, + signal: options.request.signal, + props: (options.props ?? {}) as P, + }); + } catch (error) { + if (error instanceof BridgeSSRError) throw error; + throw new BridgeSSRError( + `Unable to render Bridge remote ${options.moduleName}`, + error, + ); + } + + assertBridgeSSRResult(result); + if ( + result.moduleName !== options.moduleName || + result.instanceId !== options.instanceId + ) { + throw new BridgeSSRError( + `Bridge remote ${options.moduleName} returned mismatched identity`, + ); + } + return result; +} diff --git a/packages/bridge/bridge-shared/src/ssr.spec.ts b/packages/bridge/bridge-shared/src/ssr.spec.ts new file mode 100644 index 00000000000..4fa61a16d83 --- /dev/null +++ b/packages/bridge/bridge-shared/src/ssr.spec.ts @@ -0,0 +1,75 @@ +import { describe, expect, it, vi } from 'vitest'; +import { + BRIDGE_SSR_PROTOCOL_VERSION, + BridgeSSRError, + assertBridgeJSONValue, + renderRemoteBridge, + serializeBridgeJSON, +} from './index'; + +describe('Bridge SSR V1 contract', () => { + it('escapes executable sequences in host-carried JSON', () => { + expect(serializeBridgeJSON({ value: '\u2028\u2029' })).toBe( + '{"value":"\\u003c/script>\\u2028\\u2029"}', + ); + }); + + it('rejects cyclic and non-JSON state', () => { + const cyclic: Record = {}; + cyclic.self = cyclic; + expect(() => assertBridgeJSONValue(cyclic)).toThrow(/cyclic/); + expect(() => assertBridgeJSONValue({ value: Number.NaN })).toThrow( + /finite/, + ); + }); + + it('loads, renders, and validates a remote provider', async () => { + const renderServer = vi.fn(async (context) => ({ + protocolVersion: BRIDGE_SSR_PROTOCOL_VERSION, + moduleName: context.moduleName, + instanceId: context.instanceId, + html: '

    remote

    ', + dehydratedState: { ready: true }, + })); + const request = new Request('http://bridge.test/detail'); + await expect( + renderRemoteBridge({ + loader: async () => ({ default: () => ({ renderServer }) }), + moduleName: 'remote/app', + instanceId: 'remote-1', + request, + props: { intentional: true }, + }), + ).resolves.toMatchObject({ html: '

    remote

    ' }); + expect(renderServer).toHaveBeenCalledWith( + expect.objectContaining({ request, signal: request.signal }), + ); + }); + + it('adds context to load and contract failures', async () => { + await expect( + renderRemoteBridge({ + loader: async () => { + throw new Error('network'); + }, + moduleName: 'remote/app', + instanceId: 'remote-1', + request: new Request('http://bridge.test/'), + }), + ).rejects.toEqual( + expect.objectContaining({ + name: 'BridgeSSRError', + message: 'Unable to load Bridge remote remote/app', + }), + ); + + await expect( + renderRemoteBridge({ + loader: async () => ({ default: () => ({}) }), + moduleName: 'remote/app', + instanceId: 'remote-1', + request: new Request('http://bridge.test/'), + }), + ).rejects.toBeInstanceOf(BridgeSSRError); + }); +}); diff --git a/packages/bridge/bridge-shared/src/ssr.ts b/packages/bridge/bridge-shared/src/ssr.ts new file mode 100644 index 00000000000..e295ae62b1e --- /dev/null +++ b/packages/bridge/bridge-shared/src/ssr.ts @@ -0,0 +1,175 @@ +import { + BRIDGE_SSR_PROTOCOL_VERSION, + BridgeSSRError, + type BridgeJSONValue, + type BridgeSSRResult, +} from './type'; + +export const MF_BRIDGE_SSR_ATTR = 'data-mf-bridge-ssr'; +export const MF_BRIDGE_VERSION_ATTR = 'data-mf-bridge-version'; +export const MF_BRIDGE_MODULE_ATTR = 'data-mf-bridge-module'; +export const MF_BRIDGE_INSTANCE_ATTR = 'data-mf-bridge-instance'; + +function assertPrintable(value: string, label: string) { + if (!value || /[\u0000-\u001f\u007f]/.test(value)) { + throw new BridgeSSRError( + `Bridge SSR ${label} must be a non-empty printable string`, + ); + } +} + +export function assertBridgeSSRIdentity(value: { + moduleName: string; + instanceId: string; +}) { + assertPrintable(value.moduleName, 'moduleName'); + assertPrintable(value.instanceId, 'instanceId'); +} + +function validateJSON( + value: unknown, + path: string, + ancestors: WeakSet, +): void { + if ( + value === null || + typeof value === 'string' || + typeof value === 'boolean' + ) { + return; + } + if (typeof value === 'number') { + if (Number.isFinite(value)) return; + throw new BridgeSSRError(`Bridge SSR value at ${path} must be finite`); + } + if (typeof value !== 'object' || value === undefined) { + throw new BridgeSSRError( + `Bridge SSR value at ${path} must be JSON serializable`, + ); + } + if (ancestors.has(value)) { + throw new BridgeSSRError(`Bridge SSR value at ${path} must not be cyclic`); + } + ancestors.add(value); + if (Array.isArray(value)) { + for (let index = 0; index < value.length; index += 1) { + if (!Object.prototype.hasOwnProperty.call(value, index)) { + throw new BridgeSSRError( + `Bridge SSR array at ${path} must not be sparse`, + ); + } + validateJSON(value[index], `${path}[${index}]`, ancestors); + } + } else { + const prototype = Object.getPrototypeOf(value); + if (prototype !== Object.prototype && prototype !== null) { + throw new BridgeSSRError( + `Bridge SSR value at ${path} must use plain objects`, + ); + } + for (const [key, descriptor] of Object.entries( + Object.getOwnPropertyDescriptors(value), + )) { + if ( + !descriptor.enumerable || + !Object.prototype.hasOwnProperty.call(descriptor, 'value') + ) { + throw new BridgeSSRError( + `Bridge SSR value at ${path}.${key} must be an enumerable data property`, + ); + } + validateJSON(descriptor.value, `${path}.${key}`, ancestors); + } + if (Object.getOwnPropertySymbols(value).length > 0) { + throw new BridgeSSRError( + `Bridge SSR value at ${path} must not contain symbol keys`, + ); + } + } + ancestors.delete(value); +} + +export function assertBridgeJSONValue( + value: unknown, +): asserts value is BridgeJSONValue { + validateJSON(value, 'state', new WeakSet()); +} + +export function serializeBridgeJSON(value: BridgeJSONValue): string { + assertBridgeJSONValue(value); + return JSON.stringify(value) + .replace(/; + const allowedKeys = new Set([ + 'protocolVersion', + 'moduleName', + 'instanceId', + 'html', + 'dehydratedState', + ]); + if (Object.keys(result).some((key) => !allowedKeys.has(key))) { + throw new BridgeSSRError('Bridge SSR returned unsupported result fields'); + } + if ( + result.protocolVersion !== BRIDGE_SSR_PROTOCOL_VERSION || + typeof result.moduleName !== 'string' || + typeof result.instanceId !== 'string' || + typeof result.html !== 'string' + ) { + throw new BridgeSSRError('Bridge SSR returned an incompatible result'); + } + assertBridgeSSRIdentity({ + moduleName: result.moduleName, + instanceId: result.instanceId, + }); + if (result.dehydratedState !== undefined) { + assertBridgeJSONValue(result.dehydratedState); + } +} + +export function getBridgeSSRContainerAttrs(value: { + moduleName: string; + instanceId: string; +}): Record { + assertBridgeSSRIdentity(value); + return { + [MF_BRIDGE_SSR_ATTR]: 'true', + [MF_BRIDGE_VERSION_ATTR]: String(BRIDGE_SSR_PROTOCOL_VERSION), + [MF_BRIDGE_MODULE_ATTR]: value.moduleName, + [MF_BRIDGE_INSTANCE_ATTR]: value.instanceId, + }; +} + +export function hasBridgeSSRMarkup( + dom: HTMLElement, + value?: { moduleName?: string; instanceId?: string }, +) { + return ( + dom.getAttribute(MF_BRIDGE_SSR_ATTR) === 'true' && + dom.getAttribute(MF_BRIDGE_VERSION_ATTR) === + String(BRIDGE_SSR_PROTOCOL_VERSION) && + (!value?.moduleName || + dom.getAttribute(MF_BRIDGE_MODULE_ATTR) === value.moduleName) && + (!value?.instanceId || + dom.getAttribute(MF_BRIDGE_INSTANCE_ATTR) === value.instanceId) && + dom.hasChildNodes() + ); +} diff --git a/packages/bridge/bridge-shared/src/type.ts b/packages/bridge/bridge-shared/src/type.ts index e788d81a6ac..29bfe5af306 100644 --- a/packages/bridge/bridge-shared/src/type.ts +++ b/packages/bridge/bridge-shared/src/type.ts @@ -1,5 +1,60 @@ import type { CSSProperties } from 'react'; +export const BRIDGE_SSR_PROTOCOL_VERSION = 1 as const; + +export type BridgeJSONValue = + | null + | boolean + | number + | string + | BridgeJSONValue[] + | { [key: string]: BridgeJSONValue }; + +export type BridgeSSRPrepareResult

    > = { + props?: P; + dehydratedState?: BridgeJSONValue; +}; + +export type BridgeSSRConfig

    > = + | boolean + | { + prepare?: ( + context: BridgeServerRenderContext

    , + ) => + | void + | BridgeSSRPrepareResult

    + | Promise>; + hydrate?: ( + state: BridgeJSONValue | undefined, + ) => Partial

    | Record; + }; + +export type BridgeServerRenderContext

    > = { + moduleName: string; + instanceId: string; + request: Request; + signal: AbortSignal; + props: P; +}; + +export type BridgeSSRResult = { + protocolVersion: typeof BRIDGE_SSR_PROTOCOL_VERSION; + moduleName: string; + instanceId: string; + html: string; + dehydratedState?: BridgeJSONValue; +}; + +export class BridgeSSRError extends Error { + override readonly cause?: unknown; + + constructor(message: string, cause?: unknown) { + super(message); + this.name = 'BridgeSSRError'; + this.cause = cause; + } +} + export interface ProviderParams { moduleName?: string; basename?: string; @@ -11,4 +66,15 @@ export interface ProviderParams { export interface RenderFnParams extends ProviderParams { dom: HTMLElement; + instanceId?: string; + ssrState?: BridgeJSONValue; + signal?: AbortSignal; +} + +export interface BridgeProviderAPI { + render: (info: RenderFnParams) => void | Promise; + destroy: (info: { dom: HTMLElement }) => void; + renderServer?: ( + context: BridgeServerRenderContext, + ) => Promise; } diff --git a/packages/bridge/vue3-bridge/package.json b/packages/bridge/vue3-bridge/package.json index 8bd03c00161..60e3ed10737 100644 --- a/packages/bridge/vue3-bridge/package.json +++ b/packages/bridge/vue3-bridge/package.json @@ -15,6 +15,22 @@ "main": "./dist/index.cjs", "module": "./dist/index.js", "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "browser": { + "import": "./dist/index.js", + "require": "./dist/index.cjs" + }, + "node": { + "import": "./dist/index.server.js", + "require": "./dist/index.server.cjs" + }, + "import": "./dist/index.js", + "require": "./dist/index.cjs" + }, + "./*": "./*" + }, "files": [ "dist/", "package.json", @@ -28,7 +44,13 @@ }, "peerDependencies": { "vue": "=3", - "vue-router": "=4" + "vue-router": "=4", + "@vue/server-renderer": "^3.0.0" + }, + "peerDependenciesMeta": { + "@vue/server-renderer": { + "optional": true + } }, "dependencies": { "@module-federation/bridge-shared": "workspace:*", @@ -45,6 +67,7 @@ "vite": "^5.4.21", "vue": "^3.5.30", "vue-router": "4.4.5", + "@vue/server-renderer": "^3.5.30", "vue-tsc": "^2.2.12" } } diff --git a/packages/bridge/vue3-bridge/rstest.config.ts b/packages/bridge/vue3-bridge/rstest.config.ts index c24e78e6123..5d1bb8841bb 100644 --- a/packages/bridge/vue3-bridge/rstest.config.ts +++ b/packages/bridge/vue3-bridge/rstest.config.ts @@ -4,6 +4,11 @@ import { pluginVueJsx } from '@rsbuild/plugin-vue-jsx'; import { resolve } from 'path'; export default defineConfig({ + source: { + define: { + __APP_VERSION__: '"unknown"', + }, + }, plugins: [ pluginBabel({ include: /\.(?:jsx|tsx)$/, diff --git a/packages/bridge/vue3-bridge/src/index.server.ts b/packages/bridge/vue3-bridge/src/index.server.ts new file mode 100644 index 00000000000..a260a91227a --- /dev/null +++ b/packages/bridge/vue3-bridge/src/index.server.ts @@ -0,0 +1,16 @@ +import { + createBridgeComponentWithServerRenderer, + type ProviderFnParams, +} from './provider'; +import { renderBridgeVueToString } from './server-renderer'; + +export function createBridgeComponent(bridgeInfo: ProviderFnParams) { + return createBridgeComponentWithServerRenderer( + bridgeInfo, + renderBridgeVueToString, + ); +} + +export type { ProviderFnParams } from './provider'; +export { createRemoteComponent, createRemoteAppComponent } from './create'; +export type { RenderFnParams } from '@module-federation/bridge-shared'; diff --git a/packages/bridge/vue3-bridge/src/provider.spec.ts b/packages/bridge/vue3-bridge/src/provider.spec.ts new file mode 100644 index 00000000000..9e34fec2006 --- /dev/null +++ b/packages/bridge/vue3-bridge/src/provider.spec.ts @@ -0,0 +1,46 @@ +import { describe, expect, it, rs } from '@rstest/core'; +import { defineComponent, h } from 'vue'; +import { createMemoryHistory, createRouter } from 'vue-router'; +import { createBridgeComponentWithServerRenderer } from './provider'; + +describe('Vue Bridge server provider', () => { + it('creates a request-local app and returns the thin V1 result', async () => { + const serverRenderer = rs.fn(async () => '

    vue remote

    '); + const factory = createBridgeComponentWithServerRenderer( + { + rootComponent: defineComponent(() => () => h('p', 'vue remote')), + appOptions: () => ({ + router: createRouter({ + history: createMemoryHistory(), + routes: [ + { + path: '/detail', + component: defineComponent(() => () => h('p')), + }, + ], + }), + }), + ssr: true, + }, + serverRenderer, + ); + const provider = factory(); + const request = new Request('http://bridge.test/detail'); + await expect( + provider.renderServer!({ + moduleName: 'vue/remote', + instanceId: 'vue-1', + request, + signal: request.signal, + props: {}, + }), + ).resolves.toEqual({ + protocolVersion: 1, + moduleName: 'vue/remote', + instanceId: 'vue-1', + html: '

    vue remote

    ', + dehydratedState: undefined, + }); + expect(serverRenderer).toHaveBeenCalledOnce(); + }); +}); diff --git a/packages/bridge/vue3-bridge/src/provider.ts b/packages/bridge/vue3-bridge/src/provider.ts index 6b3e66eee41..0c2e6723aad 100644 --- a/packages/bridge/vue3-bridge/src/provider.ts +++ b/packages/bridge/vue3-bridge/src/provider.ts @@ -1,6 +1,14 @@ import * as Vue from 'vue'; import * as VueRouter from 'vue-router'; -import { RenderFnParams } from '@module-federation/bridge-shared'; +import { + BRIDGE_SSR_PROTOCOL_VERSION, + hasBridgeSSRMarkup, + type BridgeSSRConfig, + type BridgeSSRPrepareResult, + type BridgeSSRResult, + type BridgeServerRenderContext, + type RenderFnParams, +} from '@module-federation/bridge-shared'; import { LoggerInstance } from './utils'; import { getInstance } from '@module-federation/runtime'; import { processRoutes } from './routeUtils'; @@ -11,6 +19,9 @@ type AddOptionsFnParams = { app: Vue.App; basename: RenderFnParams['basename']; memoryRoute: RenderFnParams['memoryRoute']; + request?: Request; + signal?: AbortSignal; + ssr: boolean; [key: string]: any; }; @@ -18,95 +29,193 @@ export type ProviderFnParams = { rootComponent: Vue.Component; appOptions: (params: AddOptionsFnParams) => { router?: VueRouter.Router; - /** Called with the bridge's internal router after creation but before navigation. - * Use this to register global guards (beforeEach, afterEach, etc.) that would - * otherwise be lost when the bridge recreates the router. */ afterRouterCreate?: (router: VueRouter.Router) => void; } | void; + ssr?: BridgeSSRConfig>; }; -export function createBridgeComponent(bridgeInfo: ProviderFnParams) { - const rootMap = new Map(); - const instance = getInstance(); +export type BridgeVueServerRenderer = ( + app: Vue.App, + context: Record, +) => string | Promise; + +type BridgeAppInfo = Omit & { + dom?: HTMLElement; + request?: Request; + url?: string; +}; + +async function setupBridgeApp( + bridgeInfo: ProviderFnParams, + info: BridgeAppInfo, + props: Record, + mode: 'ssr' | 'hydrate' | 'csr', +) { + if (info.signal?.aborted) throw info.signal.reason; + const app = (mode === 'csr' ? Vue.createApp : Vue.createSSRApp)( + bridgeInfo.rootComponent, + props, + ); + const options = bridgeInfo.appOptions({ + ...props, + app, + basename: info.basename, + memoryRoute: info.memoryRoute, + hashRoute: info.hashRoute, + request: info.request, + signal: info.signal, + ssr: mode === 'ssr', + }); + let router: VueRouter.Router | undefined; + if (options?.router) { + const effectiveMemoryRoute = + mode === 'ssr' ? { entryPath: info.url ?? '/' } : info.memoryRoute; + const processed = processRoutes({ + router: options.router, + basename: info.basename, + memoryRoute: effectiveMemoryRoute, + hashRoute: info.hashRoute, + }); + router = VueRouter.createRouter({ + ...options.router.options, + history: processed.history, + routes: processed.routes, + }); + processed.patchRouter?.(router); + options.afterRouterCreate?.(router); + if (effectiveMemoryRoute) { + await router.push(effectiveMemoryRoute.entryPath); + } + app.use(router); + if (mode !== 'csr') await router.isReady(); + } + if (info.signal?.aborted) throw info.signal.reason; + return { app, router }; +} + +function serverLocation(request: Request, basename?: string) { + const url = new URL(request.url); + let pathname = url.pathname || '/'; + const base = (basename || '/').replace(/\/$/, '') || '/'; + if (base !== '/' && (pathname === base || pathname.startsWith(`${base}/`))) { + pathname = pathname.slice(base.length) || '/'; + } + return `${pathname}${url.search}`; +} + +export function createBridgeComponentWithServerRenderer( + bridgeInfo: ProviderFnParams, + serverRenderer?: BridgeVueServerRenderer, +) { + const roots = new Map(); + const runtime = getInstance(); + return () => { - return { + const config = + typeof bridgeInfo.ssr === 'object' ? bridgeInfo.ssr : undefined; + const provider: { + __APP_VERSION__: string; + render: (info: RenderFnParams) => Promise; + destroy: (info: { dom: HTMLElement }) => void; + renderServer?: ( + context: BridgeServerRenderContext>, + ) => Promise; + } = { __APP_VERSION__, - async render(info: RenderFnParams) { - LoggerInstance.debug(`createBridgeComponent render Info`, info); + async render(info) { + if (info.signal?.aborted) return; const { moduleName, dom, basename, memoryRoute, hashRoute, - ...propsInfo + instanceId, + ssrState, + signal, + ...applicationProps } = info; - const app = Vue.createApp(bridgeInfo.rootComponent, propsInfo); - rootMap.set(dom, app); - const beforeBridgeRenderRes = - await instance?.bridgeHook?.lifecycle?.beforeBridgeRender?.emit(info); - + await runtime?.bridgeHook?.lifecycle?.beforeBridgeRender?.emit(info); const extraProps = beforeBridgeRenderRes && typeof beforeBridgeRenderRes === 'object' && - beforeBridgeRenderRes?.extraProps - ? beforeBridgeRenderRes?.extraProps + beforeBridgeRenderRes.extraProps + ? beforeBridgeRenderRes.extraProps : {}; - - const bridgeOptions = bridgeInfo.appOptions({ - app, - basename, - memoryRoute, - hashRoute, - ...propsInfo, - ...extraProps, + const shouldHydrate = hasBridgeSSRMarkup(dom, { + moduleName, + instanceId, }); - if (bridgeOptions?.router) { - const { history, routes, patchRouter } = processRoutes({ - router: bridgeOptions.router, - basename: info.basename, - memoryRoute: info.memoryRoute, - hashRoute: info.hashRoute, - }); - - const router = VueRouter.createRouter({ - ...bridgeOptions.router.options, - history, - routes, - }); - - if (patchRouter) { - patchRouter(router); - } - - if (bridgeOptions.afterRouterCreate) { - bridgeOptions.afterRouterCreate(router); - } - - LoggerInstance.debug(`createBridgeComponent render router info>>>`, { - moduleName, - router, - }); - // memory route Initializes the route - if (memoryRoute) { - await router.push(memoryRoute.entryPath); - } - - app.use(router); - } - - app.mount(dom); - instance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit(info); + const hydrated = + shouldHydrate && config?.hydrate ? config.hydrate(ssrState) : {}; + const nextProps = { ...hydrated, ...applicationProps, ...extraProps }; + const { app } = await setupBridgeApp( + bridgeInfo, + { basename, memoryRoute, hashRoute, instanceId, signal }, + nextProps, + shouldHydrate ? 'hydrate' : 'csr', + ); + if (signal?.aborted) return; + roots.set(dom, app); + app.mount(dom, shouldHydrate); + runtime?.bridgeHook?.lifecycle?.afterBridgeRender?.emit(info); + LoggerInstance.debug('createBridgeComponent rendered', { moduleName }); }, - destroy(info: { dom: HTMLElement }) { - LoggerInstance.debug(`createBridgeComponent destroy Info`, info); - const root = rootMap.get(info?.dom); - - instance?.bridgeHook?.lifecycle?.beforeBridgeDestroy?.emit(info); - root?.unmount(); - instance?.bridgeHook?.lifecycle?.afterBridgeDestroy?.emit(info); + destroy({ dom }) { + const info = { dom }; + LoggerInstance.debug('createBridgeComponent destroy Info', info); + runtime?.bridgeHook?.lifecycle?.beforeBridgeDestroy?.emit(info); + roots.get(dom)?.unmount(); + roots.delete(dom); + runtime?.bridgeHook?.lifecycle?.afterBridgeDestroy?.emit(info); }, }; + + if (serverRenderer && bridgeInfo.ssr) { + provider.renderServer = async (context) => { + if (context.signal.aborted) throw context.signal.reason; + const preparedValue = await config?.prepare?.(context); + const prepared = (preparedValue || {}) as BridgeSSRPrepareResult< + Record + >; + const renderInfo = prepared.props ?? context.props; + const { basename, memoryRoute, hashRoute, ...applicationProps } = + renderInfo; + delete applicationProps.moduleName; + const { app } = await setupBridgeApp( + bridgeInfo, + { + moduleName: context.moduleName, + basename: basename as string | undefined, + memoryRoute: memoryRoute as RenderFnParams['memoryRoute'], + hashRoute: Boolean(hashRoute), + request: context.request, + signal: context.signal, + url: serverLocation( + context.request, + basename as string | undefined, + ), + }, + applicationProps, + 'ssr', + ); + const ssrContext: Record = {}; + const html = await serverRenderer(app, ssrContext); + if (context.signal.aborted) throw context.signal.reason; + return { + protocolVersion: BRIDGE_SSR_PROTOCOL_VERSION, + moduleName: context.moduleName, + instanceId: context.instanceId, + html, + dehydratedState: prepared.dehydratedState, + }; + }; + } + return provider; }; } + +export function createBridgeComponent(bridgeInfo: ProviderFnParams) { + return createBridgeComponentWithServerRenderer(bridgeInfo); +} diff --git a/packages/bridge/vue3-bridge/src/remoteApp.tsx b/packages/bridge/vue3-bridge/src/remoteApp.tsx index 3a04bb951f2..d32f5e4e947 100644 --- a/packages/bridge/vue3-bridge/src/remoteApp.tsx +++ b/packages/bridge/vue3-bridge/src/remoteApp.tsx @@ -9,7 +9,11 @@ import { useAttrs, nextTick, } from 'vue'; -import { dispatchPopstateEnv } from '@module-federation/bridge-shared'; +import { + dispatchPopstateEnv, + getBridgeSSRContainerAttrs, + type BridgeSSRResult, +} from '@module-federation/bridge-shared'; import { useRoute } from 'vue-router'; import { LoggerInstance } from './utils'; import { getInstance } from '@module-federation/runtime'; @@ -23,6 +27,8 @@ export default defineComponent({ hashRoute: Boolean, providerInfo: Function, rootAttrs: Object, + ssr: Object, + instanceId: String, }, inheritAttrs: false, setup(props) { @@ -35,6 +41,8 @@ export default defineComponent({ const route = useRoute(); const hostInstance = getInstance(); const componentAttrs = useAttrs(); + const ssrPayload = props.ssr as BridgeSSRResult | undefined; + const instanceId = props.instanceId || ssrPayload?.instanceId; const getBridgeRenderProps = () => ({ name: props.moduleName, @@ -58,6 +66,8 @@ export default defineComponent({ basename: props.basename, memoryRoute: props.memoryRoute, hashRoute: props.hashRoute, + instanceId, + ssrState: ssrPayload?.dehydratedState, }; LoggerInstance.debug( `createRemoteAppComponent LazyComponent render >>>`, @@ -149,6 +159,18 @@ export default defineComponent({ destroyComponent(); }); - return () =>
    ; + return () => ( +
    + ); }, }); diff --git a/packages/bridge/vue3-bridge/src/server-renderer.ts b/packages/bridge/vue3-bridge/src/server-renderer.ts new file mode 100644 index 00000000000..bf6d7415596 --- /dev/null +++ b/packages/bridge/vue3-bridge/src/server-renderer.ts @@ -0,0 +1,7 @@ +import { renderToString } from '@vue/server-renderer'; +import type { BridgeVueServerRenderer } from './provider'; + +export const renderBridgeVueToString: BridgeVueServerRenderer = ( + app, + context, +) => renderToString(app, context); diff --git a/packages/bridge/vue3-bridge/vite.config.ts b/packages/bridge/vue3-bridge/vite.config.ts index 1edf7166783..f5bfe76d640 100644 --- a/packages/bridge/vue3-bridge/vite.config.ts +++ b/packages/bridge/vue3-bridge/vite.config.ts @@ -8,12 +8,22 @@ export default defineConfig({ plugins: [vue(), vueJsx()], build: { lib: { - entry: path.resolve(__dirname, 'src/index.ts'), + entry: { + index: path.resolve(__dirname, 'src/index.ts'), + 'index.server': path.resolve(__dirname, 'src/index.server.ts'), + }, formats: ['cjs', 'es'], - fileName: 'index', + fileName: (format, entryName) => + entryName === 'index' + ? format === 'es' + ? 'index.js' + : 'index.cjs' + : format === 'es' + ? `${entryName}.js` + : `${entryName}.cjs`, }, rollupOptions: { - external: ['vue', 'vue-router'], + external: ['vue', 'vue-router', '@vue/server-renderer'], }, }, define: { diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 52cec333b83..b0ec56f2911 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -12,6 +12,7 @@ packages: - 'apps/manifest-demo/*' - 'apps/esbuild' - 'apps/*' + - 'apps/bridge-ssr-demo/*' - 'webpack' - 'assemble-release-plan' - 'packages/runtime-plugins/*' diff --git a/tools/scripts/ci-local.mjs b/tools/scripts/ci-local.mjs index cd35d74bcff..d6ab4f3e56a 100644 --- a/tools/scripts/ci-local.mjs +++ b/tools/scripts/ci-local.mjs @@ -332,6 +332,27 @@ const jobs = [ ), ], }, + { + name: 'e2e-bridge-ssr', + env: SKIP_DEVTOOLS_POSTINSTALL_ENV, + steps: [ + installDependenciesStep(), + step('Build packages', (ctx) => runPackagesBuild(ctx)), + step('Bridge SSR development acceptance', (ctx) => + runCommand('pnpm', ['run', 'e2e:bridge:ssr'], ctx), + ), + step('Bridge SSR production acceptance', (ctx) => + runCommand('pnpm', ['run', 'e2e:bridge:ssr:production'], ctx), + ), + step('Bridge SSR Vite smoke (non-blocking)', async (ctx) => { + try { + await runCommand('pnpm', ['run', 'e2e:bridge:ssr:vite-smoke'], ctx); + } catch (error) { + console.warn('[ci:local] Non-blocking Vite smoke failed:', error); + } + }), + ], + }, { name: 'metro-affected-check', env: METRO_E2E_ENV, diff --git a/tools/scripts/run-bridge-ssr-e2e.mjs b/tools/scripts/run-bridge-ssr-e2e.mjs new file mode 100644 index 00000000000..479bd350c50 --- /dev/null +++ b/tools/scripts/run-bridge-ssr-e2e.mjs @@ -0,0 +1,212 @@ +#!/usr/bin/env node +import { spawn } from 'node:child_process'; +import { + DETACHED_PROCESS_GROUP, + shutdownServe, + spawnWithPromise, +} from './e2e-process-utils.mjs'; + +const viteSmoke = process.env.BRIDGE_SSR_REMOTE_BUNDLER === 'vite'; +const production = process.env.BRIDGE_SSR_MODE === 'production' || viteSmoke; +let stopping = false; + +function startOwned(label, command, args, env) { + const child = spawn(command, args, { + stdio: 'inherit', + detached: true, + env: { ...process.env, ...env }, + }); + child[DETACHED_PROCESS_GROUP] = true; + const exit = new Promise((resolve, reject) => { + child.once('exit', (code, signal) => { + if (stopping) resolve({ code, signal }); + else + reject(new Error(`${label} exited unexpectedly (${signal ?? code})`)); + }); + child.once('error', reject); + }); + return { child, exit }; +} + +async function run(command, args, env) { + await spawnWithPromise(command, args, { + env: { ...process.env, ...env }, + }).promise; +} + +async function build(env) { + if (viteSmoke) { + await run( + 'pnpm', + ['--filter', 'bridge-ssr-remote-vue', 'run', 'build:vite'], + env, + ); + await run( + 'pnpm', + [ + 'exec', + 'turbo', + 'run', + 'build', + '--filter=bridge-ssr-host', + '--force', + '--env-mode=loose', + ], + env, + ); + } else { + await run( + 'pnpm', + [ + 'exec', + 'turbo', + 'run', + 'build', + '--filter=bridge-ssr-host', + '--filter=bridge-ssr-host-vue', + '--filter=bridge-ssr-remote-react', + '--filter=bridge-ssr-remote-vue', + ], + env, + ); + } + await run( + process.execPath, + ['tools/scripts/verify-bridge-ssr-browser-bundles.mjs'], + env, + ); +} + +async function main() { + const env = { + HOST: process.env.HOST ?? 'localhost', + BRIDGE_SSR_REMOTE_BUNDLER: viteSmoke ? 'vite' : 'rsbuild', + ...(production ? { BRIDGE_SSR_MODE: 'production' } : {}), + }; + if (production) await build(env); + + const apps = []; + if (viteSmoke) { + apps.push( + startOwned( + 'Vue Vite remote', + process.execPath, + [ + 'apps/bridge-ssr-demo/shared/serveDist.mjs', + 'apps/bridge-ssr-demo/remote-vue/dist-vite', + '2402', + ], + env, + ), + startOwned( + 'React production host', + 'pnpm', + ['--filter', 'bridge-ssr-host', 'run', 'serve:production'], + env, + ), + ); + } else if (production) { + for (const [framework, port] of [ + ['react', '2301'], + ['vue', '2302'], + ]) { + apps.push( + startOwned( + `${framework} remote`, + process.execPath, + [ + 'apps/bridge-ssr-demo/shared/serveDist.mjs', + `apps/bridge-ssr-demo/remote-${framework}/dist`, + port, + ], + env, + ), + ); + } + apps.push( + startOwned( + 'React production host', + 'pnpm', + ['--filter', 'bridge-ssr-host', 'run', 'serve:production'], + env, + ), + startOwned( + 'Vue production host', + 'pnpm', + ['--filter', 'bridge-ssr-host-vue', 'run', 'serve:production'], + env, + ), + ); + } else { + apps.push( + startOwned( + 'React remote', + 'pnpm', + ['--filter', 'bridge-ssr-remote-react', 'run', 'dev'], + env, + ), + startOwned( + 'Vue remote', + 'pnpm', + ['--filter', 'bridge-ssr-remote-vue', 'run', 'dev'], + env, + ), + startOwned( + 'React host', + 'pnpm', + ['--filter', 'bridge-ssr-host', 'run', 'dev'], + env, + ), + startOwned( + 'Vue host', + 'pnpm', + ['--filter', 'bridge-ssr-host-vue', 'run', 'dev'], + env, + ), + ); + } + + try { + const ports = viteSmoke + ? ['tcp:2300', 'tcp:2402'] + : ['tcp:2300', 'tcp:2301', 'tcp:2302', 'tcp:2303']; + await Promise.race([ + spawnWithPromise('npx', ['wait-on', '--timeout=240000', ...ports]) + .promise, + Promise.race(apps.map((app) => app.exit)), + ]); + await Promise.race([ + run('pnpm', ['--filter', 'bridge-ssr-host', 'run', 'e2e:ssr:ci'], env), + Promise.race(apps.map((app) => app.exit)), + ]); + if (!viteSmoke) { + await Promise.race([ + run( + 'pnpm', + ['--filter', 'bridge-ssr-host-vue', 'run', 'e2e:ssr:ci'], + env, + ), + Promise.race(apps.map((app) => app.exit)), + ]); + } + } finally { + stopping = true; + await Promise.allSettled( + apps.map(({ child, exit }) => shutdownServe(child, exit)), + ); + } +} + +process.on('uncaughtException', (error) => { + console.error('[bridge-ssr-e2e] uncaught exception', error); + process.exitCode = 1; +}); +process.on('unhandledRejection', (error) => { + console.error('[bridge-ssr-e2e] unhandled rejection', error); + process.exitCode = 1; +}); + +main().catch((error) => { + console.error('[bridge-ssr-e2e] failed', error); + process.exitCode = 1; +}); diff --git a/tools/scripts/verify-bridge-ssr-browser-bundles.mjs b/tools/scripts/verify-bridge-ssr-browser-bundles.mjs new file mode 100644 index 00000000000..cd960b67689 --- /dev/null +++ b/tools/scripts/verify-bridge-ssr-browser-bundles.mjs @@ -0,0 +1,49 @@ +#!/usr/bin/env node +import { readFile, readdir, stat } from 'node:fs/promises'; +import path from 'node:path'; + +const roots = + process.env.BRIDGE_SSR_REMOTE_BUNDLER === 'vite' + ? [ + 'apps/bridge-ssr-demo/remote-vue/dist-vite/assets', + 'apps/bridge-ssr-demo/remote-vue/dist-vite/remoteEntry.js', + ] + : [ + 'apps/bridge-ssr-demo/remote-react/dist/static', + 'apps/bridge-ssr-demo/remote-vue/dist/static', + ]; +const forbidden = [ + 'react-dom/server', + '@vue/server-renderer', + 'export-app.server', +]; + +async function files(directory) { + if ((await stat(directory)).isFile()) return [directory]; + const entries = await readdir(directory, { withFileTypes: true }); + return ( + await Promise.all( + entries.map((entry) => { + const target = path.join(directory, entry.name); + return entry.isDirectory() ? files(target) : [target]; + }), + ) + ).flat(); +} + +for (const root of roots) { + for (const file of await files(root)) { + if (!/\.(?:js|mjs|cjs)$/.test(file)) continue; + const source = await readFile(file, 'utf8'); + for (const token of forbidden) { + if (source.includes(token)) { + throw new Error( + `Browser bundle ${file} contains server-only token ${token}`, + ); + } + } + } +} +console.log( + '[bridge-ssr] browser bundles exclude server-only renderers and preparation', +); From 6bc00870a7ae56748180841de492ba989b5743fb Mon Sep 17 00:00:00 2001 From: Kevin Beier Date: Sat, 18 Jul 2026 15:53:53 +0200 Subject: [PATCH 18/32] fix(bridge): harden SSR hydration boundaries --- apps/website-new/docs/en/guide/bridge/ssr.mdx | 2 + packages/bridge/bridge-react/README.md | 15 +++++ .../bridge-react/__tests__/router.spec.tsx | 12 ++++ .../src/remote/RemoteAppWrapper.spec.tsx | 56 +++++++++++++++++++ .../src/remote/RemoteAppWrapper.tsx | 17 ++++-- .../bridge-react/src/router/default.tsx | 12 ++++ .../bridge-react/src/router/v6.spec.tsx | 17 ++++++ .../bridge/bridge-react/src/router/v6.tsx | 6 ++ packages/bridge/bridge-shared/src/index.ts | 1 + packages/bridge/bridge-shared/src/ssr.spec.ts | 26 +++++++++ packages/bridge/bridge-shared/src/ssr.ts | 17 ++++++ .../vue3-bridge/__tests__/remoteApp.test.ts | 1 + .../bridge/vue3-bridge/src/provider.spec.ts | 32 +++++++++++ packages/bridge/vue3-bridge/src/provider.ts | 7 ++- packages/bridge/vue3-bridge/src/remoteApp.tsx | 6 +- 15 files changed, 220 insertions(+), 7 deletions(-) create mode 100644 packages/bridge/bridge-react/src/remote/RemoteAppWrapper.spec.tsx create mode 100644 packages/bridge/bridge-react/src/router/v6.spec.tsx diff --git a/apps/website-new/docs/en/guide/bridge/ssr.mdx b/apps/website-new/docs/en/guide/bridge/ssr.mdx index bc78c0d62c0..1d47481ded9 100644 --- a/apps/website-new/docs/en/guide/bridge/ssr.mdx +++ b/apps/website-new/docs/en/guide/bridge/ssr.mdx @@ -11,6 +11,8 @@ Bridge SSR V1 lets a federated application provider return a buffered HTML islan React data routers and other React or Router versions keep their existing client-rendering support but are not supported for SSR in V1. +React Router v6 remotes must alias `react-router-dom$` to `@module-federation/bridge-react/dist/router-v6.es.js` in both their browser and Node builds. The default `router.es.js` adapter is CSR-only. Attempting to use the default adapter or `RouterProvider` during SSR throws a configuration error. + ## Remote provider Set `ssr: true` when no request preparation is needed. If preparation is required, map the same federated export key to separate browser and Node source files. The browser file supplies `hydrate`; the Node file supplies `prepare`. This keeps server renderers and request-only code out of browser chunks. diff --git a/packages/bridge/bridge-react/README.md b/packages/bridge/bridge-react/README.md index ee86f2bddea..b1cf3c2d80e 100644 --- a/packages/bridge/bridge-react/README.md +++ b/packages/bridge/bridge-react/README.md @@ -74,6 +74,21 @@ export default defineConfig({ }); ``` +For Bridge SSR V1 with declarative React Router v6, both the browser and Node +builds must alias `react-router-dom$` to the version-specific adapter instead: + +```js +alias: { + 'react-router-dom$': path.resolve( + __dirname, + 'node_modules/@module-federation/bridge-react/dist/router-v6.es.js', + ), +} +``` + +The default `router.es.js` adapter remains the multi-version CSR adapter. React +data routers and `RouterProvider` are not supported for Bridge SSR V1. + # 3. Load the module with routing ```js diff --git a/packages/bridge/bridge-react/__tests__/router.spec.tsx b/packages/bridge/bridge-react/__tests__/router.spec.tsx index 3892a863965..95f1cbfd0f0 100644 --- a/packages/bridge/bridge-react/__tests__/router.spec.tsx +++ b/packages/bridge/bridge-react/__tests__/router.spec.tsx @@ -13,6 +13,18 @@ import { RouterContext } from '../src/provider/context'; import { getHtml, getWindowImpl } from './util'; describe('react router proxy', () => { + it('fails clearly when the generic router adapter is used for SSR', () => { + expect(() => + render( + + +
    + + , + ), + ).toThrow(/router-v6 alias/); + }); + it('BrowserRouter not wraper context', async () => { let { container } = render( diff --git a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.spec.tsx b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.spec.tsx new file mode 100644 index 00000000000..c4928f35b7d --- /dev/null +++ b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.spec.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import { renderToStaticMarkup } from 'react-dom/server'; +import { describe, expect, it } from '@rstest/core'; +import { RemoteAppWrapper } from './RemoteAppWrapper'; + +const baseProps = { + moduleName: 'remote/app', + providerInfo: () => ({ render() {}, destroy() {} }), + exportName: 'default', + fallback: () => null, + loading: null, +}; + +describe('RemoteAppWrapper SSR payload boundary', () => { + it('injects only a valid result matching the mounted module and instance', () => { + const result = { + protocolVersion: 1 as const, + moduleName: 'remote/app', + instanceId: 'remote-1', + html: '

    server remote

    ', + }; + const html = renderToStaticMarkup( + , + ); + expect(html).toContain('data-mf-bridge-instance="remote-1"'); + expect(html).toContain('

    server remote

    '); + + const mismatch = renderToStaticMarkup( + , + ); + expect(mismatch).not.toContain('data-mf-bridge-ssr'); + expect(mismatch).not.toContain('server remote'); + }); + + it('rejects malformed host-carried results', () => { + expect(() => + renderToStaticMarkup( + invalid

    ', + } as any + } + />, + ), + ).toThrow(/incompatible result/); + }); +}); diff --git a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx index ed6f85bd968..b4ad5eeac1a 100644 --- a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx +++ b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx @@ -7,7 +7,10 @@ import { LoggerInstance, getRootDomDefaultClassName } from '../utils'; import { federationRuntime } from '../provider/plugin'; import { RemoteComponentProps, RemoteAppParams } from '../types'; import type { RemoteAppSSRProps } from '../types'; -import { getBridgeSSRContainerAttrs } from '@module-federation/bridge-shared'; +import { + getBridgeSSRContainerAttrs, + getMatchingBridgeSSRResult, +} from '@module-federation/bridge-shared'; export const RemoteAppWrapper = forwardRef(function ( props: RemoteAppParams & RemoteComponentProps & RemoteAppSSRProps, @@ -26,8 +29,12 @@ export const RemoteAppWrapper = forwardRef(function ( instanceId: suppliedInstanceId, ...resProps } = props; - const instanceId = suppliedInstanceId || ssr?.instanceId; - const hasSSRPayload = Boolean(ssr && instanceId); + const ssrPayload = getMatchingBridgeSSRResult(ssr, { + moduleName, + instanceId: suppliedInstanceId, + }); + const instanceId = suppliedInstanceId || ssrPayload?.instanceId; + const hasSSRPayload = Boolean(ssrPayload && instanceId); const instance = federationRuntime.instance; const rootRef: React.MutableRefObject = @@ -92,7 +99,7 @@ export const RemoteAppWrapper = forwardRef(function ( memoryRoute, fallback, instanceId, - ssrState: ssr?.dehydratedState, + ssrState: ssrPayload?.dehydratedState, ...resProps, }; renderDom.current = rootRef.current; @@ -118,7 +125,7 @@ export const RemoteAppWrapper = forwardRef(function ( : {})} {...(hasSSRPayload ? { - dangerouslySetInnerHTML: { __html: ssr!.html }, + dangerouslySetInnerHTML: { __html: ssrPayload!.html }, suppressHydrationWarning: true, } : {})} diff --git a/packages/bridge/bridge-react/src/router/default.tsx b/packages/bridge/bridge-react/src/router/default.tsx index c986f7da74a..e29ec8f4a20 100644 --- a/packages/bridge/bridge-react/src/router/default.tsx +++ b/packages/bridge/bridge-react/src/router/default.tsx @@ -18,6 +18,12 @@ function WrapperRouter( WrapperRouterProps: props, }); + if (routerContextProps?.ssrLocation) { + throw new Error( + 'Bridge SSR V1 with React Router v6 requires the @module-federation/bridge-react/router-v6 alias', + ); + } + if (routerContextProps?.memoryRoute) { return ( { + it('fails clearly when a data router is used for SSR', () => { + expect(() => + renderToStaticMarkup( + + + , + ), + ).toThrow(/does not support React Router data routers/); + }); +}); diff --git a/packages/bridge/bridge-react/src/router/v6.tsx b/packages/bridge/bridge-react/src/router/v6.tsx index 52897ecdc6e..7a396973816 100644 --- a/packages/bridge/bridge-react/src/router/v6.tsx +++ b/packages/bridge/bridge-react/src/router/v6.tsx @@ -64,6 +64,12 @@ function WraperRouterProvider( 'create' + 'BrowserRouter' ]; + if (routerContextProps.ssrLocation) { + throw new Error( + 'Bridge SSR V1 does not support React Router data routers or RouterProvider', + ); + } + if (routerContextProps.memoryRoute) { const MemeoryRouterInstance = createMemoryRouter(routers, { initialEntries: [routerContextProps?.memoryRoute.entryPath], diff --git a/packages/bridge/bridge-shared/src/index.ts b/packages/bridge/bridge-shared/src/index.ts index 4c4886467f5..67c11c9b4e1 100644 --- a/packages/bridge/bridge-shared/src/index.ts +++ b/packages/bridge/bridge-shared/src/index.ts @@ -17,6 +17,7 @@ export { assertBridgeJSONValue, assertBridgeSSRIdentity, assertBridgeSSRResult, + getMatchingBridgeSSRResult, getBridgeSSRContainerAttrs, hasBridgeSSRMarkup, serializeBridgeJSON, diff --git a/packages/bridge/bridge-shared/src/ssr.spec.ts b/packages/bridge/bridge-shared/src/ssr.spec.ts index 4fa61a16d83..d7a0d5293f5 100644 --- a/packages/bridge/bridge-shared/src/ssr.spec.ts +++ b/packages/bridge/bridge-shared/src/ssr.spec.ts @@ -3,6 +3,7 @@ import { BRIDGE_SSR_PROTOCOL_VERSION, BridgeSSRError, assertBridgeJSONValue, + getMatchingBridgeSSRResult, renderRemoteBridge, serializeBridgeJSON, } from './index'; @@ -23,6 +24,31 @@ describe('Bridge SSR V1 contract', () => { ); }); + it('validates host-carried results before matching their identity', () => { + const result = { + protocolVersion: BRIDGE_SSR_PROTOCOL_VERSION, + moduleName: 'remote/app', + instanceId: 'remote-1', + html: '

    remote

    ', + } as const; + + expect( + getMatchingBridgeSSRResult(result, { + moduleName: 'remote/app', + instanceId: 'remote-1', + }), + ).toBe(result); + expect( + getMatchingBridgeSSRResult(result, { moduleName: 'other/app' }), + ).toBeUndefined(); + expect(() => + getMatchingBridgeSSRResult( + { ...result, protocolVersion: 2 }, + { moduleName: 'remote/app' }, + ), + ).toThrow(/incompatible result/); + }); + it('loads, renders, and validates a remote provider', async () => { const renderServer = vi.fn(async (context) => ({ protocolVersion: BRIDGE_SSR_PROTOCOL_VERSION, diff --git a/packages/bridge/bridge-shared/src/ssr.ts b/packages/bridge/bridge-shared/src/ssr.ts index e295ae62b1e..090a555ee50 100644 --- a/packages/bridge/bridge-shared/src/ssr.ts +++ b/packages/bridge/bridge-shared/src/ssr.ts @@ -145,6 +145,23 @@ export function assertBridgeSSRResult( } } +export function getMatchingBridgeSSRResult( + value: unknown, + expected: { moduleName?: string; instanceId?: string }, +): BridgeSSRResult | undefined { + if (value === undefined) return undefined; + assertBridgeSSRResult(value); + if ( + (expected.moduleName !== undefined && + value.moduleName !== expected.moduleName) || + (expected.instanceId !== undefined && + value.instanceId !== expected.instanceId) + ) { + return undefined; + } + return value; +} + export function getBridgeSSRContainerAttrs(value: { moduleName: string; instanceId: string; diff --git a/packages/bridge/vue3-bridge/__tests__/remoteApp.test.ts b/packages/bridge/vue3-bridge/__tests__/remoteApp.test.ts index ffc10f60dfd..059d6ec431e 100644 --- a/packages/bridge/vue3-bridge/__tests__/remoteApp.test.ts +++ b/packages/bridge/vue3-bridge/__tests__/remoteApp.test.ts @@ -9,6 +9,7 @@ const { dispatchPopstateEnv } = rs.hoisted(() => ({ rs.mock('@module-federation/bridge-shared', () => ({ dispatchPopstateEnv, + getMatchingBridgeSSRResult: () => undefined, })); rs.mock('@module-federation/runtime', () => ({ diff --git a/packages/bridge/vue3-bridge/src/provider.spec.ts b/packages/bridge/vue3-bridge/src/provider.spec.ts index 9e34fec2006..27806cd484d 100644 --- a/packages/bridge/vue3-bridge/src/provider.spec.ts +++ b/packages/bridge/vue3-bridge/src/provider.spec.ts @@ -43,4 +43,36 @@ describe('Vue Bridge server provider', () => { }); expect(serverRenderer).toHaveBeenCalledOnce(); }); + + it('unmounts the previous app before rendering again into the same DOM node', async () => { + const provider = createBridgeComponentWithServerRenderer({ + rootComponent: defineComponent({ + props: { label: String }, + setup: (props) => () => h('p', props.label), + }), + appOptions: () => undefined, + })(); + const dom = document.createElement('div'); + + await provider.render({ + dom, + moduleName: 'vue/remote', + label: 'first', + } as any); + const firstApp = (dom as HTMLElement & { __vue_app__?: any }).__vue_app__; + const unmount = rs.spyOn(firstApp, 'unmount'); + + await provider.render({ + dom, + moduleName: 'vue/remote', + label: 'second', + } as any); + expect(unmount).toHaveBeenCalledOnce(); + expect(dom.textContent).toBe('second'); + expect((dom as HTMLElement & { __vue_app__?: any }).__vue_app__).not.toBe( + firstApp, + ); + + provider.destroy({ dom }); + }); }); diff --git a/packages/bridge/vue3-bridge/src/provider.ts b/packages/bridge/vue3-bridge/src/provider.ts index 0c2e6723aad..86f0777f1f5 100644 --- a/packages/bridge/vue3-bridge/src/provider.ts +++ b/packages/bridge/vue3-bridge/src/provider.ts @@ -143,6 +143,11 @@ export function createBridgeComponentWithServerRenderer( beforeBridgeRenderRes.extraProps ? beforeBridgeRenderRes.extraProps : {}; + const previousApp = roots.get(dom); + if (previousApp) { + previousApp.unmount(); + roots.delete(dom); + } const shouldHydrate = hasBridgeSSRMarkup(dom, { moduleName, instanceId, @@ -157,8 +162,8 @@ export function createBridgeComponentWithServerRenderer( shouldHydrate ? 'hydrate' : 'csr', ); if (signal?.aborted) return; - roots.set(dom, app); app.mount(dom, shouldHydrate); + roots.set(dom, app); runtime?.bridgeHook?.lifecycle?.afterBridgeRender?.emit(info); LoggerInstance.debug('createBridgeComponent rendered', { moduleName }); }, diff --git a/packages/bridge/vue3-bridge/src/remoteApp.tsx b/packages/bridge/vue3-bridge/src/remoteApp.tsx index d32f5e4e947..9fcfbb60a71 100644 --- a/packages/bridge/vue3-bridge/src/remoteApp.tsx +++ b/packages/bridge/vue3-bridge/src/remoteApp.tsx @@ -12,6 +12,7 @@ import { import { dispatchPopstateEnv, getBridgeSSRContainerAttrs, + getMatchingBridgeSSRResult, type BridgeSSRResult, } from '@module-federation/bridge-shared'; import { useRoute } from 'vue-router'; @@ -41,7 +42,10 @@ export default defineComponent({ const route = useRoute(); const hostInstance = getInstance(); const componentAttrs = useAttrs(); - const ssrPayload = props.ssr as BridgeSSRResult | undefined; + const ssrPayload = getMatchingBridgeSSRResult(props.ssr, { + moduleName: props.moduleName, + instanceId: props.instanceId, + }) as BridgeSSRResult | undefined; const instanceId = props.instanceId || ssrPayload?.instanceId; const getBridgeRenderProps = () => ({ From c264ea6667dcca9ce08049c9fa5ff95e75b7573b Mon Sep 17 00:00:00 2001 From: Kevin Beier Date: Sat, 18 Jul 2026 17:00:12 +0200 Subject: [PATCH 19/32] fix(bridge): hydrate SSR islands from document slots --- .../host-vue/src/entry.client.ts | 3 + .../host-vue/src/entry.server.ts | 7 +- .../host-vue/src/ssrContext.ts | 46 ++- .../host/e2e/bridge-ssr-browser.spec.ts | 23 +- .../host/e2e/bridge-ssr-nojs.spec.ts | 11 + .../bridge-ssr-demo/host/src/entry.client.tsx | 11 +- .../bridge-ssr-demo/host/src/entry.server.tsx | 2 + .../host/src/lib/hostSsrContext.ts | 8 +- .../host/src/lib/ssrContext.ts | 31 +- .../shared/createHostServer.mjs | 4 +- .../bridge-react/src/hydration.spec.tsx | 108 +++++++ .../bridge/bridge-react/src/hydration.tsx | 83 +++++ packages/bridge/bridge-react/src/index.ts | 3 + .../src/remote/RemoteAppWrapper.spec.tsx | 2 + .../src/remote/RemoteAppWrapper.tsx | 67 ++-- packages/bridge/bridge-react/src/types.ts | 7 +- packages/bridge/bridge-react/src/v18.ts | 1 + packages/bridge/bridge-shared/src/index.ts | 13 + packages/bridge/bridge-shared/src/ssr.spec.ts | 50 +++ packages/bridge/bridge-shared/src/ssr.ts | 302 ++++++++++++++++++ packages/bridge/bridge-shared/src/type.ts | 27 ++ .../vue3-bridge/__tests__/remoteApp.test.ts | 2 +- packages/bridge/vue3-bridge/src/create.ts | 9 + packages/bridge/vue3-bridge/src/hydration.ts | 17 + .../bridge/vue3-bridge/src/index.server.ts | 2 + packages/bridge/vue3-bridge/src/index.ts | 2 + packages/bridge/vue3-bridge/src/remoteApp.tsx | 83 ++++- 27 files changed, 867 insertions(+), 57 deletions(-) create mode 100644 packages/bridge/bridge-react/src/hydration.spec.tsx create mode 100644 packages/bridge/bridge-react/src/hydration.tsx create mode 100644 packages/bridge/vue3-bridge/src/hydration.ts diff --git a/apps/bridge-ssr-demo/host-vue/src/entry.client.ts b/apps/bridge-ssr-demo/host-vue/src/entry.client.ts index e83cec85dfa..3d95da30f37 100644 --- a/apps/bridge-ssr-demo/host-vue/src/entry.client.ts +++ b/apps/bridge-ssr-demo/host-vue/src/entry.client.ts @@ -1,5 +1,7 @@ import { createSSRApp } from 'vue'; import { createRouter, createWebHistory } from 'vue-router'; +import { createBridgeHydrationRegistry } from '@module-federation/bridge-shared'; +import { provideBridgeHydrationRegistry } from '@module-federation/bridge-vue3'; import App from './App.vue'; import { readHostSSRContext } from './ssrContext'; @@ -9,5 +11,6 @@ const router = createRouter({ }); const app = createSSRApp(App, { ssrContext: readHostSSRContext() }); app.use(router); +provideBridgeHydrationRegistry(app, createBridgeHydrationRegistry(document)); await router.isReady(); app.mount('#root'); diff --git a/apps/bridge-ssr-demo/host-vue/src/entry.server.ts b/apps/bridge-ssr-demo/host-vue/src/entry.server.ts index 5da8cd99a98..818631b00e9 100644 --- a/apps/bridge-ssr-demo/host-vue/src/entry.server.ts +++ b/apps/bridge-ssr-demo/host-vue/src/entry.server.ts @@ -2,6 +2,7 @@ import { createSSRApp } from 'vue'; import { renderToString } from '@vue/server-renderer'; import { createMemoryHistory, createRouter } from 'vue-router'; import App from './App.vue'; +import { toHostHydrationContext } from './ssrContext'; import { prepareSSRContext, type PrepareSSRContextOptions, @@ -25,5 +26,9 @@ export async function render( options: PrepareSSRContextOptions = {}, ) { const { app, ssrContext } = await createHostApp(url, options); - return { html: await renderToString(app), ssrContext }; + return { + html: await renderToString(app), + ssrContext, + hydrationContext: toHostHydrationContext(ssrContext), + }; } diff --git a/apps/bridge-ssr-demo/host-vue/src/ssrContext.ts b/apps/bridge-ssr-demo/host-vue/src/ssrContext.ts index 52d784a2610..b6a605f44d7 100644 --- a/apps/bridge-ssr-demo/host-vue/src/ssrContext.ts +++ b/apps/bridge-ssr-demo/host-vue/src/ssrContext.ts @@ -1,18 +1,56 @@ -import type { BridgeSSRResult } from '@module-federation/bridge-shared'; +import { + assertBridgeSSRReference, + toBridgeSSRReference, + type BridgeSSRReference, + type BridgeSSRResult, +} from '@module-federation/bridge-shared'; + +export type RemoteSSRData = BridgeSSRResult | BridgeSSRReference; export type HostSSRContext = { url: string; - reactRemote?: BridgeSSRResult; - reactPair?: [BridgeSSRResult, BridgeSSRResult]; + reactRemote?: RemoteSSRData; + reactPair?: [RemoteSSRData, RemoteSSRData]; +}; + +export type HostHydrationContext = { + url: string; + reactRemote?: BridgeSSRReference; + reactPair?: [BridgeSSRReference, BridgeSSRReference]; }; +function toReference(data: RemoteSSRData): BridgeSSRReference { + if ('html' in data) return toBridgeSSRReference(data); + assertBridgeSSRReference(data); + return data; +} + +export function toHostHydrationContext( + context: HostSSRContext, +): HostHydrationContext { + return { + url: context.url, + ...(context.reactRemote + ? { reactRemote: toReference(context.reactRemote) } + : {}), + ...(context.reactPair + ? { + reactPair: context.reactPair.map(toReference) as [ + BridgeSSRReference, + BridgeSSRReference, + ], + } + : {}), + }; +} + export const HOST_SSR_CONTEXT_SCRIPT_ID = 'bridge-ssr-host-context'; export function readHostSSRContext() { const script = document.getElementById(HOST_SSR_CONTEXT_SCRIPT_ID); if (!script?.textContent) return undefined; try { - return JSON.parse(script.textContent) as HostSSRContext; + return JSON.parse(script.textContent) as HostHydrationContext; } catch { return undefined; } diff --git a/apps/bridge-ssr-demo/host/e2e/bridge-ssr-browser.spec.ts b/apps/bridge-ssr-demo/host/e2e/bridge-ssr-browser.spec.ts index 113abff34e3..be739f4e1e5 100644 --- a/apps/bridge-ssr-demo/host/e2e/bridge-ssr-browser.spec.ts +++ b/apps/bridge-ssr-demo/host/e2e/bridge-ssr-browser.spec.ts @@ -40,7 +40,10 @@ test('server-renders a deep route and remote navigation updates the URL', async page, }, testInfo) => { const remote = direction(testInfo.project.name); - await page.goto(remote.detail); + await page.goto(`${remote.detail}?source=e2e#bridge-state`); + await expect(page).toHaveURL( + new RegExp(`${remote.detail}\\?source=e2e#bridge-state$`), + ); await expect( page.getByRole('heading', { name: remote.detailHeading }), ).toBeVisible(); @@ -77,6 +80,24 @@ test('host navigation enters, leaves, and returns through CSR without reload', a .toBe('alive'); }); +test('consumes direct-visit SSR once and revisits through CSR', async ({ + page, +}, testInfo) => { + const remote = direction(testInfo.project.name); + await page.goto(remote.route); + await expect(page.locator('[data-mf-bridge-ssr="true"]')).toHaveCount(1); + await expect( + page.getByRole('heading', { name: remote.homeHeading }), + ).toBeVisible(); + + await page.getByRole('link', { name: 'Home' }).first().click(); + await page.locator(remote.hostLink).first().click(); + await expect( + page.getByRole('heading', { name: remote.homeHeading }), + ).toBeVisible(); + await expect(page.locator('[data-mf-bridge-ssr="true"]')).toHaveCount(0); +}); + test('two instances of one React remote hydrate independently', async ({ page, }, testInfo) => { diff --git a/apps/bridge-ssr-demo/host/e2e/bridge-ssr-nojs.spec.ts b/apps/bridge-ssr-demo/host/e2e/bridge-ssr-nojs.spec.ts index 5628de49bbd..db31282b8c9 100644 --- a/apps/bridge-ssr-demo/host/e2e/bridge-ssr-nojs.spec.ts +++ b/apps/bridge-ssr-demo/host/e2e/bridge-ssr-nojs.spec.ts @@ -12,7 +12,18 @@ test('raw response contains the cross-framework remote route', async ({ expect(response.ok()).toBeTruthy(); expect(html).toContain(heading); expect(html).toContain('data-mf-bridge-ssr="true"'); + expect(html).toContain('data-mf-bridge-slot="true"'); + expect(html).toContain('data-mf-bridge-state="true"'); expect(html).toContain('bridge-ssr-host-context'); + expect(html.match(new RegExp(heading, 'g'))).toHaveLength(1); + + const contextMatch = html.match( + /
    ', + 'unexpected', + ); + expect(() => + createBridgeHydrationRegistry(document).peek('remote/app', 'remote-1'), + ).toThrow(/only its direct mount and state children/); + + document.body.innerHTML = original.replace( + '"state":', + '"html":"duplicate","state":', + ); + expect(() => + createBridgeHydrationRegistry(document).peek('remote/app', 'remote-1'), + ).toThrow(/incompatible state envelope/); + }); +}); diff --git a/packages/bridge/bridge-react/src/hydration.tsx b/packages/bridge/bridge-react/src/hydration.tsx new file mode 100644 index 00000000000..b131dfe162f --- /dev/null +++ b/packages/bridge/bridge-react/src/hydration.tsx @@ -0,0 +1,83 @@ +import React from 'react'; +import { + BRIDGE_SSR_PROTOCOL_VERSION, + MF_BRIDGE_STATE_ATTR, + getBridgeSSRContainerAttrs, + getBridgeSSRSlotAttrs, + serializeBridgeSSRStateEnvelope, + type BridgeHydrationRegistry, + type BridgeHydrationSnapshot, + type BridgeSSRResult, +} from '@module-federation/bridge-shared'; +import { getRootDomDefaultClassName } from './utils'; + +const BridgeHydrationContext = React.createContext< + BridgeHydrationRegistry | undefined +>(undefined); + +export function BridgeHydrationProvider({ + registry, + children, +}: { + registry: BridgeHydrationRegistry; + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} + +export function useBridgeHydrationRegistry() { + return React.useContext(BridgeHydrationContext); +} + +export function BridgeRemoteSlot({ + moduleName, + instanceId, + payload, + snapshot, + className, + style, + mountRef, +}: { + moduleName: string; + instanceId: string; + payload?: BridgeSSRResult; + snapshot?: BridgeHydrationSnapshot; + className?: string; + style?: React.CSSProperties; + mountRef?: React.Ref; +}) { + const html = payload?.html ?? snapshot?.html ?? ''; + const state = payload?.dehydratedState ?? snapshot?.state; + const rootClassName = + `${getRootDomDefaultClassName(moduleName)} ${className || ''}`.trim(); + + return ( +
    +
    + \u2028\u2029' }, + }), + ).toBe( + '{"protocolVersion":1,"moduleName":"remote/app","instanceId":"remote-1","state":{"value":"\\u003c/script>\\u2028\\u2029"}}', + ); + expect(() => + serializeBridgeSSRStateEnvelope({ + protocolVersion: BRIDGE_SSR_PROTOCOL_VERSION, + moduleName: 'remote/app', + instanceId: 'remote-1', + html: '

    must not be serialized

    ', + } as any), + ).toThrow(/state envelope is incompatible/); + }); + it('loads, renders, and validates a remote provider', async () => { const renderServer = vi.fn(async (context) => ({ protocolVersion: BRIDGE_SSR_PROTOCOL_VERSION, diff --git a/packages/bridge/bridge-shared/src/ssr.ts b/packages/bridge/bridge-shared/src/ssr.ts index 090a555ee50..586f70659a6 100644 --- a/packages/bridge/bridge-shared/src/ssr.ts +++ b/packages/bridge/bridge-shared/src/ssr.ts @@ -1,14 +1,21 @@ import { BRIDGE_SSR_PROTOCOL_VERSION, BridgeSSRError, + type BridgeHydrationRegistry, + type BridgeHydrationSnapshot, type BridgeJSONValue, + type BridgeSSRReference, type BridgeSSRResult, + type BridgeSSRStateEnvelope, } from './type'; export const MF_BRIDGE_SSR_ATTR = 'data-mf-bridge-ssr'; export const MF_BRIDGE_VERSION_ATTR = 'data-mf-bridge-version'; export const MF_BRIDGE_MODULE_ATTR = 'data-mf-bridge-module'; export const MF_BRIDGE_INSTANCE_ATTR = 'data-mf-bridge-instance'; +export const MF_BRIDGE_SLOT_ATTR = 'data-mf-bridge-slot'; +export const MF_BRIDGE_MOUNT_ATTR = 'data-mf-bridge-mount'; +export const MF_BRIDGE_STATE_ATTR = 'data-mf-bridge-state'; function assertPrintable(value: string, label: string) { if (!value || /[\u0000-\u001f\u007f]/.test(value)) { @@ -111,6 +118,72 @@ export function serializeBridgeSSRResult(result: BridgeSSRResult): string { .replace(/\u2029/g, '\\u2029'); } +export function toBridgeSSRReference( + result: BridgeSSRResult, +): BridgeSSRReference { + assertBridgeSSRResult(result); + return Object.freeze({ + protocolVersion: result.protocolVersion, + moduleName: result.moduleName, + instanceId: result.instanceId, + }); +} + +export function assertBridgeSSRReference( + value: unknown, +): asserts value is BridgeSSRReference { + if (!value || typeof value !== 'object') { + throw new BridgeSSRError('Bridge SSR reference is invalid'); + } + const reference = value as Partial; + if ( + Object.keys(reference).some( + (key) => + key !== 'protocolVersion' && + key !== 'moduleName' && + key !== 'instanceId', + ) || + reference.protocolVersion !== BRIDGE_SSR_PROTOCOL_VERSION || + typeof reference.moduleName !== 'string' || + typeof reference.instanceId !== 'string' + ) { + throw new BridgeSSRError('Bridge SSR reference is incompatible'); + } + assertBridgeSSRIdentity({ + moduleName: reference.moduleName, + instanceId: reference.instanceId, + }); +} + +export function serializeBridgeSSRStateEnvelope( + envelope: BridgeSSRStateEnvelope, +): string { + const allowedKeys = new Set([ + 'protocolVersion', + 'moduleName', + 'instanceId', + 'state', + ]); + if ( + !envelope || + typeof envelope !== 'object' || + Array.isArray(envelope) || + Object.keys(envelope).some((key) => !allowedKeys.has(key)) + ) { + throw new BridgeSSRError('Bridge SSR state envelope is incompatible'); + } + assertBridgeSSRReference({ + protocolVersion: envelope.protocolVersion, + moduleName: envelope.moduleName, + instanceId: envelope.instanceId, + }); + if (envelope.state !== undefined) assertBridgeJSONValue(envelope.state); + return JSON.stringify(envelope) + .replace(/ { + assertBridgeSSRIdentity(value); + return { + [MF_BRIDGE_SLOT_ATTR]: 'true', [MF_BRIDGE_VERSION_ATTR]: String(BRIDGE_SSR_PROTOCOL_VERSION), [MF_BRIDGE_MODULE_ATTR]: value.moduleName, [MF_BRIDGE_INSTANCE_ATTR]: value.instanceId, @@ -190,3 +298,197 @@ export function hasBridgeSSRMarkup( dom.hasChildNodes() ); } + +function directChildrenWithAttribute( + parent: Element, + attribute: string, +): T[] { + return Array.from(parent.children).filter( + (child) => child.getAttribute(attribute) === 'true', + ) as T[]; +} + +function freezeJSONValue( + value: BridgeJSONValue | undefined, +): BridgeJSONValue | undefined { + if (!value || typeof value !== 'object' || Object.isFrozen(value)) { + return value; + } + if (Array.isArray(value)) value.forEach((item) => freezeJSONValue(item)); + else Object.values(value).forEach((item) => freezeJSONValue(item)); + Object.freeze(value); + return value; +} + +function hydrationError(message: string, cause?: unknown) { + return new BridgeSSRError(message, cause); +} + +function readSlotSnapshot(slot: HTMLElement): BridgeHydrationSnapshot { + const protocolVersion = Number(slot.getAttribute(MF_BRIDGE_VERSION_ATTR)); + const moduleName = slot.getAttribute(MF_BRIDGE_MODULE_ATTR) || ''; + const instanceId = slot.getAttribute(MF_BRIDGE_INSTANCE_ATTR) || ''; + assertBridgeSSRIdentity({ moduleName, instanceId }); + if (protocolVersion !== BRIDGE_SSR_PROTOCOL_VERSION) { + throw hydrationError( + `Bridge SSR slot ${instanceId} uses unsupported protocol version ${protocolVersion}`, + ); + } + + const mounts = directChildrenWithAttribute( + slot, + MF_BRIDGE_MOUNT_ATTR, + ); + const scripts = directChildrenWithAttribute( + slot, + MF_BRIDGE_STATE_ATTR, + ); + if (mounts.length !== 1 || scripts.length !== 1) { + throw hydrationError( + `Bridge SSR slot ${instanceId} must contain exactly one direct mount and state child`, + ); + } + + const [mount] = mounts; + const [script] = scripts; + if ( + slot.children.length !== 2 || + slot.children[0] !== mount || + slot.children[1] !== script || + script.tagName !== 'SCRIPT' + ) { + throw hydrationError( + `Bridge SSR slot ${instanceId} must contain only its direct mount and state children in order`, + ); + } + if ( + mount.getAttribute(MF_BRIDGE_MODULE_ATTR) !== moduleName || + mount.getAttribute(MF_BRIDGE_INSTANCE_ATTR) !== instanceId || + mount.getAttribute(MF_BRIDGE_VERSION_ATTR) !== String(protocolVersion) + ) { + throw hydrationError( + `Bridge SSR slot ${instanceId} mount metadata does not match its slot`, + ); + } + if (script.type !== 'application/json' || !script.textContent) { + throw hydrationError( + `Bridge SSR slot ${instanceId} has an invalid state envelope`, + ); + } + + let envelope: BridgeSSRStateEnvelope; + try { + envelope = JSON.parse(script.textContent) as BridgeSSRStateEnvelope; + } catch (error) { + throw hydrationError( + `Bridge SSR slot ${instanceId} state envelope is not valid JSON`, + error, + ); + } + const envelopeKeys = Object.keys(envelope); + if ( + !envelope || + typeof envelope !== 'object' || + Array.isArray(envelope) || + envelopeKeys.some( + (key) => + key !== 'protocolVersion' && + key !== 'moduleName' && + key !== 'instanceId' && + key !== 'state', + ) + ) { + throw hydrationError( + `Bridge SSR slot ${instanceId} has an incompatible state envelope`, + ); + } + if ( + envelope.protocolVersion !== protocolVersion || + envelope.moduleName !== moduleName || + envelope.instanceId !== instanceId + ) { + throw hydrationError( + `Bridge SSR slot ${instanceId} state metadata does not match its slot`, + ); + } + if (envelope.state !== undefined) assertBridgeJSONValue(envelope.state); + + return Object.freeze({ + protocolVersion: BRIDGE_SSR_PROTOCOL_VERSION, + moduleName, + instanceId, + html: mount.innerHTML, + state: freezeJSONValue(envelope.state), + }); +} + +export function createBridgeHydrationRegistry( + root?: ParentNode, +): BridgeHydrationRegistry { + const hydrationRoot = + root ?? (typeof document === 'undefined' ? undefined : document); + if (!hydrationRoot) { + throw hydrationError( + 'createBridgeHydrationRegistry requires a document root on the server', + ); + } + const snapshots = new Map(); + const errors = new Map(); + + for (const slot of Array.from( + hydrationRoot.querySelectorAll( + `[${MF_BRIDGE_SLOT_ATTR}="true"]`, + ), + )) { + const instanceId = slot.getAttribute(MF_BRIDGE_INSTANCE_ATTR) || ''; + if (snapshots.has(instanceId) || errors.has(instanceId)) { + snapshots.delete(instanceId); + errors.set( + instanceId, + hydrationError(`Duplicate Bridge SSR instanceId ${instanceId}`), + ); + continue; + } + try { + const snapshot = readSlotSnapshot(slot); + snapshots.set(snapshot.instanceId, snapshot); + } catch (error) { + errors.set( + instanceId, + error instanceof BridgeSSRError + ? error + : hydrationError( + `Unable to read Bridge SSR slot ${instanceId}`, + error, + ), + ); + } + } + + return { + peek(moduleName, instanceId) { + const error = errors.get(instanceId); + if (error) throw error; + const snapshot = snapshots.get(instanceId); + if (!snapshot) return undefined; + if (snapshot.moduleName !== moduleName) { + throw hydrationError( + `Bridge SSR instance ${instanceId} belongs to ${snapshot.moduleName}, not ${moduleName}`, + ); + } + return snapshot; + }, + consume(moduleName, instanceId) { + const snapshot = this.peek(moduleName, instanceId); + snapshots.delete(instanceId); + errors.delete(instanceId); + return snapshot; + }, + fail(moduleName, instanceId) { + const snapshot = snapshots.get(instanceId); + if (snapshot && snapshot.moduleName !== moduleName) return; + snapshots.delete(instanceId); + errors.delete(instanceId); + }, + }; +} diff --git a/packages/bridge/bridge-shared/src/type.ts b/packages/bridge/bridge-shared/src/type.ts index 29bfe5af306..65205b4ccba 100644 --- a/packages/bridge/bridge-shared/src/type.ts +++ b/packages/bridge/bridge-shared/src/type.ts @@ -45,6 +45,33 @@ export type BridgeSSRResult = { dehydratedState?: BridgeJSONValue; }; +/** Identity-only payload safe to serialize into a host hydration context. */ +export type BridgeSSRReference = Pick< + BridgeSSRResult, + 'protocolVersion' | 'moduleName' | 'instanceId' +>; + +export type BridgeSSRStateEnvelope = BridgeSSRReference & { + state?: BridgeJSONValue; +}; + +export type BridgeHydrationSnapshot = BridgeSSRReference & { + html: string; + state?: BridgeJSONValue; +}; + +export interface BridgeHydrationRegistry { + peek( + moduleName: string, + instanceId: string, + ): BridgeHydrationSnapshot | undefined; + consume( + moduleName: string, + instanceId: string, + ): BridgeHydrationSnapshot | undefined; + fail(moduleName: string, instanceId: string): void; +} + export class BridgeSSRError extends Error { override readonly cause?: unknown; diff --git a/packages/bridge/vue3-bridge/__tests__/remoteApp.test.ts b/packages/bridge/vue3-bridge/__tests__/remoteApp.test.ts index 059d6ec431e..2f7bf27991d 100644 --- a/packages/bridge/vue3-bridge/__tests__/remoteApp.test.ts +++ b/packages/bridge/vue3-bridge/__tests__/remoteApp.test.ts @@ -9,7 +9,7 @@ const { dispatchPopstateEnv } = rs.hoisted(() => ({ rs.mock('@module-federation/bridge-shared', () => ({ dispatchPopstateEnv, - getMatchingBridgeSSRResult: () => undefined, + getMatchingBridgeSSRPayload: () => undefined, })); rs.mock('@module-federation/runtime', () => ({ diff --git a/packages/bridge/vue3-bridge/src/create.ts b/packages/bridge/vue3-bridge/src/create.ts index 9fe415acee8..2c3033220dd 100644 --- a/packages/bridge/vue3-bridge/src/create.ts +++ b/packages/bridge/vue3-bridge/src/create.ts @@ -2,9 +2,18 @@ import { type AsyncComponentOptions, defineAsyncComponent, h } from 'vue'; import { useRoute } from 'vue-router'; import RemoteApp from './remoteApp.jsx'; import { LoggerInstance } from './utils.js'; +import type { + BridgeSSRReference, + BridgeSSRResult, +} from '@module-federation/bridge-shared'; declare const __APP_VERSION__: string; +export type RemoteAppSSRProps = { + ssr?: BridgeSSRResult | BridgeSSRReference; + instanceId?: string; +}; + export function createRemoteAppComponent(info: { loader: () => Promise; export?: string; diff --git a/packages/bridge/vue3-bridge/src/hydration.ts b/packages/bridge/vue3-bridge/src/hydration.ts new file mode 100644 index 00000000000..1375ac12bff --- /dev/null +++ b/packages/bridge/vue3-bridge/src/hydration.ts @@ -0,0 +1,17 @@ +import { inject, type App, type InjectionKey } from 'vue'; +import type { BridgeHydrationRegistry } from '@module-federation/bridge-shared'; + +export const BridgeHydrationRegistryKey: InjectionKey = + Symbol.for('mf.bridge.hydration-registry'); + +export function provideBridgeHydrationRegistry( + app: App, + registry: BridgeHydrationRegistry, +) { + app.provide(BridgeHydrationRegistryKey, registry); + return app; +} + +export function useBridgeHydrationRegistry() { + return inject(BridgeHydrationRegistryKey, undefined); +} diff --git a/packages/bridge/vue3-bridge/src/index.server.ts b/packages/bridge/vue3-bridge/src/index.server.ts index a260a91227a..9743a3fb20a 100644 --- a/packages/bridge/vue3-bridge/src/index.server.ts +++ b/packages/bridge/vue3-bridge/src/index.server.ts @@ -13,4 +13,6 @@ export function createBridgeComponent(bridgeInfo: ProviderFnParams) { export type { ProviderFnParams } from './provider'; export { createRemoteComponent, createRemoteAppComponent } from './create'; +export type { RemoteAppSSRProps } from './create'; +export { provideBridgeHydrationRegistry } from './hydration'; export type { RenderFnParams } from '@module-federation/bridge-shared'; diff --git a/packages/bridge/vue3-bridge/src/index.ts b/packages/bridge/vue3-bridge/src/index.ts index fbf7a554075..1de0572548e 100644 --- a/packages/bridge/vue3-bridge/src/index.ts +++ b/packages/bridge/vue3-bridge/src/index.ts @@ -1,4 +1,6 @@ export { createBridgeComponent } from './provider'; export type { ProviderFnParams } from './provider'; export { createRemoteComponent, createRemoteAppComponent } from './create'; +export type { RemoteAppSSRProps } from './create'; +export { provideBridgeHydrationRegistry } from './hydration'; export type { RenderFnParams } from '@module-federation/bridge-shared'; diff --git a/packages/bridge/vue3-bridge/src/remoteApp.tsx b/packages/bridge/vue3-bridge/src/remoteApp.tsx index 9fcfbb60a71..82e832e4f54 100644 --- a/packages/bridge/vue3-bridge/src/remoteApp.tsx +++ b/packages/bridge/vue3-bridge/src/remoteApp.tsx @@ -10,14 +10,19 @@ import { nextTick, } from 'vue'; import { + BRIDGE_SSR_PROTOCOL_VERSION, dispatchPopstateEnv, getBridgeSSRContainerAttrs, - getMatchingBridgeSSRResult, + getBridgeSSRSlotAttrs, + getMatchingBridgeSSRPayload, + serializeBridgeSSRStateEnvelope, + type BridgeSSRReference, type BridgeSSRResult, } from '@module-federation/bridge-shared'; import { useRoute } from 'vue-router'; import { LoggerInstance } from './utils'; import { getInstance } from '@module-federation/runtime'; +import { useBridgeHydrationRegistry } from './hydration'; export default defineComponent({ name: 'RemoteApp', @@ -42,11 +47,25 @@ export default defineComponent({ const route = useRoute(); const hostInstance = getInstance(); const componentAttrs = useAttrs(); - const ssrPayload = getMatchingBridgeSSRResult(props.ssr, { + const ssrPayload = getMatchingBridgeSSRPayload(props.ssr, { moduleName: props.moduleName, instanceId: props.instanceId, - }) as BridgeSSRResult | undefined; + }); const instanceId = props.instanceId || ssrPayload?.instanceId; + const serverPayload = + ssrPayload && 'html' in ssrPayload + ? (ssrPayload as BridgeSSRResult) + : undefined; + const reference = + ssrPayload && !('html' in ssrPayload) + ? (ssrPayload as BridgeSSRReference) + : undefined; + const registry = useBridgeHydrationRegistry(); + const snapshot = + reference && instanceId + ? registry?.peek(reference.moduleName, instanceId) + : undefined; + const hasSSRPayload = Boolean((serverPayload || snapshot) && instanceId); const getBridgeRenderProps = () => ({ name: props.moduleName, @@ -71,7 +90,7 @@ export default defineComponent({ memoryRoute: props.memoryRoute, hashRoute: props.hashRoute, instanceId, - ssrState: ssrPayload?.dehydratedState, + ssrState: serverPayload?.dehydratedState ?? snapshot?.state, }; LoggerInstance.debug( `createRemoteAppComponent LazyComponent render >>>`, @@ -84,8 +103,14 @@ export default defineComponent({ )) || {}; renderProps = { ...renderProps, ...beforeBridgeRenderRes.extraProps }; - providerReturn.render(renderProps); + await providerReturn.render(renderProps); isRendered.value = true; + if (snapshot && instanceId) { + registry?.consume( + props.moduleName || reference!.moduleName, + instanceId, + ); + } hostInstance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit(renderProps); }; @@ -163,18 +188,42 @@ export default defineComponent({ destroyComponent(); }); - return () => ( -
    { + const mount = ( +
    + ); + if (!hasSSRPayload || !instanceId) return mount; + const moduleName = props.moduleName || ssrPayload!.moduleName; + return ( +
    + {mount} +
    ', @@ -105,4 +105,34 @@ describe('Bridge hydration registry', () => { createBridgeHydrationRegistry(document).peek('remote/app', 'remote-1'), ).toThrow(/incompatible state envelope/); }); + + it('allows the same instanceId across different module names', () => { + const second = { + ...result, + moduleName: 'other/app', + html: '

    other remote

    ', + }; + document.body.innerHTML = + renderToStaticMarkup( + , + ) + + renderToStaticMarkup( + , + ); + const registry = createBridgeHydrationRegistry(document); + expect(registry.peek('remote/app', 'remote-1')?.html).toBe( + '

    server remote

    ', + ); + expect(registry.peek('other/app', 'remote-1')?.html).toBe( + '

    other remote

    ', + ); + }); }); diff --git a/packages/bridge/bridge-react/src/provider/versions/bridge-server.tsx b/packages/bridge/bridge-react/src/provider/versions/bridge-server.tsx index ab3839cdcbb..58ad7d952a8 100644 --- a/packages/bridge/bridge-react/src/provider/versions/bridge-server.tsx +++ b/packages/bridge/bridge-react/src/provider/versions/bridge-server.tsx @@ -34,6 +34,7 @@ export function createServerBridgeComponent( const config = typeof bridgeInfo.ssr === 'object' ? bridgeInfo.ssr : undefined; const preparedValue = await config?.prepare?.(context); + if (context.signal.aborted) throw context.signal.reason; const prepared = (preparedValue || {}) as BridgeSSRPrepareResult; const renderInfo = (prepared.props ?? context.props) as T & ProviderParams; diff --git a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx index 45b07332dd8..047f99fc6a0 100644 --- a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx +++ b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx @@ -14,6 +14,7 @@ import { federationRuntime } from '../provider/plugin'; import { RemoteComponentProps, RemoteAppParams } from '../types'; import type { RemoteAppSSRProps } from '../types'; import { + BridgeSSRError, getMatchingBridgeSSRPayload, type BridgeSSRReference, type BridgeSSRResult, @@ -35,6 +36,25 @@ function scheduleBridgeDestroy(destroy: () => void) { else void Promise.resolve().then(destroy); } +function destroyProviderRoot( + provider: { destroy?: (info: { dom: HTMLElement }) => void } | null, + dom: HTMLElement | null, + destroyInfo: Record, +) { + if (!provider?.destroy || !dom) return; + try { + federationRuntime.instance?.bridgeHook?.lifecycle?.beforeBridgeDestroy?.emit( + destroyInfo, + ); + provider.destroy({ dom }); + federationRuntime.instance?.bridgeHook?.lifecycle?.afterBridgeDestroy?.emit( + destroyInfo, + ); + } catch (error) { + LoggerInstance.error('Bridge remote destroy failed', error); + } +} + export const RemoteAppWrapper = forwardRef(function ( props: RemoteAppParams & RemoteComponentProps & RemoteAppSSRProps, ref, @@ -66,6 +86,11 @@ export const RemoteAppWrapper = forwardRef(function ( ? (ssrPayload as BridgeSSRReference) : undefined; const registry = useBridgeHydrationRegistry(); + if (reference && !registry) { + throw new BridgeSSRError( + 'Bridge SSR references require BridgeHydrationProvider before hydrateRoot', + ); + } const hydrationSnapshotRef = useRef<{ identity: string; snapshot: ReturnType['peek']>; @@ -78,7 +103,7 @@ export const RemoteAppWrapper = forwardRef(function ( ) { hydrationSnapshotRef.current = { identity: hydrationIdentity, - snapshot: registry?.peek(reference!.moduleName, instanceId!), + snapshot: registry!.peek(reference!.moduleName, instanceId!), }; } const snapshot = hydrationIdentity @@ -132,17 +157,7 @@ export const RemoteAppWrapper = forwardRef(function ( ...resProps, }; scheduleBridgeDestroy(() => { - try { - instance?.bridgeHook?.lifecycle?.beforeBridgeDestroy?.emit( - destroyInfo, - ); - provider.destroy({ dom }); - instance?.bridgeHook?.lifecycle?.afterBridgeDestroy?.emit( - destroyInfo, - ); - } catch (error) { - LoggerInstance.error('Bridge remote destroy failed', error); - } + destroyProviderRoot(provider, dom, destroyInfo); }); }; }, [moduleName, providerInfo]); @@ -171,6 +186,21 @@ export const RemoteAppWrapper = forwardRef(function ( if (areRenderInputsEqual(lastRenderInputsRef.current, renderInputs)) return; lastRenderInputsRef.current = renderInputs; + const previousDom = renderDom.current; + if (previousDom && previousDom !== dom) { + // SSR slot <-> CSR mount transitions replace the ref target. Destroy the + // previous provider root before rendering into the new DOM node. + destroyProviderRoot(provider, previousDom, { + moduleName, + dom: previousDom, + basename, + memoryRoute, + fallback, + ...resProps, + }); + } + renderDom.current = dom; + const renderProps = { moduleName, dom, @@ -182,7 +212,6 @@ export const RemoteAppWrapper = forwardRef(function ( signal, ...resProps, }; - renderDom.current = dom; renderQueueRef.current = renderQueueRef.current .then(async () => { @@ -192,12 +221,16 @@ export const RemoteAppWrapper = forwardRef(function ( renderProps, ) || {}, )) as { extraProps?: Record }; + if (signal.aborted || !dom.isConnected) return; const currentRenderProps = { ...renderProps, ...beforeBridgeRenderRes.extraProps, }; await provider.render(currentRenderProps); - if (signal.aborted || !dom.isConnected) return; + if (signal.aborted || !dom.isConnected) { + provider.destroy?.({ dom }); + return; + } if ( snapshot && instanceId && diff --git a/packages/bridge/bridge-shared/src/renderRemoteBridge.ts b/packages/bridge/bridge-shared/src/renderRemoteBridge.ts index 556ad8ba6b8..4bab133046c 100644 --- a/packages/bridge/bridge-shared/src/renderRemoteBridge.ts +++ b/packages/bridge/bridge-shared/src/renderRemoteBridge.ts @@ -43,6 +43,13 @@ export async function renderRemoteBridge

    >( ); } + if (options.request.signal.aborted) { + throw new BridgeSSRError( + `Bridge SSR request for ${options.moduleName} was aborted`, + options.request.signal.reason, + ); + } + const exportName = options.export ?? 'default'; const factory = remoteModule[exportName]; if (typeof factory !== 'function') { diff --git a/packages/bridge/bridge-shared/src/ssr.spec.ts b/packages/bridge/bridge-shared/src/ssr.spec.ts index 18feaea2968..b26786a207f 100644 --- a/packages/bridge/bridge-shared/src/ssr.spec.ts +++ b/packages/bridge/bridge-shared/src/ssr.spec.ts @@ -25,6 +25,29 @@ describe('Bridge SSR V1 contract', () => { expect(() => assertBridgeJSONValue({ value: Number.NaN })).toThrow( /finite/, ); + expect(() => + assertBridgeJSONValue(JSON.parse('{"__proto__":{"polluted":true}}')), + ).toThrow(/__proto__/); + }); + + it('treats empty SSR markup as hydration-eligible when markers match', async () => { + const { hasBridgeSSRMarkup, getBridgeSSRContainerAttrs } = + await import('./ssr'); + const attrs = getBridgeSSRContainerAttrs({ + moduleName: 'remote/app', + instanceId: 'remote-1', + }); + const dom = { + getAttribute(name: string) { + return attrs[name] ?? null; + }, + } as HTMLElement; + expect( + hasBridgeSSRMarkup(dom, { + moduleName: 'remote/app', + instanceId: 'remote-1', + }), + ).toBe(true); }); it('validates host-carried results before matching their identity', () => { diff --git a/packages/bridge/bridge-shared/src/ssr.ts b/packages/bridge/bridge-shared/src/ssr.ts index 586f70659a6..9ec952d9759 100644 --- a/packages/bridge/bridge-shared/src/ssr.ts +++ b/packages/bridge/bridge-shared/src/ssr.ts @@ -77,6 +77,11 @@ function validateJSON( for (const [key, descriptor] of Object.entries( Object.getOwnPropertyDescriptors(value), )) { + if (key === '__proto__' || key === 'prototype' || key === 'constructor') { + throw new BridgeSSRError( + `Bridge SSR value at ${path} must not contain ${key}`, + ); + } if ( !descriptor.enumerable || !Object.prototype.hasOwnProperty.call(descriptor, 'value') @@ -287,6 +292,8 @@ export function hasBridgeSSRMarkup( dom: HTMLElement, value?: { moduleName?: string; instanceId?: string }, ) { + // Empty SSR output is still hydration-eligible: trust markers/identity, not + // child presence. Remotes may render null/empty fragments with state only. return ( dom.getAttribute(MF_BRIDGE_SSR_ATTR) === 'true' && dom.getAttribute(MF_BRIDGE_VERSION_ATTR) === @@ -294,8 +301,7 @@ export function hasBridgeSSRMarkup( (!value?.moduleName || dom.getAttribute(MF_BRIDGE_MODULE_ATTR) === value.moduleName) && (!value?.instanceId || - dom.getAttribute(MF_BRIDGE_INSTANCE_ATTR) === value.instanceId) && - dom.hasChildNodes() + dom.getAttribute(MF_BRIDGE_INSTANCE_ATTR) === value.instanceId) ); } @@ -324,16 +330,21 @@ function hydrationError(message: string, cause?: unknown) { return new BridgeSSRError(message, cause); } +function hydrationIdentityKey(moduleName: string, instanceId: string) { + return `${moduleName}\0${instanceId}`; +} + function readSlotSnapshot(slot: HTMLElement): BridgeHydrationSnapshot { - const protocolVersion = Number(slot.getAttribute(MF_BRIDGE_VERSION_ATTR)); + const versionAttr = slot.getAttribute(MF_BRIDGE_VERSION_ATTR); const moduleName = slot.getAttribute(MF_BRIDGE_MODULE_ATTR) || ''; const instanceId = slot.getAttribute(MF_BRIDGE_INSTANCE_ATTR) || ''; assertBridgeSSRIdentity({ moduleName, instanceId }); - if (protocolVersion !== BRIDGE_SSR_PROTOCOL_VERSION) { + if (versionAttr !== String(BRIDGE_SSR_PROTOCOL_VERSION)) { throw hydrationError( - `Bridge SSR slot ${instanceId} uses unsupported protocol version ${protocolVersion}`, + `Bridge SSR slot ${moduleName}:${instanceId} uses unsupported protocol version ${versionAttr}`, ); } + const protocolVersion = BRIDGE_SSR_PROTOCOL_VERSION; const mounts = directChildrenWithAttribute( slot, @@ -429,7 +440,7 @@ export function createBridgeHydrationRegistry( root ?? (typeof document === 'undefined' ? undefined : document); if (!hydrationRoot) { throw hydrationError( - 'createBridgeHydrationRegistry requires a document root on the server', + 'createBridgeHydrationRegistry requires a document root', ); } const snapshots = new Map(); @@ -440,55 +451,58 @@ export function createBridgeHydrationRegistry( `[${MF_BRIDGE_SLOT_ATTR}="true"]`, ), )) { + const moduleName = slot.getAttribute(MF_BRIDGE_MODULE_ATTR) || ''; const instanceId = slot.getAttribute(MF_BRIDGE_INSTANCE_ATTR) || ''; - if (snapshots.has(instanceId) || errors.has(instanceId)) { - snapshots.delete(instanceId); + const key = hydrationIdentityKey(moduleName, instanceId); + if (snapshots.has(key) || errors.has(key)) { + snapshots.delete(key); errors.set( - instanceId, - hydrationError(`Duplicate Bridge SSR instanceId ${instanceId}`), + key, + hydrationError( + `Duplicate Bridge SSR identity ${moduleName}:${instanceId}`, + ), ); continue; } try { const snapshot = readSlotSnapshot(slot); - snapshots.set(snapshot.instanceId, snapshot); + snapshots.set( + hydrationIdentityKey(snapshot.moduleName, snapshot.instanceId), + snapshot, + ); } catch (error) { errors.set( - instanceId, + key, error instanceof BridgeSSRError ? error : hydrationError( - `Unable to read Bridge SSR slot ${instanceId}`, + `Unable to read Bridge SSR slot ${moduleName}:${instanceId}`, error, ), ); } } + const peek = (moduleName: string, instanceId: string) => { + const key = hydrationIdentityKey(moduleName, instanceId); + const error = errors.get(key); + if (error) throw error; + return snapshots.get(key); + }; + return { - peek(moduleName, instanceId) { - const error = errors.get(instanceId); - if (error) throw error; - const snapshot = snapshots.get(instanceId); - if (!snapshot) return undefined; - if (snapshot.moduleName !== moduleName) { - throw hydrationError( - `Bridge SSR instance ${instanceId} belongs to ${snapshot.moduleName}, not ${moduleName}`, - ); - } - return snapshot; - }, + peek, consume(moduleName, instanceId) { - const snapshot = this.peek(moduleName, instanceId); - snapshots.delete(instanceId); - errors.delete(instanceId); + const key = hydrationIdentityKey(moduleName, instanceId); + const snapshot = peek(moduleName, instanceId); + snapshots.delete(key); + errors.delete(key); return snapshot; }, fail(moduleName, instanceId) { - const snapshot = snapshots.get(instanceId); - if (snapshot && snapshot.moduleName !== moduleName) return; - snapshots.delete(instanceId); - errors.delete(instanceId); + const key = hydrationIdentityKey(moduleName, instanceId); + snapshots.delete(key); + errors.delete(key); }, }; } diff --git a/packages/bridge/bridge-shared/src/type.ts b/packages/bridge/bridge-shared/src/type.ts index 65205b4ccba..4e1c86874ea 100644 --- a/packages/bridge/bridge-shared/src/type.ts +++ b/packages/bridge/bridge-shared/src/type.ts @@ -41,6 +41,7 @@ export type BridgeSSRResult = { protocolVersion: typeof BRIDGE_SSR_PROTOCOL_VERSION; moduleName: string; instanceId: string; + /** Trusted remote HTML. Remotes are treated as trusted HTML producers. */ html: string; dehydratedState?: BridgeJSONValue; }; diff --git a/packages/bridge/vue3-bridge/src/provider.spec.ts b/packages/bridge/vue3-bridge/src/provider.spec.ts index 3071d4540d2..0979d3afc28 100644 --- a/packages/bridge/vue3-bridge/src/provider.spec.ts +++ b/packages/bridge/vue3-bridge/src/provider.spec.ts @@ -149,4 +149,38 @@ describe('Vue Bridge server provider', () => { expect(dom.textContent).toBe('updated'); provider.destroy({ dom }); }); + + it('ignores apps created before an aborted client mount', async () => { + const controller = new AbortController(); + const provider = createBridgeComponentWithServerRenderer({ + rootComponent: defineComponent(() => () => h('p', 'remote')), + appOptions: () => { + queueMicrotask(() => controller.abort(new Error('cancelled'))); + return { + router: createRouter({ + history: createMemoryHistory(), + routes: [ + { + path: '/', + component: defineComponent(() => () => h('p')), + }, + ], + }), + }; + }, + })(); + const dom = document.createElement('div'); + document.body.appendChild(dom); + await expect( + provider.render({ + dom, + moduleName: 'vue/remote', + memoryRoute: { entryPath: '/' }, + signal: controller.signal, + }), + ).resolves.toBeUndefined(); + expect( + (dom as HTMLElement & { __vue_app__?: any }).__vue_app__, + ).toBeUndefined(); + }); }); diff --git a/packages/bridge/vue3-bridge/src/provider.ts b/packages/bridge/vue3-bridge/src/provider.ts index 8f33db17afa..2e68ac3e6f7 100644 --- a/packages/bridge/vue3-bridge/src/provider.ts +++ b/packages/bridge/vue3-bridge/src/provider.ts @@ -181,13 +181,22 @@ export function createBridgeComponentWithServerRenderer( roots.delete(dom); } const reactiveProps = Vue.shallowReactive(nextProps); - const { app } = await setupBridgeApp( - bridgeInfo, - { basename, memoryRoute, hashRoute, instanceId, signal }, - reactiveProps, - shouldHydrate ? 'hydrate' : 'csr', - ); - if (signal?.aborted) return; + let app: Vue.App | undefined; + try { + ({ app } = await setupBridgeApp( + bridgeInfo, + { basename, memoryRoute, hashRoute, instanceId, signal }, + reactiveProps, + shouldHydrate ? 'hydrate' : 'csr', + )); + } catch (error) { + if (signal?.aborted) return; + throw error; + } + if (signal?.aborted) { + // Never mounted: drop the request-local app without unmount warnings. + return; + } app.mount(dom, shouldHydrate); if (signal?.aborted || !dom.isConnected) { app.unmount(); @@ -211,6 +220,7 @@ export function createBridgeComponentWithServerRenderer( provider.renderServer = async (context) => { if (context.signal.aborted) throw context.signal.reason; const preparedValue = await config?.prepare?.(context); + if (context.signal.aborted) throw context.signal.reason; const prepared = (preparedValue || {}) as BridgeSSRPrepareResult< Record >; @@ -235,6 +245,7 @@ export function createBridgeComponentWithServerRenderer( applicationProps, 'ssr', ); + if (context.signal.aborted) throw context.signal.reason; const ssrContext: Record = {}; const html = await serverRenderer(app, ssrContext); if (context.signal.aborted) throw context.signal.reason; diff --git a/packages/bridge/vue3-bridge/src/remoteApp.tsx b/packages/bridge/vue3-bridge/src/remoteApp.tsx index e5b2094c044..7a3fc5e5451 100644 --- a/packages/bridge/vue3-bridge/src/remoteApp.tsx +++ b/packages/bridge/vue3-bridge/src/remoteApp.tsx @@ -69,14 +69,19 @@ export default defineComponent({ ? (ssrPayload as BridgeSSRReference) : undefined; const registry = useBridgeHydrationRegistry(); + if (reference && !registry) { + throw new Error( + 'Bridge SSR references require provideBridgeHydrationRegistry before mount', + ); + } const snapshot = reference && instanceId - ? registry?.peek(reference.moduleName, instanceId) + ? registry!.peek(reference.moduleName, instanceId) : undefined; const hasSSRPayload = Boolean((serverPayload || snapshot) && instanceId); const getBridgeRenderProps = () => ({ - name: props.moduleName, + moduleName: props.moduleName, dom: rootRef.value, basename: props.basename, memoryRoute: props.memoryRoute, @@ -128,9 +133,12 @@ export default defineComponent({ wasDeactivated.value || !dom.isConnected ) { - providerReturn.destroy?.({ dom }); + // Only destroy if this provider is still the active one. A newer + // providerInfo watch may already have destroyed and replaced it. if (providerInfoRef.value === providerReturn) { + providerReturn.destroy?.({ dom }); providerInfoRef.value = null; + isRendered.value = false; } return; } @@ -158,7 +166,9 @@ export default defineComponent({ const destroyComponent = () => { const providerReturn = providerInfoRef.value as any; - if (!providerReturn || !isRendered.value) { + // Destroy whenever a provider was obtained. A failed/aborted render may + // still have mounted an app before rejecting, so do not gate on isRendered. + if (!providerReturn) { return; } LoggerInstance.debug( From 90c2a5f92d3eb7fee37dd5ecd75f5e1f55ef9b61 Mon Sep 17 00:00:00 2001 From: Kevin Beier Date: Sat, 18 Jul 2026 22:42:44 +0200 Subject: [PATCH 23/32] fix(bridge): invalidate unconsumed SSR hydration snapshots Claim registry snapshots before provider.render and fail them on cancel so SPA revisits cannot hydrate stale request-time state. KeepAlive reactivation falls back to CSR, and demo hosts stop re-seeding SSR refs after navigation. Co-authored-by: Cursor --- .husky/commit-msg | 3 +- apps/bridge-ssr-demo/host-vue/src/App.vue | 15 +- .../host/src/lib/useHostSsrContext.ts | 24 +- .../bridge-react/src/hydration.spec.tsx | 9 + .../src/remote/RemoteAppWrapper.spec.tsx | 120 ++++++++++ .../src/remote/RemoteAppWrapper.tsx | 67 +++++- .../__tests__/remoteApp.ssr.test.ts | 221 ++++++++++++++++++ packages/bridge/vue3-bridge/src/remoteApp.tsx | 83 +++++-- 8 files changed, 508 insertions(+), 34 deletions(-) create mode 100644 packages/bridge/vue3-bridge/__tests__/remoteApp.ssr.test.ts diff --git a/.husky/commit-msg b/.husky/commit-msg index 693dbea0ca6..087d40d63ce 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,5 +1,4 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" - -pnpm run commitlint ${1} +pnpm run commitlint --edit "${1}" diff --git a/apps/bridge-ssr-demo/host-vue/src/App.vue b/apps/bridge-ssr-demo/host-vue/src/App.vue index aaa0d334d81..7df3e1cc223 100644 --- a/apps/bridge-ssr-demo/host-vue/src/App.vue +++ b/apps/bridge-ssr-demo/host-vue/src/App.vue @@ -1,5 +1,5 @@ diff --git a/apps/bridge-ssr-demo/host/src/lib/useHostSsrContext.ts b/apps/bridge-ssr-demo/host/src/lib/useHostSsrContext.ts index 89873221f46..14f955c61ed 100644 --- a/apps/bridge-ssr-demo/host/src/lib/useHostSsrContext.ts +++ b/apps/bridge-ssr-demo/host/src/lib/useHostSsrContext.ts @@ -1,4 +1,4 @@ -import { useMemo } from 'react'; +import { useMemo, useRef } from 'react'; import { useLocation } from 'react-router-dom'; import { readHostSSRContextFromDocument } from './hostSsrContext'; import { resolveHostSsrContextForLocation } from './remoteRoutes'; @@ -8,20 +8,36 @@ function getLocationUrl(pathname: string, search: string) { return `${pathname}${search}`; } +function seedPathname(context?: HostSSRContext) { + return context?.url?.split('?')[0]?.split('#')[0]; +} + /** * Nuxt-style SSR takeover: * - Direct visit / hard refresh: use SSR payload embedded in the document (or passed from server render). * - Client-side navigations: no document reload; remotes mount via federated CSR + bridge hydrate. + * + * After the user navigates away from the seeded path, never re-attach the + * document SSR reference — even if they return to the same URL. */ export function useHostSsrContext(initialContext?: HostSSRContext) { const location = useLocation(); const locationUrl = getLocationUrl(location.pathname, location.search); const documentContext = useMemo(() => readHostSSRContextFromDocument(), []); + const seedPathRef = useRef( + seedPathname(initialContext) ?? seedPathname(documentContext), + ); + const seedConsumedRef = useRef(false); + + if (seedPathRef.current && location.pathname !== seedPathRef.current) { + seedConsumedRef.current = true; + } - const seedContext = - initialContext?.url?.split('?')[0]?.split('#')[0] === location.pathname + const seedContext = seedConsumedRef.current + ? undefined + : seedPathname(initialContext) === location.pathname ? initialContext - : documentContext?.url?.split('?')[0]?.split('#')[0] === location.pathname + : seedPathname(documentContext) === location.pathname ? documentContext : undefined; diff --git a/packages/bridge/bridge-react/src/hydration.spec.tsx b/packages/bridge/bridge-react/src/hydration.spec.tsx index 4154aad18f8..d12b97a35a4 100644 --- a/packages/bridge/bridge-react/src/hydration.spec.tsx +++ b/packages/bridge/bridge-react/src/hydration.spec.tsx @@ -135,4 +135,13 @@ describe('Bridge hydration registry', () => { '

    other remote

    ', ); }); + + it('fail clears a peeked snapshot so later peeks miss', () => { + installSlot(); + const registry = createBridgeHydrationRegistry(document); + expect(registry.peek('remote/app', 'remote-1')).toBeDefined(); + registry.fail('remote/app', 'remote-1'); + expect(registry.peek('remote/app', 'remote-1')).toBeUndefined(); + expect(registry.consume('remote/app', 'remote-1')).toBeUndefined(); + }); }); diff --git a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.spec.tsx b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.spec.tsx index 9fa426e84ab..00795890271 100644 --- a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.spec.tsx +++ b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.spec.tsx @@ -2,8 +2,13 @@ import React, { createRef } from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; import { act, render, waitFor } from '@testing-library/react'; import { afterEach, describe, expect, it, rs } from '@rstest/core'; +import { + createBridgeHydrationRegistry, + toBridgeSSRReference, +} from '@module-federation/bridge-shared'; import { RemoteAppWrapper } from './RemoteAppWrapper'; import { ErrorBoundary } from '../error-boundary'; +import { BridgeHydrationProvider, BridgeRemoteSlot } from '../hydration'; const baseProps = { moduleName: 'remote/app', @@ -62,6 +67,7 @@ describe('RemoteAppWrapper SSR payload boundary', () => { describe('RemoteAppWrapper lifecycle', () => { afterEach(() => { rs.restoreAllMocks(); + document.body.innerHTML = ''; }); it('supports changing between object, callback, and absent forwarded refs', async () => { @@ -153,4 +159,118 @@ describe('RemoteAppWrapper lifecycle', () => { await act(async () => queued[0]()); expect(provider.destroy).toHaveBeenCalledOnce(); }); + + it('claims the registry snapshot before render and clears it on cancel', async () => { + const queued: Array<() => void> = []; + rs.spyOn(globalThis, 'queueMicrotask').mockImplementation((callback) => { + queued.push(callback as () => void); + }); + + const result = { + protocolVersion: 1 as const, + moduleName: 'remote/app', + instanceId: 'remote-1', + html: '

    server remote

    ', + dehydratedState: { ready: true }, + }; + document.body.innerHTML = renderToStaticMarkup( + , + ); + const registry = createBridgeHydrationRegistry(document); + let finishRender!: () => void; + const provider = { + render: rs.fn( + () => + new Promise((resolve) => { + finishRender = resolve; + }), + ), + destroy: rs.fn(), + }; + + const view = render( + + provider} + /> + , + ); + + await waitFor(() => expect(provider.render).toHaveBeenCalledOnce()); + expect(registry.peek('remote/app', 'remote-1')).toBeUndefined(); + expect( + (provider.render.mock.calls[0] as unknown as [{ ssrState?: unknown }])[0] + .ssrState, + ).toEqual({ ready: true }); + + view.unmount(); + finishRender(); + for (const task of queued.splice(0)) { + await act(async () => task()); + } + expect(registry.peek('remote/app', 'remote-1')).toBeUndefined(); + }); + + it('forces CSR when a second consumer loses the snapshot claim', async () => { + const result = { + protocolVersion: 1 as const, + moduleName: 'remote/app', + instanceId: 'remote-1', + html: '

    server remote

    ', + dehydratedState: { ready: true }, + }; + document.body.innerHTML = renderToStaticMarkup( + , + ); + const registry = createBridgeHydrationRegistry(document); + const first = { + render: rs.fn((info: { ssrState?: unknown }) => info), + destroy: rs.fn(), + }; + const second = { + render: rs.fn((info: { ssrState?: unknown }) => info), + destroy: rs.fn(), + }; + + render( + + first} + /> + second} + /> + , + ); + + await waitFor(() => expect(first.render).toHaveBeenCalledOnce()); + await waitFor(() => expect(second.render).toHaveBeenCalledOnce()); + + const states = [first, second].map((provider) => { + const call = provider.render.mock.calls[0] as unknown as [ + { ssrState?: { ready?: boolean } }, + ]; + return call[0].ssrState; + }); + expect(states.filter((state) => state?.ready === true)).toHaveLength(1); + expect(states.filter((state) => state === undefined)).toHaveLength(1); + }); }); diff --git a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx index 047f99fc6a0..0ce4293fae5 100644 --- a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx +++ b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx @@ -16,6 +16,11 @@ import type { RemoteAppSSRProps } from '../types'; import { BridgeSSRError, getMatchingBridgeSSRPayload, + MF_BRIDGE_INSTANCE_ATTR, + MF_BRIDGE_MODULE_ATTR, + MF_BRIDGE_MOUNT_ATTR, + MF_BRIDGE_SSR_ATTR, + MF_BRIDGE_VERSION_ATTR, type BridgeSSRReference, type BridgeSSRResult, } from '@module-federation/bridge-shared'; @@ -36,6 +41,14 @@ function scheduleBridgeDestroy(destroy: () => void) { else void Promise.resolve().then(destroy); } +function clearBridgeSSRMountAttrs(dom: HTMLElement) { + dom.removeAttribute(MF_BRIDGE_SSR_ATTR); + dom.removeAttribute(MF_BRIDGE_MOUNT_ATTR); + dom.removeAttribute(MF_BRIDGE_VERSION_ATTR); + dom.removeAttribute(MF_BRIDGE_MODULE_ATTR); + dom.removeAttribute(MF_BRIDGE_INSTANCE_ATTR); +} + function destroyProviderRoot( provider: { destroy?: (info: { dom: HTMLElement }) => void } | null, dom: HTMLElement | null, @@ -136,16 +149,26 @@ export const RemoteAppWrapper = forwardRef(function ( mountControllerRef.current = new AbortController(); setProviderReady(true); } catch (error) { - if (snapshot && instanceId) registry?.fail(moduleName, instanceId); + if (snapshot && instanceId) + registry?.fail(reference?.moduleName || moduleName, instanceId); setRenderError(error); } return () => { const provider = providerInfoRef.current; const dom = renderDom.current; + const releaseUnclaimedSnapshot = + Boolean(snapshot && instanceId) && + consumedIdentityRef.current !== hydrationIdentity; mountControllerRef.current?.abort(); providerInfoRef.current = null; mountControllerRef.current = null; + // Drop unclaimed snapshots synchronously so a fast SPA remount cannot + // peek the same identity. StrictMode remounts keep the peeked snapshot in + // this instance's ref and can still hydrate after a lost registry claim. + if (releaseUnclaimedSnapshot) { + registry?.fail(reference?.moduleName || moduleName, instanceId!); + } if (!provider?.destroy || !dom || destroyedRef.current) return; destroyedRef.current = true; const destroyInfo = { @@ -201,6 +224,30 @@ export const RemoteAppWrapper = forwardRef(function ( } renderDom.current = dom; + // Claim the registry snapshot before any await so a cancelled mount cannot + // leave it peekable for a later SPA visit. This instance may still hydrate + // from the peeked snapshot object after a StrictMode remount. + let ssrState = serverPayload?.dehydratedState; + if (snapshot && instanceId && registry) { + if (consumedIdentityRef.current !== hydrationIdentity) { + const claimed = registry.consume( + reference?.moduleName || moduleName, + instanceId, + ); + if (Object.is(claimed, snapshot)) { + consumedIdentityRef.current = hydrationIdentity; + ssrState = snapshot.state; + } else { + // Another consumer already claimed this identity — force CSR. + consumedIdentityRef.current = hydrationIdentity; + ssrState = undefined; + clearBridgeSSRMountAttrs(dom); + } + } else { + ssrState = snapshot.state; + } + } + const renderProps = { moduleName, dom, @@ -208,7 +255,7 @@ export const RemoteAppWrapper = forwardRef(function ( memoryRoute, fallback, instanceId, - ssrState: serverPayload?.dehydratedState ?? snapshot?.state, + ssrState, signal, ...resProps, }; @@ -231,22 +278,18 @@ export const RemoteAppWrapper = forwardRef(function ( provider.destroy?.({ dom }); return; } - if ( - snapshot && - instanceId && - consumedIdentityRef.current !== hydrationIdentity - ) { - registry?.consume(moduleName, instanceId); - consumedIdentityRef.current = hydrationIdentity; - } instance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit( currentRenderProps, ); }) .catch((error) => { if (signal.aborted) return; - if (snapshot && instanceId) { - registry?.fail(moduleName, instanceId); + if ( + snapshot && + instanceId && + consumedIdentityRef.current !== hydrationIdentity + ) { + registry?.fail(reference?.moduleName || moduleName, instanceId); } setRenderError(error); }); diff --git a/packages/bridge/vue3-bridge/__tests__/remoteApp.ssr.test.ts b/packages/bridge/vue3-bridge/__tests__/remoteApp.ssr.test.ts new file mode 100644 index 00000000000..7c7b5368351 --- /dev/null +++ b/packages/bridge/vue3-bridge/__tests__/remoteApp.ssr.test.ts @@ -0,0 +1,221 @@ +import { afterEach, beforeEach, describe, expect, it, rs } from '@rstest/core'; +import { createApp, defineComponent, h, KeepAlive, nextTick } from 'vue'; +import { createMemoryHistory, createRouter, RouterView } from 'vue-router'; +import { + BRIDGE_SSR_PROTOCOL_VERSION, + createBridgeHydrationRegistry, + MF_BRIDGE_SSR_ATTR, + toBridgeSSRReference, +} from '@module-federation/bridge-shared'; +import RemoteApp from '../src/remoteApp'; +import { provideBridgeHydrationRegistry } from '../src/hydration'; + +rs.mock('@module-federation/runtime', () => ({ + getInstance: () => ({ + bridgeHook: { + lifecycle: { + beforeBridgeRender: { emit: rs.fn(async () => ({})) }, + afterBridgeRender: { emit: rs.fn() }, + beforeBridgeDestroy: { emit: rs.fn() }, + afterBridgeDestroy: { emit: rs.fn() }, + }, + }, + }), +})); + +const flushBridgeRender = async () => { + await nextTick(); + await Promise.resolve(); + await nextTick(); +}; + +const installSlot = () => { + document.body.innerHTML = + '
    ' + + '

    server remote

    ' + + '' + + '
    '; +}; + +describe('RemoteApp SSR lifecycle', () => { + let root: HTMLDivElement; + + beforeEach(() => { + document.body.innerHTML = ''; + root = document.createElement('div'); + }); + + afterEach(() => { + document.body.innerHTML = ''; + }); + + const mountApp = (app: ReturnType) => { + document.body.appendChild(root); + app.mount(root); + }; + + it('claims the registry snapshot before provider render', async () => { + const result = { + protocolVersion: BRIDGE_SSR_PROTOCOL_VERSION, + moduleName: 'ecApp', + instanceId: 'ec:1', + html: '

    server remote

    ', + dehydratedState: { ready: true }, + }; + installSlot(); + const registry = createBridgeHydrationRegistry(document); + expect(registry.peek('ecApp', 'ec:1')).toBeDefined(); + + const providerReturn = { + render: rs.fn(), + destroy: rs.fn(), + }; + const App = defineComponent({ + setup: () => () => + h(RemoteApp, { + moduleName: 'ecApp', + instanceId: 'ec:1', + ssr: toBridgeSSRReference(result), + providerInfo: () => providerReturn, + }), + }); + const app = createApp(App); + provideBridgeHydrationRegistry(app, registry); + // RemoteApp calls useRoute(); give it a router even for the non-route case. + const router = createRouter({ + history: createMemoryHistory(), + routes: [{ path: '/', component: { template: '
    ' } }], + }); + app.use(router); + await router.isReady(); + mountApp(app); + await flushBridgeRender(); + + expect(providerReturn.render).toHaveBeenCalledTimes(1); + expect(providerReturn.render.mock.calls[0][0].ssrState).toEqual({ + ready: true, + }); + expect(registry.peek('ecApp', 'ec:1')).toBeUndefined(); + app.unmount(); + }); + + it('claims SSR once under KeepAlive and reactivates through CSR', async () => { + const result = { + protocolVersion: BRIDGE_SSR_PROTOCOL_VERSION, + moduleName: 'ecApp', + instanceId: 'ec:1', + html: '

    server remote

    ', + dehydratedState: { ready: true }, + }; + installSlot(); + const registry = createBridgeHydrationRegistry(document); + const providerReturn = { + render: rs.fn(), + destroy: rs.fn(), + }; + const RemoteRoute = defineComponent({ + setup() { + return () => + h(RemoteApp, { + moduleName: 'ecApp', + basename: '/ec', + instanceId: 'ec:1', + ssr: toBridgeSSRReference(result), + providerInfo: () => providerReturn, + }); + }, + }); + + const router = createRouter({ + history: createMemoryHistory(), + routes: [ + { path: '/', component: { template: '
    home
    ' } }, + { path: '/ec/:pathMatch(.*)*', component: RemoteRoute }, + ], + }); + + const App = defineComponent({ + setup() { + return () => + h(RouterView, null, { + default: ({ Component }) => + h(KeepAlive, null, () => (Component ? h(Component) : null)), + }); + }, + }); + + const app = createApp(App); + provideBridgeHydrationRegistry(app, registry); + app.use(router); + + await router.push('/ec'); + await router.isReady(); + mountApp(app); + await flushBridgeRender(); + + expect(providerReturn.render).toHaveBeenCalledTimes(1); + expect(providerReturn.render.mock.calls[0][0].ssrState).toEqual({ + ready: true, + }); + expect(registry.peek('ecApp', 'ec:1')).toBeUndefined(); + + await router.push('/'); + await flushBridgeRender(); + expect(providerReturn.destroy).toHaveBeenCalledTimes(1); + + await router.push('/ec'); + await flushBridgeRender(); + expect(providerReturn.render).toHaveBeenCalledTimes(2); + expect(providerReturn.render.mock.calls[1][0].ssrState).toBeUndefined(); + const remountDom = providerReturn.render.mock.calls[1][0] + .dom as HTMLElement; + expect(remountDom.getAttribute(MF_BRIDGE_SSR_ATTR)).toBeNull(); + + app.unmount(); + }); + + it('releases an unclaimed SSR snapshot when unmounted before render settles', async () => { + const result = { + protocolVersion: BRIDGE_SSR_PROTOCOL_VERSION, + moduleName: 'ecApp', + instanceId: 'ec:1', + html: '

    server remote

    ', + dehydratedState: { ready: true }, + }; + installSlot(); + const registry = createBridgeHydrationRegistry(document); + expect(registry.peek('ecApp', 'ec:1')).toBeDefined(); + + const providerReturn = { + render: rs.fn( + () => + new Promise(() => { + /* never settles */ + }), + ), + destroy: rs.fn(), + }; + const App = defineComponent({ + setup: () => () => + h(RemoteApp, { + moduleName: 'ecApp', + instanceId: 'ec:1', + ssr: toBridgeSSRReference(result), + providerInfo: () => providerReturn, + }), + }); + const app = createApp(App); + provideBridgeHydrationRegistry(app, registry); + const router = createRouter({ + history: createMemoryHistory(), + routes: [{ path: '/', component: { template: '
    ' } }], + }); + app.use(router); + await router.isReady(); + mountApp(app); + // Unmount before the render queue microtask claims the snapshot. + app.unmount(); + await flushBridgeRender(); + expect(registry.peek('ecApp', 'ec:1')).toBeUndefined(); + }); +}); diff --git a/packages/bridge/vue3-bridge/src/remoteApp.tsx b/packages/bridge/vue3-bridge/src/remoteApp.tsx index 7a3fc5e5451..63660c01c24 100644 --- a/packages/bridge/vue3-bridge/src/remoteApp.tsx +++ b/packages/bridge/vue3-bridge/src/remoteApp.tsx @@ -17,6 +17,11 @@ import { getBridgeSSRContainerAttrs, getBridgeSSRSlotAttrs, getMatchingBridgeSSRPayload, + MF_BRIDGE_INSTANCE_ATTR, + MF_BRIDGE_MODULE_ATTR, + MF_BRIDGE_MOUNT_ATTR, + MF_BRIDGE_SSR_ATTR, + MF_BRIDGE_VERSION_ATTR, serializeBridgeSSRStateEnvelope, type BridgeSSRReference, type BridgeSSRResult, @@ -26,6 +31,14 @@ import { LoggerInstance } from './utils'; import { getInstance } from '@module-federation/runtime'; import { useBridgeHydrationRegistry } from './hydration'; +function clearBridgeSSRMountAttrs(dom: HTMLElement) { + dom.removeAttribute(MF_BRIDGE_SSR_ATTR); + dom.removeAttribute(MF_BRIDGE_MOUNT_ATTR); + dom.removeAttribute(MF_BRIDGE_VERSION_ATTR); + dom.removeAttribute(MF_BRIDGE_MODULE_ATTR); + dom.removeAttribute(MF_BRIDGE_INSTANCE_ATTR); +} + export default defineComponent({ name: 'RemoteApp', props: { @@ -50,6 +63,8 @@ export default defineComponent({ const controller = new AbortController(); let renderQueue = Promise.resolve(); let consumedSnapshot = false; + let hydratedOnce = false; + let csrOnly = false; let providerGeneration = 0; const route = useRoute(); const hostInstance = getInstance(); @@ -79,6 +94,14 @@ export default defineComponent({ ? registry!.peek(reference.moduleName, instanceId) : undefined; const hasSSRPayload = Boolean((serverPayload || snapshot) && instanceId); + const registryModuleName = + props.moduleName || reference?.moduleName || ssrPayload?.moduleName || ''; + + const releaseUnclaimedSnapshot = () => { + if (!snapshot || !instanceId || consumedSnapshot || !registry) return; + registry.fail(registryModuleName, instanceId); + consumedSnapshot = true; + }; const getBridgeRenderProps = () => ({ moduleName: props.moduleName, @@ -103,6 +126,33 @@ export default defineComponent({ const providerReturn = providerInfoRef.value || props.providerInfo?.(); providerInfoRef.value = providerReturn; const wasRendered = isRendered.value; + + // Claim before any await so cancel cannot leave a peekable snapshot. + // After a claim (even if render aborts), never hydrate again — CSR only. + let ssrState = + wasRendered || hydratedOnce || consumedSnapshot + ? undefined + : serverPayload?.dehydratedState; + if ( + !wasRendered && + !hydratedOnce && + !consumedSnapshot && + snapshot && + instanceId && + registry + ) { + const claimed = registry.consume(registryModuleName, instanceId); + if (Object.is(claimed, snapshot)) { + consumedSnapshot = true; + ssrState = snapshot.state; + } else { + consumedSnapshot = true; + hydratedOnce = true; + ssrState = undefined; + clearBridgeSSRMountAttrs(dom); + } + } + let renderProps = { ...componentAttrs, moduleName: props.moduleName, @@ -111,9 +161,7 @@ export default defineComponent({ memoryRoute: props.memoryRoute, hashRoute: props.hashRoute, instanceId, - ssrState: wasRendered - ? undefined - : (serverPayload?.dehydratedState ?? snapshot?.state), + ssrState, signal: controller.signal, }; LoggerInstance.debug( @@ -143,12 +191,10 @@ export default defineComponent({ return; } isRendered.value = true; - if (!consumedSnapshot && snapshot && instanceId) { - registry?.consume( - props.moduleName || reference!.moduleName, - instanceId, - ); - consumedSnapshot = true; + // One-shot hydrate for this instance. Keep SSR markers in the DOM so + // hosts/tests can observe them; strip only on KeepAlive deactivate. + if (snapshot || serverPayload) { + hydratedOnce = true; } hostInstance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit( renderProps, @@ -156,8 +202,9 @@ export default defineComponent({ }); renderQueue = pending.catch((error) => { if (controller.signal.aborted || wasDeactivated.value) return; - if (snapshot && instanceId) { - registry?.fail(props.moduleName || reference!.moduleName, instanceId); + if (snapshot && instanceId && !consumedSnapshot) { + registry?.fail(registryModuleName, instanceId); + consumedSnapshot = true; } renderError.value = error; }); @@ -264,12 +311,18 @@ export default defineComponent({ onDeactivated(() => { isActive.value = false; wasDeactivated.value = true; + releaseUnclaimedSnapshot(); + if (consumedSnapshot) hydratedOnce = true; + csrOnly = true; + const dom = rootRef.value as HTMLElement | null; + if (dom) clearBridgeSSRMountAttrs(dom); destroyComponent(); }); onBeforeUnmount(() => { controller.abort(); watchStopHandle(); + releaseUnclaimedSnapshot(); destroyComponent(); }); @@ -278,17 +331,19 @@ export default defineComponent({ const mount = (
    ); - if (!hasSSRPayload || !instanceId) return mount; + if (!hasSSRPayload || !instanceId || csrOnly) return mount; const moduleName = props.moduleName || ssrPayload!.moduleName; return (
    From 7fee8603654f1b955b6c85b33e058fc42246e402 Mon Sep 17 00:00:00 2001 From: Kevin Beier Date: Tue, 11 Aug 2026 18:59:43 +0200 Subject: [PATCH 24/32] fix(bridge): destroy remote root once when render settles after unmount Guard the post-render abort path with destroyedRef so cleanup and the render queue cannot both call provider.destroy on the same DOM node. Co-authored-by: Cursor --- .github/workflows/e2e-bridge-ssr.yml | 4 +- .../src/remote/RemoteAppWrapper.spec.tsx | 29 + .../src/remote/RemoteAppWrapper.tsx | 5 +- pnpm-lock.yaml | 1977 +++++++++-------- 4 files changed, 1076 insertions(+), 939 deletions(-) diff --git a/.github/workflows/e2e-bridge-ssr.yml b/.github/workflows/e2e-bridge-ssr.yml index 9cb1a7a5595..f56f7631528 100644 --- a/.github/workflows/e2e-bridge-ssr.yml +++ b/.github/workflows/e2e-bridge-ssr.yml @@ -22,7 +22,7 @@ jobs: - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: - node-version: '20' + node-version: '24' cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm run build:packages @@ -38,7 +38,7 @@ jobs: - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: - node-version: '20' + node-version: '24' cache: pnpm - run: pnpm install --frozen-lockfile - run: pnpm run build:packages diff --git a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.spec.tsx b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.spec.tsx index 00795890271..8ce74ffe351 100644 --- a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.spec.tsx +++ b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.spec.tsx @@ -218,6 +218,35 @@ describe('RemoteAppWrapper lifecycle', () => { expect(registry.peek('remote/app', 'remote-1')).toBeUndefined(); }); + it('destroys provider only once when render settles after unmount', async () => { + const queued: Array<() => void> = []; + rs.spyOn(globalThis, 'queueMicrotask').mockImplementation((callback) => { + queued.push(callback as () => void); + }); + let finishRender!: () => void; + const provider = { + render: rs.fn( + () => + new Promise((resolve) => { + finishRender = resolve; + }), + ), + destroy: rs.fn(), + }; + + const view = render( + provider} />, + ); + await waitFor(() => expect(provider.render).toHaveBeenCalledOnce()); + + view.unmount(); + finishRender(); + for (const task of queued.splice(0)) { + await act(async () => task()); + } + expect(provider.destroy).toHaveBeenCalledOnce(); + }); + it('forces CSR when a second consumer loses the snapshot claim', async () => { const result = { protocolVersion: 1 as const, diff --git a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx index 0ce4293fae5..55eee7978b1 100644 --- a/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx +++ b/packages/bridge/bridge-react/src/remote/RemoteAppWrapper.tsx @@ -275,7 +275,10 @@ export const RemoteAppWrapper = forwardRef(function ( }; await provider.render(currentRenderProps); if (signal.aborted || !dom.isConnected) { - provider.destroy?.({ dom }); + if (!destroyedRef.current) { + destroyedRef.current = true; + provider.destroy?.({ dom }); + } return; } instance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a9703668c97..eb215d18590 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -406,7 +406,7 @@ importers: version: 4.2.3(typescript@6.0.3)(vite@7.3.5(@types/node@20.19.5)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)) vitest: specifier: 3.2.6 - version: 3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@20.19.5)(jiti@2.6.1)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) + version: 3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@20.19.5)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) vue-tsc: specifier: ^2.2.10 version: 2.2.12(typescript@6.0.3) @@ -549,6 +549,196 @@ importers: specifier: 5.104.1 version: 5.104.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(esbuild@0.28.1)(webpack-cli@5.1.4) + apps/bridge-ssr-demo/host: + dependencies: + '@module-federation/bridge-react': + specifier: workspace:* + version: link:../../../packages/bridge/bridge-react + '@module-federation/bridge-shared': + specifier: workspace:* + version: link:../../../packages/bridge/bridge-shared + '@module-federation/enhanced': + specifier: workspace:* + version: link:../../../packages/enhanced + express: + specifier: ^4.21.2 + version: 4.22.1 + react: + specifier: ~18.3.1 + version: 18.3.1 + react-dom: + specifier: ~18.3.1 + version: 18.3.1(react@18.3.1) + react-router-dom: + specifier: 6.30.2 + version: 6.30.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + vue: + specifier: ^3.5.30 + version: 3.5.30(typescript@5.0.4) + vue-router: + specifier: 4.4.5 + version: 4.4.5(vue@3.5.30(typescript@5.0.4)) + devDependencies: + '@module-federation/rsbuild-plugin': + specifier: workspace:* + version: link:../../../packages/rsbuild-plugin + '@playwright/test': + specifier: 1.57.0 + version: 1.57.0 + '@rsbuild/core': + specifier: 1.7.3 + version: 1.7.3 + '@rsbuild/plugin-react': + specifier: ^1.4.5 + version: 1.4.5(@rsbuild/core@1.7.3)(webpack-hot-middleware@2.26.1) + '@types/express': + specifier: ^4.17.21 + version: 4.17.21 + '@types/react': + specifier: ~18.2.0 + version: 18.2.79 + '@types/react-dom': + specifier: ~18.3.0 + version: 18.3.7(@types/react@18.2.79) + typescript: + specifier: ~5.0.4 + version: 5.0.4 + + apps/bridge-ssr-demo/host-vue: + dependencies: + '@module-federation/bridge-react': + specifier: workspace:* + version: link:../../../packages/bridge/bridge-react + '@module-federation/bridge-shared': + specifier: workspace:* + version: link:../../../packages/bridge/bridge-shared + '@module-federation/bridge-vue3': + specifier: workspace:* + version: link:../../../packages/bridge/vue3-bridge + '@module-federation/enhanced': + specifier: workspace:* + version: link:../../../packages/enhanced + '@module-federation/runtime': + specifier: workspace:* + version: link:../../../packages/runtime + '@vue/server-renderer': + specifier: ^3.5.30 + version: 3.5.30(vue@3.5.30(typescript@5.0.4)) + express: + specifier: ^4.21.2 + version: 4.22.1 + react: + specifier: 18.3.1 + version: 18.3.1 + react-dom: + specifier: 18.3.1 + version: 18.3.1(react@18.3.1) + vue: + specifier: ^3.5.30 + version: 3.5.30(typescript@5.0.4) + vue-router: + specifier: 4.4.5 + version: 4.4.5(vue@3.5.30(typescript@5.0.4)) + devDependencies: + '@module-federation/rsbuild-plugin': + specifier: workspace:* + version: link:../../../packages/rsbuild-plugin + '@playwright/test': + specifier: 1.57.0 + version: 1.57.0 + '@rsbuild/core': + specifier: 1.7.3 + version: 1.7.3 + '@rsbuild/plugin-vue': + specifier: ^1.2.6 + version: 1.2.9(@rsbuild/core@1.7.3)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(vue@3.5.30(typescript@5.0.4)) + typescript: + specifier: ~5.0.4 + version: 5.0.4 + + apps/bridge-ssr-demo/remote-react: + dependencies: + '@module-federation/bridge-react': + specifier: workspace:* + version: link:../../../packages/bridge/bridge-react + react: + specifier: ~18.3.1 + version: 18.3.1 + react-dom: + specifier: ~18.3.1 + version: 18.3.1(react@18.3.1) + react-router-dom: + specifier: 6.30.2 + version: 6.30.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + devDependencies: + '@module-federation/rsbuild-plugin': + specifier: workspace:* + version: link:../../../packages/rsbuild-plugin + '@rsbuild/core': + specifier: 1.7.3 + version: 1.7.3 + '@rsbuild/plugin-react': + specifier: ^1.4.5 + version: 1.4.5(@rsbuild/core@1.7.3)(webpack-hot-middleware@2.26.1) + '@types/react': + specifier: ~18.2.0 + version: 18.2.79 + '@types/react-dom': + specifier: ~18.3.0 + version: 18.3.7(@types/react@18.2.79) + typescript: + specifier: ~5.0.4 + version: 5.0.4 + + apps/bridge-ssr-demo/remote-vue: + dependencies: + '@module-federation/bridge-vue3': + specifier: workspace:* + version: link:../../../packages/bridge/vue3-bridge + '@vue/server-renderer': + specifier: ^3.5.30 + version: 3.5.30(vue@3.5.30(typescript@5.0.4)) + vue: + specifier: ^3.5.30 + version: 3.5.30(typescript@5.0.4) + vue-router: + specifier: 4.4.5 + version: 4.4.5(vue@3.5.30(typescript@5.0.4)) + devDependencies: + '@module-federation/rsbuild-plugin': + specifier: workspace:* + version: link:../../../packages/rsbuild-plugin + '@module-federation/vite': + specifier: 1.16.16 + version: 1.16.16(typescript@5.0.4)(vite@5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0))(vue-tsc@2.2.12(typescript@5.0.4)) + '@rsbuild/core': + specifier: 1.7.3 + version: 1.7.3 + '@rsbuild/plugin-vue': + specifier: ^1.2.6 + version: 1.2.9(@rsbuild/core@1.7.3)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(vue@3.5.30(typescript@5.0.4)) + '@vitejs/plugin-vue': + specifier: ^5.0.4 + version: 5.2.4(vite@5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0))(vue@3.5.30(typescript@5.0.4)) + typescript: + specifier: ~5.0.4 + version: 5.0.4 + vite: + specifier: ^5.4.21 + version: 5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) + + apps/bridge-ssr-demo/shared: + dependencies: + '@module-federation/bridge-shared': + specifier: workspace:* + version: link:../../../packages/bridge/bridge-shared + '@rsbuild/core': + specifier: 1.7.3 + version: 1.7.3 + express: + specifier: ^4.21.2 + version: 4.22.1 + apps/bundle-size: dependencies: antd: @@ -1091,7 +1281,7 @@ importers: version: 7.28.2 '@modern-js/runtime': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@module-federation/modern-js-v3': specifier: workspace:* version: link:../../../packages/modernjs-v3 @@ -1110,7 +1300,7 @@ importers: version: 2.59.0(typescript@7.0.2) '@modern-js/app-tools': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) '@modern-js/eslint-config': specifier: 2.59.0 version: 2.59.0(typescript@7.0.2) @@ -1152,7 +1342,7 @@ importers: version: 7.28.2 '@modern-js/runtime': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@module-federation/modern-js-v3': specifier: workspace:* version: link:../../../packages/modernjs-v3 @@ -1171,7 +1361,7 @@ importers: version: 2.59.0(typescript@7.0.2) '@modern-js/app-tools': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) '@modern-js/eslint-config': specifier: 2.59.0 version: 2.59.0(typescript@7.0.2) @@ -1249,7 +1439,7 @@ importers: version: 7.28.2 '@modern-js/runtime': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@module-federation/modern-js-v3': specifier: workspace:* version: link:../../../packages/modernjs-v3 @@ -1268,7 +1458,7 @@ importers: version: 2.59.0(typescript@7.0.2) '@modern-js/app-tools': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) '@modern-js/eslint-config': specifier: 2.59.0 version: 2.59.0(typescript@7.0.2) @@ -1341,7 +1531,7 @@ importers: version: 7.28.2 '@modern-js/runtime': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@module-federation/modern-js-v3': specifier: workspace:* version: link:../../../packages/modernjs-v3 @@ -1360,7 +1550,7 @@ importers: version: 2.59.0(typescript@7.0.2) '@modern-js/app-tools': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) '@modern-js/eslint-config': specifier: 2.59.0 version: 2.59.0(typescript@7.0.2) @@ -1402,7 +1592,7 @@ importers: version: 7.28.2 '@modern-js/runtime': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@module-federation/modern-js-v3': specifier: workspace:* version: link:../../../packages/modernjs-v3 @@ -1421,7 +1611,7 @@ importers: version: 2.59.0(typescript@7.0.2) '@modern-js/app-tools': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) '@modern-js/eslint-config': specifier: 2.59.0 version: 2.59.0(typescript@7.0.2) @@ -1463,7 +1653,7 @@ importers: version: 7.28.2 '@modern-js/runtime': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@module-federation/modern-js-v3': specifier: workspace:* version: link:../../../packages/modernjs-v3 @@ -1482,7 +1672,7 @@ importers: version: 2.59.0(typescript@7.0.2) '@modern-js/app-tools': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) '@modern-js/eslint-config': specifier: 2.59.0 version: 2.59.0(typescript@7.0.2) @@ -1524,7 +1714,7 @@ importers: version: 7.28.2 '@modern-js/runtime': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@module-federation/modern-js-v3': specifier: workspace:* version: link:../../../packages/modernjs-v3 @@ -1543,7 +1733,7 @@ importers: version: 2.59.0(typescript@7.0.2) '@modern-js/app-tools': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) '@modern-js/eslint-config': specifier: 2.59.0 version: 2.59.0(typescript@7.0.2) @@ -1585,7 +1775,7 @@ importers: version: 7.28.2 '@modern-js/runtime': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@module-federation/modern-js-v3': specifier: workspace:* version: link:../../../packages/modernjs-v3 @@ -1604,7 +1794,7 @@ importers: version: 2.59.0(typescript@7.0.2) '@modern-js/app-tools': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) '@modern-js/eslint-config': specifier: 2.59.0 version: 2.59.0(typescript@7.0.2) @@ -2066,7 +2256,7 @@ importers: version: 18.3.7(@types/react@18.3.28) tailwindcss: specifier: ^3.4.3 - version: 3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@5.9.3)) + version: 3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@26.2.0)(typescript@5.9.3)) typescript: specifier: ^5.4.5 version: 5.9.3 @@ -2115,7 +2305,7 @@ importers: version: 18.3.7(@types/react@18.3.28) tailwindcss: specifier: ^3.4.3 - version: 3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2)) + version: 3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@26.2.0)(typescript@7.0.2)) typescript: specifier: 7.0.2 version: 7.0.2 @@ -2146,7 +2336,7 @@ importers: version: 2.0.1(@rsbuild/core@2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(vue@3.5.30(typescript@7.0.2)) tailwindcss: specifier: ^3.4.3 - version: 3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2)) + version: 3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@26.2.0)(typescript@7.0.2)) typescript: specifier: 7.0.2 version: 7.0.2 @@ -2266,7 +2456,7 @@ importers: version: 0.5.1 tailwindcss: specifier: ^3.4.3 - version: 3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2)) + version: 3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@26.2.0)(typescript@7.0.2)) typescript: specifier: 7.0.2 version: 7.0.2 @@ -2413,7 +2603,7 @@ importers: version: 2.1.0(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23)) '@rslib/core': specifier: ^0.23.2 - version: 0.23.2(@microsoft/api-extractor@7.57.7(@types/node@26.2.0))(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(typescript@6.0.3) + version: 0.23.2(@microsoft/api-extractor@7.57.7(@types/node@26.2.0))(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(typescript@7.0.2) '@types/react': specifier: ^18.3.11 version: 18.3.28 @@ -2431,10 +2621,10 @@ importers: version: 8.6.17(prettier@3.8.1) storybook-addon-rslib: specifier: ^1.0.1 - version: 1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rslib/core@0.23.2(@microsoft/api-extractor@7.57.7(@types/node@26.2.0))(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(typescript@6.0.3))(storybook-builder-rsbuild@1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/react@18.3.28)(storybook@8.6.17(prettier@3.8.1))(tslib@2.8.1)(typescript@6.0.3))(typescript@6.0.3) + version: 1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rslib/core@0.23.2(@microsoft/api-extractor@7.57.7(@types/node@26.2.0))(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(typescript@7.0.2))(storybook-builder-rsbuild@1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/react@18.3.28)(storybook@8.6.17(prettier@3.8.1))(tslib@2.8.1)(typescript@7.0.2))(typescript@7.0.2) storybook-react-rsbuild: specifier: ^1.0.1 - version: 1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(storybook@8.6.17(prettier@3.8.1))(tslib@2.8.1)(typescript@6.0.3)(webpack@5.104.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(esbuild@0.25.5)(webpack-cli@5.1.4)) + version: 1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(storybook@8.6.17(prettier@3.8.1))(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(esbuild@0.25.5)(webpack-cli@5.1.4)) apps/rstest-federation-host: devDependencies: @@ -2696,7 +2886,7 @@ importers: version: 7.28.2 '@modern-js/runtime': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@module-federation/enhanced': specifier: workspace:* version: link:../../../../packages/enhanced @@ -2715,7 +2905,7 @@ importers: version: 2.59.0(typescript@7.0.2) '@modern-js/app-tools': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@3.14.2)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@3.14.2)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) '@modern-js/plugin-server': specifier: 2.68.0 version: 2.68.0(@babel/traverse@7.29.8)(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -2766,7 +2956,7 @@ importers: version: 7.28.2 '@modern-js/runtime': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@module-federation/enhanced': specifier: workspace:* version: link:../../../../packages/enhanced @@ -2785,7 +2975,7 @@ importers: version: 2.59.0(typescript@7.0.2) '@modern-js/app-tools': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) '@modern-js/eslint-config': specifier: 2.59.0 version: 2.59.0(typescript@7.0.2) @@ -2833,7 +3023,7 @@ importers: version: 7.28.2 '@modern-js/runtime': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@module-federation/modern-js-v3': specifier: workspace:* version: link:../../../../packages/modernjs-v3 @@ -2852,7 +3042,7 @@ importers: version: 2.59.0(typescript@7.0.2) '@modern-js/app-tools': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@3.14.2)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@3.14.2)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) '@modern-js/eslint-config': specifier: 2.59.0 version: 2.59.0(typescript@7.0.2) @@ -2909,7 +3099,7 @@ importers: version: 7.28.2 '@modern-js/runtime': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@module-federation/modern-js-v3': specifier: workspace:* version: link:../../../../packages/modernjs-v3 @@ -2928,7 +3118,7 @@ importers: version: 2.59.0(typescript@7.0.2) '@modern-js/app-tools': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) '@modern-js/eslint-config': specifier: 2.59.0 version: 2.59.0(typescript@7.0.2) @@ -2979,10 +3169,10 @@ importers: version: link:../../packages/runtime '@rsbuild/plugin-sass': specifier: ^2.0.1 - version: 2.0.1(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1)) + version: 2.0.1(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) '@rspress/core': specifier: 2.0.14 - version: 2.0.14(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(@types/mdast@4.0.4)(@types/react@19.2.14)(core-js@3.36.1)(micromark-util-types@2.0.2)(micromark@4.0.2) + version: 2.0.14(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/mdast@4.0.4)(@types/react@19.2.14)(core-js@3.49.0)(micromark-util-types@2.0.2)(micromark@4.0.2) framer-motion: specifier: ^10.0.0 version: 10.18.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -2997,10 +3187,10 @@ importers: version: 7.15.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) tailwindcss: specifier: ^3.2.7 - version: 3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@6.0.3)) + version: 3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2)) xgplayer: specifier: ^3.0.16 - version: 3.0.23(core-js@3.36.1) + version: 3.0.23(core-js@3.49.0) devDependencies: '@types/node': specifier: ^20.19.5 @@ -3013,7 +3203,7 @@ importers: version: 19.2.3(@types/react@19.2.14) zephyr-rspress-plugin: specifier: ^1.1.2 - version: 1.1.2(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1))(@rspack/core@1.3.9(@swc/helpers@0.5.23))(@rspress/core@2.0.14(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(@types/mdast@4.0.4)(@types/react@19.2.14)(core-js@3.36.1)(micromark-util-types@2.0.2)(micromark@4.0.2))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) + version: 1.1.2(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@rspress/core@2.0.14(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/mdast@4.0.4)(@types/react@19.2.14)(core-js@3.49.0)(micromark-util-types@2.0.2)(micromark@4.0.2))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) packages/assemble-release-plan: dependencies: @@ -3082,6 +3272,9 @@ importers: hono: specifier: 4.12.34 version: 4.12.34 + jsdom: + specifier: 20.0.3 + version: 20.0.3 react: specifier: 18.3.1 version: 18.3.1 @@ -3134,6 +3327,9 @@ importers: vite: specifier: ^5.4.21 version: 5.4.21(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) + vitest: + specifier: 1.6.0 + version: 1.6.0(@edge-runtime/vm@3.2.0)(@types/node@20.19.5)(jsdom@20.0.3)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) vue-tsc: specifier: ^2.0.6 version: 2.2.12(typescript@7.0.2) @@ -3165,6 +3361,9 @@ importers: '@vitejs/plugin-vue-jsx': specifier: ^4.0.0 version: 4.2.0(vite@5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0))(vue@3.5.30(typescript@7.0.2)) + '@vue/server-renderer': + specifier: ^3.5.30 + version: 3.5.30(vue@3.5.30(typescript@7.0.2)) typescript: specifier: 7.0.2 version: 7.0.2 @@ -3279,7 +3478,7 @@ importers: version: 7.0.2 vitest: specifier: 3.2.6 - version: 3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@20.19.5)(jiti@2.6.1)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) + version: 3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@20.19.5)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) packages/cli: dependencies: @@ -3341,7 +3540,7 @@ importers: version: 1.2.5 rsbuild-plugin-publint: specifier: ^0.2.1 - version: 0.2.1(@rsbuild/core@2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) + version: 0.2.1(@rsbuild/core@1.7.3) packages/dts-plugin: dependencies: @@ -3725,10 +3924,10 @@ importers: devDependencies: '@modern-js/app-tools': specifier: 2.70.5 - version: 2.70.5(@rspack/core@1.7.9(@swc/helpers@0.5.17))(@swc/core@1.15.41(@swc/helpers@0.5.17))(encoding@0.1.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(styled-components@6.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(type-fest@2.19.0)(typescript@7.0.2)(webpack-cli@5.1.4)(webpack-dev-server@5.2.3(webpack-cli@5.1.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.25.5)(webpack-cli@5.1.4)))(webpack-hot-middleware@2.26.1) + version: 2.70.5(@rspack/core@1.7.9(@swc/helpers@0.5.17))(@swc/core@1.15.41(@swc/helpers@0.5.17))(encoding@0.1.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(styled-components@6.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@26.2.0)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(type-fest@2.19.0)(typescript@7.0.2)(webpack-cli@5.1.4)(webpack-dev-server@5.2.3(webpack-cli@5.1.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.25.5)(webpack-cli@5.1.4)))(webpack-hot-middleware@2.26.1) '@modern-js/module-tools': specifier: 2.70.5 - version: 2.70.5(@types/node@20.19.5)(typescript@7.0.2) + version: 2.70.5(@types/node@26.2.0)(typescript@7.0.2) '@modern-js/runtime': specifier: 2.70.5 version: 2.70.5(react-dom@19.2.7(react@19.2.7))(react-server-dom-webpack@19.2.4(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.25.5)(webpack-cli@5.1.4)))(react@19.2.7) @@ -3746,7 +3945,7 @@ importers: version: 1.4.5(@rsbuild/core@1.3.21)(webpack-hot-middleware@2.26.1) '@rslib/core': specifier: 0.23.2 - version: 0.23.2(@microsoft/api-extractor@7.57.7(@types/node@20.19.5))(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(typescript@7.0.2) + version: 0.23.2(@microsoft/api-extractor@7.57.7(@types/node@26.2.0))(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(typescript@7.0.2) '@rstest/core': specifier: ^0.10.6 version: 0.10.6(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(jsdom@20.0.3) @@ -3801,10 +4000,10 @@ importers: devDependencies: '@modern-js/app-tools': specifier: 3.5.0 - version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4)) + version: 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@26.2.0)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4)) '@modern-js/module-tools': specifier: 2.70.5 - version: 2.70.5(@types/node@20.19.5)(typescript@7.0.2) + version: 2.70.5(@types/node@26.2.0)(typescript@7.0.2) '@modern-js/runtime': specifier: 3.5.0 version: 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) @@ -3822,7 +4021,7 @@ importers: version: 1.4.5(@rsbuild/core@2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(webpack-hot-middleware@2.26.1) '@rslib/core': specifier: 0.23.2 - version: 0.23.2(@microsoft/api-extractor@7.57.7(@types/node@20.19.5))(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(typescript@7.0.2) + version: 0.23.2(@microsoft/api-extractor@7.57.7(@types/node@26.2.0))(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(typescript@7.0.2) '@rspack/core': specifier: 2.0.6 version: 2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17) @@ -4253,7 +4452,7 @@ importers: version: link:../sdk '@nx/react': specifier: '>= 16.0.0' - version: 22.5.4(@babel/core@7.29.7)(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(@swc/helpers@0.5.23)(@types/babel__core@7.20.5)(@zkochan/js-yaml@0.0.7)(esbuild@0.25.5)(eslint@9.39.3(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23)))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)(vite@7.3.5(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))(vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jiti@2.6.1)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))(vue-tsc@2.2.12(typescript@7.0.2))(webpack-cli@5.1.4) + version: 22.5.4(@babel/core@7.29.7)(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(@swc/helpers@0.5.23)(@types/babel__core@7.20.5)(@zkochan/js-yaml@0.0.7)(esbuild@0.25.5)(eslint@9.39.3(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23)))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)(vite@7.3.6(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))(vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0))(vue-tsc@2.2.12(typescript@7.0.2))(webpack-cli@5.1.4) '@nx/webpack': specifier: '>= 16.0.0' version: 22.5.4(@babel/traverse@7.29.8)(@rspack/core@1.6.8(@swc/helpers@0.5.23))(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.25.5)(html-webpack-plugin@5.6.6(@rspack/core@1.6.8(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.25.5)(webpack-cli@5.1.4)))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23)))(typescript@7.0.2)(vue-template-compiler@2.7.16)(webpack-cli@5.1.4) @@ -4269,7 +4468,7 @@ importers: version: 22.5.4(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(@swc/helpers@0.5.23)(esbuild@0.25.5)(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23)))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)(vue-tsc@2.2.12(typescript@7.0.2))(webpack-cli@5.1.4) '@rsbuild/core': specifier: 2.1.4 - version: 2.1.4(@module-federation/runtime-tools@2.2.2(node-fetch@2.7.0(encoding@0.1.13)))(core-js@3.49.0) + version: 2.1.4(@module-federation/runtime-tools@0.21.6)(core-js@3.49.0) '@storybook/core': specifier: ^8.4.6 version: 8.6.14(prettier@3.8.1)(storybook@8.6.17(prettier@3.8.1)) @@ -4788,56 +4987,48 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@ast-grep/napi-linux-arm64-gnu@0.37.0': resolution: {integrity: sha512-L7Sj0lXy8X+BqSMgr1LB8cCoWk0rericdeu+dC8/c8zpsav5Oo2IQKY1PmiZ7H8IHoFBbURLf8iklY9wsD+cyA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@ast-grep/napi-linux-arm64-musl@0.35.0': resolution: {integrity: sha512-1EcvHPwyWpCL/96LuItBYGfeI5FaMTRvL+dHbO/hL5q1npqbb5qn+ppJwtNOjTPz8tayvgggxVk9T4C2O7taYA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@ast-grep/napi-linux-arm64-musl@0.37.0': resolution: {integrity: sha512-LF9sAvYy6es/OdyJDO3RwkX3I82Vkfsng1sqUBcoWC1jVb1wX5YVzHtpQox9JrEhGl+bNp7FYxB4Qba9OdA5GA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@ast-grep/napi-linux-x64-gnu@0.35.0': resolution: {integrity: sha512-FDzNdlqmQnsiWXhnLxusw5AOfEcEM+5xtmrnAf3SBRFr86JyWD9qsynnFYC2pnP9hlMfifNH2TTmMpyGJW49Xw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@ast-grep/napi-linux-x64-gnu@0.37.0': resolution: {integrity: sha512-TViz5/klqre6aSmJzswEIjApnGjJzstG/SE8VDWsrftMBMYt2PTu3MeluZVwzSqDao8doT/P+6U11dU05UOgxw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@ast-grep/napi-linux-x64-musl@0.35.0': resolution: {integrity: sha512-wlmndjfBafT8u5p4DBnoRQyoCSGNuVSz7rT3TqhvlHcPzUouRWMn95epU9B1LNLyjXvr9xHeRjSktyCN28w57Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@ast-grep/napi-linux-x64-musl@0.37.0': resolution: {integrity: sha512-/BcCH33S9E3ovOAEoxYngUNXgb+JLg991sdyiNP2bSoYd30a9RHrG7CYwW6fMgua3ijQ474eV6cq9yZO1bCpXg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@ast-grep/napi-win32-arm64-msvc@0.35.0': resolution: {integrity: sha512-gkhJeYc4rrZLX2icLxalPikTLMR57DuIYLwLr9g+StHYXIsGHrbfrE6Nnbdd8Izfs34ArFCrcwdaMrGlvOPSeg==} @@ -5853,28 +6044,24 @@ packages: engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - libc: [musl] '@biomejs/cli-linux-arm64@2.4.7': resolution: {integrity: sha512-om6FugwmibzfP/6ALj5WRDVSND4H2G9X0nkI1HZpp2ySf9lW2j0X68oQSaHEnls6666oy4KDsc5RFjT4m0kV0w==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - libc: [glibc] '@biomejs/cli-linux-x64-musl@2.4.7': resolution: {integrity: sha512-00kx4YrBMU8374zd2wHuRV5wseh0rom5HqRND+vDldJPrWwQw+mzd/d8byI9hPx926CG+vWzq6AeiT7Yi5y59g==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - libc: [musl] '@biomejs/cli-linux-x64@2.4.7': resolution: {integrity: sha512-bV8/uo2Tj+gumnk4sUdkerWyCPRabaZdv88IpbmDWARQQoA/Q0YaqPz1a+LSEDIL7OfrnPi9Hq1Llz4ZIGyIQQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - libc: [glibc] '@biomejs/cli-win32-arm64@2.4.7': resolution: {integrity: sha512-hOUHBMlFCvDhu3WCq6vaBoG0dp0LkWxSEnEEsxxXvOa9TfT6ZBnbh72A/xBM7CBYB7WgwqboetzFEVDnMxelyw==} @@ -6194,9 +6381,6 @@ packages: '@emnapi/core@1.11.3': resolution: {integrity: sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==} - '@emnapi/core@1.9.0': - resolution: {integrity: sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==} - '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} @@ -6206,12 +6390,6 @@ packages: '@emnapi/runtime@1.11.3': resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} - '@emnapi/runtime@1.9.0': - resolution: {integrity: sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==} - - '@emnapi/wasi-threads@1.2.0': - resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} - '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} @@ -7570,209 +7748,177 @@ packages: resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm64@1.3.0': resolution: {integrity: sha512-C0SqjoFKnszqa44EQ7xoaT48nnO0lOyXEULfXMWi8krrjOPGYkeK30Okzla6ATbBYsyZ0ySinK0FVkpv3DwzfQ==} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.3.0': resolution: {integrity: sha512-A8UpHoUDW4DwnXoV6+q3C1s7QLRAHtPDEjWuNZjwHMyoCNZnm0GeNN8ls9f/bsEYTRQRW96C/n34XJQHJ2fT7A==} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.3.0': resolution: {integrity: sha512-WOpkVxAjFd369iaIzEgNRreFD+gWdUMIGD5zplhNKNeqS6mm5dac3q2AFyCBmzYoAdouzZvRBgxy4z8QHZb4/A==} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.3.0': resolution: {integrity: sha512-DRWw0mOHusrCCuw2rqP87oLg6PGlkomVDFqw2hIwsSfwWpu4k3XLcBPaKKl6ct/GtL/cwNkgwjV/tc0Mqht3VA==} cpu: [riscv64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.3.0': resolution: {integrity: sha512-9APy+nFWhHS+kzLgWZfLcyrUd7YqnAQVa4BPOo4xkoHpdoktOAPG4cEr9+Jpl0TtqfVmcMJimNL5qNTyyOHZNA==} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.3.0': resolution: {integrity: sha512-y9RNUYDe2A1UAdhLyfeOodGRszQdaEoe4nfOpp/sNVPl2CWIcUyFaDoCh4vPLPxu19803j2naLqZup2WxDXCLA==} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-arm64@1.3.0': resolution: {integrity: sha512-cC1wkC0Mlucd0KSiGrLkJnB/ZqPvZCntc/Lk7ZnYO5ZSbF2euNek4Xvxafojq+wN1q/W0eprdpUIjUr/EV2PBg==} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.3.0': resolution: {integrity: sha512-LiYMhUZicB1QG//+RvmYZpXJO8fYRENfp+MZUCnG9aw+AKvGAy9gPaCnuwsPcBFs8EV66M0NNxj9VHcNklE8zw==} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm64@0.35.0': resolution: {integrity: sha512-4+4XHLNT5wDT0roYlHTEmH9lDKt0acf9Tv+3hM3iceOirkxrR404/3WjAYZ9F9CkHrxeRcGLJXbi4vluMZ9O+A==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.35.0': resolution: {integrity: sha512-VVlpEWwizEFIOom0zdoeKuO5nuTswzVE5uHcBNvHzmeHUpNFajY3HFfbQ+zIH4E2kVaZ/yVxmsShW56TtEy4uA==} engines: {node: '>=20.9.0'} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-linux-ppc64@0.35.0': resolution: {integrity: sha512-N3hzbEpUTJC8pWpPVJvgzGxM+so/MAXc8O2s/53B0LL9ZGpfXpME7Wizkc5d/8fRBlBtkDjzoZGDCqqNDHqLEw==} engines: {node: '>=20.9.0'} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] - libc: [glibc] '@img/sharp-linux-riscv64@0.35.0': resolution: {integrity: sha512-l6vmKVPnbS0RhVMbyxP5meAARsbhCnBN4fy31qz0+3a6Rv4jEqfzDrT89y6ZPkCi0AJGnwp2En528yXo401Hpw==} engines: {node: '>=20.9.0'} cpu: [riscv64] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.35.0': resolution: {integrity: sha512-MYlMiPFiv/EKPAHnp3yNZ9AAWFsxga9c5Bkc6wkar6bqzHLlkGVJHRm0u1ei+VXnZxp3Mz9MG9ZIsI8vSOf3sQ==} engines: {node: '>=20.9.0'} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.35.0': resolution: {integrity: sha512-TYaItB5oj1ioXjhyn2xrR208vf+YuIIcHptQWRRaBmFhvIvL9D72DXN8w75xup0KXA8UdEAhQ9Qb2S49FD/9Cw==} engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-arm64@0.35.0': resolution: {integrity: sha512-DSTb6ijQzqe6DdAaOBVqJ/SYf1vO8EW5bK6X6LRXufEBebf2722VCdvBUtZ3rtV0x2ApfPNDy/p7LrrjaWjiyQ==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.35.0': resolution: {integrity: sha512-K7ykQ+26Rt6+4BTU80AuGgTPIYX86UxiAKT4rcXX/WNTo7k1ZxpKz+TguHnwVpCqQK3B5PK0vZ0ZBe6nz/ib1w==} engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} @@ -8864,6 +9010,15 @@ packages: vue-tsc: optional: true + '@module-federation/dts-plugin@2.7.0': + resolution: {integrity: sha512-mVKeGUf/7iqRMAFfikhsr2zXtA70WuzJdS1bPqqoeLQNRGXBLDjedcDG26RpIlsvuZcmIOqgN5Z6qw7Bh/HZUg==} + peerDependencies: + typescript: ^4.9.0 || ^5.0.0 || ^6.0.0 + vue-tsc: '>=1.0.24' + peerDependenciesMeta: + vue-tsc: + optional: true + '@module-federation/enhanced@0.21.6': resolution: {integrity: sha512-8PFQxtmXc6ukBC4CqGIoc96M2Ly9WVwCPu4Ffvt+K/SB6rGbeFeZoYAwREV1zGNMJ5v5ly6+AHIEOBxNuSnzSg==} hasBin: true @@ -8915,6 +9070,9 @@ packages: '@module-federation/error-codes@2.2.2': resolution: {integrity: sha512-e+dxUrqrdRbhfvg8TyG0UQBQAjYZ8pI2b3HWfESLXqWi3xCiivZSnqsPN+zychrQ1hDZAdCheZ9zT91zhMrkxw==} + '@module-federation/error-codes@2.7.0': + resolution: {integrity: sha512-syToF3H77IbBhJ7auGMCIb5ZDmJ5tvaqSeEvncJrOCq7JBT96F4UDlQDyNh6kCVznvYqqHsPeEMrfI9b5/Omlg==} + '@module-federation/error-codes@2.8.2': resolution: {integrity: sha512-8inlDv48QOjA//CLQ3epjoHEiMQGsz1Pmtu2N+s7gQVggn6AYHpjnMe8AsyGxtpaPg3wbX0HmBZtRFggpXUB9A==} @@ -8934,6 +9092,9 @@ packages: '@module-federation/managers@2.2.2': resolution: {integrity: sha512-YuUCUdjwXGsFEWC6YwNjX+XC8V4i47549ljXarHBhCVIYIluigivpG5ZDq/kyoZQoeR9UnUwzMiKzt79y0f7Dg==} + '@module-federation/managers@2.7.0': + resolution: {integrity: sha512-cWohiUvSrY6dIfhwsRABmEWfvJiAD5u/gxU7XRk7bx5nYPj7qn5gvYWJtvLNWzenluHZR6sib+03QMlyo+MYKQ==} + '@module-federation/manifest@0.21.6': resolution: {integrity: sha512-yg93+I1qjRs5B5hOSvjbjmIoI2z3th8/yst9sfwvx4UDOG1acsE3HHMyPN0GdoIGwplC/KAnU5NmUz4tREUTGQ==} @@ -8993,6 +9154,9 @@ packages: '@module-federation/runtime-core@2.2.2': resolution: {integrity: sha512-JL+W6Yol1+CPJ662H1SEQLwxfBU2kCKhUcYrMr/X6j0qFWB8x5PBSpQbwAIcJiKfflHgBaJZypmCKmq8qRv3Aw==} + '@module-federation/runtime-core@2.7.0': + resolution: {integrity: sha512-5ROZLVIeV9YnWO2RwCwSHcy6sh48yclErO/2GZ2Xe8lFubPrFirgU8pbwBjZw+All0ZzN44BGS4ECRMVFzVcpg==} + '@module-federation/runtime-core@2.8.2': resolution: {integrity: sha512-PEkkK9MUp+nUCeQMS4ox3QGZfwwxgfjGA7P4umEnr5c3y8DLNDR+26tyHf/Gkjen2VsjlcyL+mEAQo1Zi4IE3g==} @@ -9053,6 +9217,9 @@ packages: '@module-federation/runtime@2.2.2': resolution: {integrity: sha512-zV6kbAUU1tQZr4KrZXQhzQP3WTb7oMRlIFw4UBhbh2JhAKGYS5CNc/n7+RV+mDxIs//qVmVzdSpJtTOMBLeFCw==} + '@module-federation/runtime@2.7.0': + resolution: {integrity: sha512-UtLozKKNvhT0D1+F0MEWsAmddJ39ItKW15E22LVMAwXmYZRSnzIvJQ2Y6kQ4LwhWABsw/GRSpUDex5OfhpSQPw==} + '@module-federation/runtime@2.8.2': resolution: {integrity: sha512-SUoP+PD5EjSPSi6FxEPGIZoRkFifxdeYcVQbJE9mO0VEjF51gAk3/TgX8k0vzUryOBPmXekLr9SfQXU6DqUtvA==} @@ -9088,6 +9255,9 @@ packages: node-fetch: optional: true + '@module-federation/sdk@2.7.0': + resolution: {integrity: sha512-piiLEjaIdjbNq8E11Di6vsfryhcdN/+sBCH6NjG7gSU2VHHoHEayZQWWL7VVdS6rVjexF9McLhPTSrl0adUU+A==} + '@module-federation/sdk@2.8.2': resolution: {integrity: sha512-OPS/lbQjraLXoWniQpCwQ/vqgURHTrhsackSNcOPmcJHM3LyR+DabxUc0pl8jAqExsW2l+uepQq7+/Gkei871w==} @@ -9097,6 +9267,15 @@ packages: '@module-federation/third-party-dts-extractor@2.2.2': resolution: {integrity: sha512-BWKLXQ2Me+zw6y2yhk8/URuVcyYFP1aJZlTqb7KpYeSJEp2z5jk8sZX2R42GraAGAwSe9IwcW6Y4Za/eoxt/tA==} + '@module-federation/third-party-dts-extractor@2.7.0': + resolution: {integrity: sha512-hZJKkngQ4hwe0U+vrT3KOsU11qoHCQK0wB4x1bXoTgpTfV9j5NSuddOyRmwbvXpir9bDWh3xy7ghqsx3mFf3kA==} + + '@module-federation/vite@1.16.16': + resolution: {integrity: sha512-XtgLXydgUblSzIJaRljVrg5xyogABEUUnTsSXX11W/q55XR+mnpKInsGY3uBgX09GbjSW5DNHWal+1zKt2d7uw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + '@module-federation/webpack-bundler-runtime@0.1.6': resolution: {integrity: sha512-K5WhKZ4RVNaMEtfHsd/9CNCgGKB0ipbm/tgweNNeC11mEuBTNxJ09Y630vg3WPkKv9vfMCuXg2p2Dk+Q/KWTSA==} @@ -9174,35 +9353,30 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@napi-rs/canvas-linux-arm64-musl@0.1.100': resolution: {integrity: sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@napi-rs/canvas-linux-riscv64-gnu@0.1.100': resolution: {integrity: sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] - libc: [glibc] '@napi-rs/canvas-linux-x64-gnu@0.1.100': resolution: {integrity: sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@napi-rs/canvas-linux-x64-musl@0.1.100': resolution: {integrity: sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@napi-rs/canvas-win32-arm64-msvc@0.1.100': resolution: {integrity: sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw==} @@ -9261,49 +9435,42 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@napi-rs/nice-linux-arm64-musl@1.1.1': resolution: {integrity: sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@napi-rs/nice-linux-ppc64-gnu@1.1.1': resolution: {integrity: sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==} engines: {node: '>= 10'} cpu: [ppc64] os: [linux] - libc: [glibc] '@napi-rs/nice-linux-riscv64-gnu@1.1.1': resolution: {integrity: sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] - libc: [glibc] '@napi-rs/nice-linux-s390x-gnu@1.1.1': resolution: {integrity: sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==} engines: {node: '>= 10'} cpu: [s390x] os: [linux] - libc: [glibc] '@napi-rs/nice-linux-x64-gnu@1.1.1': resolution: {integrity: sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@napi-rs/nice-linux-x64-musl@1.1.1': resolution: {integrity: sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@napi-rs/nice-openharmony-arm64@1.1.1': resolution: {integrity: sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==} @@ -9395,56 +9562,48 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@next/swc-linux-arm64-gnu@16.1.5': resolution: {integrity: sha512-qNIb42o3C02ccIeSeKjacF3HXotGsxh/FMk/rSRmCzOVMtoWH88odn2uZqF8RLsSUWHcAqTgYmPD3pZ03L9ZAA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@next/swc-linux-arm64-musl@14.2.33': resolution: {integrity: sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@next/swc-linux-arm64-musl@16.1.5': resolution: {integrity: sha512-U+kBxGUY1xMAzDTXmuVMfhaWUZQAwzRaHJ/I6ihtR5SbTVUEaDRiEU9YMjy1obBWpdOBuk1bcm+tsmifYSygfw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@next/swc-linux-x64-gnu@14.2.33': resolution: {integrity: sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@next/swc-linux-x64-gnu@16.1.5': resolution: {integrity: sha512-gq2UtoCpN7Ke/7tKaU7i/1L7eFLfhMbXjNghSv0MVGF1dmuoaPeEVDvkDuO/9LVa44h5gqpWeJ4mRRznjDv7LA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@next/swc-linux-x64-musl@14.2.33': resolution: {integrity: sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@next/swc-linux-x64-musl@16.1.5': resolution: {integrity: sha512-bQWSE729PbXT6mMklWLf8dotislPle2L70E9q6iwETYEOt092GDn0c+TTNj26AjmeceSsC4ndyGsK5nKqHYXjQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@next/swc-win32-arm64-msvc@14.2.33': resolution: {integrity: sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==} @@ -9548,25 +9707,21 @@ packages: resolution: {integrity: sha512-mPji9PzleWPvXpmFDKaXpTymRgZkk/hW8JHGhvEZpKHHXMYgTGWC+BqOEM2A4dYC4bu4fi9RrteL7aouRRWJoQ==} cpu: [arm64] os: [linux] - libc: [glibc] '@nx/nx-linux-arm64-musl@22.5.4': resolution: {integrity: sha512-hF/HvEhbCjcFpTgY7RbP1tUTbp0M1adZq4ckyW8mwhDWQ/MDsc8FnOHwCO3Bzy9ZeJM0zQUES6/m0Onz8geaEA==} cpu: [arm64] os: [linux] - libc: [musl] '@nx/nx-linux-x64-gnu@22.5.4': resolution: {integrity: sha512-1+vicSYEOtc7CNMoRCjo59no4gFe8w2nGIT127wk1yeW3EJzRVNlOA7Deu10NUUbzLeOvHc8EFOaU7clT+F7XQ==} cpu: [x64] os: [linux] - libc: [glibc] '@nx/nx-linux-x64-musl@22.5.4': resolution: {integrity: sha512-/KjndxVB14yU0SJOhqADHOWoTy4Y45h5RjW3cxcXlPSJZz7ar1FnlLne1rWMMMUttepc8ku+3T//SGKi2eu+Nw==} cpu: [x64] os: [linux] - libc: [musl] '@nx/nx-win32-arm64-msvc@22.5.4': resolution: {integrity: sha512-CrYt9FwhjOI6ZNy/G6YHLJmZuXCFJ24BCxugPXiZ7knDx7eGrr7owGgfht4SSiK3KCX40CvWCBJfqR4ZSgaSUA==} @@ -9643,37 +9798,31 @@ packages: resolution: {integrity: sha512-u2ndfeEUrW898eXM+qPxIN8TvTPjI90NDQBRgaxxkOfNw3xaotloeiZGz5+Yzlfxgvxr9DY9FdYkqhUhSnGhOw==} cpu: [arm64] os: [linux] - libc: [glibc] '@oxc-resolver/binding-linux-arm64-musl@5.3.0': resolution: {integrity: sha512-TzbjmFkcnESGuVItQ2diKacX8vu5G0bH3BHmIlmY4OSRLyoAlrJFwGKAHmh6C9+Amfcjo2rx8vdm7swzmsGC6Q==} cpu: [arm64] os: [linux] - libc: [musl] '@oxc-resolver/binding-linux-riscv64-gnu@5.3.0': resolution: {integrity: sha512-NH3pjAqh8nuN29iRuRfTY42Vn03ctoR9VE8llfoUKUfhHUjFHYOXK5VSkhjj1usG8AeuesvqrQnLptCRQVTi/Q==} cpu: [riscv64] os: [linux] - libc: [glibc] '@oxc-resolver/binding-linux-s390x-gnu@5.3.0': resolution: {integrity: sha512-tuZtkK9sJYh2MC2uhol1M/8IMTB6ZQ5jmqP2+k5XNXnOb/im94Y5uV/u2lXwVyIuKHZZHtr+0d1HrOiNahoKpw==} cpu: [s390x] os: [linux] - libc: [glibc] '@oxc-resolver/binding-linux-x64-gnu@5.3.0': resolution: {integrity: sha512-VzhPYmZCtoES/ThcPdGSmMop7JlwgqtSvlgtKCW15ByV2JKyl8kHAHnPSBfpIooXb0ehFnRdxFtL9qtAEWy01g==} cpu: [x64] os: [linux] - libc: [glibc] '@oxc-resolver/binding-linux-x64-musl@5.3.0': resolution: {integrity: sha512-Hi39cWzul24rGljN4Vf1lxjXzQdCrdxO5oCT7KJP4ndSlqIUODJnfnMAP1YhcnIRvNvk+5E6sZtnEmFUd/4d8Q==} cpu: [x64] os: [linux] - libc: [musl] '@oxc-resolver/binding-wasm32-wasi@5.3.0': resolution: {integrity: sha512-ddujvHhP3chmHnSXRlkPVUeYj4/B7eLZwL4yUid+df3WCbVh6DgoT9RmllZn21AhxgKtMdekDdyVJYKFd8tl4A==} @@ -9723,42 +9872,36 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.6': resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.6': resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.6': resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.6': resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.6': resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [musl] '@parcel/watcher-win32-arm64@2.5.6': resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} @@ -11627,70 +11770,60 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.9': resolution: {integrity: sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-arm64-musl@1.0.0-rc.3': resolution: {integrity: sha512-Z03/wrqau9Bicfgb3Dbs6SYTHliELk2PM2LpG2nFd+cGupTMF5kanLEcj2vuuJLLhptNyS61rtk7SOZ+lPsTUA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [musl] '@rolldown/binding-linux-arm64-musl@1.0.0-rc.9': resolution: {integrity: sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [musl] '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.9': resolution: {integrity: sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.9': resolution: {integrity: sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] - libc: [glibc] '@rolldown/binding-linux-x64-gnu@1.0.0-rc.3': resolution: {integrity: sha512-iSXXZsQp08CSilff/DCTFZHSVEpEwdicV3W8idHyrByrcsRDVh9sGC3sev6d8BygSGj3vt8GvUKBPCoyMA4tgQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-x64-gnu@1.0.0-rc.9': resolution: {integrity: sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-x64-musl@1.0.0-rc.3': resolution: {integrity: sha512-qaj+MFudtdCv9xZo9znFvkgoajLdc+vwf0Kz5N44g+LU5XMe+IsACgn3UG7uTRlCCvhMAGXm1XlpEA5bZBrOcw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [musl] '@rolldown/binding-linux-x64-musl@1.0.0-rc.9': resolution: {integrity: sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [musl] '@rolldown/binding-openharmony-arm64@1.0.0-rc.3': resolution: {integrity: sha512-U662UnMETyjT65gFmG9ma+XziENrs7BBnENi/27swZPYagubfHRirXHG2oMl+pEax2WvO7Kb9gHZmMakpYqBHQ==} @@ -11904,157 +12037,131 @@ packages: resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-gnueabihf@4.62.2': resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.59.0': resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm-musleabihf@4.62.2': resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.59.0': resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-gnu@4.62.2': resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.59.0': resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-musl@4.62.2': resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.59.0': resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} cpu: [loong64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-loong64-gnu@4.62.2': resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==} cpu: [loong64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.59.0': resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} cpu: [loong64] os: [linux] - libc: [musl] '@rollup/rollup-linux-loong64-musl@4.62.2': resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==} cpu: [loong64] os: [linux] - libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.59.0': resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.62.2': resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.59.0': resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} cpu: [ppc64] os: [linux] - libc: [musl] '@rollup/rollup-linux-ppc64-musl@4.62.2': resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==} cpu: [ppc64] os: [linux] - libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.59.0': resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.62.2': resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.59.0': resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} cpu: [riscv64] os: [linux] - libc: [musl] '@rollup/rollup-linux-riscv64-musl@4.62.2': resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==} cpu: [riscv64] os: [linux] - libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.59.0': resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.62.2': resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.59.0': resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.62.2': resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-musl@4.59.0': resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-linux-x64-musl@4.62.2': resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-openbsd-x64@4.59.0': resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} @@ -12466,6 +12573,14 @@ packages: '@rsbuild/core': optional: true + '@rsbuild/plugin-vue@1.2.9': + resolution: {integrity: sha512-ufD4eufkZZlNK3iY5NWg57AMK9qrTFmHycDkSTfRTua4Qczf7q9s7rCLYVfVv2w36cOXJIewM+376jD0zaQShQ==} + peerDependencies: + '@rsbuild/core': ^1.0.0 || ^2.0.0-0 + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@rsbuild/plugin-vue@2.0.1': resolution: {integrity: sha512-JbQ/e4J7lICXC6JpovJS9PHlIT0Vl1XngTni3HuVkXF82Q18k8nd0RmRDVRDFcb/mvqij5ITwZsez9h3DoYcQQ==} peerDependencies: @@ -12674,361 +12789,301 @@ packages: resolution: {integrity: sha512-/24UytJXrK+7CsucDb30GCKYIJ8nG6ceqbJyOtsJv9zeArNLHkxrYGSyjHJIpQfwVN17BPP4RNOi+yIZ3ZgDyA==} cpu: [arm64] os: [linux] - libc: [glibc] '@rspack/binding-linux-arm64-gnu@1.0.14': resolution: {integrity: sha512-JogYtL3VQS9wJ3p3FNhDqinm7avrMsdwz4erP7YCjD7idob93GYAE7dPrHUzSNVnCBYXRaHJYZHDQs7lKVcYZw==} cpu: [arm64] os: [linux] - libc: [glibc] '@rspack/binding-linux-arm64-gnu@1.3.11': resolution: {integrity: sha512-NIOaIfYUmJs1XL4lbGVtcMm1KlA/6ZR6oAbs2ekofKXtJYAFQgnLTf7ZFmIwVjS0mP78BmeSNcIM6pd2w5id4w==} cpu: [arm64] os: [linux] - libc: [glibc] '@rspack/binding-linux-arm64-gnu@1.3.15': resolution: {integrity: sha512-D/YjYk9snKvYm1Elotq8/GsEipB4ZJWVv/V8cZ+ohhFNOPzygENi6JfyI06TryBTQiN0/JDZqt/S9RaWBWnMqw==} cpu: [arm64] os: [linux] - libc: [glibc] '@rspack/binding-linux-arm64-gnu@1.3.9': resolution: {integrity: sha512-pBKnS2Fbn9cDtWe1KcD1qRjQlJwQhP9pFW2KpxdjE7qXbaO11IHtem6dLZwdpNqbDn9QgyfdVGXBDvBaP1tGwA==} cpu: [arm64] os: [linux] - libc: [glibc] '@rspack/binding-linux-arm64-gnu@1.5.8': resolution: {integrity: sha512-UAWCsOnpkvy8eAVRo0uipbHXDhnoDq5zmqWTMhpga0/a3yzCp2e+fnjZb/qnFNYb5MeL0O1mwMOYgn1M3oHILQ==} cpu: [arm64] os: [linux] - libc: [glibc] '@rspack/binding-linux-arm64-gnu@1.6.0-beta.1': resolution: {integrity: sha512-UyUoh5RXHTWCktqPVnqoc5rwlWyLkWqGu6ga+iyJHDxdxlrHFfwJnTSnCd4y8cRadf7CrmjHElxE61GU3WCYhw==} cpu: [arm64] os: [linux] - libc: [glibc] '@rspack/binding-linux-arm64-gnu@1.6.8': resolution: {integrity: sha512-fvZX6xZPvBT8qipSpvkKMX5M7yd2BSpZNCZXcefw6gA3uC7LI3gu+er0LrDXY1PtPzVuHTyDx+abwWpagV3PiQ==} cpu: [arm64] os: [linux] - libc: [glibc] '@rspack/binding-linux-arm64-gnu@1.7.9': resolution: {integrity: sha512-qhUGI/uVfvLmKWts4QkVHGL8yfUyJkblZs+OFD5Upa2y676EOsbQgWsCwX4xGB6Tv+TOzFP0SLh/UfO8ZfdE+w==} cpu: [arm64] os: [linux] - libc: [glibc] '@rspack/binding-linux-arm64-gnu@2.0.0-beta.0': resolution: {integrity: sha512-nTtYtklRZD4sb2RIFCF9YS8tZ/MjpqIBKVS3YIvdXcfHUdVfmQHTZGtwEuZGg6AxTC5L1hcvkYmTXCG0ok7auw==} cpu: [arm64] os: [linux] - libc: [glibc] '@rspack/binding-linux-arm64-gnu@2.0.6': resolution: {integrity: sha512-H6ACzeM1KBxYDEF8YAim3501Jb1aCsSG79Gjm1M4pwJ5OJPK2ydiJEa438ugXmh0962eKYMHI2yZY0sQq8txaw==} cpu: [arm64] os: [linux] - libc: [glibc] '@rspack/binding-linux-arm64-gnu@2.0.8': resolution: {integrity: sha512-pSI+npPQE/uDtiboqvcOIRJbEV2+B+H1xffmko/gw50la92oTUW60kVULFwsb6L0+GVCzIcwX3yq60GtYIn+Ug==} cpu: [arm64] os: [linux] - libc: [glibc] '@rspack/binding-linux-arm64-gnu@2.1.2': resolution: {integrity: sha512-My4m40tyJSgiCEf3bB2KIEX710q3nZg99LIjy+8Zxgi3oZTkg1bFmFRusFU5U4eN5408zfSqDDGvjDE3Yv7o4w==} cpu: [arm64] os: [linux] - libc: [glibc] '@rspack/binding-linux-arm64-gnu@2.1.8': resolution: {integrity: sha512-KLniMc9GzhKpVqhPzaJo3KJwzdAllXVVqZIk/uL1QipXOxs57fgM4u7IexKPFVla0o/u1PQG/Ah2YLDmda24Ow==} cpu: [arm64] os: [linux] - libc: [glibc] '@rspack/binding-linux-arm64-musl@0.7.5': resolution: {integrity: sha512-6RcxG42mLM01Pa6UYycACu/Nu9qusghAPUJumb8b8x5TRIDEtklYC5Ck6Rmagm+8E0ucMude2E/D4rMdIFcS3A==} cpu: [arm64] os: [linux] - libc: [musl] '@rspack/binding-linux-arm64-musl@1.0.14': resolution: {integrity: sha512-qgybhxI/nnoa8CUz7zKTC0Oh37NZt9uRxsSV7+ZYrfxqbrVCoNVuutPpY724uUHy1M6W34kVEm1uT1N4Ka5cZg==} cpu: [arm64] os: [linux] - libc: [musl] '@rspack/binding-linux-arm64-musl@1.3.11': resolution: {integrity: sha512-CRRAQ379uzA2QfD9HHNtxuuqzGksUapMVcTLY5NIXWfvHLUJShdlSJQv3UQcqgAJNrMY7Ex1PnoQs1jZgUiqZA==} cpu: [arm64] os: [linux] - libc: [musl] '@rspack/binding-linux-arm64-musl@1.3.15': resolution: {integrity: sha512-lJbBsPMOiR0hYPCSM42yp7QiZjfo0ALtX7ws2wURpsQp3BMfRVAmXU3Ixpo2XCRtG1zj8crHaCmAWOJTS0smsA==} cpu: [arm64] os: [linux] - libc: [musl] '@rspack/binding-linux-arm64-musl@1.3.9': resolution: {integrity: sha512-0B+iiINW0qOEkBE9exsRcdmcHtYIWAoJGnXrz9tUiiewRxX0Cmm0MjD2HAVUAggJZo+9IN8RGz5PopCjJ/dn1g==} cpu: [arm64] os: [linux] - libc: [musl] '@rspack/binding-linux-arm64-musl@1.5.8': resolution: {integrity: sha512-GnSvGT4GjokPSD45cTtE+g7LgghuxSP1MRmvd+Vp/I8pnxTVSTsebRod4TAqyiv+l11nuS8yqNveK9qiOkBLWw==} cpu: [arm64] os: [linux] - libc: [musl] '@rspack/binding-linux-arm64-musl@1.6.0-beta.1': resolution: {integrity: sha512-JAXVKHQieN4Ruvs7MstvsPUtRBSAROqJ0abCh4rXdV+FzncKp/ZkdfjQploDhBWtWfU8rPvIjaxeZcPfHMI5/A==} cpu: [arm64] os: [linux] - libc: [musl] '@rspack/binding-linux-arm64-musl@1.6.8': resolution: {integrity: sha512-++XMKcMNrt59HcFBLnRaJcn70k3X0GwkAegZBVpel8xYIAgvoXT5+L8P1ExId/yTFxqedaz8DbcxQnNmMozviw==} cpu: [arm64] os: [linux] - libc: [musl] '@rspack/binding-linux-arm64-musl@1.7.9': resolution: {integrity: sha512-VjfmR1hgO9n3L6MaE5KG+DXSrrLVqHHOkVcOtS2LMq3bjMTwbBywY7ycymcLnX5KJsol8d3ZGYep6IfSOt3lFA==} cpu: [arm64] os: [linux] - libc: [musl] '@rspack/binding-linux-arm64-musl@2.0.0-beta.0': resolution: {integrity: sha512-S2fshx0Rf7/XYwoMLaqFsVg4y+VAfHzubrczy8AW5xIs6UNC3eRLVTgShLerUPtF6SG+v6NQxQ9JI3vOo2qPOA==} cpu: [arm64] os: [linux] - libc: [musl] '@rspack/binding-linux-arm64-musl@2.0.6': resolution: {integrity: sha512-QTFmBg0n+L397Wi8CIjbd5pe/hxpHnqCDaG1A7e2NWX8Fj9zulAoKLiKflQa1ELEhAY4Foq88aX75+Ilt2tHcw==} cpu: [arm64] os: [linux] - libc: [musl] '@rspack/binding-linux-arm64-musl@2.0.8': resolution: {integrity: sha512-igjJ43yxWQ72GZqjDDZSSHax9/Vg+6rLMmOvFglTJUkQpB4Tyvu/YjW+WRjYj2xRw6blOjLxUSJWASvuSqqlvg==} cpu: [arm64] os: [linux] - libc: [musl] '@rspack/binding-linux-arm64-musl@2.1.2': resolution: {integrity: sha512-yt+GGWUH7WPE8K97cRc8OpZhH7Pbj1vU+lkvKbDtF/rR8X9a/bJsA/nBqyUV2oBKOVbrp5I8rFZlnDskMqgvKw==} cpu: [arm64] os: [linux] - libc: [musl] '@rspack/binding-linux-arm64-musl@2.1.8': resolution: {integrity: sha512-yUKAxHNGnICtw5RnxFWu4dHtsz/tdt7rbeFcsINNVre9HcrRxf5XP+FbOGL/SMxd9oM9XCo10paU2WckTKwbEA==} cpu: [arm64] os: [linux] - libc: [musl] '@rspack/binding-linux-riscv64-gnu@2.1.2': resolution: {integrity: sha512-uys8Jyw8Z3ralvICbN/L/nZfy5qELIwpOY72rhIqhoDYwFcL4fmMaY7WsvUcJOjCB2rqOcWPaWKuF2oPvo9iDQ==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rspack/binding-linux-riscv64-gnu@2.1.8': resolution: {integrity: sha512-gg4S1jaitwYPHR9HZ3zNGH1EK2GXINm66p4kEpOP1gbc+akyOouVF/dMcu9NGPlRg58FbEhVRZYKu7Z/zcpKHg==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rspack/binding-linux-riscv64-musl@2.1.2': resolution: {integrity: sha512-JYNVQwqCaRGQWvjHQYzZkIzQiwllMaJwh4Rdu3ww6W2OJcJUqT08sL1pkOtU0iCxT4VUYiRRcp93VGTGpHr8fg==} cpu: [riscv64] os: [linux] - libc: [musl] '@rspack/binding-linux-riscv64-musl@2.1.8': resolution: {integrity: sha512-b/aU5j1h368SLNyz5u+flqpZVhzSZ1UIslaj9sZJuAvqkGWv3xsjc/28/PTo/RYXCxd0FNVAxTxWHKvRiAAS8w==} cpu: [riscv64] os: [linux] - libc: [musl] '@rspack/binding-linux-x64-gnu@0.7.5': resolution: {integrity: sha512-R0Lu4CJN2nWMW7WzPBuCIju80cQPpcaqwKJDj/quwQySpJJZ6c5qGwB8mntqjxIzZDrNH6u0OkpiUTbvWZj8ww==} cpu: [x64] os: [linux] - libc: [glibc] '@rspack/binding-linux-x64-gnu@1.0.14': resolution: {integrity: sha512-5vzaDRw3/sGKo3ax/1cU3/cxqNjajwlt2LU288vXNe1/n8oe/pcDfYcTugpOe/A1DqzadanudJszLpFcKsaFtQ==} cpu: [x64] os: [linux] - libc: [glibc] '@rspack/binding-linux-x64-gnu@1.3.11': resolution: {integrity: sha512-k3OyvLneX2ZeL8z/OzPojpImqy6PgqKJD+NtOvcr/TgbgADHZ3xQttf6B2X+qnZMAgOZ+RTeTkOFrvsg9AEKmA==} cpu: [x64] os: [linux] - libc: [glibc] '@rspack/binding-linux-x64-gnu@1.3.15': resolution: {integrity: sha512-qGB8ucHklrzNg6lsAS36VrBsCbOw0acgpQNqTE5cuHWrp1Pu3GFTRiFEogenxEmzoRbohMZt0Ev5grivrcgKBQ==} cpu: [x64] os: [linux] - libc: [glibc] '@rspack/binding-linux-x64-gnu@1.3.9': resolution: {integrity: sha512-82izGJw/qxJ4xaHJy/A4MF7aTRT9tE6VlWoWM4rJmqRszfujN/w54xJRie9jkt041TPvJWGNpYD4Hjpt0/n/oA==} cpu: [x64] os: [linux] - libc: [glibc] '@rspack/binding-linux-x64-gnu@1.5.8': resolution: {integrity: sha512-XLxh5n/pzUfxsugz/8rVBv+Tx2nqEM+9rharK69kfooDsQNKyz7PANllBQ/v4svJ+W0BRHnDL4qXSGdteZeEjA==} cpu: [x64] os: [linux] - libc: [glibc] '@rspack/binding-linux-x64-gnu@1.6.0-beta.1': resolution: {integrity: sha512-LqAos71CJS5/V4knX9T7T68oGz0XPRZ2IJmI3jEByRlNcyZdxYeQ7Dw09JO9Y5Xj0T+0cudOeL2MxHcD3gTF/w==} cpu: [x64] os: [linux] - libc: [glibc] '@rspack/binding-linux-x64-gnu@1.6.8': resolution: {integrity: sha512-tv3BWkTE1TndfX+DsE1rSTg8fBevCxujNZ3MlfZ22Wfy9x1FMXTJlWG8VIOXmaaJ1wUHzv8S7cE2YUUJ2LuiCg==} cpu: [x64] os: [linux] - libc: [glibc] '@rspack/binding-linux-x64-gnu@1.7.9': resolution: {integrity: sha512-0kldV+3WTs/VYDWzxJ7K40hCW26IHtnk8xPK3whKoo1649rgeXXa0EdsU5P7hG8Ef5SWQjHHHZ/fuHYSO3Y6HA==} cpu: [x64] os: [linux] - libc: [glibc] '@rspack/binding-linux-x64-gnu@2.0.0-beta.0': resolution: {integrity: sha512-yx5Fk1gl7lfkvqcjolNLCNeduIs6C2alMsQ/kZ1pLeP5MPquVOYNqs6EcDPIp+fUjo3lZYtnJBiZKK+QosbzYg==} cpu: [x64] os: [linux] - libc: [glibc] '@rspack/binding-linux-x64-gnu@2.0.6': resolution: {integrity: sha512-rerCAz022zf0ewxI+7n3SrqLEaxCL+MXRxKjK5FLUGFa8UkIrivq+VUP/1OB6JLh2Bucebc7Y9WoWHvtk22mLA==} cpu: [x64] os: [linux] - libc: [glibc] '@rspack/binding-linux-x64-gnu@2.0.8': resolution: {integrity: sha512-zrkoEOnqj1hOEBO5T2I/2Ts2HSJsYFh1qXwMpK4dMJFGGNWDfNeUa6/LF5uq3VINF3JUl7RL47AgrucoSZJXPA==} cpu: [x64] os: [linux] - libc: [glibc] '@rspack/binding-linux-x64-gnu@2.1.2': resolution: {integrity: sha512-KDoPy0Msf/JLhxgPPrJQzZeB4Qpqd32em8AP5lSW2s6jR5I35dHgAe9xc2A++EQtnSrU4GTn6DBvFC7q84SihQ==} cpu: [x64] os: [linux] - libc: [glibc] '@rspack/binding-linux-x64-gnu@2.1.8': resolution: {integrity: sha512-EyegohSx0BJRqieCg9f/caCqFARRWkqI5hwJt6k530MoOTLeq8I3vsbeg24/2MktwIC1dmJi8bl0+WhPKQs4eQ==} cpu: [x64] os: [linux] - libc: [glibc] '@rspack/binding-linux-x64-musl@0.7.5': resolution: {integrity: sha512-dDgi/ThikMy1m4llxPeEXDCA2I8F8ezFS/eCPLZGU2/J1b4ALwDjuRsMmo+VXSlFCKgIt98V6h1woeg7nu96yg==} cpu: [x64] os: [linux] - libc: [musl] '@rspack/binding-linux-x64-musl@1.0.14': resolution: {integrity: sha512-4U6QD9xVS1eGme52DuJr6Fg/KdcUfJ+iKwH49Up460dZ/fLvGylnVGA+V0mzPlKi8gfy7NwFuYXZdu3Pwi1YYg==} cpu: [x64] os: [linux] - libc: [musl] '@rspack/binding-linux-x64-musl@1.3.11': resolution: {integrity: sha512-2agcELyyQ95jWGCW0YWD0TvAcN40yUjmxn9NXQBLHPX5Eb07NaHXairMsvV9vqQsPsq0nxxfd9Wsow18Y5r/Hw==} cpu: [x64] os: [linux] - libc: [musl] '@rspack/binding-linux-x64-musl@1.3.15': resolution: {integrity: sha512-qRn6e40fLQP+N2rQD8GAj/h4DakeTIho32VxTIaHRVuzw68ZD7VmKkwn55ssN370ejmey35ZdoNFNE12RBrMZA==} cpu: [x64] os: [linux] - libc: [musl] '@rspack/binding-linux-x64-musl@1.3.9': resolution: {integrity: sha512-V9nDg63iPI6Z7kM11UPV5kBdOdLXPIu3IgI2ObON5Rd4KEZr7RLo/Q4HKzj0IH27Zwl5qeBJdx69zZdu66eOqg==} cpu: [x64] os: [linux] - libc: [musl] '@rspack/binding-linux-x64-musl@1.5.8': resolution: {integrity: sha512-gE0+MZmwF+01p9/svpEESkzkLpBkVUG2o03YMpwXYC/maeRRhWvF8BJ7R3i/Ls/jFGSE87dKX5NbRLVzqksq/w==} cpu: [x64] os: [linux] - libc: [musl] '@rspack/binding-linux-x64-musl@1.6.0-beta.1': resolution: {integrity: sha512-E4dRMzIHYaoYkgmDTFLrgnGtdspbAuVbLfaPF9AWW5YkQn52obGAgbbNb1wi1JJ5f29nTBoLauYCucEO5IGFvA==} cpu: [x64] os: [linux] - libc: [musl] '@rspack/binding-linux-x64-musl@1.6.8': resolution: {integrity: sha512-DCGgZ5/in1O3FjHWqXnDsncRy+48cMhfuUAAUyl0yDj1NpsZu9pP+xfGLvGcQTiYrVl7IH9Aojf1eShP/77WGA==} cpu: [x64] os: [linux] - libc: [musl] '@rspack/binding-linux-x64-musl@1.7.9': resolution: {integrity: sha512-Gi4872cFtc2d83FKATR6Qcf2VBa/tFCqffI/IwRRl6Hx5FulEBqx+tH7gAuRVF693vrbXNxK+FQ+k4iEsEJxrw==} cpu: [x64] os: [linux] - libc: [musl] '@rspack/binding-linux-x64-musl@2.0.0-beta.0': resolution: {integrity: sha512-sBX4b2W0PgehlAVT224k0Q6GaH6t9HP+hBNDrbX/g6d0hfxZN56gm5NfOTOD1Rien4v7OBEejJ3/uFbm1WjwYQ==} cpu: [x64] os: [linux] - libc: [musl] '@rspack/binding-linux-x64-musl@2.0.6': resolution: {integrity: sha512-96IgOFXQjX6Wbxd+DCYJFy2r/VMu1OoHifW4Cr3kGTYDKoQOIMLwb0ieu/ILp2dGWFMZo5S8odiByAmNICAOIA==} cpu: [x64] os: [linux] - libc: [musl] '@rspack/binding-linux-x64-musl@2.0.8': resolution: {integrity: sha512-6CtDaGZjNDvJd9TBp7a9zABbrPORO21W96+3ZcGBn0YNUPUk4ARxIxrTTpeJ/1F41QDM8AYIkGDdqEYMqTYBsA==} cpu: [x64] os: [linux] - libc: [musl] '@rspack/binding-linux-x64-musl@2.1.2': resolution: {integrity: sha512-66hWmIGvn4zCKAYXJE9Bp5SNSLYnLFq2Ke/efE+ZtWy43Dd5vk9AAOmThVGBwdwmIxmGtHGCp+cAuS4G0wu0TA==} cpu: [x64] os: [linux] - libc: [musl] '@rspack/binding-linux-x64-musl@2.1.8': resolution: {integrity: sha512-I6E+goN+UQ297q4r1qdbiAyNCI3t0+a5Y0xDIAPOZfRDRxDTnH/LF8/y65gjsJoKRKyn7zxRC0T/NURTkRNQ9A==} cpu: [x64] os: [linux] - libc: [musl] '@rspack/binding-wasm32-wasi@1.5.8': resolution: {integrity: sha512-cfg3niNHeJuxuml1Vy9VvaJrI/5TakzoaZvKX2g5S24wfzR50Eyy4JAsZ+L2voWQQp1yMJbmPYPmnTCTxdJQBQ==} @@ -14170,98 +14225,84 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] - libc: [glibc] '@swc/core-linux-arm64-gnu@1.15.8': resolution: {integrity: sha512-o+1y5u6k2FfPYbTRUPvurwzNt5qd0NTumCTFscCNuBksycloXY16J8L+SMW5QRX59n4Hp9EmFa3vpvNHRVv1+Q==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - libc: [glibc] '@swc/core-linux-arm64-gnu@1.7.26': resolution: {integrity: sha512-YKevOV7abpjcAzXrhsl+W48Z9mZvgoVs2eP5nY+uoMAdP2b3GxC0Df1Co0I90o2lkzO4jYBpTMcZlmUXLdXn+Q==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - libc: [glibc] '@swc/core-linux-arm64-musl@1.15.41': resolution: {integrity: sha512-dXu/5vd4gh8symyhRF+4G7gOPkjmb4pONhh7sl+6GSiW0LOKZlfu5kXmyFbTz9smOT7jgr002qY9b1nujjXt2A==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - libc: [musl] '@swc/core-linux-arm64-musl@1.15.8': resolution: {integrity: sha512-koiCqL09EwOP1S2RShCI7NbsQuG6r2brTqUYE7pV7kZm9O17wZ0LSz22m6gVibpwEnw8jI3IE1yYsQTVpluALw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - libc: [musl] '@swc/core-linux-arm64-musl@1.7.26': resolution: {integrity: sha512-3w8iZICMkQQON0uIcvz7+Q1MPOW6hJ4O5ETjA0LSP/tuKqx30hIniCGOgPDnv3UTMruLUnQbtBwVCZTBKR3Rkg==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - libc: [musl] '@swc/core-linux-ppc64-gnu@1.15.41': resolution: {integrity: sha512-XGO6zVPXoPE0gf/XnI4jBbafNT13AYgoh6ns0JCSdOetI/kqVf0vhpz7NuNgAzZrMVCsmieqjPoTwViDgh4mOQ==} engines: {node: '>=10'} cpu: [ppc64] os: [linux] - libc: [glibc] '@swc/core-linux-s390x-gnu@1.15.41': resolution: {integrity: sha512-0WUglRwyZtW+iMi7J3iFdrCxreZZIKf4egTwEQfIYRsqFax69A0OrFj+NIoFSE03xBT/IFRrg+S8K6f9Ky+4hA==} engines: {node: '>=10'} cpu: [s390x] os: [linux] - libc: [glibc] '@swc/core-linux-x64-gnu@1.15.41': resolution: {integrity: sha512-VxkuQK59c0tHm6uJZCUrS3cyA2JhGGfdU6e41SZz0x/JS+4Sm7C1mIc97In14vkZJopEt7yXA2TouCqZDSygEA==} engines: {node: '>=10'} cpu: [x64] os: [linux] - libc: [glibc] '@swc/core-linux-x64-gnu@1.15.8': resolution: {integrity: sha512-4p6lOMU3bC+Vd5ARtKJ/FxpIC5G8v3XLoPEZ5s7mLR8h7411HWC/LmTXDHcrSXRC55zvAVia1eldy6zDLz8iFQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] - libc: [glibc] '@swc/core-linux-x64-gnu@1.7.26': resolution: {integrity: sha512-c+pp9Zkk2lqb06bNGkR2Looxrs7FtGDMA4/aHjZcCqATgp348hOKH5WPvNLBl+yPrISuWjbKDVn3NgAvfvpH4w==} engines: {node: '>=10'} cpu: [x64] os: [linux] - libc: [glibc] '@swc/core-linux-x64-musl@1.15.41': resolution: {integrity: sha512-/0qXIu1ZxggLuovLb22vFfKHq2AA4n6Whw5UwmVCHk4pkw7KWnPIQpMCEqUMPsNkFJig7PPp/TSYFu8ZEb2rtQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] - libc: [musl] '@swc/core-linux-x64-musl@1.15.8': resolution: {integrity: sha512-z3XBnbrZAL+6xDGAhJoN4lOueIxC/8rGrJ9tg+fEaeqLEuAtHSW2QHDHxDwkxZMjuF/pZ6MUTjHjbp8wLbuRLA==} engines: {node: '>=10'} cpu: [x64] os: [linux] - libc: [musl] '@swc/core-linux-x64-musl@1.7.26': resolution: {integrity: sha512-PgtyfHBF6xG87dUSSdTJHwZ3/8vWZfNIXQV2GlwEpslrOkGqy+WaiiyE7Of7z9AvDILfBBBcJvJ/r8u980wAfQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] - libc: [musl] '@swc/core-win32-arm64-msvc@1.15.41': resolution: {integrity: sha512-Y481sMNZM6rECh9VO4+y26N1lWEDAyxnBZskUf37fl90uHE946VHfmiVQWT0uMFOhyJJFovGTRuF4W82dwewUg==} @@ -14518,9 +14559,6 @@ packages: cpu: [arm64] os: [win32] - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - '@tybys/wasm-util@0.10.3': resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} @@ -14734,9 +14772,6 @@ packages: '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - '@types/express-serve-static-core@4.19.8': - resolution: {integrity: sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==} - '@types/express-serve-static-core@4.19.9': resolution: {integrity: sha512-QP2ESEe/ImWY0HDwNAnK9PvEffUyhLTnWkk7KXzHfyeWAnlrDe1fN77bXl6ia8KT3wPlmA7t9/VPRpnf4Ex9sg==} @@ -14916,9 +14951,6 @@ packages: '@types/pug@2.0.10': resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==} - '@types/qs@6.15.0': - resolution: {integrity: sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==} - '@types/qs@6.15.1': resolution: {integrity: sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==} @@ -15476,49 +15508,41 @@ packages: resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} cpu: [arm64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-arm64-musl@1.11.1': resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} cpu: [arm64] os: [linux] - libc: [musl] '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} cpu: [ppc64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} cpu: [riscv64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} cpu: [riscv64] os: [linux] - libc: [musl] '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} cpu: [s390x] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-x64-gnu@1.11.1': resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} cpu: [x64] os: [linux] - libc: [glibc] '@unrs/resolver-binding-linux-x64-musl@1.11.1': resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} cpu: [x64] os: [linux] - libc: [musl] '@unrs/resolver-binding-wasm32-wasi@1.11.1': resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} @@ -15630,6 +15654,9 @@ packages: vite: ^5.0.0 || ^6.0.0 vue: ^3.2.25 + '@vitest/expect@1.6.0': + resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==} + '@vitest/expect@3.2.6': resolution: {integrity: sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==} @@ -15650,15 +15677,27 @@ packages: '@vitest/pretty-format@3.2.7': resolution: {integrity: sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==} + '@vitest/runner@1.6.0': + resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==} + '@vitest/runner@3.2.6': resolution: {integrity: sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q==} + '@vitest/snapshot@1.6.0': + resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==} + '@vitest/snapshot@3.2.6': resolution: {integrity: sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw==} + '@vitest/spy@1.6.0': + resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==} + '@vitest/spy@3.2.6': resolution: {integrity: sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg==} + '@vitest/utils@1.6.0': + resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==} + '@vitest/utils@3.2.6': resolution: {integrity: sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg==} @@ -16050,6 +16089,10 @@ packages: resolution: {integrity: sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==} engines: {node: '>=8.9'} + adm-zip@0.5.10: + resolution: {integrity: sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==} + engines: {node: '>=6.0'} + adm-zip@0.5.16: resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} engines: {node: '>=12.0'} @@ -16391,6 +16434,9 @@ packages: assert@2.1.0: resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} + assertion-error@1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -17068,6 +17114,10 @@ packages: ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chai@4.5.0: + resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} + engines: {node: '>=4'} + chai@5.3.3: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} @@ -17142,6 +17192,9 @@ packages: chardet@2.1.1: resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + check-error@2.1.3: resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} @@ -18280,6 +18333,10 @@ packages: babel-plugin-macros: optional: true + deep-eql@4.1.4: + resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} + engines: {node: '>=6'} + deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} @@ -19483,6 +19540,9 @@ packages: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + ext-list@2.2.2: resolution: {integrity: sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==} engines: {node: '>=0.10.0'} @@ -20015,6 +20075,9 @@ packages: resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} engines: {node: '>=18'} + get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -21858,6 +21921,10 @@ packages: resolution: {integrity: sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==} engines: {node: '>= 12.13.0'} + local-pkg@0.5.1: + resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} + engines: {node: '>=14'} + locate-path@3.0.0: resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} engines: {node: '>=6'} @@ -21978,6 +22045,9 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} @@ -23298,6 +23368,10 @@ packages: resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-limit@5.0.0: + resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} + engines: {node: '>=18'} + p-limit@6.2.0: resolution: {integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==} engines: {node: '>=18'} @@ -23512,6 +23586,9 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + pathval@2.0.1: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} @@ -26075,112 +26152,96 @@ packages: engines: {node: '>=14.0.0'} cpu: [arm64] os: [linux] - libc: glibc sass-embedded-linux-arm64@1.98.0: resolution: {integrity: sha512-axOE3t2MTBwCtkUCbrdM++Gj0gC0fdHJPrgzQ+q1WUmY9NoNMGqflBtk5mBZaWUeha2qYO3FawxCB8lctFwCtw==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [linux] - libc: glibc sass-embedded-linux-arm@1.100.0: resolution: {integrity: sha512-9Ul7O1eKrc5YlhwWjkp8tZPSe3UEwSZ1uwUZOQom1HL0pRlBA6F/IlGZYFTLwnHMIP1fc77MMNaBRfc05mKMpw==} engines: {node: '>=14.0.0'} cpu: [arm] os: [linux] - libc: glibc sass-embedded-linux-arm@1.98.0: resolution: {integrity: sha512-03baQZCxVyEp8v1NWBRlzGYrmVT/LK7ZrHlF1piscGiGxwfdxoLXVuxsylx3qn/dD/4i/rh7Bzk7reK1br9jvQ==} engines: {node: '>=14.0.0'} cpu: [arm] os: [linux] - libc: glibc sass-embedded-linux-musl-arm64@1.100.0: resolution: {integrity: sha512-XpACJB2KjSLjf2e9uuvGVdOURsoNrFqgRiihhXyUHK9W0t3LIHb7z5MA/7XGPIT9bWSOO2zyw+rH/FHtDV/Yrg==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [linux] - libc: musl sass-embedded-linux-musl-arm64@1.98.0: resolution: {integrity: sha512-LeqNxQA8y4opjhe68CcFvMzCSrBuJqYVFbwElEj9bagHXQHTp9xVPJRn6VcrC+0VLEDq13HVXMv7RslIuU0zmA==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [linux] - libc: musl sass-embedded-linux-musl-arm@1.100.0: resolution: {integrity: sha512-sl0JgbGloPyJg66XXx5UDSDScZ0oU85DpMQU4JU/sCUCFj1Z8zZ69SJWKTCNE4/jwnce7WI2zPCV5AG+RHOZJw==} engines: {node: '>=14.0.0'} cpu: [arm] os: [linux] - libc: musl sass-embedded-linux-musl-arm@1.98.0: resolution: {integrity: sha512-OBkjTDPYR4hSaueOGIM6FDpl9nt/VZwbSRpbNu9/eEJcxE8G/vynRugW8KRZmCFjPy8j/jkGBvvS+k9iOqKV3g==} engines: {node: '>=14.0.0'} cpu: [arm] os: [linux] - libc: musl sass-embedded-linux-musl-riscv64@1.100.0: resolution: {integrity: sha512-ShvI0Kx04mwoCARwZ0UjiT97isQvzO80tAt91zmFyHLN9kelc/IrQi940farSm2xQVPCKdeVyeG0ekBsokSpYQ==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [linux] - libc: musl sass-embedded-linux-musl-riscv64@1.98.0: resolution: {integrity: sha512-7w6hSuOHKt8FZsmjRb3iGSxEzM87fO9+M8nt5JIQYMhHTj5C+JY/vcske0v715HCVj5e1xyTnbGXf8FcASeAIw==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [linux] - libc: musl sass-embedded-linux-musl-x64@1.100.0: resolution: {integrity: sha512-TDBCRWNuS4RDLQXvRc1gjZlWiWTWaWGp0Bwu/IKwJxov81lsvrCs3TihTyNXtW7V5aoN4Ky3r0QOkNb3mwmBnA==} engines: {node: '>=14.0.0'} cpu: [x64] os: [linux] - libc: musl sass-embedded-linux-musl-x64@1.98.0: resolution: {integrity: sha512-QikNyDEJOVqPmxyCFkci8ZdCwEssdItfjQFJB+D+Uy5HFqcS5Lv3d3GxWNX/h1dSb23RPyQdQc267ok5SbEyJw==} engines: {node: '>=14.0.0'} cpu: [x64] os: [linux] - libc: musl sass-embedded-linux-riscv64@1.100.0: resolution: {integrity: sha512-j4ENJGOheO+fm3j/yorLxCjBP6/XskrZx7dTLlT+lXYwN/qqCqoA/gsNLI0McS3DFM6GBwPiffzWsdWS8t6sEQ==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [linux] - libc: glibc sass-embedded-linux-riscv64@1.98.0: resolution: {integrity: sha512-E7fNytc/v4xFBQKzgzBddV/jretA4ULAPO6XmtBiQu4zZBdBozuSxsQLe2+XXeb0X4S2GIl72V7IPABdqke/vA==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [linux] - libc: glibc sass-embedded-linux-x64@1.100.0: resolution: {integrity: sha512-0vUSN8j0WGtCJIOPh//EmUvYGHW0QOe5iul8qyhPk50MAcw49MA0r34AhftjDdx94ILPF6vApFs0gwHPQRlpVA==} engines: {node: '>=14.0.0'} cpu: [x64] os: [linux] - libc: glibc sass-embedded-linux-x64@1.98.0: resolution: {integrity: sha512-VsvP0t/uw00mMNPv3vwyYKUrFbqzxQHnRMO+bHdAMjvLw4NFf6mscpym9Bzf+NXwi1ZNKnB6DtXjmcpcvqFqYg==} engines: {node: '>=14.0.0'} cpu: [x64] os: [linux] - libc: glibc sass-embedded-unknown-all@1.100.0: resolution: {integrity: sha512-c+naBgWId4MIpToXcI0DgqetjdAkwTTAxFAuOaBz7HUXLdyG1oZRrEvSsbe41nEdQOKH0vgofVFCeSQgoXOG9A==} @@ -26982,6 +27043,9 @@ packages: resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} engines: {node: '>=14.16'} + strip-literal@2.1.1: + resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} + strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} @@ -27381,6 +27445,10 @@ packages: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} + tinyspy@2.2.1: + resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} + engines: {node: '>=14.0.0'} + tinyspy@4.0.4: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} @@ -27741,6 +27809,10 @@ packages: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} + type-detect@4.1.0: + resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} + engines: {node: '>=4'} + type-fest@0.16.0: resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} engines: {node: '>=10'} @@ -27830,6 +27902,11 @@ packages: engines: {node: '>=4.2.0'} hasBin: true + typescript@5.0.4: + resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} + engines: {node: '>=12.20'} + hasBin: true + typescript@5.8.2: resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} engines: {node: '>=14.17'} @@ -27902,6 +27979,10 @@ packages: resolution: {integrity: sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==} engines: {node: '>=14.0'} + undici@7.28.0: + resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==} + engines: {node: '>=20.18.1'} + undici@7.29.0: resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==} engines: {node: '>=20.18.1'} @@ -28255,6 +28336,11 @@ packages: victory-vendor@36.9.2: resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + vite-node@1.6.0: + resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + vite-node@3.2.4: resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -28379,6 +28465,31 @@ packages: yaml: optional: true + vitest@1.6.0: + resolution: {integrity: sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 1.6.0 + '@vitest/ui': 1.6.0 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vitest@3.2.6: resolution: {integrity: sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -29379,10 +29490,10 @@ snapshots: '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) '@babel/helpers': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@babel/template': 7.29.7 '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3(supports-color@8.1.1) @@ -29424,8 +29535,8 @@ snapshots: '@babel/generator@7.29.7': dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 @@ -29449,7 +29560,7 @@ snapshots: '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/helper-annotate-as-pure@7.29.7': dependencies: @@ -29567,28 +29678,28 @@ snapshots: '@babel/helper-module-imports@7.28.6': dependencies: '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.28.6(supports-color@5.5.0)': dependencies: '@babel/traverse': 7.29.7(supports-color@5.5.0) - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.29.7': dependencies: '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.29.7(supports-color@5.5.0)': dependencies: '@babel/traverse': 7.29.7(supports-color@5.5.0) - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -29690,7 +29801,7 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -29733,7 +29844,7 @@ snapshots: '@babel/helpers@7.29.7': dependencies: '@babel/template': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/parser@7.29.2': dependencies: @@ -29741,7 +29852,7 @@ snapshots: '@babel/parser@7.29.7': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/parser@7.29.8': dependencies: @@ -31242,8 +31353,8 @@ snapshots: '@babel/template@7.29.7': dependencies: '@babel/code-frame': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@babel/traverse@7.29.0': dependencies: @@ -31260,11 +31371,11 @@ snapshots: '@babel/traverse@7.29.7': dependencies: '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 + '@babel/generator': 7.29.8 '@babel/helper-globals': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@babel/template': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -31272,11 +31383,11 @@ snapshots: '@babel/traverse@7.29.7(supports-color@5.5.0)': dependencies: '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 + '@babel/generator': 7.29.8 '@babel/helper-globals': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@babel/template': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 debug: 4.4.3(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -31409,6 +31520,37 @@ snapshots: transitivePeerDependencies: - '@types/node' + '@changesets/cli@2.30.0(@types/node@26.2.0)': + dependencies: + '@changesets/apply-release-plan': 7.1.0 + '@changesets/assemble-release-plan': link:packages/assemble-release-plan + '@changesets/changelog-git': 0.2.1 + '@changesets/config': 3.1.3 + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/get-release-plan': 4.0.15 + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.7 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@changesets/write': 0.4.0 + '@inquirer/external-editor': 1.0.3(@types/node@26.2.0) + '@manypkg/get-packages': 1.1.3 + ansi-colors: 4.1.3 + enquirer: 2.4.1 + fs-extra: 7.0.1 + mri: 1.2.0 + package-manager-detector: 0.2.11 + picocolors: 1.1.1 + resolve-from: 5.0.0 + semver: 7.6.3 + spawndamnit: 3.0.1 + term-size: 2.2.1 + transitivePeerDependencies: + - '@types/node' + '@changesets/config@3.1.3': dependencies: '@changesets/errors': 0.2.0 @@ -31830,18 +31972,12 @@ snapshots: dependencies: '@emnapi/wasi-threads': 1.2.2 tslib: 2.8.1 + optional: true '@emnapi/core@1.11.3': dependencies: '@emnapi/wasi-threads': 1.2.3 tslib: 2.8.1 - optional: true - - '@emnapi/core@1.9.0': - dependencies: - '@emnapi/wasi-threads': 1.2.0 - tslib: 2.8.1 - optional: true '@emnapi/runtime@1.10.0': dependencies: @@ -31857,16 +31993,6 @@ snapshots: dependencies: tslib: 2.8.1 - '@emnapi/runtime@1.9.0': - dependencies: - tslib: 2.8.1 - optional: true - - '@emnapi/wasi-threads@1.2.0': - dependencies: - tslib: 2.8.1 - optional: true - '@emnapi/wasi-threads@1.2.1': dependencies: tslib: 2.8.1 @@ -31875,11 +32001,11 @@ snapshots: '@emnapi/wasi-threads@1.2.2': dependencies: tslib: 2.8.1 + optional: true '@emnapi/wasi-threads@1.2.3': dependencies: tslib: 2.8.1 - optional: true '@emotion/babel-plugin@11.13.5': dependencies: @@ -32948,7 +33074,7 @@ snapshots: '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.9.0 + '@emnapi/runtime': 1.11.3 optional: true '@img/sharp-wasm32@0.35.0': @@ -32986,6 +33112,13 @@ snapshots: optionalDependencies: '@types/node': 20.19.5 + '@inquirer/external-editor@1.0.3(@types/node@26.2.0)': + dependencies: + chardet: 2.1.1 + iconv-lite: 0.7.2 + optionalDependencies: + '@types/node': 26.2.0 + '@internationalized/date@3.12.2': dependencies: '@swc/helpers': 0.5.17 @@ -33626,11 +33759,11 @@ snapshots: '@mdx-js/mdx@3.1.1': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 '@types/mdx': 2.0.13 - acorn: 8.17.0 + acorn: 8.18.0 collapse-white-space: 2.1.0 devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 @@ -33639,7 +33772,7 @@ snapshots: hast-util-to-jsx-runtime: 2.3.6 markdown-extensions: 2.0.0 recma-build-jsx: 1.0.0 - recma-jsx: 1.0.1(acorn@8.17.0) + recma-jsx: 1.0.1(acorn@8.18.0) recma-stringify: 1.0.0 rehype-recma: 1.0.0 remark-mdx: 3.1.1 @@ -33924,7 +34057,7 @@ snapshots: '@swc/helpers': 0.5.1 redux: 4.2.1 - '@modern-js/app-tools@2.70.5(@rspack/core@1.7.9(@swc/helpers@0.5.17))(@swc/core@1.15.41(@swc/helpers@0.5.17))(encoding@0.1.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(styled-components@6.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(type-fest@2.19.0)(typescript@7.0.2)(webpack-cli@5.1.4)(webpack-dev-server@5.2.3(webpack-cli@5.1.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.25.5)(webpack-cli@5.1.4)))(webpack-hot-middleware@2.26.1)': + '@modern-js/app-tools@2.70.5(@rspack/core@1.7.9(@swc/helpers@0.5.17))(@swc/core@1.15.41(@swc/helpers@0.5.17))(encoding@0.1.13)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rollup@4.62.2)(styled-components@6.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@26.2.0)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(type-fest@2.19.0)(typescript@7.0.2)(webpack-cli@5.1.4)(webpack-dev-server@5.2.3(webpack-cli@5.1.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.25.5)(webpack-cli@5.1.4)))(webpack-hot-middleware@2.26.1)': dependencies: '@babel/parser': 7.29.2 '@babel/traverse': 7.29.0 @@ -33937,7 +34070,7 @@ snapshots: '@modern-js/plugin-v2': 2.70.5(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@modern-js/prod-server': 2.70.5(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@modern-js/rsbuild-plugin-esbuild': 2.70.5(@swc/core@1.15.41(@swc/helpers@0.5.17))(webpack-cli@5.1.4) - '@modern-js/server': 2.70.5(@babel/traverse@7.29.0)(@rsbuild/core@1.7.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0) + '@modern-js/server': 2.70.5(@babel/traverse@7.29.0)(@rsbuild/core@1.7.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@26.2.0)(typescript@7.0.2))(tsconfig-paths@4.2.0) '@modern-js/server-core': 2.70.5(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@modern-js/server-utils': 2.70.5(@babel/traverse@7.29.0)(@rsbuild/core@1.7.3) '@modern-js/types': 2.70.5 @@ -33955,7 +34088,7 @@ snapshots: pkg-types: 1.3.1 std-env: 3.10.0 optionalDependencies: - ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@20.19.5)(typescript@7.0.2) + ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@26.2.0)(typescript@7.0.2) tsconfig-paths: 4.2.0 transitivePeerDependencies: - '@parcel/css' @@ -34048,17 +34181,17 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@modern-js/app-tools@3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@3.14.2)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1)))': + '@modern-js/app-tools@3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@26.2.0)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4))': dependencies: '@babel/parser': 7.29.7 '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 - '@modern-js/builder': 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) + '@modern-js/builder': 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4)) '@modern-js/i18n-utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/plugin': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/plugin-data-loader': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/prod-server': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@modern-js/server': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@3.14.2) + '@modern-js/server': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@26.2.0)(typescript@7.0.2))(tsconfig-paths@4.2.0) '@modern-js/server-core': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/server-utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/types': 3.5.0 @@ -34074,8 +34207,8 @@ snapshots: pkg-types: 1.3.1 std-env: 3.10.0 optionalDependencies: - ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2) - tsconfig-paths: 3.14.2 + ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@26.2.0)(typescript@7.0.2) + tsconfig-paths: 4.2.0 transitivePeerDependencies: - '@module-federation/runtime-tools' - '@parcel/css' @@ -34101,17 +34234,17 @@ snapshots: - utf-8-validate - webpack - '@modern-js/app-tools@3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1)))': + '@modern-js/app-tools@3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@3.14.2)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1)))': dependencies: '@babel/parser': 7.29.7 '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 - '@modern-js/builder': 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) + '@modern-js/builder': 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) '@modern-js/i18n-utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/plugin': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/plugin-data-loader': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/prod-server': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@modern-js/server': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0) + '@modern-js/server': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@3.14.2) '@modern-js/server-core': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/server-utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/types': 3.5.0 @@ -34128,7 +34261,7 @@ snapshots: std-env: 3.10.0 optionalDependencies: ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2) - tsconfig-paths: 4.2.0 + tsconfig-paths: 3.14.2 transitivePeerDependencies: - '@module-federation/runtime-tools' - '@parcel/css' @@ -34154,12 +34287,12 @@ snapshots: - utf-8-validate - webpack - '@modern-js/app-tools@3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4))': + '@modern-js/app-tools@3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1)))': dependencies: '@babel/parser': 7.29.7 '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 - '@modern-js/builder': 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) + '@modern-js/builder': 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) '@modern-js/i18n-utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/plugin': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/plugin-data-loader': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -34207,59 +34340,6 @@ snapshots: - utf-8-validate - webpack - '@modern-js/app-tools@3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(core-js@3.49.0)(encoding@0.1.13)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4))': - dependencies: - '@babel/parser': 7.29.7 - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 - '@modern-js/builder': 3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4)) - '@modern-js/i18n-utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@modern-js/plugin': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@modern-js/plugin-data-loader': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@modern-js/prod-server': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@modern-js/server': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0) - '@modern-js/server-core': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@modern-js/server-utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@modern-js/types': 3.5.0 - '@modern-js/utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) - '@swc/core': 1.15.41(@swc/helpers@0.5.17) - '@swc/helpers': 0.5.17 - es-module-lexer: 1.7.0 - flatted: 3.4.2 - import-meta-resolve: 4.2.0 - mlly: 1.8.2 - ndepe: 0.1.13(encoding@0.1.13)(rollup@4.62.2) - pkg-types: 1.3.1 - std-env: 3.10.0 - optionalDependencies: - ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@20.19.5)(typescript@7.0.2) - tsconfig-paths: 4.2.0 - transitivePeerDependencies: - - '@module-federation/runtime-tools' - - '@parcel/css' - - '@rspack/core' - - '@swc/css' - - '@typescript/native-preview' - - bufferutil - - clean-css - - core-js - - csso - - debug - - devcert - - encoding - - esbuild - - lightningcss - - react - - react-dom - - react-server-dom-rspack - - rollup - - supports-color - - tslib - - typescript - - utf-8-validate - - webpack - '@modern-js/babel-compiler@2.68.0': dependencies: '@babel/core': 7.29.7 @@ -34319,7 +34399,7 @@ snapshots: '@babel/preset-env': 7.29.2(@babel/core@7.29.0) '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) '@babel/runtime': 7.28.2 - '@babel/types': 7.29.0 + '@babel/types': 7.29.8 '@rsbuild/plugin-babel': 1.0.1-rc.4(@rsbuild/core@1.0.1-rc.4) '@swc/helpers': 0.5.3 '@types/babel__core': 7.20.5 @@ -34382,7 +34462,7 @@ snapshots: '@babel/preset-env': 7.29.2(@babel/core@7.29.7) '@babel/preset-typescript': 7.28.5(@babel/core@7.29.7) '@babel/runtime': 7.28.2 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@rsbuild/plugin-babel': 1.1.0(@rsbuild/core@1.7.3) '@swc/helpers': 0.5.17 '@types/babel__core': 7.20.5 @@ -34392,72 +34472,20 @@ snapshots: - '@rsbuild/core' - supports-color - '@modern-js/builder@3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1)))': - dependencies: - '@modern-js/utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) - '@rsbuild/plugin-assets-retry': 2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) - '@rsbuild/plugin-check-syntax': 2.0.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) - '@rsbuild/plugin-css-minimizer': 2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(esbuild@0.28.1)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) - '@rsbuild/plugin-less': 1.6.4(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) - '@rsbuild/plugin-react': 2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23)) - '@rsbuild/plugin-rem': 1.0.6(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) - '@rsbuild/plugin-sass': 1.5.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) - '@rsbuild/plugin-source-build': 1.0.6(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) - '@rsbuild/plugin-svgr': 2.0.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23))(typescript@7.0.2) - '@rsbuild/plugin-type-check': 1.5.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@7.0.2) - '@rsbuild/plugin-typed-css-modules': 1.2.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) - '@swc/core': 1.15.41(@swc/helpers@0.5.17) - '@swc/helpers': 0.5.17 - autoprefixer: 10.4.27(postcss@8.5.23) - browserslist: 4.28.2 - core-js: 3.49.0 - cssnano: 6.1.2(postcss@8.5.23) - html-minifier-terser: 7.2.0 - lodash: 4.18.1 - postcss: 8.5.23 - postcss-custom-properties: 13.3.12(postcss@8.5.23) - postcss-flexbugs-fixes: 5.0.2(postcss@8.5.23) - postcss-font-variant: 5.0.0(postcss@8.5.23) - postcss-initial: 4.0.1(postcss@8.5.23) - postcss-media-minmax: 5.0.0(postcss@8.5.23) - postcss-nesting: 12.1.5(postcss@8.5.23) - postcss-page-break: 3.0.4(postcss@8.5.23) - rsbuild-plugin-rsc: 0.1.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - rspack-manifest-plugin: 5.2.2(@rspack/core@1.3.9(@swc/helpers@0.5.23)) - ts-deepmerge: 7.0.3 - transitivePeerDependencies: - - '@module-federation/runtime-tools' - - '@parcel/css' - - '@rspack/core' - - '@swc/css' - - '@typescript/native-preview' - - clean-css - - csso - - esbuild - - lightningcss - - react - - react-dom - - react-server-dom-rspack - - supports-color - - tslib - - typescript - - webpack - - '@modern-js/builder@3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4))': + '@modern-js/builder@3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4))': dependencies: '@modern-js/utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) '@rsbuild/plugin-assets-retry': 2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) '@rsbuild/plugin-check-syntax': 2.0.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) - '@rsbuild/plugin-css-minimizer': 2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(esbuild@0.28.1)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) - '@rsbuild/plugin-less': 1.6.4(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) - '@rsbuild/plugin-react': 2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23)) + '@rsbuild/plugin-css-minimizer': 2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(esbuild@0.28.1)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4)) + '@rsbuild/plugin-less': 1.6.4(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4)) + '@rsbuild/plugin-react': 2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17)) '@rsbuild/plugin-rem': 1.0.6(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) '@rsbuild/plugin-sass': 1.5.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) '@rsbuild/plugin-source-build': 1.0.6(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) - '@rsbuild/plugin-svgr': 2.0.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23))(typescript@7.0.2) - '@rsbuild/plugin-type-check': 1.5.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@7.0.2) + '@rsbuild/plugin-svgr': 2.0.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(typescript@7.0.2) + '@rsbuild/plugin-type-check': 1.5.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(tslib@2.8.1)(typescript@7.0.2) '@rsbuild/plugin-typed-css-modules': 1.2.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) '@swc/core': 1.15.41(@swc/helpers@0.5.17) '@swc/helpers': 0.5.17 @@ -34475,8 +34503,8 @@ snapshots: postcss-media-minmax: 5.0.0(postcss@8.5.23) postcss-nesting: 12.1.5(postcss@8.5.23) postcss-page-break: 3.0.4(postcss@8.5.23) - rsbuild-plugin-rsc: 0.1.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - rspack-manifest-plugin: 5.2.2(@rspack/core@1.3.9(@swc/helpers@0.5.23)) + rsbuild-plugin-rsc: 0.1.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + rspack-manifest-plugin: 5.2.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17)) ts-deepmerge: 7.0.3 transitivePeerDependencies: - '@module-federation/runtime-tools' @@ -34496,20 +34524,20 @@ snapshots: - typescript - webpack - '@modern-js/builder@3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4))': + '@modern-js/builder@3.5.0(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1)))': dependencies: '@modern-js/utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) '@rsbuild/plugin-assets-retry': 2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) '@rsbuild/plugin-check-syntax': 2.0.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) - '@rsbuild/plugin-css-minimizer': 2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(esbuild@0.28.1)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4)) - '@rsbuild/plugin-less': 1.6.4(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4)) - '@rsbuild/plugin-react': 2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17)) + '@rsbuild/plugin-css-minimizer': 2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(esbuild@0.28.1)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) + '@rsbuild/plugin-less': 1.6.4(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) + '@rsbuild/plugin-react': 2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23)) '@rsbuild/plugin-rem': 1.0.6(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) '@rsbuild/plugin-sass': 1.5.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) '@rsbuild/plugin-source-build': 1.0.6(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) - '@rsbuild/plugin-svgr': 2.0.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(typescript@7.0.2) - '@rsbuild/plugin-type-check': 1.5.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(tslib@2.8.1)(typescript@7.0.2) + '@rsbuild/plugin-svgr': 2.0.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(typescript@7.0.2) + '@rsbuild/plugin-type-check': 1.5.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@7.0.2) '@rsbuild/plugin-typed-css-modules': 1.2.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)) '@swc/core': 1.15.41(@swc/helpers@0.5.17) '@swc/helpers': 0.5.17 @@ -34527,8 +34555,8 @@ snapshots: postcss-media-minmax: 5.0.0(postcss@8.5.23) postcss-nesting: 12.1.5(postcss@8.5.23) postcss-page-break: 3.0.4(postcss@8.5.23) - rsbuild-plugin-rsc: 0.1.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) - rspack-manifest-plugin: 5.2.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17)) + rsbuild-plugin-rsc: 0.1.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + rspack-manifest-plugin: 5.2.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23)) ts-deepmerge: 7.0.3 transitivePeerDependencies: - '@module-federation/runtime-tools' @@ -34583,7 +34611,7 @@ snapshots: - react - react-dom - '@modern-js/module-tools@2.70.5(@types/node@20.19.5)(typescript@7.0.2)': + '@modern-js/module-tools@2.70.5(@types/node@26.2.0)(typescript@7.0.2)': dependencies: '@ampproject/remapping': 2.3.0 '@ast-grep/napi': 0.35.0 @@ -34591,7 +34619,7 @@ snapshots: '@babel/types': 7.29.0 '@modern-js/core': 2.70.5 '@modern-js/plugin': 2.70.5 - '@modern-js/plugin-changeset': 2.70.5(@types/node@20.19.5) + '@modern-js/plugin-changeset': 2.70.5(@types/node@26.2.0) '@modern-js/plugin-i18n': 2.70.5 '@modern-js/swc-plugins': 0.6.11(@swc/helpers@0.5.17) '@modern-js/types': 2.70.5 @@ -34665,9 +34693,9 @@ snapshots: '@swc/helpers': 0.5.17 esbuild: 0.25.5 - '@modern-js/plugin-changeset@2.70.5(@types/node@20.19.5)': + '@modern-js/plugin-changeset@2.70.5(@types/node@26.2.0)': dependencies: - '@changesets/cli': 2.30.0(@types/node@20.19.5) + '@changesets/cli': 2.30.0(@types/node@26.2.0) '@changesets/git': 2.0.0 '@changesets/read': 0.6.7 '@modern-js/plugin-i18n': 2.70.5 @@ -34883,23 +34911,23 @@ snapshots: react-dom: 19.2.4(react@19.2.4) react-server-dom-webpack: 19.2.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.19))(esbuild@0.18.20)(webpack-cli@5.1.4)) - '@modern-js/render@3.5.0(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@modern-js/render@3.5.0(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': dependencies: '@modern-js/types': 3.5.0 '@modern-js/utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@swc/helpers': 0.5.17 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-server-dom-rspack: 0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-server-dom-rspack: 0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@modern-js/render@3.5.0(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@modern-js/render@3.5.0(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': dependencies: '@modern-js/types': 3.5.0 '@modern-js/utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@swc/helpers': 0.5.17 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-server-dom-rspack: 0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-server-dom-rspack: 0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/rsbuild-plugin-esbuild@2.70.5(@swc/core@1.15.41(@swc/helpers@0.5.17))(webpack-cli@5.1.4)': dependencies: @@ -35048,13 +35076,13 @@ snapshots: - react-server-dom-webpack - supports-color - '@modern-js/runtime@3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@modern-js/runtime@3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': dependencies: '@loadable/component': 5.16.7(react@18.3.1) '@loadable/server': 5.16.7(@loadable/component@5.16.7(react@18.3.1))(react@18.3.1) '@modern-js/plugin': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/plugin-data-loader': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@modern-js/render': 3.5.0(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + '@modern-js/render': 3.5.0(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@modern-js/runtime-utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/types': 3.5.0 '@modern-js/utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -35077,13 +35105,13 @@ snapshots: - core-js - react-server-dom-rspack - '@modern-js/runtime@3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': + '@modern-js/runtime@3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': dependencies: '@loadable/component': 5.16.7(react@18.3.1) '@loadable/server': 5.16.7(@loadable/component@5.16.7(react@18.3.1))(react@18.3.1) '@modern-js/plugin': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/plugin-data-loader': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@modern-js/render': 3.5.0(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + '@modern-js/render': 3.5.0(react-dom@18.3.1(react@18.3.1))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@modern-js/runtime-utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/types': 3.5.0 '@modern-js/utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -35275,7 +35303,7 @@ snapshots: - react - react-dom - '@modern-js/server@2.70.5(@babel/traverse@7.29.0)(@rsbuild/core@1.7.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)': + '@modern-js/server@2.70.5(@babel/traverse@7.29.0)(@rsbuild/core@1.7.3)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@26.2.0)(typescript@7.0.2))(tsconfig-paths@4.2.0)': dependencies: '@babel/core': 7.29.7 '@babel/register': 7.28.6(@babel/core@7.29.7) @@ -35292,7 +35320,7 @@ snapshots: path-to-regexp: 6.3.0 ws: 8.21.0 optionalDependencies: - ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@20.19.5)(typescript@7.0.2) + ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@26.2.0)(typescript@7.0.2) tsconfig-paths: 4.2.0 transitivePeerDependencies: - '@babel/traverse' @@ -35333,7 +35361,7 @@ snapshots: - supports-color - utf-8-validate - '@modern-js/server@3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@20.19.5)(typescript@7.0.2))(tsconfig-paths@4.2.0)': + '@modern-js/server@3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@26.2.0)(typescript@7.0.2))(tsconfig-paths@4.2.0)': dependencies: '@modern-js/runtime-utils': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@modern-js/server-core': 3.5.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -35348,7 +35376,7 @@ snapshots: path-to-regexp: 6.3.0 ws: 8.21.0 optionalDependencies: - ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@20.19.5)(typescript@7.0.2) + ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@26.2.0)(typescript@7.0.2) tsconfig-paths: 4.2.0 transitivePeerDependencies: - '@module-federation/runtime-tools' @@ -35570,7 +35598,7 @@ snapshots: dependencies: '@babel/core': 7.29.7 '@babel/preset-react': 7.28.5(@babel/core@7.29.7) - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@modern-js/babel-preset': 2.70.5(@rsbuild/core@1.7.3) '@modern-js/flight-server-transform-plugin': 2.70.5 '@modern-js/utils': 2.70.5 @@ -35650,7 +35678,7 @@ snapshots: dependencies: '@babel/core': 7.29.0 '@babel/preset-react': 7.28.5(@babel/core@7.29.0) - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@modern-js/babel-preset': 2.70.8(@rsbuild/core@1.7.3) '@modern-js/flight-server-transform-plugin': 2.70.8 '@modern-js/utils': 2.70.8 @@ -35730,7 +35758,7 @@ snapshots: dependencies: '@babel/core': 7.29.0 '@babel/preset-react': 7.28.5(@babel/core@7.29.0) - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@modern-js/babel-preset': 2.70.8(@rsbuild/core@1.7.3) '@modern-js/flight-server-transform-plugin': 2.70.8 '@modern-js/utils': 2.70.8 @@ -35974,6 +36002,24 @@ snapshots: - supports-color - utf-8-validate + '@module-federation/dts-plugin@2.7.0(typescript@5.0.4)(vue-tsc@2.2.12(typescript@5.0.4))': + dependencies: + '@module-federation/error-codes': 2.7.0 + '@module-federation/managers': 2.7.0 + '@module-federation/sdk': 2.7.0 + '@module-federation/third-party-dts-extractor': 2.7.0 + adm-zip: 0.5.10 + isomorphic-ws: 5.0.0(ws@8.21.0) + node-schedule: 2.1.1 + typescript: 5.0.4 + undici: 7.28.0 + ws: 8.21.0 + optionalDependencies: + vue-tsc: 2.2.12(typescript@5.0.4) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@module-federation/enhanced@0.21.6(@rspack/core@1.6.8(@swc/helpers@0.5.23))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)(vue-tsc@2.2.12(typescript@7.0.2))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.25.5)(webpack-cli@5.1.4))': dependencies: '@module-federation/bridge-react-webpack-plugin': 0.21.6 @@ -36049,6 +36095,8 @@ snapshots: '@module-federation/error-codes@2.2.2': {} + '@module-federation/error-codes@2.7.0': {} + '@module-federation/error-codes@2.8.2': optional: true @@ -36074,6 +36122,11 @@ snapshots: transitivePeerDependencies: - node-fetch + '@module-federation/managers@2.7.0': + dependencies: + '@module-federation/sdk': 2.7.0 + empathic: 2.0.0 + '@module-federation/manifest@0.21.6(typescript@7.0.2)(vue-tsc@2.2.12(typescript@7.0.2))': dependencies: '@module-federation/dts-plugin': 0.21.6(typescript@7.0.2)(vue-tsc@2.2.12(typescript@7.0.2)) @@ -36205,6 +36258,11 @@ snapshots: transitivePeerDependencies: - node-fetch + '@module-federation/runtime-core@2.7.0': + dependencies: + '@module-federation/error-codes': 2.7.0 + '@module-federation/sdk': 2.7.0 + '@module-federation/runtime-core@2.8.2': dependencies: '@module-federation/error-codes': 2.8.2 @@ -36316,6 +36374,12 @@ snapshots: transitivePeerDependencies: - node-fetch + '@module-federation/runtime@2.7.0': + dependencies: + '@module-federation/error-codes': 2.7.0 + '@module-federation/runtime-core': 2.7.0 + '@module-federation/sdk': 2.7.0 + '@module-federation/runtime@2.8.2': dependencies: '@module-federation/error-codes': 2.8.2 @@ -36343,6 +36407,8 @@ snapshots: optionalDependencies: node-fetch: 2.7.0(encoding@0.1.13) + '@module-federation/sdk@2.7.0': {} + '@module-federation/sdk@2.8.2': optional: true @@ -36358,6 +36424,23 @@ snapshots: fs-extra: 9.1.0 resolve: 1.22.8 + '@module-federation/third-party-dts-extractor@2.7.0': + dependencies: + empathic: 2.0.0 + exsolve: 1.0.8 + + '@module-federation/vite@1.16.16(typescript@5.0.4)(vite@5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0))(vue-tsc@2.2.12(typescript@5.0.4))': + dependencies: + '@module-federation/dts-plugin': 2.7.0(typescript@5.0.4)(vue-tsc@2.2.12(typescript@5.0.4)) + '@module-federation/runtime': 2.7.0 + '@module-federation/sdk': 2.7.0 + vite: 5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - vue-tsc + '@module-federation/webpack-bundler-runtime@0.1.6': dependencies: '@module-federation/runtime': 0.1.6 @@ -36563,20 +36646,20 @@ snapshots: '@napi-rs/wasm-runtime@0.2.12': dependencies: - '@emnapi/core': 1.9.0 + '@emnapi/core': 1.11.3 '@emnapi/runtime': 1.11.3 - '@tybys/wasm-util': 0.10.1 + '@tybys/wasm-util': 0.10.3 optional: true '@napi-rs/wasm-runtime@0.2.4': dependencies: - '@emnapi/core': 1.11.1 + '@emnapi/core': 1.11.3 '@emnapi/runtime': 1.11.3 '@tybys/wasm-util': 0.9.0 '@napi-rs/wasm-runtime@1.0.7': dependencies: - '@emnapi/core': 1.11.1 + '@emnapi/core': 1.11.3 '@emnapi/runtime': 1.11.3 '@tybys/wasm-util': 0.10.3 optional: true @@ -36585,7 +36668,7 @@ snapshots: dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.1 + '@tybys/wasm-util': 0.10.3 optional: true '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': @@ -36816,7 +36899,7 @@ snapshots: '@nx/nx-win32-x64-msvc@22.5.4': optional: true - '@nx/react@22.5.4(@babel/core@7.29.7)(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(@swc/helpers@0.5.23)(@types/babel__core@7.20.5)(@zkochan/js-yaml@0.0.7)(esbuild@0.25.5)(eslint@9.39.3(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23)))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)(vite@7.3.5(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))(vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jiti@2.6.1)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))(vue-tsc@2.2.12(typescript@7.0.2))(webpack-cli@5.1.4)': + '@nx/react@22.5.4(@babel/core@7.29.7)(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(@swc/helpers@0.5.23)(@types/babel__core@7.20.5)(@zkochan/js-yaml@0.0.7)(esbuild@0.25.5)(eslint@9.39.3(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23)))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)(vite@7.3.6(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))(vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0))(vue-tsc@2.2.12(typescript@7.0.2))(webpack-cli@5.1.4)': dependencies: '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))) '@nx/eslint': 22.5.4(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(@zkochan/js-yaml@0.0.7)(eslint@9.39.3(jiti@2.6.1))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))) @@ -36833,7 +36916,7 @@ snapshots: semver: 7.6.3 tslib: 2.8.1 optionalDependencies: - '@nx/vite': 22.5.4(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23)))(typescript@7.0.2)(vite@7.3.5(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))(vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jiti@2.6.1)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0)) + '@nx/vite': 22.5.4(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23)))(typescript@7.0.2)(vite@7.3.6(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))(vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)) transitivePeerDependencies: - '@babel/core' - '@babel/traverse' @@ -36863,20 +36946,20 @@ snapshots: dependencies: '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))) '@nx/js': 22.5.4(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))) - '@rollup/plugin-babel': 6.1.0(@babel/core@7.29.7)(@types/babel__core@7.20.5)(rollup@4.59.0) - '@rollup/plugin-commonjs': 25.0.8(rollup@4.59.0) - '@rollup/plugin-image': 3.0.3(rollup@4.59.0) - '@rollup/plugin-json': 6.1.0(rollup@4.59.0) - '@rollup/plugin-node-resolve': 15.3.1(rollup@4.59.0) - '@rollup/plugin-typescript': 12.3.0(rollup@4.59.0)(tslib@2.8.1)(typescript@7.0.2) + '@rollup/plugin-babel': 6.1.0(@babel/core@7.29.7)(@types/babel__core@7.20.5)(rollup@4.62.2) + '@rollup/plugin-commonjs': 25.0.8(rollup@4.62.2) + '@rollup/plugin-image': 3.0.3(rollup@4.62.2) + '@rollup/plugin-json': 6.1.0(rollup@4.62.2) + '@rollup/plugin-node-resolve': 15.3.1(rollup@4.62.2) + '@rollup/plugin-typescript': 12.3.0(rollup@4.62.2)(tslib@2.8.1)(typescript@7.0.2) autoprefixer: 10.4.20(postcss@8.5.23) concat-with-sourcemaps: 1.1.0 picocolors: 1.1.1 picomatch: 4.0.2 postcss: 8.5.23 postcss-modules: 6.0.1(postcss@8.5.23) - rollup: 4.59.0 - rollup-plugin-typescript2: 0.36.0(rollup@4.59.0)(typescript@7.0.2) + rollup: 4.62.2 + rollup-plugin-typescript2: 0.36.0(rollup@4.62.2)(typescript@7.0.2) tslib: 2.8.1 transitivePeerDependencies: - '@babel/core' @@ -36890,11 +36973,11 @@ snapshots: - typescript - verdaccio - '@nx/vite@22.5.4(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23)))(typescript@7.0.2)(vite@7.3.5(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))(vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jiti@2.6.1)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))': + '@nx/vite@22.5.4(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23)))(typescript@7.0.2)(vite@7.3.6(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))(vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0))': dependencies: '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))) '@nx/js': 22.5.4(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))) - '@nx/vitest': 22.5.4(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23)))(typescript@7.0.2)(vite@7.3.5(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))(vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jiti@2.6.1)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0)) + '@nx/vitest': 22.5.4(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23)))(typescript@7.0.2)(vite@7.3.6(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))(vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)) '@phenomnomnominal/tsquery': 6.1.4(typescript@7.0.2) ajv: 8.18.0 enquirer: 2.3.6 @@ -36902,8 +36985,8 @@ snapshots: semver: 7.8.5 tsconfig-paths: 4.2.0 tslib: 2.8.1 - vite: 7.3.5(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0) - vitest: 3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jiti@2.6.1)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0) + vite: 7.3.6(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0) + vitest: 3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0) transitivePeerDependencies: - '@babel/traverse' - '@swc-node/register' @@ -36915,7 +36998,7 @@ snapshots: - verdaccio optional: true - '@nx/vitest@22.5.4(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23)))(typescript@7.0.2)(vite@7.3.5(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))(vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jiti@2.6.1)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))': + '@nx/vitest@22.5.4(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23)))(typescript@7.0.2)(vite@7.3.6(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))(vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0))': dependencies: '@nx/devkit': 22.5.4(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))) '@nx/js': 22.5.4(@babel/traverse@7.29.8)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))(nx@22.5.4(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.13))(@swc/types@0.1.27)(typescript@6.0.3))(@swc/core@1.15.41(@swc/helpers@0.5.23))) @@ -36923,8 +37006,8 @@ snapshots: semver: 7.8.5 tslib: 2.8.1 optionalDependencies: - vite: 7.3.5(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0) - vitest: 3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jiti@2.6.1)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0) + vite: 7.3.6(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0) + vitest: 3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0) transitivePeerDependencies: - '@babel/traverse' - '@swc-node/register' @@ -39825,50 +39908,50 @@ snapshots: optionalDependencies: rollup: 4.62.2 - '@rollup/plugin-babel@6.1.0(@babel/core@7.29.7)(@types/babel__core@7.20.5)(rollup@4.59.0)': + '@rollup/plugin-babel@6.1.0(@babel/core@7.29.7)(@types/babel__core@7.20.5)(rollup@4.62.2)': dependencies: '@babel/core': 7.29.7 '@babel/helper-module-imports': 7.29.7 - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@rollup/pluginutils': 5.3.0(rollup@4.62.2) optionalDependencies: '@types/babel__core': 7.20.5 - rollup: 4.59.0 + rollup: 4.62.2 transitivePeerDependencies: - supports-color - '@rollup/plugin-commonjs@25.0.8(rollup@4.59.0)': + '@rollup/plugin-commonjs@25.0.8(rollup@4.62.2)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@rollup/pluginutils': 5.3.0(rollup@4.62.2) commondir: 1.0.1 estree-walker: 2.0.2 glob: 8.1.0 is-reference: 1.2.1 magic-string: 0.30.21 optionalDependencies: - rollup: 4.59.0 + rollup: 4.62.2 - '@rollup/plugin-image@3.0.3(rollup@4.59.0)': + '@rollup/plugin-image@3.0.3(rollup@4.62.2)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@rollup/pluginutils': 5.3.0(rollup@4.62.2) mini-svg-data-uri: 1.4.4 optionalDependencies: - rollup: 4.59.0 + rollup: 4.62.2 - '@rollup/plugin-json@6.1.0(rollup@4.59.0)': + '@rollup/plugin-json@6.1.0(rollup@4.62.2)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@rollup/pluginutils': 5.3.0(rollup@4.62.2) optionalDependencies: - rollup: 4.59.0 + rollup: 4.62.2 - '@rollup/plugin-node-resolve@15.3.1(rollup@4.59.0)': + '@rollup/plugin-node-resolve@15.3.1(rollup@4.62.2)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@rollup/pluginutils': 5.3.0(rollup@4.62.2) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 resolve: 1.22.8 optionalDependencies: - rollup: 4.59.0 + rollup: 4.62.2 '@rollup/plugin-replace@6.0.1(rollup@4.62.2)': dependencies: @@ -39877,13 +39960,13 @@ snapshots: optionalDependencies: rollup: 4.62.2 - '@rollup/plugin-typescript@12.3.0(rollup@4.59.0)(tslib@2.8.1)(typescript@7.0.2)': + '@rollup/plugin-typescript@12.3.0(rollup@4.62.2)(tslib@2.8.1)(typescript@7.0.2)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@rollup/pluginutils': 5.3.0(rollup@4.62.2) resolve: 1.22.8 typescript: 7.0.2 optionalDependencies: - rollup: 4.59.0 + rollup: 4.62.2 tslib: 2.8.1 '@rollup/pluginutils@4.2.1': @@ -39891,17 +39974,9 @@ snapshots: estree-walker: 2.0.2 picomatch: 2.3.1 - '@rollup/pluginutils@5.3.0(rollup@4.59.0)': - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.3 - optionalDependencies: - rollup: 4.59.0 - '@rollup/pluginutils@5.3.0(rollup@4.62.2)': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: @@ -40139,20 +40214,11 @@ snapshots: - '@module-federation/runtime-tools' '@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)': - dependencies: - '@rspack/core': 2.1.2(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23) - '@swc/helpers': 0.5.23 - optionalDependencies: - core-js: 3.49.0 - transitivePeerDependencies: - - '@module-federation/runtime-tools' - - '@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1)': dependencies: '@rspack/core': 2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23) '@swc/helpers': 0.5.23 optionalDependencies: - core-js: 3.36.1 + core-js: 3.49.0 transitivePeerDependencies: - '@module-federation/runtime-tools' @@ -40165,9 +40231,9 @@ snapshots: transitivePeerDependencies: - '@module-federation/runtime-tools' - '@rsbuild/core@2.1.4(@module-federation/runtime-tools@2.2.2(node-fetch@2.7.0(encoding@0.1.13)))(core-js@3.49.0)': + '@rsbuild/core@2.1.4(@module-federation/runtime-tools@0.21.6)(core-js@3.49.0)': dependencies: - '@rspack/core': 2.1.2(@module-federation/runtime-tools@2.2.2(node-fetch@2.7.0(encoding@0.1.13)))(@swc/helpers@0.5.23) + '@rspack/core': 2.1.2(@module-federation/runtime-tools@0.21.6)(@swc/helpers@0.5.23) '@swc/helpers': 0.5.23 optionalDependencies: core-js: 3.49.0 @@ -40273,7 +40339,7 @@ snapshots: '@rsbuild/plugin-check-syntax@1.6.1(@rsbuild/core@1.7.3)': dependencies: - acorn: 8.17.0 + acorn: 8.18.0 browserslist-to-es-version: 1.4.1 htmlparser2: 10.0.0 picocolors: 1.1.1 @@ -40283,7 +40349,7 @@ snapshots: '@rsbuild/plugin-check-syntax@2.0.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))': dependencies: - acorn: 8.17.0 + acorn: 8.18.0 browserslist-to-es-version: 1.4.1 htmlparser2: 12.0.0 picocolors: 1.1.1 @@ -40366,44 +40432,17 @@ snapshots: - lightningcss - webpack - '@rsbuild/plugin-css-minimizer@2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(esbuild@0.28.1)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4))': - dependencies: - css-minimizer-webpack-plugin: 8.0.0(esbuild@0.28.1)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) - reduce-configs: 1.1.2 - optionalDependencies: - '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) - transitivePeerDependencies: - - '@parcel/css' - - '@swc/css' - - clean-css - - csso - - esbuild - - lightningcss - - webpack - '@rsbuild/plugin-less@1.6.0(@rsbuild/core@1.7.3)': dependencies: '@rsbuild/core': 1.7.3 deepmerge: 4.3.1 reduce-configs: 1.1.2 - '@rsbuild/plugin-less@1.6.4(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1)))': - dependencies: - deepmerge: 4.3.1 - less: 4.6.4 - less-loader: 12.3.3(@rspack/core@1.3.9(@swc/helpers@0.5.23))(less@4.6.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) - reduce-configs: 1.1.2 - optionalDependencies: - '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) - transitivePeerDependencies: - - '@rspack/core' - - webpack - - '@rsbuild/plugin-less@1.6.4(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4))': + '@rsbuild/plugin-less@1.6.4(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4))': dependencies: deepmerge: 4.3.1 less: 4.6.4 - less-loader: 12.3.3(@rspack/core@1.3.9(@swc/helpers@0.5.23))(less@4.6.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) + less-loader: 12.3.3(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(less@4.6.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4)) reduce-configs: 1.1.2 optionalDependencies: '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) @@ -40411,11 +40450,11 @@ snapshots: - '@rspack/core' - webpack - '@rsbuild/plugin-less@1.6.4(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4))': + '@rsbuild/plugin-less@1.6.4(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1)))': dependencies: deepmerge: 4.3.1 less: 4.6.4 - less-loader: 12.3.3(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(less@4.6.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4)) + less-loader: 12.3.3(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(less@4.6.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))) reduce-configs: 1.1.2 optionalDependencies: '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) @@ -40520,15 +40559,6 @@ snapshots: transitivePeerDependencies: - webpack-hot-middleware - '@rsbuild/plugin-react@2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23))': - dependencies: - '@rspack/plugin-react-refresh': 2.0.0(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-refresh@0.18.0) - react-refresh: 0.18.0 - optionalDependencies: - '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) - transitivePeerDependencies: - - '@rspack/core' - '@rsbuild/plugin-react@2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))': dependencies: '@rspack/plugin-react-refresh': 2.0.0(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-refresh@0.18.0) @@ -40538,12 +40568,12 @@ snapshots: transitivePeerDependencies: - '@rspack/core' - '@rsbuild/plugin-react@2.0.1(@rsbuild/core@2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1))(@rspack/core@1.3.9(@swc/helpers@0.5.23))': + '@rsbuild/plugin-react@2.0.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))': dependencies: - '@rspack/plugin-react-refresh': 2.0.0(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-refresh@0.18.0) + '@rspack/plugin-react-refresh': 2.0.0(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-refresh@0.18.0) react-refresh: 0.18.0 optionalDependencies: - '@rsbuild/core': 2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1) + '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) transitivePeerDependencies: - '@rspack/core' @@ -40556,18 +40586,18 @@ snapshots: transitivePeerDependencies: - '@rspack/core' - '@rsbuild/plugin-react@2.1.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23))': + '@rsbuild/plugin-react@2.1.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))': dependencies: - '@rspack/plugin-react-refresh': 2.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-refresh@0.18.0) + '@rspack/plugin-react-refresh': 2.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-refresh@0.18.0) react-refresh: 0.18.0 optionalDependencies: '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) transitivePeerDependencies: - '@rspack/core' - '@rsbuild/plugin-react@2.1.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))': + '@rsbuild/plugin-react@2.1.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))': dependencies: - '@rspack/plugin-react-refresh': 2.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-refresh@0.18.0) + '@rspack/plugin-react-refresh': 2.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-refresh@0.18.0) react-refresh: 0.18.0 optionalDependencies: '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) @@ -40643,7 +40673,7 @@ snapshots: optionalDependencies: '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) - '@rsbuild/plugin-sass@2.0.1(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1))': + '@rsbuild/plugin-sass@2.0.1(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))': dependencies: deepmerge: 4.3.1 loader-utils: 2.0.4 @@ -40651,7 +40681,7 @@ snapshots: reduce-configs: 2.0.1 sass-embedded: 1.100.0 optionalDependencies: - '@rsbuild/core': 2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1) + '@rsbuild/core': 2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) '@rsbuild/plugin-source-build@1.0.4(@rsbuild/core@1.7.3)': dependencies: @@ -40690,12 +40720,12 @@ snapshots: - typescript - webpack-hot-middleware - '@rsbuild/plugin-svgr@2.0.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23))(typescript@7.0.2)': + '@rsbuild/plugin-svgr@2.0.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(typescript@7.0.2)': dependencies: - '@rsbuild/plugin-react': 2.1.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23)) + '@rsbuild/plugin-react': 2.1.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17)) '@svgr/core': 8.1.0(typescript@7.0.2) - '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@6.0.3)) - '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@6.0.3))(typescript@7.0.2) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@7.0.2)) + '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@7.0.2))(typescript@7.0.2) deepmerge: 4.3.1 loader-utils: 3.3.1 optionalDependencies: @@ -40705,12 +40735,12 @@ snapshots: - supports-color - typescript - '@rsbuild/plugin-svgr@2.0.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(typescript@7.0.2)': + '@rsbuild/plugin-svgr@2.0.3(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(typescript@7.0.2)': dependencies: - '@rsbuild/plugin-react': 2.1.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17)) + '@rsbuild/plugin-react': 2.1.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23)) '@svgr/core': 8.1.0(typescript@7.0.2) - '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@7.0.2)) - '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@7.0.2))(typescript@7.0.2) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@6.0.3)) + '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@6.0.3))(typescript@7.0.2) deepmerge: 4.3.1 loader-utils: 3.3.1 optionalDependencies: @@ -40752,12 +40782,12 @@ snapshots: - tslib - typescript - '@rsbuild/plugin-type-check@1.5.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@1.3.9(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@7.0.2)': + '@rsbuild/plugin-type-check@1.5.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(tslib@2.8.1)(typescript@7.0.2)': dependencies: deepmerge: 4.3.1 json5: 2.2.3 reduce-configs: 1.1.2 - ts-checker-rspack-plugin: 1.5.1(@rspack/core@1.3.9(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@7.0.2) + ts-checker-rspack-plugin: 1.5.1(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(tslib@2.8.1)(typescript@7.0.2) optionalDependencies: '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) transitivePeerDependencies: @@ -40765,12 +40795,12 @@ snapshots: - tslib - typescript - '@rsbuild/plugin-type-check@1.5.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(tslib@2.8.1)(typescript@7.0.2)': + '@rsbuild/plugin-type-check@1.5.0(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@7.0.2)': dependencies: deepmerge: 4.3.1 json5: 2.2.3 reduce-configs: 1.1.2 - ts-checker-rspack-plugin: 1.5.1(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(tslib@2.8.1)(typescript@7.0.2) + ts-checker-rspack-plugin: 1.5.1(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@7.0.2) optionalDependencies: '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) transitivePeerDependencies: @@ -40778,12 +40808,12 @@ snapshots: - tslib - typescript - '@rsbuild/plugin-type-check@1.5.0(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@6.0.3)': + '@rsbuild/plugin-type-check@1.5.0(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@7.0.2)': dependencies: deepmerge: 4.3.1 json5: 2.2.3 reduce-configs: 1.1.2 - ts-checker-rspack-plugin: 1.5.1(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@6.0.3) + ts-checker-rspack-plugin: 1.5.1(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@7.0.2) optionalDependencies: '@rsbuild/core': 2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) transitivePeerDependencies: @@ -40810,6 +40840,16 @@ snapshots: - '@babel/core' - supports-color + '@rsbuild/plugin-vue@1.2.9(@rsbuild/core@1.7.3)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(vue@3.5.30(typescript@5.0.4))': + dependencies: + rspack-vue-loader: 17.5.1(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(vue@3.5.30(typescript@5.0.4)) + optionalDependencies: + '@rsbuild/core': 1.7.3 + transitivePeerDependencies: + - '@rspack/core' + - '@vue/compiler-sfc' + - vue + '@rsbuild/plugin-vue@2.0.1(@rsbuild/core@2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(vue@3.5.30(typescript@7.0.2))': dependencies: rspack-vue-loader: 17.5.1(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(vue@3.5.30(typescript@7.0.2)) @@ -40922,18 +40962,6 @@ snapshots: - '@typescript/native-preview' - core-js - '@rslib/core@0.23.2(@microsoft/api-extractor@7.57.7(@types/node@20.19.5))(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(typescript@7.0.2)': - dependencies: - '@rsbuild/core': 2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) - rsbuild-plugin-dts: 0.23.2(@microsoft/api-extractor@7.57.7(@types/node@20.19.5))(@rsbuild/core@2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(typescript@7.0.2) - optionalDependencies: - '@microsoft/api-extractor': 7.57.7(@types/node@20.19.5) - typescript: 7.0.2 - transitivePeerDependencies: - - '@module-federation/runtime-tools' - - '@typescript/native-preview' - - core-js - '@rslib/core@0.23.2(@microsoft/api-extractor@7.57.7(@types/node@22.19.15))(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(typescript@6.0.3)': dependencies: '@rsbuild/core': 2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) @@ -41758,11 +41786,11 @@ snapshots: '@module-federation/runtime-tools': 2.8.2 '@swc/helpers': 0.5.23 - '@rspack/core@2.1.2(@module-federation/runtime-tools@2.2.2(node-fetch@2.7.0(encoding@0.1.13)))(@swc/helpers@0.5.23)': + '@rspack/core@2.1.2(@module-federation/runtime-tools@0.21.6)(@swc/helpers@0.5.23)': dependencies: '@rspack/binding': 2.1.2 optionalDependencies: - '@module-federation/runtime-tools': 2.2.2(node-fetch@2.7.0(encoding@0.1.13)) + '@module-federation/runtime-tools': 0.21.6 '@swc/helpers': 0.5.23 '@rspack/core@2.1.2(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23)': @@ -41825,12 +41853,6 @@ snapshots: optionalDependencies: webpack-hot-middleware: 2.26.1 - '@rspack/plugin-react-refresh@2.0.0(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-refresh@0.18.0)': - dependencies: - react-refresh: 0.18.0 - optionalDependencies: - '@rspack/core': 1.3.9(@swc/helpers@0.5.23) - '@rspack/plugin-react-refresh@2.0.0(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-refresh@0.18.0)': dependencies: react-refresh: 0.18.0 @@ -41849,12 +41871,6 @@ snapshots: optionalDependencies: '@rspack/core': 0.7.5(@swc/helpers@0.5.23) - '@rspack/plugin-react-refresh@2.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-refresh@0.18.0)': - dependencies: - react-refresh: 0.18.0 - optionalDependencies: - '@rspack/core': 1.3.9(@swc/helpers@0.5.23) - '@rspack/plugin-react-refresh@2.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-refresh@0.18.0)': dependencies: react-refresh: 0.18.0 @@ -41873,13 +41889,13 @@ snapshots: optionalDependencies: '@rspack/core': 2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23) - '@rspress/core@2.0.14(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(@types/mdast@4.0.4)(@types/react@19.2.14)(core-js@3.36.1)(micromark-util-types@2.0.2)(micromark@4.0.2)': + '@rspress/core@2.0.14(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/mdast@4.0.4)(@types/react@18.3.28)(core-js@3.49.0)(micromark-util-types@2.0.2)(micromark@4.0.2)': dependencies: '@mdx-js/mdx': 3.1.1 - '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.7) - '@rsbuild/core': 2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1) - '@rsbuild/plugin-react': 2.0.1(@rsbuild/core@2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1))(@rspack/core@1.3.9(@swc/helpers@0.5.23)) - '@rspress/shared': 2.0.14(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1) + '@mdx-js/react': 3.1.1(@types/react@18.3.28)(react@19.2.7) + '@rsbuild/core': 2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) + '@rsbuild/plugin-react': 2.0.1(@rsbuild/core@2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23)) + '@rspress/shared': 2.0.14(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) '@shikijs/rehype': 4.2.0 '@types/unist': 3.0.3 '@unhead/react': 2.1.15(react@19.2.7) @@ -41923,10 +41939,10 @@ snapshots: - micromark-util-types - supports-color - '@rspress/core@2.0.14(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/mdast@4.0.4)(@types/react@18.3.28)(core-js@3.49.0)(micromark-util-types@2.0.2)(micromark@4.0.2)': + '@rspress/core@2.0.14(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/mdast@4.0.4)(@types/react@19.2.14)(core-js@3.49.0)(micromark-util-types@2.0.2)(micromark@4.0.2)': dependencies: '@mdx-js/mdx': 3.1.1 - '@mdx-js/react': 3.1.1(@types/react@18.3.28)(react@19.2.7) + '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.7) '@rsbuild/core': 2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) '@rsbuild/plugin-react': 2.0.1(@rsbuild/core@2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23)) '@rspress/shared': 2.0.14(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) @@ -41973,15 +41989,6 @@ snapshots: - micromark-util-types - supports-color - '@rspress/shared@2.0.14(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1)': - dependencies: - '@rsbuild/core': 2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1) - '@shikijs/rehype': 4.2.0 - unified: 11.0.5 - transitivePeerDependencies: - - '@module-federation/runtime-tools' - - core-js - '@rspress/shared@2.0.14(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)': dependencies: '@rsbuild/core': 2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) @@ -42372,7 +42379,7 @@ snapshots: dependencies: '@babel/core': 7.29.7 '@babel/preset-env': 7.29.2(@babel/core@7.29.7) - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@ndelangen/get-tarball': 3.0.9 '@storybook/codemod': 7.6.24 '@storybook/core-common': 7.6.24(encoding@0.1.13) @@ -42768,7 +42775,7 @@ snapshots: '@storybook/csf': 0.1.13 '@storybook/global': 5.0.0 '@storybook/types': 7.6.24 - '@types/qs': 6.15.0 + '@types/qs': 6.15.1 dequal: 2.0.3 lodash: 4.18.1 memoizerific: 1.11.3 @@ -42783,16 +42790,16 @@ snapshots: '@storybook/preview@7.6.24': {} - '@storybook/react-docgen-typescript-plugin@1.0.1(typescript@6.0.3)(webpack@5.104.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(esbuild@0.25.5)(webpack-cli@5.1.4))': + '@storybook/react-docgen-typescript-plugin@1.0.1(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(esbuild@0.25.5)(webpack-cli@5.1.4))': dependencies: debug: 4.4.3(supports-color@8.1.1) endent: 2.1.0 find-cache-dir: 3.3.2 flat-cache: 3.2.0 micromatch: 4.0.8 - react-docgen-typescript: 2.4.0(typescript@6.0.3) + react-docgen-typescript: 2.4.0(typescript@7.0.2) tslib: 2.8.1 - typescript: 6.0.3 + typescript: 7.0.2 webpack: 5.104.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(esbuild@0.25.5)(webpack-cli@5.1.4) transitivePeerDependencies: - supports-color @@ -42879,7 +42886,7 @@ snapshots: - encoding - supports-color - '@storybook/react@8.6.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.17(prettier@3.8.1))(typescript@6.0.3)': + '@storybook/react@8.6.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.17(prettier@3.8.1))(typescript@7.0.2)': dependencies: '@storybook/components': 8.6.18(storybook@8.6.17(prettier@3.8.1)) '@storybook/global': 5.0.0 @@ -42891,7 +42898,7 @@ snapshots: react-dom: 18.3.1(react@18.3.1) storybook: 8.6.17(prettier@3.8.1) optionalDependencies: - typescript: 6.0.3 + typescript: 7.0.2 '@storybook/react@9.0.9(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(storybook@8.6.17(prettier@3.8.1))(typescript@6.0.3)': dependencies: @@ -43517,11 +43524,6 @@ snapshots: '@turbo/windows-arm64@2.10.2': optional: true - '@tybys/wasm-util@0.10.1': - dependencies: - tslib: 2.8.1 - optional: true - '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 @@ -43546,24 +43548,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@types/body-parser@1.19.6': dependencies: @@ -43597,7 +43599,7 @@ snapshots: '@types/connect-history-api-fallback@1.5.4': dependencies: - '@types/express-serve-static-core': 4.19.8 + '@types/express-serve-static-core': 4.19.9 '@types/node': 20.19.5 '@types/connect@3.4.38': @@ -43773,11 +43775,11 @@ snapshots: '@types/esquery@1.5.4': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/estree-jsx@1.0.5': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/estree@0.0.51': {} @@ -43785,16 +43787,9 @@ snapshots: '@types/estree@1.0.9': {} - '@types/express-serve-static-core@4.19.8': - dependencies: - '@types/node': 20.19.5 - '@types/qs': 6.15.0 - '@types/range-parser': 1.2.7 - '@types/send': 1.2.1 - '@types/express-serve-static-core@4.19.9': dependencies: - '@types/node': 26.2.0 + '@types/node': 20.19.5 '@types/qs': 6.15.1 '@types/range-parser': 1.2.7 '@types/send': 1.2.1 @@ -43802,8 +43797,8 @@ snapshots: '@types/express@4.17.21': dependencies: '@types/body-parser': 1.19.6 - '@types/express-serve-static-core': 4.19.8 - '@types/qs': 6.15.0 + '@types/express-serve-static-core': 4.19.9 + '@types/qs': 6.15.1 '@types/serve-static': 2.2.0 '@types/express@4.17.25': @@ -43968,6 +43963,7 @@ snapshots: '@types/node@26.2.0': dependencies: undici-types: 8.3.0 + optional: true '@types/normalize-package-data@2.4.4': {} @@ -43983,8 +43979,6 @@ snapshots: '@types/pug@2.0.10': {} - '@types/qs@6.15.0': {} - '@types/qs@6.15.1': {} '@types/range-parser@1.2.7': {} @@ -44016,7 +44010,7 @@ snapshots: '@types/react-router-dom@5.3.3': dependencies: '@types/history': 4.7.11 - '@types/react': 18.3.28 + '@types/react': 19.2.14 '@types/react-router': 5.1.20 '@types/react-router@5.1.20': @@ -44797,8 +44791,8 @@ snapshots: dependencies: '@mapbox/node-pre-gyp': 1.0.11(encoding@0.1.13) '@rollup/pluginutils': 4.2.1 - acorn: 8.17.0 - acorn-import-attributes: 1.9.5(acorn@8.17.0) + acorn: 8.18.0 + acorn-import-attributes: 1.9.5(acorn@8.18.0) async-sema: 3.1.1 bindings: 1.5.0 estree-walker: 2.0.2 @@ -44815,8 +44809,8 @@ snapshots: dependencies: '@mapbox/node-pre-gyp': 2.0.3(encoding@0.1.13) '@rollup/pluginutils': 5.3.0(rollup@4.62.2) - acorn: 8.17.0 - acorn-import-attributes: 1.9.5(acorn@8.17.0) + acorn: 8.18.0 + acorn-import-attributes: 1.9.5(acorn@8.18.0) async-sema: 3.1.1 bindings: 1.5.0 estree-walker: 2.0.2 @@ -44958,11 +44952,22 @@ snapshots: vite: 5.4.21(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) vue: 3.5.30(typescript@7.0.2) + '@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0))(vue@3.5.30(typescript@5.0.4))': + dependencies: + vite: 5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) + vue: 3.5.30(typescript@5.0.4) + '@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0))(vue@3.5.30(typescript@7.0.2))': dependencies: vite: 5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) vue: 3.5.30(typescript@7.0.2) + '@vitest/expect@1.6.0': + dependencies: + '@vitest/spy': 1.6.0 + '@vitest/utils': 1.6.0 + chai: 4.5.0 + '@vitest/expect@3.2.6': dependencies: '@types/chai': 5.2.3 @@ -44971,23 +44976,23 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.6(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(vite@7.3.6(@types/node@20.19.5)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))': + '@vitest/mocker@3.2.6(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(vite@5.4.21(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0))': dependencies: '@vitest/spy': 3.2.6 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3) - vite: 7.3.6(@types/node@20.19.5)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) + vite: 5.4.21(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) - '@vitest/mocker@3.2.6(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(vite@7.3.6(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0))': + '@vitest/mocker@3.2.6(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(vite@5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0))': dependencies: '@vitest/spy': 3.2.6 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3) - vite: 7.3.6(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0) + vite: 5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0) optional: true '@vitest/pretty-format@3.2.6': @@ -44998,22 +45003,45 @@ snapshots: dependencies: tinyrainbow: 2.0.0 + '@vitest/runner@1.6.0': + dependencies: + '@vitest/utils': 1.6.0 + p-limit: 5.0.0 + pathe: 1.1.2 + '@vitest/runner@3.2.6': dependencies: '@vitest/utils': 3.2.6 pathe: 2.0.3 strip-literal: 3.1.0 + '@vitest/snapshot@1.6.0': + dependencies: + magic-string: 0.30.21 + pathe: 1.1.2 + pretty-format: 29.7.0 + '@vitest/snapshot@3.2.6': dependencies: '@vitest/pretty-format': 3.2.6 magic-string: 0.30.21 pathe: 2.0.3 + '@vitest/spy@1.6.0': + dependencies: + tinyspy: 2.2.1 + '@vitest/spy@3.2.6': dependencies: tinyspy: 4.0.4 + '@vitest/utils@1.6.0': + dependencies: + diff-sequences: 29.6.3 + estree-walker: 3.0.3 + loupe: 2.3.7 + pretty-format: 29.7.0 + '@vitest/utils@3.2.6': dependencies: '@vitest/pretty-format': 3.2.6 @@ -45058,7 +45086,7 @@ snapshots: '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) '@babel/template': 7.29.7 '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@vue/babel-helper-vue-transform-on': 1.5.0 '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.29.0) '@vue/shared': 3.5.30 @@ -45074,7 +45102,7 @@ snapshots: '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.7) '@babel/template': 7.29.7 '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@vue/babel-helper-vue-transform-on': 1.5.0 '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.29.7) '@vue/shared': 3.5.30 @@ -45090,7 +45118,7 @@ snapshots: '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.7) '@babel/template': 7.29.7 '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@vue/babel-helper-vue-transform-on': 2.0.1 '@vue/babel-plugin-resolve-type': 2.0.1(@babel/core@7.29.7) '@vue/shared': 3.5.30 @@ -45105,7 +45133,7 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-module-imports': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@vue/compiler-sfc': 3.5.30 transitivePeerDependencies: - supports-color @@ -45116,7 +45144,7 @@ snapshots: '@babel/core': 7.29.7 '@babel/helper-module-imports': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@vue/compiler-sfc': 3.5.30 transitivePeerDependencies: - supports-color @@ -45127,14 +45155,14 @@ snapshots: '@babel/core': 7.29.7 '@babel/helper-module-imports': 7.29.7 '@babel/helper-plugin-utils': 7.28.6 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@vue/compiler-sfc': 3.5.30 transitivePeerDependencies: - supports-color '@vue/compiler-core@3.5.30': dependencies: - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@vue/shared': 3.5.30 entities: 7.0.1 estree-walker: 2.0.2 @@ -45147,7 +45175,7 @@ snapshots: '@vue/compiler-sfc@3.5.30': dependencies: - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@vue/compiler-core': 3.5.30 '@vue/compiler-dom': 3.5.30 '@vue/compiler-ssr': 3.5.30 @@ -45197,6 +45225,20 @@ snapshots: optionalDependencies: typescript: 7.0.2 + '@vue/language-core@2.2.12(typescript@5.0.4)': + dependencies: + '@volar/language-core': 2.4.15 + '@vue/compiler-dom': 3.5.30 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.30 + alien-signals: 1.0.13 + minimatch: 9.0.9 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + optionalDependencies: + typescript: 5.0.4 + optional: true + '@vue/language-core@2.2.12(typescript@6.0.3)': dependencies: '@volar/language-core': 2.4.15 @@ -45239,6 +45281,12 @@ snapshots: '@vue/shared': 3.5.30 csstype: 3.2.3 + '@vue/server-renderer@3.5.30(vue@3.5.30(typescript@5.0.4))': + dependencies: + '@vue/compiler-ssr': 3.5.30 + '@vue/shared': 3.5.30 + vue: 3.5.30(typescript@5.0.4) + '@vue/server-renderer@3.5.30(vue@3.5.30(typescript@6.0.3))': dependencies: '@vue/compiler-ssr': 3.5.30 @@ -45578,16 +45626,16 @@ snapshots: acorn-globals@7.0.1: dependencies: - acorn: 8.17.0 + acorn: 8.18.0 acorn-walk: 8.3.5 acorn-import-attributes@1.9.5(acorn@8.16.0): dependencies: acorn: 8.16.0 - acorn-import-attributes@1.9.5(acorn@8.17.0): + acorn-import-attributes@1.9.5(acorn@8.18.0): dependencies: - acorn: 8.17.0 + acorn: 8.18.0 acorn-import-phases@1.0.4(acorn@8.17.0): dependencies: @@ -45597,9 +45645,9 @@ snapshots: dependencies: acorn: 7.4.1 - acorn-jsx@5.3.2(acorn@8.17.0): + acorn-jsx@5.3.2(acorn@8.18.0): dependencies: - acorn: 8.17.0 + acorn: 8.18.0 acorn-loose@8.5.2: dependencies: @@ -45609,7 +45657,7 @@ snapshots: acorn-walk@8.3.5: dependencies: - acorn: 8.17.0 + acorn: 8.18.0 acorn@7.4.1: {} @@ -45626,6 +45674,8 @@ snapshots: loader-utils: 2.0.4 regex-parser: 2.3.1 + adm-zip@0.5.10: {} + adm-zip@0.5.16: {} adm-zip@0.5.18: {} @@ -46251,6 +46301,8 @@ snapshots: object.assign: 4.1.7 util: 0.12.5 + assertion-error@1.1.0: {} + assertion-error@2.0.1: {} assign-symbols@1.0.0: {} @@ -46876,7 +46928,7 @@ snapshots: dependencies: ansi-align: 3.0.1 camelcase: 7.0.1 - chalk: 5.0.1 + chalk: 5.6.2 cli-boxes: 3.0.0 string-width: 5.1.2 type-fest: 2.19.0 @@ -47170,6 +47222,16 @@ snapshots: ccount@2.0.1: {} + chai@4.5.0: + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.3 + deep-eql: 4.1.4 + get-func-name: 2.0.2 + loupe: 2.3.7 + pathval: 1.1.1 + type-detect: 4.1.0 + chai@5.3.3: dependencies: assertion-error: 2.0.1 @@ -47238,6 +47300,10 @@ snapshots: chardet@2.1.1: {} + check-error@1.0.3: + dependencies: + get-func-name: 2.0.2 + check-error@2.1.3: {} check-more-types@2.24.0: {} @@ -48113,18 +48179,6 @@ snapshots: optionalDependencies: esbuild: 0.28.1 - css-minimizer-webpack-plugin@8.0.0(esbuild@0.28.1)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - cssnano: 7.1.3(postcss@8.5.23) - jest-worker: 30.4.1 - postcss: 8.5.23 - schema-utils: 4.3.0 - serialize-javascript: 7.0.7 - webpack: 5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4) - optionalDependencies: - esbuild: 0.28.1 - css-select@4.3.0: dependencies: boolbase: 1.0.0 @@ -48644,6 +48698,10 @@ snapshots: optionalDependencies: babel-plugin-macros: 3.1.0 + deep-eql@4.1.4: + dependencies: + type-detect: 4.1.0 + deep-eql@5.0.2: {} deep-equal@1.0.1: {} @@ -49230,7 +49288,7 @@ snapshots: esast-util-from-js@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 - acorn: 8.17.0 + acorn: 8.18.0 esast-util-from-estree: 2.0.0 vfile-message: 4.0.3 @@ -49547,7 +49605,7 @@ snapshots: eslint: 9.26.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@6.0.3))(eslint@9.26.0(jiti@2.6.1)))(eslint@9.26.0(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@6.0.3))(eslint@9.26.0(jiti@2.6.1)))(eslint@9.26.0(jiti@2.6.1)))(eslint@9.26.0(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.1(eslint@9.26.0(jiti@2.6.1)) eslint-plugin-react: 7.37.2(eslint@9.26.0(jiti@2.6.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.26.0(jiti@2.6.1)) @@ -49588,7 +49646,7 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@6.0.3))(eslint@9.26.0(jiti@2.6.1)))(eslint@9.26.0(jiti@2.6.1)))(eslint@9.26.0(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -49713,7 +49771,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.26.0(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@6.0.3))(eslint@9.26.0(jiti@2.6.1)))(eslint@9.26.0(jiti@2.6.1)))(eslint@9.26.0(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -49725,7 +49783,7 @@ snapshots: eslint: 9.26.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@6.0.3))(eslint@9.26.0(jiti@2.6.1)))(eslint@9.26.0(jiti@2.6.1)))(eslint@9.26.0(jiti@2.6.1)) - hasown: 2.0.2 + hasown: 2.0.4 is-core-module: 2.16.1 is-glob: 4.0.3 minimatch: 3.1.5 @@ -49851,7 +49909,7 @@ snapshots: eslint-plugin-react-hooks@7.0.1(eslint@9.26.0(jiti@2.6.1)): dependencies: '@babel/core': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 eslint: 9.26.0(jiti@2.6.1) hermes-parser: 0.25.1 zod: 4.1.12 @@ -50118,14 +50176,14 @@ snapshots: espree@10.4.0: dependencies: - acorn: 8.17.0 - acorn-jsx: 5.3.2(acorn@8.17.0) + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) eslint-visitor-keys: 4.2.1 espree@9.6.1: dependencies: - acorn: 8.17.0 - acorn-jsx: 5.3.2(acorn@8.17.0) + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} @@ -50152,7 +50210,7 @@ snapshots: estree-util-attach-comments@3.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 estree-util-build-jsx@3.0.1: dependencies: @@ -50165,7 +50223,7 @@ snapshots: estree-util-scope@1.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 devlop: 1.1.0 estree-util-to-js@2.0.0: @@ -50183,7 +50241,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esutils@2.0.3: {} @@ -50423,6 +50481,8 @@ snapshots: transitivePeerDependencies: - supports-color + exsolve@1.0.8: {} + ext-list@2.2.2: dependencies: mime-db: 1.54.0 @@ -50845,7 +50905,7 @@ snapshots: asynckit: 0.4.0 combined-stream: 1.0.8 es-set-tostringtag: 2.1.0 - hasown: 2.0.2 + hasown: 2.0.4 mime-types: 2.1.35 form-data@4.0.6: @@ -51034,6 +51094,8 @@ snapshots: get-east-asian-width@1.6.0: {} + get-func-name@2.0.2: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -51482,7 +51544,7 @@ snapshots: hast-util-to-estree@3.1.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 comma-separated-tokens: 2.0.3 @@ -51517,7 +51579,7 @@ snapshots: hast-util-to-jsx-runtime@2.3.6: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/hast': 3.0.4 '@types/unist': 3.0.3 comma-separated-tokens: 2.0.3 @@ -52198,7 +52260,7 @@ snapshots: is-core-module@2.16.1: dependencies: - hasown: 2.0.2 + hasown: 2.0.4 is-core-module@2.16.2: dependencies: @@ -52366,7 +52428,7 @@ snapshots: is-reference@1.2.1: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 is-regex@1.2.1: dependencies: @@ -52945,10 +53007,10 @@ snapshots: jest-snapshot@29.7.0: dependencies: '@babel/core': 7.29.7 - '@babel/generator': 7.29.7 + '@babel/generator': 7.29.8 '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.7) '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.7) - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 @@ -53151,7 +53213,7 @@ snapshots: jsdom@20.0.3: dependencies: abab: 2.0.6 - acorn: 8.17.0 + acorn: 8.18.0 acorn-globals: 7.0.1 cssom: 0.5.0 cssstyle: 2.3.0 @@ -53360,26 +53422,19 @@ snapshots: less: 4.6.4 webpack: 5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.25.5)(webpack-cli@5.1.4) - less-loader@12.3.3(@rspack/core@1.3.9(@swc/helpers@0.5.23))(less@4.6.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))): - dependencies: - less: 4.6.4 - optionalDependencies: - '@rspack/core': 1.3.9(@swc/helpers@0.5.23) - webpack: 5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1)) - - less-loader@12.3.3(@rspack/core@1.3.9(@swc/helpers@0.5.23))(less@4.6.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)): + less-loader@12.3.3(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(less@4.6.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4)): dependencies: less: 4.6.4 optionalDependencies: - '@rspack/core': 1.3.9(@swc/helpers@0.5.23) - webpack: 5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4) + '@rspack/core': 2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17) + webpack: 5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4) - less-loader@12.3.3(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(less@4.6.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4)): + less-loader@12.3.3(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(less@4.6.4)(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1))): dependencies: less: 4.6.4 optionalDependencies: - '@rspack/core': 2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17) - webpack: 5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.17))(esbuild@0.28.1)(webpack-cli@5.1.4) + '@rspack/core': 2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23) + webpack: 5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4(webpack-dev-server@5.2.3)(webpack@5.104.1)) less@4.6.4: dependencies: @@ -53531,6 +53586,11 @@ snapshots: loader-utils@3.3.1: {} + local-pkg@0.5.1: + dependencies: + mlly: 1.8.2 + pkg-types: 1.3.1 + locate-path@3.0.0: dependencies: p-locate: 3.0.0 @@ -53644,6 +53704,10 @@ snapshots: dependencies: js-tokens: 4.0.0 + loupe@2.3.7: + dependencies: + get-func-name: 2.0.2 + loupe@3.2.1: {} lower-case@2.0.2: @@ -54229,7 +54293,7 @@ snapshots: metro-source-map@0.83.5: dependencies: '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 flow-enums-runtime: 0.0.6 invariant: 2.2.4 metro-symbolicate: 0.83.5 @@ -54276,7 +54340,7 @@ snapshots: metro-transform-plugins@0.83.5: dependencies: '@babel/core': 7.29.7 - '@babel/generator': 7.29.7 + '@babel/generator': 7.29.8 '@babel/template': 7.29.7 '@babel/traverse': 7.29.7 flow-enums-runtime: 0.0.6 @@ -54288,8 +54352,8 @@ snapshots: dependencies: '@babel/core': 7.29.0 '@babel/generator': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 flow-enums-runtime: 0.0.6 metro: 0.82.5 metro-babel-transformer: 0.82.5 @@ -54307,9 +54371,9 @@ snapshots: metro-transform-worker@0.83.5: dependencies: '@babel/core': 7.29.7 - '@babel/generator': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 flow-enums-runtime: 0.0.6 metro: 0.83.5 metro-babel-transformer: 0.83.5 @@ -54535,7 +54599,7 @@ snapshots: micromark-extension-mdx-expression@3.0.1: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 devlop: 1.1.0 micromark-factory-mdx-expression: 2.0.3 micromark-factory-space: 2.0.1 @@ -54546,7 +54610,7 @@ snapshots: micromark-extension-mdx-jsx@3.0.2: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 micromark-factory-mdx-expression: 2.0.3 @@ -54563,7 +54627,7 @@ snapshots: micromark-extension-mdxjs-esm@3.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 micromark-util-character: 2.1.1 @@ -54575,8 +54639,8 @@ snapshots: micromark-extension-mdxjs@3.0.0: dependencies: - acorn: 8.17.0 - acorn-jsx: 5.3.2(acorn@8.17.0) + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) micromark-extension-mdx-expression: 3.0.1 micromark-extension-mdx-jsx: 3.0.2 micromark-extension-mdx-md: 2.0.0 @@ -54599,7 +54663,7 @@ snapshots: micromark-factory-mdx-expression@2.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 devlop: 1.1.0 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 @@ -54663,7 +54727,7 @@ snapshots: micromark-util-events-to-acorn@2.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/unist': 3.0.3 devlop: 1.1.0 estree-util-visit: 2.0.0 @@ -54898,21 +54962,21 @@ snapshots: mlly@1.6.1: dependencies: - acorn: 8.17.0 + acorn: 8.18.0 pathe: 1.1.2 pkg-types: 1.3.1 ufo: 1.6.3 mlly@1.8.1: dependencies: - acorn: 8.17.0 + acorn: 8.18.0 pathe: 2.0.3 pkg-types: 1.3.1 ufo: 1.6.3 mlly@1.8.2: dependencies: - acorn: 8.17.0 + acorn: 8.18.0 pathe: 2.0.3 pkg-types: 1.3.1 ufo: 1.6.3 @@ -55703,6 +55767,10 @@ snapshots: dependencies: yocto-queue: 1.2.2 + p-limit@5.0.0: + dependencies: + yocto-queue: 1.2.2 + p-limit@6.2.0: dependencies: yocto-queue: 1.2.2 @@ -55905,6 +55973,8 @@ snapshots: pathe@2.0.3: {} + pathval@1.1.1: {} + pathval@2.0.1: {} pause-stream@0.0.11: @@ -56214,29 +56284,29 @@ snapshots: postcss: 8.4.49 ts-node: 10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@20.19.5)(typescript@6.0.3) - postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@5.9.3)): + postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2)): dependencies: lilconfig: 3.1.3 yaml: 2.8.2 optionalDependencies: postcss: 8.4.49 - ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@5.9.3) + ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2) - postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@6.0.3)): + postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@26.2.0)(typescript@5.9.3)): dependencies: lilconfig: 3.1.3 yaml: 2.8.2 optionalDependencies: postcss: 8.4.49 - ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@6.0.3) + ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@26.2.0)(typescript@5.9.3) - postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2)): + postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@26.2.0)(typescript@7.0.2)): dependencies: lilconfig: 3.1.3 yaml: 2.8.2 optionalDependencies: postcss: 8.4.49 - ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2) + ts-node: 10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@26.2.0)(typescript@7.0.2) postcss-load-config@4.0.2(postcss@8.5.23)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@22.19.15)(typescript@6.0.3)): dependencies: @@ -58370,7 +58440,7 @@ snapshots: react-docgen@6.0.0-alpha.3: dependencies: '@babel/core': 7.29.7 - '@babel/generator': 7.29.7 + '@babel/generator': 7.29.8 ast-types: 0.14.2 commander: 2.20.3 doctrine: 3.0.0 @@ -58386,7 +58456,7 @@ snapshots: dependencies: '@babel/core': 7.29.7 '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.28.0 '@types/doctrine': 0.0.9 @@ -58890,15 +58960,15 @@ snapshots: optionalDependencies: react-dom: 18.3.1(react@18.3.1) - react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@rspack/core': 1.3.9(@swc/helpers@0.5.23) + '@rspack/core': 2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@rspack/core': 2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17) + '@rspack/core': 2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -59134,14 +59204,14 @@ snapshots: recma-build-jsx@1.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 estree-util-build-jsx: 3.0.1 vfile: 6.0.3 - recma-jsx@1.0.1(acorn@8.17.0): + recma-jsx@1.0.1(acorn@8.18.0): dependencies: - acorn: 8.17.0 - acorn-jsx: 5.3.2(acorn@8.17.0) + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) estree-util-to-js: 2.0.0 recma-parse: 1.0.0 recma-stringify: 1.0.0 @@ -59149,14 +59219,14 @@ snapshots: recma-parse@1.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esast-util-from-js: 2.0.1 unified: 11.0.5 vfile: 6.0.3 recma-stringify@1.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 estree-util-to-js: 2.0.0 unified: 11.0.5 vfile: 6.0.3 @@ -59272,7 +59342,7 @@ snapshots: rehype-recma@1.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/hast': 3.0.4 hast-util-to-estree: 3.1.3 transitivePeerDependencies: @@ -59646,12 +59716,12 @@ snapshots: globby: 10.0.1 is-plain-object: 3.0.1 - rollup-plugin-typescript2@0.36.0(rollup@4.59.0)(typescript@7.0.2): + rollup-plugin-typescript2@0.36.0(rollup@4.62.2)(typescript@7.0.2): dependencies: '@rollup/pluginutils': 4.2.1 find-cache-dir: 3.3.2 fs-extra: 10.1.0 - rollup: 4.59.0 + rollup: 4.62.2 semver: 7.8.5 tslib: 2.8.1 typescript: 7.0.2 @@ -59763,14 +59833,6 @@ snapshots: '@microsoft/api-extractor': 7.57.7(@types/node@20.19.5) typescript: 6.0.3 - rsbuild-plugin-dts@0.23.2(@microsoft/api-extractor@7.57.7(@types/node@20.19.5))(@rsbuild/core@2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(typescript@7.0.2): - dependencies: - '@ast-grep/napi': 0.37.0 - '@rsbuild/core': 2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) - optionalDependencies: - '@microsoft/api-extractor': 7.57.7(@types/node@20.19.5) - typescript: 7.0.2 - rsbuild-plugin-dts@0.23.2(@microsoft/api-extractor@7.57.7(@types/node@22.19.15))(@rsbuild/core@2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(typescript@6.0.3): dependencies: '@ast-grep/napi': 0.37.0 @@ -59821,22 +59883,15 @@ snapshots: optionalDependencies: '@rsbuild/core': 1.7.3 - rsbuild-plugin-publint@0.2.1(@rsbuild/core@2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)): - dependencies: - picocolors: 1.1.1 - publint: 0.2.12 - optionalDependencies: - '@rsbuild/core': 2.1.4(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) - - rsbuild-plugin-rsc@0.1.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(react-server-dom-rspack@0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): + rsbuild-plugin-rsc@0.1.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): dependencies: '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) - react-server-dom-rspack: 0.0.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-server-dom-rspack: 0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rsbuild-plugin-rsc@0.1.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(react-server-dom-rspack@0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): + rsbuild-plugin-rsc@0.1.1(@rsbuild/core@2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(react-server-dom-rspack@0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): dependencies: '@rsbuild/core': 2.1.0(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) - react-server-dom-rspack: 0.0.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-server-dom-rspack: 0.0.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rslog@1.2.3: {} @@ -59854,21 +59909,29 @@ snapshots: optionalDependencies: '@rspack/core': 1.7.9(@swc/helpers@0.5.19) - rspack-manifest-plugin@5.2.2(@rspack/core@1.3.9(@swc/helpers@0.5.23)): + rspack-manifest-plugin@5.2.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17)): dependencies: '@rspack/lite-tapable': 1.1.2 optionalDependencies: - '@rspack/core': 1.3.9(@swc/helpers@0.5.23) + '@rspack/core': 2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17) - rspack-manifest-plugin@5.2.2(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17)): + rspack-manifest-plugin@5.2.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23)): dependencies: '@rspack/lite-tapable': 1.1.2 optionalDependencies: - '@rspack/core': 2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17) + '@rspack/core': 2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23) + + rspack-vue-loader@17.5.1(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(vue@3.5.30(typescript@5.0.4)): + dependencies: + '@rspack/lite-tapable': 1.1.2 + chalk: 4.1.2 + optionalDependencies: + '@rspack/core': 2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23) + vue: 3.5.30(typescript@5.0.4) rspack-vue-loader@17.5.1(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(vue@3.5.30(typescript@7.0.2)): dependencies: - '@rspack/lite-tapable': 1.1.0 + '@rspack/lite-tapable': 1.1.2 chalk: 4.1.2 optionalDependencies: '@rspack/core': 2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23) @@ -60783,18 +60846,18 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 - storybook-addon-rslib@1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rslib/core@0.23.2(@microsoft/api-extractor@7.57.7(@types/node@26.2.0))(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(typescript@6.0.3))(storybook-builder-rsbuild@1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/react@18.3.28)(storybook@8.6.17(prettier@3.8.1))(tslib@2.8.1)(typescript@6.0.3))(typescript@6.0.3): + storybook-addon-rslib@1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rslib/core@0.23.2(@microsoft/api-extractor@7.57.7(@types/node@26.2.0))(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(typescript@7.0.2))(storybook-builder-rsbuild@1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/react@18.3.28)(storybook@8.6.17(prettier@3.8.1))(tslib@2.8.1)(typescript@7.0.2))(typescript@7.0.2): dependencies: '@rsbuild/core': 2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) - '@rslib/core': 0.23.2(@microsoft/api-extractor@7.57.7(@types/node@26.2.0))(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(typescript@6.0.3) - storybook-builder-rsbuild: 1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/react@18.3.28)(storybook@8.6.17(prettier@3.8.1))(tslib@2.8.1)(typescript@6.0.3) + '@rslib/core': 0.23.2(@microsoft/api-extractor@7.57.7(@types/node@26.2.0))(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0)(typescript@7.0.2) + storybook-builder-rsbuild: 1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/react@18.3.28)(storybook@8.6.17(prettier@3.8.1))(tslib@2.8.1)(typescript@7.0.2) optionalDependencies: - typescript: 6.0.3 + typescript: 7.0.2 - storybook-builder-rsbuild@1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/react@18.3.28)(storybook@8.6.17(prettier@3.8.1))(tslib@2.8.1)(typescript@6.0.3): + storybook-builder-rsbuild@1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/react@18.3.28)(storybook@8.6.17(prettier@3.8.1))(tslib@2.8.1)(typescript@7.0.2): dependencies: '@rsbuild/core': 2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) - '@rsbuild/plugin-type-check': 1.5.0(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@6.0.3) + '@rsbuild/plugin-type-check': 1.5.0(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@7.0.2) '@storybook/addon-docs': 8.6.18(@types/react@18.3.28)(storybook@8.6.17(prettier@3.8.1)) '@storybook/core-webpack': 8.6.18(storybook@8.6.17(prettier@3.8.1)) browser-assert: 1.2.1 @@ -60814,32 +60877,32 @@ snapshots: util: 0.12.5 util-deprecate: 1.0.2 optionalDependencies: - typescript: 6.0.3 + typescript: 7.0.2 transitivePeerDependencies: - '@rspack/core' - '@types/react' - '@typescript/native-preview' - tslib - storybook-react-rsbuild@1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(storybook@8.6.17(prettier@3.8.1))(tslib@2.8.1)(typescript@6.0.3)(webpack@5.104.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(esbuild@0.25.5)(webpack-cli@5.1.4)): + storybook-react-rsbuild@1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.62.2)(storybook@8.6.17(prettier@3.8.1))(tslib@2.8.1)(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(esbuild@0.25.5)(webpack-cli@5.1.4)): dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.62.2) '@rsbuild/core': 2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) - '@storybook/react': 8.6.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.17(prettier@3.8.1))(typescript@6.0.3) - '@storybook/react-docgen-typescript-plugin': 1.0.1(typescript@6.0.3)(webpack@5.104.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(esbuild@0.25.5)(webpack-cli@5.1.4)) + '@storybook/react': 8.6.18(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.17(prettier@3.8.1))(typescript@7.0.2) + '@storybook/react-docgen-typescript-plugin': 1.0.1(typescript@7.0.2)(webpack@5.104.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(esbuild@0.25.5)(webpack-cli@5.1.4)) '@types/node': 18.19.130 find-up: 5.0.0 magic-string: 0.30.21 react: 18.3.1 react-docgen: 7.1.1 - react-docgen-typescript: 2.4.0(typescript@6.0.3) + react-docgen-typescript: 2.4.0(typescript@7.0.2) react-dom: 18.3.1(react@18.3.1) resolve: 1.22.11 storybook: 8.6.17(prettier@3.8.1) - storybook-builder-rsbuild: 1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/react@18.3.28)(storybook@8.6.17(prettier@3.8.1))(tslib@2.8.1)(typescript@6.0.3) + storybook-builder-rsbuild: 1.0.3(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/react@18.3.28)(storybook@8.6.17(prettier@3.8.1))(tslib@2.8.1)(typescript@7.0.2) tsconfig-paths: 4.2.0 optionalDependencies: - typescript: 6.0.3 + typescript: 7.0.2 transitivePeerDependencies: - '@rspack/core' - '@storybook/test' @@ -61066,6 +61129,10 @@ snapshots: strip-json-comments@5.0.3: {} + strip-literal@2.1.1: + dependencies: + js-tokens: 9.0.1 + strip-literal@3.1.0: dependencies: js-tokens: 9.0.1 @@ -61369,7 +61436,7 @@ snapshots: transitivePeerDependencies: - ts-node - tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@5.9.3)): + tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -61388,7 +61455,7 @@ snapshots: postcss: 8.4.49 postcss-import: 15.1.0(postcss@8.4.49) postcss-js: 4.1.0(postcss@8.4.49) - postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@5.9.3)) + postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2)) postcss-nested: 6.2.0(postcss@8.4.49) postcss-selector-parser: 6.1.2 resolve: 1.22.8 @@ -61396,7 +61463,7 @@ snapshots: transitivePeerDependencies: - ts-node - tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@6.0.3)): + tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@26.2.0)(typescript@5.9.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -61415,7 +61482,7 @@ snapshots: postcss: 8.4.49 postcss-import: 15.1.0(postcss@8.4.49) postcss-js: 4.1.0(postcss@8.4.49) - postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@6.0.3)) + postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@26.2.0)(typescript@5.9.3)) postcss-nested: 6.2.0(postcss@8.4.49) postcss-selector-parser: 6.1.2 resolve: 1.22.8 @@ -61423,7 +61490,7 @@ snapshots: transitivePeerDependencies: - ts-node - tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2)): + tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@26.2.0)(typescript@7.0.2)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -61442,7 +61509,7 @@ snapshots: postcss: 8.4.49 postcss-import: 15.1.0(postcss@8.4.49) postcss-js: 4.1.0(postcss@8.4.49) - postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2)) + postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@26.2.0)(typescript@7.0.2)) postcss-nested: 6.2.0(postcss@8.4.49) postcss-selector-parser: 6.1.2 resolve: 1.22.8 @@ -61755,7 +61822,7 @@ snapshots: terser@5.48.0: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.17.0 + acorn: 8.18.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -61840,6 +61907,8 @@ snapshots: tinyrainbow@2.0.0: {} + tinyspy@2.2.1: {} + tinyspy@4.0.4: {} tldts-core@6.1.86: {} @@ -61979,18 +62048,6 @@ snapshots: transitivePeerDependencies: - tslib - ts-checker-rspack-plugin@1.5.1(@rspack/core@1.3.9(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@7.0.2): - dependencies: - '@rspack/lite-tapable': 1.1.2 - chokidar: 3.6.0 - memfs: 4.58.0(tslib@2.8.1) - picocolors: 1.1.1 - typescript: 7.0.2 - optionalDependencies: - '@rspack/core': 1.3.9(@swc/helpers@0.5.23) - transitivePeerDependencies: - - tslib - ts-checker-rspack-plugin@1.5.1(@rspack/core@2.0.6(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.17))(tslib@2.8.1)(typescript@7.0.2): dependencies: '@rspack/lite-tapable': 1.1.2 @@ -62003,13 +62060,13 @@ snapshots: transitivePeerDependencies: - tslib - ts-checker-rspack-plugin@1.5.1(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@6.0.3): + ts-checker-rspack-plugin@1.5.1(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(tslib@2.8.1)(typescript@7.0.2): dependencies: '@rspack/lite-tapable': 1.1.2 chokidar: 3.6.0 memfs: 4.58.0(tslib@2.8.1) picocolors: 1.1.1 - typescript: 6.0.3 + typescript: 7.0.2 optionalDependencies: '@rspack/core': 2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23) transitivePeerDependencies: @@ -62115,42 +62172,42 @@ snapshots: optionalDependencies: '@swc/core': 1.7.26(@swc/helpers@0.5.13) - ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@20.19.5)(typescript@7.0.2): + ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@22.19.15)(typescript@6.0.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.19.5 + '@types/node': 22.19.15 acorn: 8.17.0 acorn-walk: 8.3.5 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.4 make-error: 1.3.6 - typescript: 7.0.2 + typescript: 6.0.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: '@swc/core': 1.15.41(@swc/helpers@0.5.17) optional: true - ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@22.19.15)(typescript@6.0.3): + ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.17))(@types/node@26.2.0)(typescript@7.0.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.19.15 + '@types/node': 26.2.0 acorn: 8.17.0 acorn-walk: 8.3.5 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.4 make-error: 1.3.6 - typescript: 6.0.3 + typescript: 7.0.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: @@ -62178,7 +62235,7 @@ snapshots: '@swc/core': 1.15.41(@swc/helpers@0.5.19) optional: true - ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@5.9.3): + ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@6.0.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 @@ -62192,14 +62249,13 @@ snapshots: create-require: 1.1.1 diff: 4.0.4 make-error: 1.3.6 - typescript: 5.9.3 + typescript: 6.0.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: '@swc/core': 1.15.41(@swc/helpers@0.5.23) - optional: true - ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@6.0.3): + ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 @@ -62213,31 +62269,32 @@ snapshots: create-require: 1.1.1 diff: 4.0.4 make-error: 1.3.6 - typescript: 6.0.3 + typescript: 7.0.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: '@swc/core': 1.15.41(@swc/helpers@0.5.23) - ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@20.19.5)(typescript@7.0.2): + ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@26.2.0)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.19.5 + '@types/node': 26.2.0 acorn: 8.17.0 acorn-walk: 8.3.5 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.4 make-error: 1.3.6 - typescript: 7.0.2 + typescript: 5.9.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: '@swc/core': 1.15.41(@swc/helpers@0.5.23) + optional: true ts-node@10.9.2(@swc/core@1.15.41(@swc/helpers@0.5.23))(@types/node@26.2.0)(typescript@7.0.2): dependencies: @@ -62453,6 +62510,8 @@ snapshots: type-detect@4.0.8: {} + type-detect@4.1.0: {} + type-fest@0.16.0: {} type-fest@0.20.2: {} @@ -62560,6 +62619,8 @@ snapshots: typescript@4.9.5: {} + typescript@5.0.4: {} + typescript@5.8.2: optional: true @@ -62628,12 +62689,15 @@ snapshots: undici-types@6.21.0: {} - undici-types@8.3.0: {} + undici-types@8.3.0: + optional: true undici@5.26.5: dependencies: '@fastify/busboy': 2.1.1 + undici@7.28.0: {} + undici@7.29.0: {} unhead@2.1.15: @@ -63108,16 +63172,33 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-node@3.2.4(@types/node@20.19.5)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0): + vite-node@1.6.0(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0): + dependencies: + cac: 6.7.14 + debug: 4.4.3(supports-color@8.1.1) + pathe: 1.1.2 + picocolors: 1.1.1 + vite: 5.4.21(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite-node@3.2.4(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0): dependencies: cac: 6.7.14 debug: 4.4.3(supports-color@8.1.1) es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.6(@types/node@20.19.5)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) + vite: 5.4.21(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) transitivePeerDependencies: - '@types/node' - - jiti - less - lightningcss - sass @@ -63126,19 +63207,16 @@ snapshots: - sugarss - supports-color - terser - - tsx - - yaml - vite-node@3.2.4(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0): + vite-node@3.2.4(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0): dependencies: cac: 6.7.14 debug: 4.4.3(supports-color@8.1.1) es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.6(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0) + vite: 5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0) transitivePeerDependencies: - '@types/node' - - jiti - less - lightningcss - sass @@ -63147,8 +63225,6 @@ snapshots: - sugarss - supports-color - terser - - tsx - - yaml optional: true vite-tsconfig-paths@4.2.3(typescript@6.0.3)(vite@7.3.5(@types/node@20.19.5)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)): @@ -63165,8 +63241,8 @@ snapshots: vite@5.4.21(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0): dependencies: esbuild: 0.21.5 - postcss: 8.4.49 - rollup: 4.59.0 + postcss: 8.5.23 + rollup: 4.62.2 optionalDependencies: '@types/node': 20.19.5 fsevents: 2.3.3 @@ -63178,8 +63254,8 @@ snapshots: vite@5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0): dependencies: esbuild: 0.21.5 - postcss: 8.4.49 - rollup: 4.59.0 + postcss: 8.5.23 + rollup: 4.62.2 optionalDependencies: '@types/node': 26.2.0 fsevents: 2.3.3 @@ -63188,25 +63264,21 @@ snapshots: sass-embedded: 1.100.0 terser: 5.48.0 - vite@7.3.5(@types/node@20.19.5)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0): + vite@5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0): dependencies: - esbuild: 0.27.3 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + esbuild: 0.21.5 postcss: 8.5.23 - rollup: 4.59.0 - tinyglobby: 0.2.15 + rollup: 4.62.2 optionalDependencies: - '@types/node': 20.19.5 + '@types/node': 26.2.0 fsevents: 2.3.3 - jiti: 2.6.1 less: 4.6.4 - sass: 1.100.0 - sass-embedded: 1.100.0 + sass: 1.98.0 + sass-embedded: 1.98.0 terser: 5.48.0 - yaml: 2.9.0 + optional: true - vite@7.3.5(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0): + vite@7.3.5(@types/node@20.19.5)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0): dependencies: esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) @@ -63214,25 +63286,6 @@ snapshots: postcss: 8.5.23 rollup: 4.59.0 tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 26.2.0 - fsevents: 2.3.3 - jiti: 2.6.1 - less: 4.6.4 - sass: 1.98.0 - sass-embedded: 1.98.0 - terser: 5.48.0 - yaml: 2.9.0 - optional: true - - vite@7.3.6(@types/node@20.19.5)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0): - dependencies: - esbuild: 0.28.1 - fdir: 6.5.0(picomatch@4.0.5) - picomatch: 4.0.5 - postcss: 8.5.23 - rollup: 4.62.2 - tinyglobby: 0.2.17 optionalDependencies: '@types/node': 20.19.5 fsevents: 2.3.3 @@ -63262,11 +63315,47 @@ snapshots: yaml: 2.9.0 optional: true - vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@20.19.5)(jiti@2.6.1)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0): + vitest@1.6.0(@edge-runtime/vm@3.2.0)(@types/node@20.19.5)(jsdom@20.0.3)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0): + dependencies: + '@vitest/expect': 1.6.0 + '@vitest/runner': 1.6.0 + '@vitest/snapshot': 1.6.0 + '@vitest/spy': 1.6.0 + '@vitest/utils': 1.6.0 + acorn-walk: 8.3.5 + chai: 4.5.0 + debug: 4.4.3(supports-color@8.1.1) + execa: 8.0.1 + local-pkg: 0.5.1 + magic-string: 0.30.21 + pathe: 1.1.2 + picocolors: 1.1.1 + std-env: 3.10.0 + strip-literal: 2.1.1 + tinybench: 2.9.0 + tinypool: 0.8.4 + vite: 5.4.21(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) + vite-node: 1.6.0(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@edge-runtime/vm': 3.2.0 + '@types/node': 20.19.5 + jsdom: 20.0.3 + transitivePeerDependencies: + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@20.19.5)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.6 - '@vitest/mocker': 3.2.6(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(vite@7.3.6(@types/node@20.19.5)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)) + '@vitest/mocker': 3.2.6(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(vite@5.4.21(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)) '@vitest/pretty-format': 3.2.7 '@vitest/runner': 3.2.6 '@vitest/snapshot': 3.2.6 @@ -63284,8 +63373,8 @@ snapshots: tinyglobby: 0.2.17 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.6(@types/node@20.19.5)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) - vite-node: 3.2.4(@types/node@20.19.5)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0) + vite: 5.4.21(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) + vite-node: 3.2.4(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) why-is-node-running: 2.3.0 optionalDependencies: '@edge-runtime/vm': 3.2.0 @@ -63293,7 +63382,6 @@ snapshots: '@types/node': 20.19.5 jsdom: 20.0.3 transitivePeerDependencies: - - jiti - less - lightningcss - msw @@ -63303,14 +63391,12 @@ snapshots: - sugarss - supports-color - terser - - tsx - - yaml - vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jiti@2.6.1)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0): + vitest@3.2.6(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@26.2.0)(jsdom@20.0.3)(less@4.6.4)(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.6 - '@vitest/mocker': 3.2.6(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(vite@7.3.6(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0)) + '@vitest/mocker': 3.2.6(msw@1.3.5(@types/node@20.19.5)(encoding@0.1.13)(typescript@6.0.3))(vite@5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)) '@vitest/pretty-format': 3.2.7 '@vitest/runner': 3.2.6 '@vitest/snapshot': 3.2.6 @@ -63328,8 +63414,8 @@ snapshots: tinyglobby: 0.2.17 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.6(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0) - vite-node: 3.2.4(@types/node@26.2.0)(jiti@2.6.1)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0)(yaml@2.9.0) + vite: 5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0) + vite-node: 3.2.4(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.48.0) why-is-node-running: 2.3.0 optionalDependencies: '@edge-runtime/vm': 3.2.0 @@ -63337,7 +63423,6 @@ snapshots: '@types/node': 26.2.0 jsdom: 20.0.3 transitivePeerDependencies: - - jiti - less - lightningcss - msw @@ -63347,8 +63432,6 @@ snapshots: - sugarss - supports-color - terser - - tsx - - yaml optional: true vlq@1.0.1: {} @@ -63372,6 +63455,11 @@ snapshots: transitivePeerDependencies: - supports-color + vue-router@4.4.5(vue@3.5.30(typescript@5.0.4)): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.30(typescript@5.0.4) + vue-router@4.4.5(vue@3.5.30(typescript@7.0.2)): dependencies: '@vue/devtools-api': 6.6.4 @@ -63396,6 +63484,13 @@ snapshots: semver: 7.6.3 typescript: 7.0.2 + vue-tsc@2.2.12(typescript@5.0.4): + dependencies: + '@volar/typescript': 2.4.15 + '@vue/language-core': 2.2.12(typescript@5.0.4) + typescript: 5.0.4 + optional: true + vue-tsc@2.2.12(typescript@6.0.3): dependencies: '@volar/typescript': 2.4.15 @@ -63408,6 +63503,16 @@ snapshots: '@vue/language-core': 2.2.12(typescript@7.0.2) typescript: 7.0.2 + vue@3.5.30(typescript@5.0.4): + dependencies: + '@vue/compiler-dom': 3.5.30 + '@vue/compiler-sfc': 3.5.30 + '@vue/runtime-dom': 3.5.30 + '@vue/server-renderer': 3.5.30(vue@3.5.30(typescript@5.0.4)) + '@vue/shared': 3.5.30 + optionalDependencies: + typescript: 5.0.4 + vue@3.5.30(typescript@6.0.3): dependencies: '@vue/compiler-dom': 3.5.30 @@ -63485,7 +63590,7 @@ snapshots: webpack-bundle-analyzer@4.10.2: dependencies: '@discoveryjs/json-ext': 0.5.7 - acorn: 8.17.0 + acorn: 8.18.0 acorn-walk: 8.3.5 commander: 7.2.0 debounce: 1.2.1 @@ -63618,7 +63723,7 @@ snapshots: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 '@types/express': 4.17.25 - '@types/express-serve-static-core': 4.19.8 + '@types/express-serve-static-core': 4.19.9 '@types/serve-index': 1.9.4 '@types/serve-static': 1.15.10 '@types/sockjs': 0.3.36 @@ -63658,7 +63763,7 @@ snapshots: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 '@types/express': 4.17.25 - '@types/express-serve-static-core': 4.19.8 + '@types/express-serve-static-core': 4.19.9 '@types/serve-index': 1.9.4 '@types/serve-static': 1.15.10 '@types/sockjs': 0.3.36 @@ -63698,7 +63803,7 @@ snapshots: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 '@types/express': 4.17.25 - '@types/express-serve-static-core': 4.19.8 + '@types/express-serve-static-core': 4.19.9 '@types/serve-index': 1.9.4 '@types/serve-static': 1.15.10 '@types/sockjs': 0.3.36 @@ -63737,7 +63842,7 @@ snapshots: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 '@types/express': 4.17.25 - '@types/express-serve-static-core': 4.19.8 + '@types/express-serve-static-core': 4.19.9 '@types/serve-index': 1.9.4 '@types/serve-static': 1.15.10 '@types/sockjs': 0.3.36 @@ -64378,19 +64483,19 @@ snapshots: dependencies: os-paths: 4.4.0 - xgplayer-subtitles@3.0.23(core-js@3.36.1): + xgplayer-subtitles@3.0.23(core-js@3.49.0): dependencies: - core-js: 3.36.1 + core-js: 3.49.0 eventemitter3: 4.0.7 - xgplayer@3.0.23(core-js@3.36.1): + xgplayer@3.0.23(core-js@3.49.0): dependencies: - core-js: 3.36.1 + core-js: 3.49.0 danmu.js: 1.2.1 delegate: 3.2.0 downloadjs: 1.4.7 eventemitter3: 4.0.7 - xgplayer-subtitles: 3.0.23(core-js@3.36.1) + xgplayer-subtitles: 3.0.23(core-js@3.49.0) xml-name-validator@4.0.0: {} @@ -64535,18 +64640,18 @@ snapshots: dependencies: tslib: 2.8.1 - zephyr-rsbuild-plugin@1.1.2(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1))(@rspack/core@1.3.9(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)): + zephyr-rsbuild-plugin@1.1.2(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)): dependencies: - '@rsbuild/core': 2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1) - zephyr-rspack-plugin: 1.1.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) + '@rsbuild/core': 2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0) + zephyr-rspack-plugin: 1.1.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) transitivePeerDependencies: - '@rspack/core' - supports-color - webpack - zephyr-rspack-plugin@1.1.2(@rspack/core@1.3.9(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)): + zephyr-rspack-plugin@1.1.2(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)): dependencies: - '@rspack/core': 1.3.9(@swc/helpers@0.5.23) + '@rspack/core': 2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23) tslib: 2.8.1 zephyr-agent: 1.1.2 zephyr-xpack-internal: 1.1.2(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) @@ -64554,13 +64659,13 @@ snapshots: - supports-color - webpack - zephyr-rspress-plugin@1.1.2(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1))(@rspack/core@1.3.9(@swc/helpers@0.5.23))(@rspress/core@2.0.14(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(@types/mdast@4.0.4)(@types/react@19.2.14)(core-js@3.36.1)(micromark-util-types@2.0.2)(micromark@4.0.2))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)): + zephyr-rspress-plugin@1.1.2(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@rspress/core@2.0.14(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/mdast@4.0.4)(@types/react@19.2.14)(core-js@3.49.0)(micromark-util-types@2.0.2)(micromark@4.0.2))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)): dependencies: - '@rspress/core': 2.0.14(@module-federation/runtime-tools@2.8.2)(@rspack/core@1.3.9(@swc/helpers@0.5.23))(@types/mdast@4.0.4)(@types/react@19.2.14)(core-js@3.36.1)(micromark-util-types@2.0.2)(micromark@4.0.2) + '@rspress/core': 2.0.14(@module-federation/runtime-tools@2.8.2)(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(@types/mdast@4.0.4)(@types/react@19.2.14)(core-js@3.49.0)(micromark-util-types@2.0.2)(micromark@4.0.2) tslib: 2.8.1 zephyr-agent: 1.1.2 zephyr-edge-contract: 1.1.2 - zephyr-rsbuild-plugin: 1.1.2(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.36.1))(@rspack/core@1.3.9(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) + zephyr-rsbuild-plugin: 1.1.2(@rsbuild/core@2.1.10(@module-federation/runtime-tools@2.8.2)(core-js@3.49.0))(@rspack/core@2.1.8(@module-federation/runtime-tools@2.8.2)(@swc/helpers@0.5.23))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) zephyr-xpack-internal: 1.1.2(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.28.1)(webpack-cli@5.1.4)) transitivePeerDependencies: - '@rsbuild/core' From dc506b9d0092585ceb12fe124b9e0d434a64a00c Mon Sep 17 00:00:00 2001 From: Kevin Beier Date: Tue, 11 Aug 2026 19:50:48 +0200 Subject: [PATCH 25/32] chore(bridge): trim nonessential SSR V1 demo and surface noise Co-authored-by: Cursor --- .github/workflows/e2e-bridge-ssr.yml | 15 -- .husky/commit-msg | 3 +- .prettierignore | 3 +- apps/bridge-ssr-demo/.gitignore | 4 +- apps/bridge-ssr-demo/README.md | 13 +- apps/bridge-ssr-demo/host/public/.gitkeep | 0 apps/bridge-ssr-demo/host/src/bootstrap.tsx | 13 -- apps/bridge-ssr-demo/host/src/index.tsx | 1 - apps/bridge-ssr-demo/remote-vue/package.json | 8 +- .../remote-vue/vite.config.mts | 51 ------- apps/bridge-ssr-demo/shared/devHost.ts | 11 +- package.json | 1 - packages/bridge/bridge-shared/src/index.ts | 1 - packages/bridge/bridge-shared/src/ssr.ts | 8 - packages/bridge/vue3-bridge/README.md | 9 +- pnpm-lock.yaml | 140 ------------------ tools/scripts/ci-local.mjs | 7 - tools/scripts/run-bridge-ssr-e2e.mjs | 105 ++++--------- .../verify-bridge-ssr-browser-bundles.mjs | 14 +- 19 files changed, 48 insertions(+), 359 deletions(-) delete mode 100644 apps/bridge-ssr-demo/host/public/.gitkeep delete mode 100644 apps/bridge-ssr-demo/host/src/bootstrap.tsx delete mode 100644 apps/bridge-ssr-demo/host/src/index.tsx delete mode 100644 apps/bridge-ssr-demo/remote-vue/vite.config.mts diff --git a/.github/workflows/e2e-bridge-ssr.yml b/.github/workflows/e2e-bridge-ssr.yml index f56f7631528..da56fe37fad 100644 --- a/.github/workflows/e2e-bridge-ssr.yml +++ b/.github/workflows/e2e-bridge-ssr.yml @@ -28,18 +28,3 @@ jobs: - run: pnpm run build:packages - run: pnpm run e2e:bridge:ssr - run: pnpm run e2e:bridge:ssr:production - - vite-smoke: - runs-on: ubuntu-latest - timeout-minutes: 30 - continue-on-error: true - steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 - with: - node-version: '24' - cache: pnpm - - run: pnpm install --frozen-lockfile - - run: pnpm run build:packages - - run: pnpm run e2e:bridge:ssr:vite-smoke diff --git a/.husky/commit-msg b/.husky/commit-msg index 087d40d63ce..693dbea0ca6 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,4 +1,5 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" -pnpm run commitlint --edit "${1}" + +pnpm run commitlint ${1} diff --git a/.prettierignore b/.prettierignore index 70683db1d6b..adb50972a65 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,4 @@ -# Add files here to ignore them from prettier formatting +# Add files here to ignore them from prettier formatting /dist /coverage @@ -8,7 +8,6 @@ pnpm-lock.yaml **/dist/** **/dist-rslib/** -**/dist-vite/** **/playwright-report/** **/test-results/** apps/website-new/docs diff --git a/apps/bridge-ssr-demo/.gitignore b/apps/bridge-ssr-demo/.gitignore index a7fe3c62b30..dbd77de6c7e 100644 --- a/apps/bridge-ssr-demo/.gitignore +++ b/apps/bridge-ssr-demo/.gitignore @@ -1,3 +1 @@ -**/dist-vite/ -**/test-results/ -**/playwright-report/ +**/dist/ diff --git a/apps/bridge-ssr-demo/README.md b/apps/bridge-ssr-demo/README.md index 0cade160d2e..80b134c5fdf 100644 --- a/apps/bridge-ssr-demo/README.md +++ b/apps/bridge-ssr-demo/README.md @@ -1,24 +1,17 @@ # Bridge SSR V1 acceptance demo -This focused demo proves buffered, application-level Bridge SSR in both cross-framework directions: +Rsbuild demo for application-level Bridge SSR in both directions: - React 18 host → Vue 3 remote - Vue 3 host → React 18 remote -The server host calls `renderRemoteBridge` and passes the complete result to its remote component. That component emits a single instance-scoped document slot which owns the remote HTML and dehydrated state. The host hydration JSON contains only a versioned identity reference, so the remote HTML is transferred once. - -Before React `hydrateRoot` or the Vue host mount, the client creates a hydration registry from the document and installs it through the framework adapter. The reference resolves a validated snapshot from that registry. Successful hydration consumes the snapshot once; a later SPA revisit uses CSR. A missing slot also uses CSR, while malformed, duplicate, or identity-conflicting slots surface contextual errors. - -Client and Node builds expose the same `./export-app` key from different source files. Preparation and the framework server renderer stay in the Node graph; hydration mapping stays browser-safe. +Contract details: [Bridge SSR guide](../website-new/docs/en/guide/bridge/ssr.mdx). Run from the repository root: ```bash pnpm run e2e:bridge:ssr pnpm run e2e:bridge:ssr:production -pnpm run e2e:bridge:ssr:vite-smoke ``` -Rsbuild development and production are required. The Vite command is a non-blocking React-host → Vue-remote smoke proof. The suites cover raw HTML, single-copy transport, hydration, deep routes, host and remote navigation, CSR revisits after consumption, multiple independent instances, browser/server error monitoring, and exclusion of server-only renderers and preparation from browser bundles. - -React Router v6 remotes use the strict `router-v6` alias in browser and Node builds; the browser bundle checks are release gates, not documentation-only guidance. Assets and head management, response status/headers, shared fallbacks and timeouts, data routers, streaming, and additional framework adapters are intentionally outside V1. Without a host-owned wrapper, a slow or broken remote can delay or fail the host response. +These suites cover no-JS HTML, single-copy transport, hydration, deep routes, navigation, CSR revisits after consumption, multiple instances, and browser-bundle exclusion of server-only renderers. diff --git a/apps/bridge-ssr-demo/host/public/.gitkeep b/apps/bridge-ssr-demo/host/public/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/apps/bridge-ssr-demo/host/src/bootstrap.tsx b/apps/bridge-ssr-demo/host/src/bootstrap.tsx deleted file mode 100644 index 9e2c30be810..00000000000 --- a/apps/bridge-ssr-demo/host/src/bootstrap.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import { BrowserRouter } from 'react-router-dom'; -import App from './App'; - -const root = ReactDOM.createRoot(document.getElementById('root')!); -root.render( - - - - - , -); diff --git a/apps/bridge-ssr-demo/host/src/index.tsx b/apps/bridge-ssr-demo/host/src/index.tsx deleted file mode 100644 index b93c7a0268a..00000000000 --- a/apps/bridge-ssr-demo/host/src/index.tsx +++ /dev/null @@ -1 +0,0 @@ -import('./bootstrap'); diff --git a/apps/bridge-ssr-demo/remote-vue/package.json b/apps/bridge-ssr-demo/remote-vue/package.json index 16d0d021a78..6f211bd3812 100644 --- a/apps/bridge-ssr-demo/remote-vue/package.json +++ b/apps/bridge-ssr-demo/remote-vue/package.json @@ -6,9 +6,6 @@ "scripts": { "dev": "rsbuild dev", "build": "rsbuild build", - "build:vite": "pnpm run build:vite:web && pnpm run build:vite:ssr", - "build:vite:web": "vite build --config vite.config.mts", - "build:vite:ssr": "BRIDGE_VITE_SSR=true vite build --config vite.config.mts && cp dist-vite/ssr/remoteEntry.js dist-vite/ssr/remoteEntry.ssr.js", "preview": "rsbuild preview" }, "dependencies": { @@ -19,11 +16,8 @@ }, "devDependencies": { "@module-federation/rsbuild-plugin": "workspace:*", - "@module-federation/vite": "1.16.16", "@rsbuild/core": "1.7.3", "@rsbuild/plugin-vue": "^1.2.6", - "@vitejs/plugin-vue": "^5.0.4", - "typescript": "~5.0.4", - "vite": "^5.4.21" + "typescript": "~5.0.4" } } diff --git a/apps/bridge-ssr-demo/remote-vue/vite.config.mts b/apps/bridge-ssr-demo/remote-vue/vite.config.mts deleted file mode 100644 index 3e7ba50bbd4..00000000000 --- a/apps/bridge-ssr-demo/remote-vue/vite.config.mts +++ /dev/null @@ -1,51 +0,0 @@ -import { federation } from '@module-federation/vite'; -import vue from '@vitejs/plugin-vue'; -import { defineConfig } from 'vite'; -import path from 'node:path'; -import { bridgeSsrHostUrl } from '../shared/devHost'; - -const isSSR = process.env.BRIDGE_VITE_SSR === 'true'; -const remoteOrigin = bridgeSsrHostUrl(2402); - -export default defineConfig({ - plugins: [ - vue(), - federation({ - name: 'bridge_ssr_vue', - filename: 'remoteEntry.js', - exposes: { - './export-app': isSSR - ? './src/export-app.server.ts' - : './src/export-app.ts', - }, - shared: isSSR - ? {} - : { - vue: { singleton: true }, - 'vue-router': { singleton: true }, - }, - manifest: true, - dts: false, - target: isSSR ? 'node' : 'web', - getPublicPath: `return '${remoteOrigin}${isSSR ? '/ssr' : ''}/'`, - }), - ], - server: { - origin: remoteOrigin, - port: 2402, - }, - build: { - outDir: isSSR ? 'dist-vite/ssr' : 'dist-vite', - emptyOutDir: !isSSR, - target: isSSR ? 'node20' : 'es2020', - ssr: isSSR ? './src/ssr-env.ts' : undefined, - rollupOptions: isSSR - ? undefined - : { - input: path.resolve(__dirname, 'src/standalone.ts'), - }, - }, - ssr: { - noExternal: true, - }, -}); diff --git a/apps/bridge-ssr-demo/shared/devHost.ts b/apps/bridge-ssr-demo/shared/devHost.ts index b5aefe9ca6f..b15ab803537 100644 --- a/apps/bridge-ssr-demo/shared/devHost.ts +++ b/apps/bridge-ssr-demo/shared/devHost.ts @@ -1,15 +1,8 @@ export const BRIDGE_SSR_DEV_HOST = process.env.BRIDGE_SSR_DEV_HOST ?? 'localhost'; -export const BRIDGE_SSR_REMOTE_BUNDLER = - process.env.BRIDGE_SSR_REMOTE_BUNDLER === 'vite' ? 'vite' : 'rsbuild'; - -export const bridgeSsrRemotePort = (framework: 'react' | 'vue') => { - if (BRIDGE_SSR_REMOTE_BUNDLER === 'vite') { - return framework === 'react' ? 2401 : 2402; - } - return framework === 'react' ? 2301 : 2302; -}; +export const bridgeSsrRemotePort = (framework: 'react' | 'vue') => + framework === 'react' ? 2301 : 2302; export const bridgeSsrServerManifestPath = 'ssr/mf-manifest.json'; diff --git a/package.json b/package.json index 1a161808bd5..69cdbac4353 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,6 @@ "e2e:router": "node tools/scripts/run-router-e2e.mjs --mode=dev", "e2e:bridge:ssr": "node tools/scripts/run-bridge-ssr-e2e.mjs", "e2e:bridge:ssr:production": "BRIDGE_SSR_MODE=production node tools/scripts/run-bridge-ssr-e2e.mjs", - "e2e:bridge:ssr:vite-smoke": "BRIDGE_SSR_REMOTE_BUNDLER=vite node tools/scripts/run-bridge-ssr-e2e.mjs", "e2e:shared-tree-shaking:runtime-infer": "npx kill-port --port 3001,3002 && pnpm exec turbo run test:e2e --filter=shared-tree-shaking-no-server-host && lsof -ti tcp:3001,3002 | xargs kill", "e2e:shared-tree-shaking:server-calc": "npx kill-port --port 3001,3002,3003 && pnpm exec turbo run test:e2e --filter=shared-tree-shaking-with-server-host && lsof -ti tcp:3001,3002,3003 | xargs kill", "e2e:devtools:dev": "npx kill-port 3009 3010 3011 3012 3013 4001 && pnpm run app:manifest:dev & echo \"done\" && npx wait-on tcp:3009 tcp:3010 tcp:3011 tcp:3012 tcp:3013 && sleep 10 && pnpm exec turbo run test:e2e --filter=@module-federation/devtools", diff --git a/packages/bridge/bridge-shared/src/index.ts b/packages/bridge/bridge-shared/src/index.ts index fba1df9e3e5..21ecdb3a6fa 100644 --- a/packages/bridge/bridge-shared/src/index.ts +++ b/packages/bridge/bridge-shared/src/index.ts @@ -33,7 +33,6 @@ export { hasBridgeSSRMarkup, serializeBridgeJSON, serializeBridgeSSRStateEnvelope, - serializeBridgeSSRResult, toBridgeSSRReference, } from './ssr'; export { renderRemoteBridge } from './renderRemoteBridge'; diff --git a/packages/bridge/bridge-shared/src/ssr.ts b/packages/bridge/bridge-shared/src/ssr.ts index 9ec952d9759..10aca41c15a 100644 --- a/packages/bridge/bridge-shared/src/ssr.ts +++ b/packages/bridge/bridge-shared/src/ssr.ts @@ -115,14 +115,6 @@ export function serializeBridgeJSON(value: BridgeJSONValue): string { .replace(/\u2029/g, '\\u2029'); } -export function serializeBridgeSSRResult(result: BridgeSSRResult): string { - assertBridgeSSRResult(result); - return JSON.stringify(result) - .replace(/=1.0.24' - peerDependenciesMeta: - vue-tsc: - optional: true - '@module-federation/enhanced@0.21.6': resolution: {integrity: sha512-8PFQxtmXc6ukBC4CqGIoc96M2Ly9WVwCPu4Ffvt+K/SB6rGbeFeZoYAwREV1zGNMJ5v5ly6+AHIEOBxNuSnzSg==} hasBin: true @@ -9070,9 +9052,6 @@ packages: '@module-federation/error-codes@2.2.2': resolution: {integrity: sha512-e+dxUrqrdRbhfvg8TyG0UQBQAjYZ8pI2b3HWfESLXqWi3xCiivZSnqsPN+zychrQ1hDZAdCheZ9zT91zhMrkxw==} - '@module-federation/error-codes@2.7.0': - resolution: {integrity: sha512-syToF3H77IbBhJ7auGMCIb5ZDmJ5tvaqSeEvncJrOCq7JBT96F4UDlQDyNh6kCVznvYqqHsPeEMrfI9b5/Omlg==} - '@module-federation/error-codes@2.8.2': resolution: {integrity: sha512-8inlDv48QOjA//CLQ3epjoHEiMQGsz1Pmtu2N+s7gQVggn6AYHpjnMe8AsyGxtpaPg3wbX0HmBZtRFggpXUB9A==} @@ -9092,9 +9071,6 @@ packages: '@module-federation/managers@2.2.2': resolution: {integrity: sha512-YuUCUdjwXGsFEWC6YwNjX+XC8V4i47549ljXarHBhCVIYIluigivpG5ZDq/kyoZQoeR9UnUwzMiKzt79y0f7Dg==} - '@module-federation/managers@2.7.0': - resolution: {integrity: sha512-cWohiUvSrY6dIfhwsRABmEWfvJiAD5u/gxU7XRk7bx5nYPj7qn5gvYWJtvLNWzenluHZR6sib+03QMlyo+MYKQ==} - '@module-federation/manifest@0.21.6': resolution: {integrity: sha512-yg93+I1qjRs5B5hOSvjbjmIoI2z3th8/yst9sfwvx4UDOG1acsE3HHMyPN0GdoIGwplC/KAnU5NmUz4tREUTGQ==} @@ -9154,9 +9130,6 @@ packages: '@module-federation/runtime-core@2.2.2': resolution: {integrity: sha512-JL+W6Yol1+CPJ662H1SEQLwxfBU2kCKhUcYrMr/X6j0qFWB8x5PBSpQbwAIcJiKfflHgBaJZypmCKmq8qRv3Aw==} - '@module-federation/runtime-core@2.7.0': - resolution: {integrity: sha512-5ROZLVIeV9YnWO2RwCwSHcy6sh48yclErO/2GZ2Xe8lFubPrFirgU8pbwBjZw+All0ZzN44BGS4ECRMVFzVcpg==} - '@module-federation/runtime-core@2.8.2': resolution: {integrity: sha512-PEkkK9MUp+nUCeQMS4ox3QGZfwwxgfjGA7P4umEnr5c3y8DLNDR+26tyHf/Gkjen2VsjlcyL+mEAQo1Zi4IE3g==} @@ -9217,9 +9190,6 @@ packages: '@module-federation/runtime@2.2.2': resolution: {integrity: sha512-zV6kbAUU1tQZr4KrZXQhzQP3WTb7oMRlIFw4UBhbh2JhAKGYS5CNc/n7+RV+mDxIs//qVmVzdSpJtTOMBLeFCw==} - '@module-federation/runtime@2.7.0': - resolution: {integrity: sha512-UtLozKKNvhT0D1+F0MEWsAmddJ39ItKW15E22LVMAwXmYZRSnzIvJQ2Y6kQ4LwhWABsw/GRSpUDex5OfhpSQPw==} - '@module-federation/runtime@2.8.2': resolution: {integrity: sha512-SUoP+PD5EjSPSi6FxEPGIZoRkFifxdeYcVQbJE9mO0VEjF51gAk3/TgX8k0vzUryOBPmXekLr9SfQXU6DqUtvA==} @@ -9255,9 +9225,6 @@ packages: node-fetch: optional: true - '@module-federation/sdk@2.7.0': - resolution: {integrity: sha512-piiLEjaIdjbNq8E11Di6vsfryhcdN/+sBCH6NjG7gSU2VHHoHEayZQWWL7VVdS6rVjexF9McLhPTSrl0adUU+A==} - '@module-federation/sdk@2.8.2': resolution: {integrity: sha512-OPS/lbQjraLXoWniQpCwQ/vqgURHTrhsackSNcOPmcJHM3LyR+DabxUc0pl8jAqExsW2l+uepQq7+/Gkei871w==} @@ -9267,15 +9234,6 @@ packages: '@module-federation/third-party-dts-extractor@2.2.2': resolution: {integrity: sha512-BWKLXQ2Me+zw6y2yhk8/URuVcyYFP1aJZlTqb7KpYeSJEp2z5jk8sZX2R42GraAGAwSe9IwcW6Y4Za/eoxt/tA==} - '@module-federation/third-party-dts-extractor@2.7.0': - resolution: {integrity: sha512-hZJKkngQ4hwe0U+vrT3KOsU11qoHCQK0wB4x1bXoTgpTfV9j5NSuddOyRmwbvXpir9bDWh3xy7ghqsx3mFf3kA==} - - '@module-federation/vite@1.16.16': - resolution: {integrity: sha512-XtgLXydgUblSzIJaRljVrg5xyogABEUUnTsSXX11W/q55XR+mnpKInsGY3uBgX09GbjSW5DNHWal+1zKt2d7uw==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@module-federation/webpack-bundler-runtime@0.1.6': resolution: {integrity: sha512-K5WhKZ4RVNaMEtfHsd/9CNCgGKB0ipbm/tgweNNeC11mEuBTNxJ09Y630vg3WPkKv9vfMCuXg2p2Dk+Q/KWTSA==} @@ -16089,10 +16047,6 @@ packages: resolution: {integrity: sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==} engines: {node: '>=8.9'} - adm-zip@0.5.10: - resolution: {integrity: sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==} - engines: {node: '>=6.0'} - adm-zip@0.5.16: resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} engines: {node: '>=12.0'} @@ -19540,9 +19494,6 @@ packages: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} - exsolve@1.0.8: - resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} - ext-list@2.2.2: resolution: {integrity: sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==} engines: {node: '>=0.10.0'} @@ -27979,10 +27930,6 @@ packages: resolution: {integrity: sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==} engines: {node: '>=14.0'} - undici@7.28.0: - resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==} - engines: {node: '>=20.18.1'} - undici@7.29.0: resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==} engines: {node: '>=20.18.1'} @@ -36002,24 +35949,6 @@ snapshots: - supports-color - utf-8-validate - '@module-federation/dts-plugin@2.7.0(typescript@5.0.4)(vue-tsc@2.2.12(typescript@5.0.4))': - dependencies: - '@module-federation/error-codes': 2.7.0 - '@module-federation/managers': 2.7.0 - '@module-federation/sdk': 2.7.0 - '@module-federation/third-party-dts-extractor': 2.7.0 - adm-zip: 0.5.10 - isomorphic-ws: 5.0.0(ws@8.21.0) - node-schedule: 2.1.1 - typescript: 5.0.4 - undici: 7.28.0 - ws: 8.21.0 - optionalDependencies: - vue-tsc: 2.2.12(typescript@5.0.4) - transitivePeerDependencies: - - bufferutil - - utf-8-validate - '@module-federation/enhanced@0.21.6(@rspack/core@1.6.8(@swc/helpers@0.5.23))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(typescript@7.0.2)(vue-tsc@2.2.12(typescript@7.0.2))(webpack@5.104.1(@swc/core@1.15.41(@swc/helpers@0.5.23))(esbuild@0.25.5)(webpack-cli@5.1.4))': dependencies: '@module-federation/bridge-react-webpack-plugin': 0.21.6 @@ -36095,8 +36024,6 @@ snapshots: '@module-federation/error-codes@2.2.2': {} - '@module-federation/error-codes@2.7.0': {} - '@module-federation/error-codes@2.8.2': optional: true @@ -36122,11 +36049,6 @@ snapshots: transitivePeerDependencies: - node-fetch - '@module-federation/managers@2.7.0': - dependencies: - '@module-federation/sdk': 2.7.0 - empathic: 2.0.0 - '@module-federation/manifest@0.21.6(typescript@7.0.2)(vue-tsc@2.2.12(typescript@7.0.2))': dependencies: '@module-federation/dts-plugin': 0.21.6(typescript@7.0.2)(vue-tsc@2.2.12(typescript@7.0.2)) @@ -36258,11 +36180,6 @@ snapshots: transitivePeerDependencies: - node-fetch - '@module-federation/runtime-core@2.7.0': - dependencies: - '@module-federation/error-codes': 2.7.0 - '@module-federation/sdk': 2.7.0 - '@module-federation/runtime-core@2.8.2': dependencies: '@module-federation/error-codes': 2.8.2 @@ -36374,12 +36291,6 @@ snapshots: transitivePeerDependencies: - node-fetch - '@module-federation/runtime@2.7.0': - dependencies: - '@module-federation/error-codes': 2.7.0 - '@module-federation/runtime-core': 2.7.0 - '@module-federation/sdk': 2.7.0 - '@module-federation/runtime@2.8.2': dependencies: '@module-federation/error-codes': 2.8.2 @@ -36407,8 +36318,6 @@ snapshots: optionalDependencies: node-fetch: 2.7.0(encoding@0.1.13) - '@module-federation/sdk@2.7.0': {} - '@module-federation/sdk@2.8.2': optional: true @@ -36424,23 +36333,6 @@ snapshots: fs-extra: 9.1.0 resolve: 1.22.8 - '@module-federation/third-party-dts-extractor@2.7.0': - dependencies: - empathic: 2.0.0 - exsolve: 1.0.8 - - '@module-federation/vite@1.16.16(typescript@5.0.4)(vite@5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0))(vue-tsc@2.2.12(typescript@5.0.4))': - dependencies: - '@module-federation/dts-plugin': 2.7.0(typescript@5.0.4)(vue-tsc@2.2.12(typescript@5.0.4)) - '@module-federation/runtime': 2.7.0 - '@module-federation/sdk': 2.7.0 - vite: 5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) - transitivePeerDependencies: - - bufferutil - - typescript - - utf-8-validate - - vue-tsc - '@module-federation/webpack-bundler-runtime@0.1.6': dependencies: '@module-federation/runtime': 0.1.6 @@ -44952,11 +44844,6 @@ snapshots: vite: 5.4.21(@types/node@20.19.5)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) vue: 3.5.30(typescript@7.0.2) - '@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0))(vue@3.5.30(typescript@5.0.4))': - dependencies: - vite: 5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) - vue: 3.5.30(typescript@5.0.4) - '@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0))(vue@3.5.30(typescript@7.0.2))': dependencies: vite: 5.4.21(@types/node@26.2.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0) @@ -45225,20 +45112,6 @@ snapshots: optionalDependencies: typescript: 7.0.2 - '@vue/language-core@2.2.12(typescript@5.0.4)': - dependencies: - '@volar/language-core': 2.4.15 - '@vue/compiler-dom': 3.5.30 - '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.30 - alien-signals: 1.0.13 - minimatch: 9.0.9 - muggle-string: 0.4.1 - path-browserify: 1.0.1 - optionalDependencies: - typescript: 5.0.4 - optional: true - '@vue/language-core@2.2.12(typescript@6.0.3)': dependencies: '@volar/language-core': 2.4.15 @@ -45674,8 +45547,6 @@ snapshots: loader-utils: 2.0.4 regex-parser: 2.3.1 - adm-zip@0.5.10: {} - adm-zip@0.5.16: {} adm-zip@0.5.18: {} @@ -50481,8 +50352,6 @@ snapshots: transitivePeerDependencies: - supports-color - exsolve@1.0.8: {} - ext-list@2.2.2: dependencies: mime-db: 1.54.0 @@ -62696,8 +62565,6 @@ snapshots: dependencies: '@fastify/busboy': 2.1.1 - undici@7.28.0: {} - undici@7.29.0: {} unhead@2.1.15: @@ -63484,13 +63351,6 @@ snapshots: semver: 7.6.3 typescript: 7.0.2 - vue-tsc@2.2.12(typescript@5.0.4): - dependencies: - '@volar/typescript': 2.4.15 - '@vue/language-core': 2.2.12(typescript@5.0.4) - typescript: 5.0.4 - optional: true - vue-tsc@2.2.12(typescript@6.0.3): dependencies: '@volar/typescript': 2.4.15 diff --git a/tools/scripts/ci-local.mjs b/tools/scripts/ci-local.mjs index d6ab4f3e56a..7af10a13fcc 100644 --- a/tools/scripts/ci-local.mjs +++ b/tools/scripts/ci-local.mjs @@ -344,13 +344,6 @@ const jobs = [ step('Bridge SSR production acceptance', (ctx) => runCommand('pnpm', ['run', 'e2e:bridge:ssr:production'], ctx), ), - step('Bridge SSR Vite smoke (non-blocking)', async (ctx) => { - try { - await runCommand('pnpm', ['run', 'e2e:bridge:ssr:vite-smoke'], ctx); - } catch (error) { - console.warn('[ci:local] Non-blocking Vite smoke failed:', error); - } - }), ], }, { diff --git a/tools/scripts/run-bridge-ssr-e2e.mjs b/tools/scripts/run-bridge-ssr-e2e.mjs index 479bd350c50..c9f3b64dcb6 100644 --- a/tools/scripts/run-bridge-ssr-e2e.mjs +++ b/tools/scripts/run-bridge-ssr-e2e.mjs @@ -6,8 +6,7 @@ import { spawnWithPromise, } from './e2e-process-utils.mjs'; -const viteSmoke = process.env.BRIDGE_SSR_REMOTE_BUNDLER === 'vite'; -const production = process.env.BRIDGE_SSR_MODE === 'production' || viteSmoke; +const production = process.env.BRIDGE_SSR_MODE === 'production'; let stopping = false; function startOwned(label, command, args, env) { @@ -35,41 +34,20 @@ async function run(command, args, env) { } async function build(env) { - if (viteSmoke) { - await run( - 'pnpm', - ['--filter', 'bridge-ssr-remote-vue', 'run', 'build:vite'], - env, - ); - await run( - 'pnpm', - [ - 'exec', - 'turbo', - 'run', - 'build', - '--filter=bridge-ssr-host', - '--force', - '--env-mode=loose', - ], - env, - ); - } else { - await run( - 'pnpm', - [ - 'exec', - 'turbo', - 'run', - 'build', - '--filter=bridge-ssr-host', - '--filter=bridge-ssr-host-vue', - '--filter=bridge-ssr-remote-react', - '--filter=bridge-ssr-remote-vue', - ], - env, - ); - } + await run( + 'pnpm', + [ + 'exec', + 'turbo', + 'run', + 'build', + '--filter=bridge-ssr-host', + '--filter=bridge-ssr-host-vue', + '--filter=bridge-ssr-remote-react', + '--filter=bridge-ssr-remote-vue', + ], + env, + ); await run( process.execPath, ['tools/scripts/verify-bridge-ssr-browser-bundles.mjs'], @@ -80,32 +58,12 @@ async function build(env) { async function main() { const env = { HOST: process.env.HOST ?? 'localhost', - BRIDGE_SSR_REMOTE_BUNDLER: viteSmoke ? 'vite' : 'rsbuild', ...(production ? { BRIDGE_SSR_MODE: 'production' } : {}), }; if (production) await build(env); const apps = []; - if (viteSmoke) { - apps.push( - startOwned( - 'Vue Vite remote', - process.execPath, - [ - 'apps/bridge-ssr-demo/shared/serveDist.mjs', - 'apps/bridge-ssr-demo/remote-vue/dist-vite', - '2402', - ], - env, - ), - startOwned( - 'React production host', - 'pnpm', - ['--filter', 'bridge-ssr-host', 'run', 'serve:production'], - env, - ), - ); - } else if (production) { + if (production) { for (const [framework, port] of [ ['react', '2301'], ['vue', '2302'], @@ -167,28 +125,29 @@ async function main() { } try { - const ports = viteSmoke - ? ['tcp:2300', 'tcp:2402'] - : ['tcp:2300', 'tcp:2301', 'tcp:2302', 'tcp:2303']; await Promise.race([ - spawnWithPromise('npx', ['wait-on', '--timeout=240000', ...ports]) - .promise, + spawnWithPromise('npx', [ + 'wait-on', + '--timeout=240000', + 'tcp:2300', + 'tcp:2301', + 'tcp:2302', + 'tcp:2303', + ]).promise, Promise.race(apps.map((app) => app.exit)), ]); await Promise.race([ run('pnpm', ['--filter', 'bridge-ssr-host', 'run', 'e2e:ssr:ci'], env), Promise.race(apps.map((app) => app.exit)), ]); - if (!viteSmoke) { - await Promise.race([ - run( - 'pnpm', - ['--filter', 'bridge-ssr-host-vue', 'run', 'e2e:ssr:ci'], - env, - ), - Promise.race(apps.map((app) => app.exit)), - ]); - } + await Promise.race([ + run( + 'pnpm', + ['--filter', 'bridge-ssr-host-vue', 'run', 'e2e:ssr:ci'], + env, + ), + Promise.race(apps.map((app) => app.exit)), + ]); } finally { stopping = true; await Promise.allSettled( diff --git a/tools/scripts/verify-bridge-ssr-browser-bundles.mjs b/tools/scripts/verify-bridge-ssr-browser-bundles.mjs index cd960b67689..7080a8eaf36 100644 --- a/tools/scripts/verify-bridge-ssr-browser-bundles.mjs +++ b/tools/scripts/verify-bridge-ssr-browser-bundles.mjs @@ -2,16 +2,10 @@ import { readFile, readdir, stat } from 'node:fs/promises'; import path from 'node:path'; -const roots = - process.env.BRIDGE_SSR_REMOTE_BUNDLER === 'vite' - ? [ - 'apps/bridge-ssr-demo/remote-vue/dist-vite/assets', - 'apps/bridge-ssr-demo/remote-vue/dist-vite/remoteEntry.js', - ] - : [ - 'apps/bridge-ssr-demo/remote-react/dist/static', - 'apps/bridge-ssr-demo/remote-vue/dist/static', - ]; +const roots = [ + 'apps/bridge-ssr-demo/remote-react/dist/static', + 'apps/bridge-ssr-demo/remote-vue/dist/static', +]; const forbidden = [ 'react-dom/server', '@vue/server-renderer', From f887cac291b3198158ab31b3391595860af5c5e7 Mon Sep 17 00:00:00 2001 From: Kevin Beier Date: Tue, 11 Aug 2026 20:30:40 +0200 Subject: [PATCH 26/32] fix(bridge-vue3): derive SSR identity reactively in RemoteApp Co-authored-by: Cursor --- .../__tests__/remoteApp.ssr.test.ts | 55 ++++++- packages/bridge/vue3-bridge/src/remoteApp.tsx | 143 ++++++++++++------ 2 files changed, 152 insertions(+), 46 deletions(-) diff --git a/packages/bridge/vue3-bridge/__tests__/remoteApp.ssr.test.ts b/packages/bridge/vue3-bridge/__tests__/remoteApp.ssr.test.ts index 7c7b5368351..da8df6d845f 100644 --- a/packages/bridge/vue3-bridge/__tests__/remoteApp.ssr.test.ts +++ b/packages/bridge/vue3-bridge/__tests__/remoteApp.ssr.test.ts @@ -1,5 +1,12 @@ import { afterEach, beforeEach, describe, expect, it, rs } from '@rstest/core'; -import { createApp, defineComponent, h, KeepAlive, nextTick } from 'vue'; +import { + createApp, + defineComponent, + h, + KeepAlive, + nextTick, + reactive, +} from 'vue'; import { createMemoryHistory, createRouter, RouterView } from 'vue-router'; import { BRIDGE_SSR_PROTOCOL_VERSION, @@ -218,4 +225,50 @@ describe('RemoteApp SSR lifecycle', () => { await flushBridgeRender(); expect(registry.peek('ecApp', 'ec:1')).toBeUndefined(); }); + + it('drops SSR slot markup when ssr props clear without remount', async () => { + const result = { + protocolVersion: BRIDGE_SSR_PROTOCOL_VERSION, + moduleName: 'ecApp', + instanceId: 'ec:1', + html: '

    server remote

    ', + dehydratedState: { ready: true }, + }; + const providerReturn = { + render: rs.fn(async () => undefined), + destroy: rs.fn(), + }; + const state = reactive<{ + ssr: typeof result | undefined; + }>({ ssr: result }); + const App = defineComponent({ + setup: () => () => + h(RemoteApp, { + moduleName: 'ecApp', + instanceId: 'ec:1', + ssr: state.ssr, + providerInfo: () => providerReturn, + }), + }); + const app = createApp(App); + const router = createRouter({ + history: createMemoryHistory(), + routes: [{ path: '/', component: { template: '
    ' } }], + }); + app.use(router); + await router.isReady(); + mountApp(app); + await flushBridgeRender(); + + expect(root.querySelector('[data-mf-bridge-slot="true"]')).not.toBeNull(); + expect(root.innerHTML).toContain('server remote'); + + state.ssr = undefined; + await nextTick(); + await flushBridgeRender(); + + expect(root.querySelector('[data-mf-bridge-slot="true"]')).toBeNull(); + expect(root.querySelector(`[${MF_BRIDGE_SSR_ATTR}="true"]`)).toBeNull(); + app.unmount(); + }); }); diff --git a/packages/bridge/vue3-bridge/src/remoteApp.tsx b/packages/bridge/vue3-bridge/src/remoteApp.tsx index 63660c01c24..285e3ac07cb 100644 --- a/packages/bridge/vue3-bridge/src/remoteApp.tsx +++ b/packages/bridge/vue3-bridge/src/remoteApp.tsx @@ -1,11 +1,13 @@ import { ref, + computed, onMounted, onBeforeUnmount, onActivated, onDeactivated, onUpdated, watch, + watchEffect, defineComponent, useAttrs, nextTick, @@ -70,36 +72,65 @@ export default defineComponent({ const hostInstance = getInstance(); const componentAttrs = useAttrs(); let lastComponentAttrs = { ...componentAttrs }; - const ssrPayload = getMatchingBridgeSSRPayload(props.ssr, { - moduleName: props.moduleName, - instanceId: props.instanceId, - }); - const instanceId = props.instanceId || ssrPayload?.instanceId; - const serverPayload = - ssrPayload && 'html' in ssrPayload - ? (ssrPayload as BridgeSSRResult) + const ssrPayload = computed(() => + getMatchingBridgeSSRPayload(props.ssr, { + moduleName: props.moduleName, + instanceId: props.instanceId, + }), + ); + const instanceId = computed( + () => props.instanceId || ssrPayload.value?.instanceId, + ); + const serverPayload = computed(() => { + const payload = ssrPayload.value; + return payload && 'html' in payload + ? (payload as BridgeSSRResult) : undefined; - const reference = - ssrPayload && !('html' in ssrPayload) - ? (ssrPayload as BridgeSSRReference) + }); + const reference = computed(() => { + const payload = ssrPayload.value; + return payload && !('html' in payload) + ? (payload as BridgeSSRReference) : undefined; + }); const registry = useBridgeHydrationRegistry(); - if (reference && !registry) { - throw new Error( - 'Bridge SSR references require provideBridgeHydrationRegistry before mount', - ); - } - const snapshot = - reference && instanceId - ? registry!.peek(reference.moduleName, instanceId) + watchEffect(() => { + if (reference.value && !registry) { + throw new Error( + 'Bridge SSR references require provideBridgeHydrationRegistry before mount', + ); + } + }); + const snapshot = computed(() => { + const currentReference = reference.value; + const currentInstanceId = instanceId.value; + return currentReference && currentInstanceId + ? registry?.peek(currentReference.moduleName, currentInstanceId) : undefined; - const hasSSRPayload = Boolean((serverPayload || snapshot) && instanceId); - const registryModuleName = - props.moduleName || reference?.moduleName || ssrPayload?.moduleName || ''; + }); + const hasSSRPayload = computed(() => + Boolean((serverPayload.value || snapshot.value) && instanceId.value), + ); + const registryModuleName = computed( + () => + props.moduleName || + reference.value?.moduleName || + ssrPayload.value?.moduleName || + '', + ); const releaseUnclaimedSnapshot = () => { - if (!snapshot || !instanceId || consumedSnapshot || !registry) return; - registry.fail(registryModuleName, instanceId); + const currentSnapshot = snapshot.value; + const currentInstanceId = instanceId.value; + if ( + !currentSnapshot || + !currentInstanceId || + consumedSnapshot || + !registry + ) { + return; + } + registry.fail(registryModuleName.value, currentInstanceId); consumedSnapshot = true; }; @@ -129,22 +160,27 @@ export default defineComponent({ // Claim before any await so cancel cannot leave a peekable snapshot. // After a claim (even if render aborts), never hydrate again — CSR only. + const currentSnapshot = snapshot.value; + const currentInstanceId = instanceId.value; let ssrState = wasRendered || hydratedOnce || consumedSnapshot ? undefined - : serverPayload?.dehydratedState; + : serverPayload.value?.dehydratedState; if ( !wasRendered && !hydratedOnce && !consumedSnapshot && - snapshot && - instanceId && + currentSnapshot && + currentInstanceId && registry ) { - const claimed = registry.consume(registryModuleName, instanceId); - if (Object.is(claimed, snapshot)) { + const claimed = registry.consume( + registryModuleName.value, + currentInstanceId, + ); + if (Object.is(claimed, currentSnapshot)) { consumedSnapshot = true; - ssrState = snapshot.state; + ssrState = currentSnapshot.state; } else { consumedSnapshot = true; hydratedOnce = true; @@ -160,7 +196,7 @@ export default defineComponent({ basename: props.basename, memoryRoute: props.memoryRoute, hashRoute: props.hashRoute, - instanceId, + instanceId: currentInstanceId, ssrState, signal: controller.signal, }; @@ -193,7 +229,7 @@ export default defineComponent({ isRendered.value = true; // One-shot hydrate for this instance. Keep SSR markers in the DOM so // hosts/tests can observe them; strip only on KeepAlive deactivate. - if (snapshot || serverPayload) { + if (snapshot.value || serverPayload.value) { hydratedOnce = true; } hostInstance?.bridgeHook?.lifecycle?.afterBridgeRender?.emit( @@ -202,8 +238,10 @@ export default defineComponent({ }); renderQueue = pending.catch((error) => { if (controller.signal.aborted || wasDeactivated.value) return; - if (snapshot && instanceId && !consumedSnapshot) { - registry?.fail(registryModuleName, instanceId); + const failedSnapshot = snapshot.value; + const failedInstanceId = instanceId.value; + if (failedSnapshot && failedInstanceId && !consumedSnapshot) { + registry?.fail(registryModuleName.value, failedInstanceId); consumedSnapshot = true; } renderError.value = error; @@ -328,25 +366,38 @@ export default defineComponent({ return () => { if (renderError.value) throw renderError.value; + const currentInstanceId = instanceId.value; + const currentServerPayload = serverPayload.value; + const currentSnapshot = snapshot.value; + const currentSsrPayload = ssrPayload.value; + const showSSRMarkup = + hasSSRPayload.value && currentInstanceId && !csrOnly; const mount = (
    ); - if (!hasSSRPayload || !instanceId || csrOnly) return mount; - const moduleName = props.moduleName || ssrPayload!.moduleName; + if (!showSSRMarkup) return mount; + const moduleName = props.moduleName || currentSsrPayload!.moduleName; return ( -
    +
    {mount}