From d1dd548a041cfa1313914444f3860f85245bfb8c Mon Sep 17 00:00:00 2001 From: 2heal1 Date: Mon, 16 Jun 2025 20:19:05 +0800 Subject: [PATCH 01/16] chore(react): export createRemoteComponent and related react utils --- .changeset/config.json | 3 +- .changeset/spicy-parents-greet.md | 6 + .../provider-csr/module-federation.config.ts | 2 +- packages/modernjs/package.json | 9 +- .../modernjs/src/cli/configPlugin.spec.ts | 4 +- packages/modernjs/src/cli/configPlugin.ts | 2 +- .../cli/server/data-fetch-server-plugin.ts | 194 +------ packages/modernjs/src/constant.ts | 26 - packages/modernjs/src/interfaces/global.ts | 28 - packages/modernjs/src/runtime/index.ts | 63 ++- .../modernjs/src/ssr-runtime/devPlugin.tsx | 2 +- .../modernjs/src/ssr-runtime/downgrade.ts | 102 ---- .../injectDataFetchFunctionPlugin.tsx | 116 +--- packages/modernjs/src/utils/index.ts | 32 -- packages/react/.eslintrc.json | 41 ++ packages/react/CHANGELOG.md | 1 + packages/react/LICENSE | 21 + packages/react/README.md | 1 + packages/react/modern.config.ts | 6 + packages/react/package.json | 85 +++ packages/react/project.json | 27 + packages/react/src/index.ts | 27 + .../src/module}/AwaitDataFetch.tsx | 10 +- packages/react/src/module/constant.ts | 30 + .../src/module}/createRemoteComponent.tsx | 35 +- .../src/module/data-fetch/call-data-fetch.ts | 13 + .../data-fetch-server-middleware.ts | 191 +++++++ .../module/data-fetch/inject-data-fetch.ts | 109 ++++ .../src/module/data-fetch/runtime-plugin.ts} | 17 +- packages/react/src/module/index.ts | 35 ++ packages/react/src/module/logger.ts | 6 + packages/react/src/module/types.ts | 49 ++ .../src/module/utils.ts} | 152 ++++- .../src/module}/wrapNoSSR.tsx | 0 packages/react/tsconfig.json | 21 + pnpm-lock.yaml | 525 +++++++++++++----- 36 files changed, 1298 insertions(+), 693 deletions(-) create mode 100644 .changeset/spicy-parents-greet.md delete mode 100644 packages/modernjs/src/interfaces/global.ts delete mode 100644 packages/modernjs/src/ssr-runtime/downgrade.ts delete mode 100644 packages/modernjs/src/utils/index.ts create mode 100644 packages/react/.eslintrc.json create mode 100644 packages/react/CHANGELOG.md create mode 100644 packages/react/LICENSE create mode 100644 packages/react/README.md create mode 100644 packages/react/modern.config.ts create mode 100644 packages/react/package.json create mode 100644 packages/react/project.json create mode 100644 packages/react/src/index.ts rename packages/{modernjs/src/runtime => react/src/module}/AwaitDataFetch.tsx (95%) create mode 100644 packages/react/src/module/constant.ts rename packages/{modernjs/src/runtime => react/src/module}/createRemoteComponent.tsx (93%) create mode 100644 packages/react/src/module/data-fetch/call-data-fetch.ts create mode 100644 packages/react/src/module/data-fetch/data-fetch-server-middleware.ts create mode 100644 packages/react/src/module/data-fetch/inject-data-fetch.ts rename packages/{modernjs/src/cli/mfRuntimePlugins/auto-fetch-data.ts => react/src/module/data-fetch/runtime-plugin.ts} (88%) create mode 100644 packages/react/src/module/index.ts create mode 100644 packages/react/src/module/logger.ts create mode 100644 packages/react/src/module/types.ts rename packages/{modernjs/src/utils/dataFetch.ts => react/src/module/utils.ts} (56%) rename packages/{modernjs/src/runtime => react/src/module}/wrapNoSSR.tsx (100%) create mode 100644 packages/react/tsconfig.json diff --git a/.changeset/config.json b/.changeset/config.json index 6a62d9a7350..83b093f29db 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -27,7 +27,8 @@ "@module-federation/inject-external-runtime-core-plugin", "@module-federation/runtime-core", "create-module-federation", - "@module-federation/cli" + "@module-federation/cli", + "@module-federation/react" ] ], "ignorePatterns": ["^alpha|^beta"], diff --git a/.changeset/spicy-parents-greet.md b/.changeset/spicy-parents-greet.md new file mode 100644 index 00000000000..91f0b96d049 --- /dev/null +++ b/.changeset/spicy-parents-greet.md @@ -0,0 +1,6 @@ +--- +'@module-federation/react': patch +'@module-federation/modern-js': patch +--- + +chore(react): export createRemoteComponent and related react utils diff --git a/apps/modern-component-data-fetch/provider-csr/module-federation.config.ts b/apps/modern-component-data-fetch/provider-csr/module-federation.config.ts index bc0fc0ec85d..e8784e9e8bc 100644 --- a/apps/modern-component-data-fetch/provider-csr/module-federation.config.ts +++ b/apps/modern-component-data-fetch/provider-csr/module-federation.config.ts @@ -1,4 +1,4 @@ -import { createModuleFederationConfig } from '@module-federation/modern-js'; +import { createModuleFederationConfig } from '@module-federation/rsbuild-plugin'; export default createModuleFederationConfig({ name: 'provider_csr', diff --git a/packages/modernjs/package.json b/packages/modernjs/package.json index 1e0006801d5..859428af46e 100644 --- a/packages/modernjs/package.json +++ b/packages/modernjs/package.json @@ -55,11 +55,6 @@ "import": "./dist/esm/cli/mfRuntimePlugins/resolve-entry-ipv4.js", "require": "./dist/esm/cli/mfRuntimePlugins/resolve-entry-ipv4.js" }, - "./auto-fetch-data": { - "types": "./dist/types/cli/mfRuntimePlugins/auto-fetch-data.d.ts", - "import": "./dist/esm/cli/mfRuntimePlugins/auto-fetch-data.js", - "require": "./dist/esm/cli/mfRuntimePlugins/auto-fetch-data.js" - }, "./inject-node-fetch": { "types": "./dist/types/cli/mfRuntimePlugins/inject-node-fetch.d.ts", "import": "./dist/esm/cli/mfRuntimePlugins/inject-node-fetch.js", @@ -94,9 +89,6 @@ "resolve-entry-ipv4": [ "./dist/types/cli/mfRuntimePlugins/resolve-entry-ipv4.d.ts" ], - "auto-fetch-data": [ - "./dist/types/cli/mfRuntimePlugins/auto-fetch-data.d.ts" - ], "inject-node-fetch": [ "./dist/types/cli/mfRuntimePlugins/inject-node-fetch.d.ts" ], @@ -119,6 +111,7 @@ "@modern-js/utils": "2.67.5", "@modern-js/node-bundle-require": "2.67.6", "@module-federation/rsbuild-plugin": "workspace:*", + "@module-federation/react": "workspace:*", "fs-extra": "11.3.0", "lru-cache": "10.4.3", "@module-federation/enhanced": "workspace:*", diff --git a/packages/modernjs/src/cli/configPlugin.spec.ts b/packages/modernjs/src/cli/configPlugin.spec.ts index 732b608ea07..08b3f6e5516 100644 --- a/packages/modernjs/src/cli/configPlugin.spec.ts +++ b/packages/modernjs/src/cli/configPlugin.spec.ts @@ -34,7 +34,7 @@ describe('patchMFConfig', async () => { remoteType: 'script', runtimePlugins: [ require.resolve('@module-federation/modern-js/shared-strategy'), - require.resolve('@module-federation/modern-js/auto-fetch-data'), + require.resolve('@module-federation/react/data-fetch-runtime-plugin'), require.resolve('@module-federation/node/runtimePlugin'), require.resolve('@module-federation/modern-js/inject-node-fetch'), ], @@ -65,7 +65,7 @@ describe('patchMFConfig', async () => { remoteType: 'script', runtimePlugins: [ require.resolve('@module-federation/modern-js/shared-strategy'), - require.resolve('@module-federation/modern-js/auto-fetch-data'), + require.resolve('@module-federation/react/data-fetch-runtime-plugin'), ], shared: { react: { diff --git a/packages/modernjs/src/cli/configPlugin.ts b/packages/modernjs/src/cli/configPlugin.ts index f6ffb0bdec9..ae16a07da73 100644 --- a/packages/modernjs/src/cli/configPlugin.ts +++ b/packages/modernjs/src/cli/configPlugin.ts @@ -170,7 +170,7 @@ export const patchMFConfig = ( ); injectRuntimePlugins( - require.resolve('@module-federation/modern-js/auto-fetch-data'), + require.resolve('@module-federation/react/data-fetch-runtime-plugin'), runtimePlugins, ); diff --git a/packages/modernjs/src/cli/server/data-fetch-server-plugin.ts b/packages/modernjs/src/cli/server/data-fetch-server-plugin.ts index 138321e6168..dac15473dfb 100644 --- a/packages/modernjs/src/cli/server/data-fetch-server-plugin.ts +++ b/packages/modernjs/src/cli/server/data-fetch-server-plugin.ts @@ -1,194 +1,6 @@ -import { DATA_FETCH_QUERY, MF_DATA_FETCH_STATUS } from '../../constant'; -import logger from '../../logger'; -import { getDataFetchMap } from '../../utils'; -import { - fetchData, - initDataFetchMap, - loadDataFetchModule, -} from '../../utils/dataFetch'; -import { SEPARATOR, MANIFEST_EXT } from '@module-federation/sdk'; -import type { - MiddlewareHandler, - ServerPlugin, -} from '@modern-js/server-runtime'; -import type { NoSSRRemoteInfo } from '../../interfaces/global'; +import dataFetchMiddleWare from '@module-federation/react/data-fetch-server-middleware'; -function wrapSetTimeout( - targetPromise: Promise, - delay = 20000, - id: string, -) { - if (targetPromise && typeof targetPromise.then === 'function') { - return new Promise((resolve, reject) => { - const timeoutId = setTimeout(() => { - logger.warn(`Data fetch for ID ${id} timed out after 20 seconds.`); - reject(new Error(`Data fetch for ID ${id} timed out after 20 seconds`)); - }, delay); - - targetPromise - .then((value: any) => { - clearTimeout(timeoutId); - resolve(value); - }) - .catch((err: any) => { - clearTimeout(timeoutId); - reject(err); - }); - }); - } -} - -function addProtocol(url: string) { - if (url.startsWith('//')) { - return 'https:' + url; - } - return url; -} - -const getDecodeQuery = (url: URL, name: string) => { - const res = url.searchParams.get(name); - if (!res) { - return null; - } - return decodeURIComponent(res); -}; - -const middleware: MiddlewareHandler = async (ctx, next) => { - let url: URL; - let dataFetchId: string | null; - let params: Record; - let remoteInfo: NoSSRRemoteInfo; - try { - url = new URL(ctx.req.url); - dataFetchId = getDecodeQuery(url, DATA_FETCH_QUERY); - params = JSON.parse(getDecodeQuery(url, 'params') || '{}'); - const remoteInfoQuery = getDecodeQuery(url, 'remoteInfo'); - remoteInfo = remoteInfoQuery ? JSON.parse(remoteInfoQuery) : null; - } catch (e) { - logger.error('fetch data from server, error: ', e); - return next(); - } - - if (!dataFetchId) { - return next(); - } - logger.log('fetch data from server, dataFetchId: ', dataFetchId); - logger.debug( - 'fetch data from server, moduleInfo: ', - globalThis.__FEDERATION__?.moduleInfo, - ); - try { - const dataFetchMap = getDataFetchMap(); - if (!dataFetchMap) { - initDataFetchMap(); - } - const fetchDataPromise = dataFetchMap[dataFetchId]?.[1]; - logger.debug( - 'fetch data from server, fetchDataPromise: ', - fetchDataPromise, - ); - if ( - fetchDataPromise && - dataFetchMap[dataFetchId]?.[2] !== MF_DATA_FETCH_STATUS.ERROR - ) { - const targetPromise = fetchDataPromise[0]; - // Ensure targetPromise is thenable - const wrappedPromise = wrapSetTimeout(targetPromise, 20000, dataFetchId); - if (wrappedPromise) { - const res = await wrappedPromise; - logger.log('fetch data from server, fetchDataPromise res: ', res); - return ctx.json(res); - } - logger.error( - `Expected a Promise from fetchDataPromise[0] for dataFetchId ${dataFetchId}, but received:`, - targetPromise, - 'Will try call new dataFetch again...', - ); - } - - if (remoteInfo) { - try { - const hostInstance = globalThis.__FEDERATION__.__INSTANCES__[0]; - const remoteEntry = `${addProtocol(remoteInfo.ssrPublicPath) + remoteInfo.ssrRemoteEntry}`; - if (!hostInstance) { - throw new Error('host instance not found!'); - } - const remote = hostInstance.options.remotes.find( - (remote) => remote.name === remoteInfo.name, - ); - logger.debug('find remote: ', JSON.stringify(remote)); - if (!remote) { - hostInstance.registerRemotes([ - { - name: remoteInfo.name, - entry: remoteEntry, - entryGlobalName: remoteInfo.globalName, - }, - ]); - } else if ( - !('entry' in remote) || - !remote.entry.includes(MANIFEST_EXT) - ) { - const { hostGlobalSnapshot, remoteSnapshot } = - hostInstance.snapshotHandler.getGlobalRemoteInfo(remoteInfo); - logger.debug( - 'find hostGlobalSnapshot: ', - JSON.stringify(hostGlobalSnapshot), - ); - logger.debug('find remoteSnapshot: ', JSON.stringify(remoteSnapshot)); - - if (!hostGlobalSnapshot || !remoteSnapshot) { - if ('version' in remote) { - // @ts-ignore - delete remote.version; - } - // @ts-ignore - remote.entry = remoteEntry; - remote.entryGlobalName = remoteInfo.globalName; - } - } - } catch (e) { - ctx.status(500); - return ctx.text( - `failed to fetch ${remoteInfo.name} data, error:\n ${e}`, - ); - } - } - - const dataFetchItem = dataFetchMap[dataFetchId]; - logger.debug('fetch data from server, dataFetchItem: ', dataFetchItem); - if (dataFetchItem) { - const callFetchDataPromise = fetchData(dataFetchId, { - ...params, - isDowngrade: !remoteInfo, - }); - const wrappedPromise = wrapSetTimeout( - callFetchDataPromise, - 20000, - dataFetchId, - ); - if (wrappedPromise) { - const res = await wrappedPromise; - logger.log('fetch data from server, dataFetchItem res: ', res); - return ctx.json(res); - } - } - - const remoteId = dataFetchId.split(SEPARATOR)[0]; - const hostInstance = globalThis.__FEDERATION__.__INSTANCES__[0]; - if (!hostInstance) { - throw new Error('host instance not found!'); - } - const dataFetchFn = await loadDataFetchModule(hostInstance, remoteId); - const data = await dataFetchFn({ ...params, isDowngrade: !remoteInfo }); - logger.log('fetch data from server, loadDataFetchModule res: ', data); - return ctx.json(data); - } catch (e) { - logger.error('server plugin data fetch error: ', e); - ctx.status(500); - return ctx.text(`failed to fetch ${remoteInfo.name} data, error:\n ${e}`); - } -}; +import type { ServerPlugin } from '@modern-js/server-runtime'; const dataFetchServePlugin = (): ServerPlugin => ({ name: 'mf-data-fetch-server-plugin', @@ -198,7 +10,7 @@ const dataFetchServePlugin = (): ServerPlugin => ({ middlewares.push({ name: 'module-federation-serve-manifest', // @ts-ignore type error - handler: middleware, + handler: dataFetchMiddleWare, }); }); }, diff --git a/packages/modernjs/src/constant.ts b/packages/modernjs/src/constant.ts index 149c3b4c80a..8b547453196 100644 --- a/packages/modernjs/src/constant.ts +++ b/packages/modernjs/src/constant.ts @@ -1,28 +1,2 @@ export const LOCALHOST = 'localhost'; export const PLUGIN_IDENTIFIER = '[ Modern.js Module Federation ]'; -export const DATA_FETCH_QUERY = 'x-mf-data-fetch'; -export const DATA_FETCH_ERROR_PREFIX = - 'caught the following error during dataFetch: '; -export const LOAD_REMOTE_ERROR_PREFIX = - 'caught the following error during loadRemote: '; -export const DOWNGRADE_KEY = '_mfSSRDowngrade'; -export const DATA_FETCH_MAP_KEY = '__MF_DATA_FETCH_MAP__'; -export const DATA_FETCH_FUNCTION = '_mfDataFetch'; -export const FS_HREF = '_mfFSHref'; -export const ERROR_TYPE = { - DATA_FETCH: 1, - LOAD_REMOTE: 2, - UNKNOWN: 3, -}; -export const WRAP_DATA_FETCH_ID_IDENTIFIER = 'wrap_dfip_identifier'; -export const enum MF_DATA_FETCH_TYPE { - FETCH_SERVER = 1, - FETCH_CLIENT = 2, -} - -export const enum MF_DATA_FETCH_STATUS { - LOADED = 1, - LOADING = 2, - AWAIT = 0, - ERROR = 3, -} diff --git a/packages/modernjs/src/interfaces/global.ts b/packages/modernjs/src/interfaces/global.ts deleted file mode 100644 index 6459ce70df5..00000000000 --- a/packages/modernjs/src/interfaces/global.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MF_DATA_FETCH_TYPE, MF_DATA_FETCH_STATUS } from '../constant'; - -export type DataFetchParams = { - isDowngrade: boolean; -} & Record; -export type DataFetch = (params: DataFetchParams) => Promise; -export type MF_DATA_FETCH_MAP_VALUE = [ - [ - // getDataFetchGetter - () => Promise>, - MF_DATA_FETCH_TYPE, - // getDataFetchPromise - Promise>?, - ], - // loading, resolve, reject - [Promise, ((data: unknown) => void)?, ((err: unknown) => void)?]?, - MF_DATA_FETCH_STATUS?, -]; -export type MF_DATA_FETCH_MAP = Record; -export type MF_SSR_DOWNGRADE = string[] | true | undefined; - -export type NoSSRRemoteInfo = { - name: string; - version: string; - ssrPublicPath: string; - ssrRemoteEntry: string; - globalName: string; -}; diff --git a/packages/modernjs/src/runtime/index.ts b/packages/modernjs/src/runtime/index.ts index 6838cdbfb7b..06d8ab1dd78 100644 --- a/packages/modernjs/src/runtime/index.ts +++ b/packages/modernjs/src/runtime/index.ts @@ -1,21 +1,60 @@ +import * as mfRuntime from '@module-federation/enhanced/runtime'; +// eslint-disable-next-line @nx/enforce-module-boundaries +import { kit as rawKit, ERROR_TYPE } from '@module-federation/react/pure'; + +import type { + CollectSSRAssetsOptions, + CreateRemoteComponentOptions, +} from '@module-federation/react/pure'; + export * from '@module-federation/enhanced/runtime'; -export type { DataFetchParams } from '../interfaces/global'; -export { ERROR_TYPE } from '../constant'; -// avoid import react directly https://github.com/web-infra-dev/modern.js/issues/7096 +export { ERROR_TYPE }; + +type NewCreateRemoteComponentOptions = Omit< + CreateRemoteComponentOptions, + 'runtime' +>; +type NewCreateRemoteComponent = ( + options: NewCreateRemoteComponentOptions, +) => ReturnType< + typeof import('@module-federation/react/pure').kit.createRemoteSSRComponent< + T, + E + > +>; + export const kit = { - get createRemoteSSRComponent(): typeof import('./createRemoteComponent').createRemoteSSRComponent { - return require('./createRemoteComponent').createRemoteSSRComponent; + get createRemoteSSRComponent(): NewCreateRemoteComponent { + const { createRemoteSSRComponent } = rawKit; + return (options) => + createRemoteSSRComponent({ ...options, runtime: mfRuntime }); + }, + get createRemoteComponent(): NewCreateRemoteComponent { + const { createRemoteComponent } = rawKit; + return (options) => + createRemoteComponent({ ...options, runtime: mfRuntime }); }, - get createRemoteComponent(): typeof import('./createRemoteComponent').createRemoteComponent { - return require('./createRemoteComponent').createRemoteComponent; + get collectSSRAssets(): ( + options: Omit, + ) => ReturnType< + typeof import('@module-federation/react/pure').kit.collectSSRAssets + > { + const { collectSSRAssets } = rawKit; + return (options) => collectSSRAssets({ ...options, runtime: mfRuntime }); }, - get collectSSRAssets(): typeof import('./createRemoteComponent').collectSSRAssets { - return require('./createRemoteComponent').collectSSRAssets; + get wrapNoSSR(): ( + createComponentFn: NewCreateRemoteComponent, + ) => ( + options: Omit, 'noSSR'>, + ) => ReturnType { + return (createComponentFn) => { + return (options) => createComponentFn({ ...options, noSSR: true }); + }; }, - get wrapNoSSR(): typeof import('./wrapNoSSR').wrapNoSSR { - return require('./wrapNoSSR').wrapNoSSR; + get injectDataFetch(): typeof import('@module-federation/react/pure').kit.injectDataFetch { + return require('@module-federation/react/pure').kit.injectDataFetch; }, }; -export { setSSREnv } from '../ssr-runtime/injectDataFetchFunctionPlugin'; +export type { DataFetchParams } from '@module-federation/react/pure'; diff --git a/packages/modernjs/src/ssr-runtime/devPlugin.tsx b/packages/modernjs/src/ssr-runtime/devPlugin.tsx index d4f2f525fcf..de78ada8249 100644 --- a/packages/modernjs/src/ssr-runtime/devPlugin.tsx +++ b/packages/modernjs/src/ssr-runtime/devPlugin.tsx @@ -1,6 +1,6 @@ import type { RuntimePluginFuture } from '@modern-js/runtime'; import { SSRLiveReload } from './SSRLiveReload'; -import { flushDataFetch } from '../utils'; +import { flushDataFetch } from '@module-federation/react/data-fetch-utils'; export const mfSSRDevPlugin = (): RuntimePluginFuture => ({ name: '@module-federation/modern-js', diff --git a/packages/modernjs/src/ssr-runtime/downgrade.ts b/packages/modernjs/src/ssr-runtime/downgrade.ts deleted file mode 100644 index dad14245fc5..00000000000 --- a/packages/modernjs/src/ssr-runtime/downgrade.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { DATA_FETCH_QUERY, DOWNGRADE_KEY } from '../constant'; -import { MF_DATA_FETCH_STATUS, MF_DATA_FETCH_TYPE } from '../constant'; -import { getDataFetchMap, initDataFetchMap } from '../utils'; - -import type { - DataFetchParams, - MF_SSR_DOWNGRADE, - NoSSRRemoteInfo, -} from '../interfaces/global'; - -export function getDowngradeTag() { - return globalThis[DOWNGRADE_KEY] as MF_SSR_DOWNGRADE; -} - -export function callAllDowngrade() { - const dataFetchMap = getDataFetchMap(); - if (!dataFetchMap) { - return; - } - Object.keys(dataFetchMap).forEach((key) => { - callDowngrade(key); - }); -} - -export async function callDowngrade( - id: string, - params?: DataFetchParams, - remoteInfo?: NoSSRRemoteInfo, -) { - const dataFetchMap = getDataFetchMap(); - if (!dataFetchMap) { - return; - } - const mfDataFetch = dataFetchMap[id]; - if (mfDataFetch?.[2] === MF_DATA_FETCH_STATUS.AWAIT) { - mfDataFetch[2] = MF_DATA_FETCH_STATUS.LOADING; - let promise, res, rej; - if (mfDataFetch[1]) { - promise = mfDataFetch[1][0]; - res = mfDataFetch[1][1]; - rej = mfDataFetch[1][2]; - } else { - promise = new Promise((resolve, reject) => { - res = resolve; - rej = reject; - }); - mfDataFetch[1] = [promise, res, rej]; - } - const dataFetchType = mfDataFetch[0][1]; - if (dataFetchType === MF_DATA_FETCH_TYPE.FETCH_CLIENT) { - try { - mfDataFetch[0][0]().then((getDataFetchFn) => { - return getDataFetchFn({ - ...params, - isDowngrade: true, - }).then((data) => { - mfDataFetch[2] = MF_DATA_FETCH_STATUS.LOADED; - res(data); - }); - }); - } catch (e) { - mfDataFetch[2] = MF_DATA_FETCH_STATUS.ERROR; - rej(e); - } - } else if (dataFetchType === MF_DATA_FETCH_TYPE.FETCH_SERVER) { - try { - const currentUrl = new URL(window.location.href); - currentUrl.searchParams.set(DATA_FETCH_QUERY, encodeURIComponent(id)); - if (params) { - currentUrl.searchParams.set( - 'params', - encodeURIComponent(JSON.stringify(params)), - ); - } - if (remoteInfo) { - currentUrl.searchParams.set( - 'remoteInfo', - encodeURIComponent(JSON.stringify(remoteInfo)), - ); - } - const fetchServerQuery = globalThis.FEDERATION_SERVER_QUERY; - if (fetchServerQuery && typeof fetchServerQuery === 'object') { - Object.keys(fetchServerQuery).forEach((key) => { - currentUrl.searchParams.set( - key, - JSON.stringify(fetchServerQuery[key]), - ); - }); - } - const fetchUrl = currentUrl.toString(); - const data = await fetch(fetchUrl).then((res) => res.json()); - mfDataFetch[2] = MF_DATA_FETCH_STATUS.LOADED; - res(data); - } catch (e) { - mfDataFetch[2] = MF_DATA_FETCH_STATUS.ERROR; - rej(e); - } - } - - return promise; - } -} diff --git a/packages/modernjs/src/ssr-runtime/injectDataFetchFunctionPlugin.tsx b/packages/modernjs/src/ssr-runtime/injectDataFetchFunctionPlugin.tsx index 62e15de8d9b..f454174ff35 100644 --- a/packages/modernjs/src/ssr-runtime/injectDataFetchFunctionPlugin.tsx +++ b/packages/modernjs/src/ssr-runtime/injectDataFetchFunctionPlugin.tsx @@ -1,30 +1,8 @@ -import { - DATA_FETCH_FUNCTION, - DOWNGRADE_KEY, - FS_HREF, - MF_DATA_FETCH_STATUS, - MF_DATA_FETCH_TYPE, -} from '../constant'; -import logger from '../logger'; -import { getDataFetchMap, getDataFetchItem, initDataFetchMap } from '../utils'; -import { callAllDowngrade, callDowngrade, getDowngradeTag } from './downgrade'; +import { kit } from '@module-federation/react/pure'; +const { callDataFetch, injectDataFetch, setSSREnv } = kit; import type { RuntimePluginFuture } from '@modern-js/runtime'; -type dataFetchFunctionOptions = [ - id?: string, - data?: unknown, - downgrade?: boolean, -]; -export function setSSREnv({ - fetchServerQuery, -}: { - fetchServerQuery?: Record; -}) { - globalThis.FEDERATION_SSR = true; - globalThis.FEDERATION_SERVER_QUERY = fetchServerQuery; -} - export const injectDataFetchFunctionPlugin = ({ fetchServerQuery, }: { @@ -35,95 +13,9 @@ export const injectDataFetchFunctionPlugin = ({ setup: (api) => { api.onBeforeRender(async () => { setSSREnv({ fetchServerQuery }); - if (typeof window === 'undefined') { - return; - } - const dataFetchFunction = async function ( - options: dataFetchFunctionOptions, - ) { - const [id, data, downgrade] = options; - logger.debug('==========call data fetch function!'); - if (data) { - if (!id) { - throw new Error('id is required!'); - } - if (!getDataFetchMap()) { - initDataFetchMap(); - } - const dataFetchItem = getDataFetchItem(id); - if (dataFetchItem) { - dataFetchItem[1]?.[1]?.(data); - dataFetchItem[2] = MF_DATA_FETCH_STATUS.LOADED; - return; - } - if (!dataFetchItem) { - const dataFetchMap = getDataFetchMap(); - let res; - let rej; - const p = new Promise((resolve, reject) => { - res = resolve; - rej = reject; - }); - - dataFetchMap[id] = [ - [ - async () => async () => { - return ''; - }, - MF_DATA_FETCH_TYPE.FETCH_SERVER, - ], - [p, res, rej], - MF_DATA_FETCH_STATUS.LOADED, - ]; - res(data); - return; - } - } - - if (downgrade) { - const mfDowngrade = getDowngradeTag(); - if (!mfDowngrade) { - globalThis[DOWNGRADE_KEY] = id ? [id] : true; - } else if ( - Array.isArray(mfDowngrade) && - id && - !mfDowngrade.includes(id) - ) { - mfDowngrade.push(id); - } - } - - const mfDowngrade = getDowngradeTag(); - - if (typeof mfDowngrade === 'boolean') { - return callAllDowngrade(); - } - if (Array.isArray(mfDowngrade)) { - if (!id) { - globalThis[DOWNGRADE_KEY] = true; - return callAllDowngrade(); - } - - if (!mfDowngrade.includes(id)) { - mfDowngrade.push(id); - } - - return callDowngrade(id); - } - }; - globalThis[FS_HREF] = window.location.href; - globalThis[DATA_FETCH_FUNCTION] ||= []; - const dataFetch: Array = - globalThis[DATA_FETCH_FUNCTION]; - - await Promise.all( - dataFetch.map(async (options) => { - await dataFetchFunction(options); - }), - ); + injectDataFetch(); - // @ts-ignore - dataFetch.push = dataFetchFunction; + await callDataFetch(); }); }, }); diff --git a/packages/modernjs/src/utils/index.ts b/packages/modernjs/src/utils/index.ts deleted file mode 100644 index 9cb30ab3514..00000000000 --- a/packages/modernjs/src/utils/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { FederationHost } from '@module-federation/enhanced/runtime'; - -export function getLoadedRemoteInfos( - id: string, - instance: FederationHost | null, -) { - if (!instance) { - return; - } - const { name, expose } = instance.remoteHandler.idToRemoteMap[id] || {}; - if (!name) { - return; - } - const module = instance.moduleCache.get(name); - if (!module) { - return; - } - const { remoteSnapshot } = instance.snapshotHandler.getGlobalRemoteInfo( - module.remoteInfo, - ); - return { - ...module.remoteInfo, - snapshot: remoteSnapshot, - expose, - }; -} - -export function isCSROnly() { - return window._SSR_DATA === undefined; -} - -export * from './dataFetch'; diff --git a/packages/react/.eslintrc.json b/packages/react/.eslintrc.json new file mode 100644 index 00000000000..5c3013868ca --- /dev/null +++ b/packages/react/.eslintrc.json @@ -0,0 +1,41 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": [ + "!**/*", + "**/*.d.ts", + "**/vite.config.*.timestamp*", + "**/vitest.config.*.timestamp*" + ], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": { + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/ban-ts-comment": "warn", + "@typescript-eslint/no-var-requires": 0, + "@typescript-eslint/no-restricted-imports": [ + "error", + { + "paths": [ + { + "name": "webpack", + "message": "Please use require(normalizeWebpackPath('webpack')) instead.", + "allowTypeImports": true + } + ], + "patterns": [ + { + "group": ["webpack/lib/*"], + "message": "Please use require(normalizeWebpackPath('webpack')) instead.", + "allowTypeImports": true + } + ] + } + ] + } + }, + { + "files": ["*.js", "*.jsx"] + } + ] +} diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md new file mode 100644 index 00000000000..fa8f0625cb5 --- /dev/null +++ b/packages/react/CHANGELOG.md @@ -0,0 +1 @@ +# @module-federation/react diff --git a/packages/react/LICENSE b/packages/react/LICENSE new file mode 100644 index 00000000000..45036bbb708 --- /dev/null +++ b/packages/react/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025-present zhanghang(2heal1) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/react/README.md b/packages/react/README.md new file mode 100644 index 00000000000..2b3ce667a4d --- /dev/null +++ b/packages/react/README.md @@ -0,0 +1 @@ +# React diff --git a/packages/react/modern.config.ts b/packages/react/modern.config.ts new file mode 100644 index 00000000000..a7a46250653 --- /dev/null +++ b/packages/react/modern.config.ts @@ -0,0 +1,6 @@ +import { moduleTools, defineConfig } from '@modern-js/module-tools'; + +export default defineConfig({ + buildPreset: 'modern-js-universal', + plugins: [moduleTools()], +}); diff --git a/packages/react/package.json b/packages/react/package.json new file mode 100644 index 00000000000..cb6ac03e754 --- /dev/null +++ b/packages/react/package.json @@ -0,0 +1,85 @@ +{ + "name": "@module-federation/react", + "version": "0.15.0", + "publishConfig": { + "access": "public" + }, + "files": [ + "dist/" + ], + "author": "hanric ", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/module-federation/core", + "directory": "packages/react" + }, + "main": "./dist/cjs/index.js", + "module": "./dist/esm/index.js", + "types": "./dist/types/index.d.ts", + "exports": { + ".": { + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.js", + "require": "./dist/cjs/index.js" + }, + "./data-fetch-runtime-plugin": { + "types": "./dist/types/module/data-fetch/runtime-plugin.d.ts", + "import": "./dist/esm/module/data-fetch/runtime-plugin.js", + "require": "./dist/cjs/module/data-fetch/runtime-plugin.js" + }, + "./data-fetch-utils": { + "types": "./dist/types/module/utils.d.ts", + "import": "./dist/esm/module/utils.js", + "require": "./dist/cjs/module/utils.js" + }, + "./data-fetch-server-middleware": { + "types": "./dist/types/module/data-fetch/data-fetch-server-middleware.d.ts", + "import": "./dist/esm/module/data-fetch/data-fetch-server-middleware.js", + "require": "./dist/cjs/module/data-fetch/data-fetch-server-middleware.js" + }, + "./pure": { + "types": "./dist/types/module/index.d.ts", + "import": "./dist/esm/module/index.js", + "require": "./dist/cjs/module/index.js" + }, + "./*": "./*" + }, + "typesVersions": { + "*": { + ".": [ + "./dist/types/index.d.ts" + ], + "data-fetch-runtime-plugin": [ + "./dist/types/module/data-fetch/runtime-plugin.d.ts" + ], + "data-fetch-utils": [ + "./dist/types/module/utils.d.ts" + ], + "data-fetch-server-middleware": [ + "./dist/types/module/data-fetch/data-fetch-server-middleware.d.ts" + ], + "pure": [ + "./dist/types/module/index.d.ts" + ] + } + }, + "scripts": { + "build": "modern-module build" + }, + "dependencies": { + "@module-federation/sdk": "workspace:*", + "@swc/helpers": "^0.5.17" + }, + "peerDependencies": { + "react": ">=17" + }, + "devDependencies": { + "@types/react": "18.2.79", + "react": "18.3.1", + "typescript": "^5.2.2", + "@modern-js/module-tools": "2.67.6", + "@module-federation/runtime": "workspace:*", + "hono": "3.12.12" + } +} diff --git a/packages/react/project.json b/packages/react/project.json new file mode 100644 index 00000000000..a4e09aff327 --- /dev/null +++ b/packages/react/project.json @@ -0,0 +1,27 @@ +{ + "name": "react", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/react/src", + "projectType": "library", + "tags": ["type:pkg"], + "targets": { + "build": { + "executor": "nx:run-commands", + "outputs": ["{projectRoot}/packages/modernjs/dist"], + "dependsOn": [ + { + "target": "build", + "dependencies": true + } + ], + "options": { + "parallel": false, + "commands": [ + "pnpm i", + "cd packages/react; pnpm run build || (sleep 2 && pnpm run build)", + "cp packages/react/LICENSE packages/react/dist" + ] + } + } + } +} diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts new file mode 100644 index 00000000000..059e653ee31 --- /dev/null +++ b/packages/react/src/index.ts @@ -0,0 +1,27 @@ +import { kit, ERROR_TYPE, autoFetchDataPlugin } from './module'; +export type { + DataFetchParams, + NoSSRRemoteInfo, + CollectSSRAssetsOptions, + CreateRemoteComponentOptions, +} from './module'; + +const { + createRemoteSSRComponent, + createRemoteComponent, + collectSSRAssets, + wrapNoSSR, + injectDataFetch, + callDataFetch, +} = kit; + +export { + createRemoteSSRComponent, + createRemoteComponent, + collectSSRAssets, + wrapNoSSR, + injectDataFetch, + callDataFetch, + ERROR_TYPE, + autoFetchDataPlugin, +}; diff --git a/packages/modernjs/src/runtime/AwaitDataFetch.tsx b/packages/react/src/module/AwaitDataFetch.tsx similarity index 95% rename from packages/modernjs/src/runtime/AwaitDataFetch.tsx rename to packages/react/src/module/AwaitDataFetch.tsx index 821b05154c5..f1e41af8d6a 100644 --- a/packages/modernjs/src/runtime/AwaitDataFetch.tsx +++ b/packages/react/src/module/AwaitDataFetch.tsx @@ -1,14 +1,14 @@ import React, { MutableRefObject, ReactNode, Suspense, useRef } from 'react'; -import logger from '../logger'; +import logger from './logger'; import { DATA_FETCH_ERROR_PREFIX, LOAD_REMOTE_ERROR_PREFIX, ERROR_TYPE, - DOWNGRADE_KEY, DATA_FETCH_FUNCTION, -} from '../constant'; -import { getDataFetchIdWithErrorMsgs, wrapDataFetchId } from '../utils'; -import type { DataFetchParams } from '../interfaces/global'; +} from './constant'; + +import { getDataFetchIdWithErrorMsgs, wrapDataFetchId } from './utils'; +import type { DataFetchParams } from './types'; function isPromise(obj: any): obj is PromiseLike { return ( diff --git a/packages/react/src/module/constant.ts b/packages/react/src/module/constant.ts new file mode 100644 index 00000000000..c6b718ce1ac --- /dev/null +++ b/packages/react/src/module/constant.ts @@ -0,0 +1,30 @@ +export const PLUGIN_IDENTIFIER = '[ Module Federation React ]'; +export const DOWNGRADE_KEY = '_mfSSRDowngrade'; +export const DATA_FETCH_MAP_KEY = '__MF_DATA_FETCH_MAP__'; +export const DATA_FETCH_FUNCTION = '_mfDataFetch'; +export const FS_HREF = '_mfFSHref'; +export const ERROR_TYPE = { + DATA_FETCH: 1, + LOAD_REMOTE: 2, + UNKNOWN: 3, +}; +export const WRAP_DATA_FETCH_ID_IDENTIFIER = 'wrap_dfip_identifier'; +export const enum MF_DATA_FETCH_TYPE { + FETCH_SERVER = 1, + FETCH_CLIENT = 2, +} + +export const enum MF_DATA_FETCH_STATUS { + LOADED = 1, + LOADING = 2, + AWAIT = 0, + ERROR = 3, +} + +export const DATA_FETCH_IDENTIFIER = 'data'; +export const DATA_FETCH_CLIENT_SUFFIX = '.client'; +export const DATA_FETCH_QUERY = 'x-mf-data-fetch'; +export const DATA_FETCH_ERROR_PREFIX = + 'caught the following error during dataFetch: '; +export const LOAD_REMOTE_ERROR_PREFIX = + 'caught the following error during loadRemote: '; diff --git a/packages/modernjs/src/runtime/createRemoteComponent.tsx b/packages/react/src/module/createRemoteComponent.tsx similarity index 93% rename from packages/modernjs/src/runtime/createRemoteComponent.tsx rename to packages/react/src/module/createRemoteComponent.tsx index a9075463748..f70a5a845db 100644 --- a/packages/modernjs/src/runtime/createRemoteComponent.tsx +++ b/packages/react/src/module/createRemoteComponent.tsx @@ -1,32 +1,32 @@ import React, { ReactNode, useEffect, useState } from 'react'; -import logger from '../logger'; -import { getInstance } from '@module-federation/enhanced/runtime'; +import logger from './logger'; import { AwaitDataFetch, transformError } from './AwaitDataFetch'; import { fetchData, getDataFetchItem, getDataFetchMapKey, -} from '../utils/dataFetch'; -import { getDataFetchInfo, getLoadedRemoteInfos, setDataFetchItemLoadedStatus, wrapDataFetchId, -} from '../utils'; +} from './utils'; import { DATA_FETCH_ERROR_PREFIX, DATA_FETCH_FUNCTION, FS_HREF, LOAD_REMOTE_ERROR_PREFIX, MF_DATA_FETCH_TYPE, -} from '../constant'; +} from './constant'; + import type { ErrorInfo } from './AwaitDataFetch'; -import type { DataFetchParams, NoSSRRemoteInfo } from '../interfaces/global'; +import type { DataFetchParams, NoSSRRemoteInfo } from './types'; +import type { FederationHost } from '@module-federation/runtime'; -type IProps = { +export type IProps = { id: string; injectScript?: boolean; injectLink?: boolean; + runtime: typeof import('@module-federation/runtime'); }; export type CreateRemoteComponentOptions = { @@ -36,12 +36,12 @@ export type CreateRemoteComponentOptions = { export?: E; dataFetchParams?: DataFetchParams; noSSR?: boolean; + runtime: typeof import('@module-federation/runtime'); }; type ReactKey = { key?: React.Key | null }; -function getTargetModuleInfo(id: string) { - const instance = getInstance(); +function getTargetModuleInfo(id: string, instance?: FederationHost) { if (!instance) { return; } @@ -89,12 +89,12 @@ export function collectSSRAssets(options: IProps) { } = typeof options === 'string' ? { id: options } : options; const links: React.ReactNode[] = []; const scripts: React.ReactNode[] = []; - const instance = getInstance(); + const instance = options.runtime.getInstance(); if (!instance || (!injectLink && !injectScript)) { return [...scripts, ...links]; } - const moduleAndPublicPath = getTargetModuleInfo(id); + const moduleAndPublicPath = getTargetModuleInfo(id, instance); if (!moduleAndPublicPath) { return [...scripts, ...links]; } @@ -192,6 +192,12 @@ function getServerNeedRemoteInfo( export function createRemoteComponent( options: CreateRemoteComponentOptions, ) { + const { runtime } = options; + if (!runtime?.getInstance) { + throw new Error( + 'runtime is required if used in "@module-federation/bridge-react"!', + ); + } type ComponentType = T[E] extends (...args: any) => any ? Parameters[0] extends undefined ? ReactKey @@ -213,7 +219,7 @@ export function createRemoteComponent( const getData = async (noSSR?: boolean) => { let loadedRemoteInfo: ReturnType; let moduleId: string; - const instance = getInstance(); + const instance = runtime.getInstance(); try { const m = await callLoader(); moduleId = m && m[Symbol.for('mf_module_id')]; @@ -265,7 +271,7 @@ export function createRemoteComponent( const LazyComponent = React.lazy(async () => { const m = await callLoader(); const moduleId = m && m[Symbol.for('mf_module_id')]; - const instance = getInstance()!; + const instance = runtime.getInstance()!; const loadedRemoteInfo = getLoadedRemoteInfos(moduleId, instance); loadedRemoteInfo?.snapshot; const dataFetchMapKey = loadedRemoteInfo @@ -283,6 +289,7 @@ export function createRemoteComponent( const assets = collectSSRAssets({ id: moduleId, + runtime, }); const Com = m[exportName] as React.FC; diff --git a/packages/react/src/module/data-fetch/call-data-fetch.ts b/packages/react/src/module/data-fetch/call-data-fetch.ts new file mode 100644 index 00000000000..b3aeb6849ec --- /dev/null +++ b/packages/react/src/module/data-fetch/call-data-fetch.ts @@ -0,0 +1,13 @@ +import { DATA_FETCH_FUNCTION } from '../constant'; +import { dataFetchFunction } from './inject-data-fetch'; + +export async function callDataFetch() { + const dataFetch = globalThis[DATA_FETCH_FUNCTION]; + if (dataFetch) { + await Promise.all( + dataFetch.map(async (options) => { + await dataFetchFunction(options); + }), + ); + } +} diff --git a/packages/react/src/module/data-fetch/data-fetch-server-middleware.ts b/packages/react/src/module/data-fetch/data-fetch-server-middleware.ts new file mode 100644 index 00000000000..d314665e0eb --- /dev/null +++ b/packages/react/src/module/data-fetch/data-fetch-server-middleware.ts @@ -0,0 +1,191 @@ +import { DATA_FETCH_QUERY, MF_DATA_FETCH_STATUS } from '../constant'; +import { + getDataFetchMap, + fetchData, + initDataFetchMap, + loadDataFetchModule, +} from '../utils'; +import { SEPARATOR, MANIFEST_EXT } from '@module-federation/sdk'; +import logger from '../logger'; + +import type { NoSSRRemoteInfo } from '../types'; +import type { MiddlewareHandler } from 'hono'; + +function wrapSetTimeout( + targetPromise: Promise, + delay = 20000, + id: string, +) { + if (targetPromise && typeof targetPromise.then === 'function') { + return new Promise((resolve, reject) => { + const timeoutId = setTimeout(() => { + logger.warn(`Data fetch for ID ${id} timed out after 20 seconds.`); + reject(new Error(`Data fetch for ID ${id} timed out after 20 seconds`)); + }, delay); + + targetPromise + .then((value: any) => { + clearTimeout(timeoutId); + resolve(value); + }) + .catch((err: any) => { + clearTimeout(timeoutId); + reject(err); + }); + }); + } +} + +function addProtocol(url: string) { + if (url.startsWith('//')) { + return 'https:' + url; + } + return url; +} + +const getDecodeQuery = (url: URL, name: string) => { + const res = url.searchParams.get(name); + if (!res) { + return null; + } + return decodeURIComponent(res); +}; + +const dataFetchServerMiddleware: MiddlewareHandler = async (ctx, next) => { + let url: URL; + let dataFetchId: string | null; + let params: Record; + let remoteInfo: NoSSRRemoteInfo; + try { + url = new URL(ctx.req.url); + dataFetchId = getDecodeQuery(url, DATA_FETCH_QUERY); + params = JSON.parse(getDecodeQuery(url, 'params') || '{}'); + const remoteInfoQuery = getDecodeQuery(url, 'remoteInfo'); + remoteInfo = remoteInfoQuery ? JSON.parse(remoteInfoQuery) : null; + } catch (e) { + logger.error('fetch data from server, error: ', e); + return next(); + } + + if (!dataFetchId) { + return next(); + } + logger.log('fetch data from server, dataFetchId: ', dataFetchId); + logger.debug( + 'fetch data from server, moduleInfo: ', + globalThis.__FEDERATION__?.moduleInfo, + ); + try { + const dataFetchMap = getDataFetchMap(); + if (!dataFetchMap) { + initDataFetchMap(); + } + const fetchDataPromise = dataFetchMap[dataFetchId]?.[1]; + logger.debug( + 'fetch data from server, fetchDataPromise: ', + fetchDataPromise, + ); + if ( + fetchDataPromise && + dataFetchMap[dataFetchId]?.[2] !== MF_DATA_FETCH_STATUS.ERROR + ) { + const targetPromise = fetchDataPromise[0]; + // Ensure targetPromise is thenable + const wrappedPromise = wrapSetTimeout(targetPromise, 20000, dataFetchId); + if (wrappedPromise) { + const res = await wrappedPromise; + logger.log('fetch data from server, fetchDataPromise res: ', res); + return ctx.json(res); + } + logger.error( + `Expected a Promise from fetchDataPromise[0] for dataFetchId ${dataFetchId}, but received:`, + targetPromise, + 'Will try call new dataFetch again...', + ); + } + + if (remoteInfo) { + try { + const hostInstance = globalThis.__FEDERATION__.__INSTANCES__[0]; + const remoteEntry = `${addProtocol(remoteInfo.ssrPublicPath) + remoteInfo.ssrRemoteEntry}`; + if (!hostInstance) { + throw new Error('host instance not found!'); + } + const remote = hostInstance.options.remotes.find( + (remote) => remote.name === remoteInfo.name, + ); + logger.debug('find remote: ', JSON.stringify(remote)); + if (!remote) { + hostInstance.registerRemotes([ + { + name: remoteInfo.name, + entry: remoteEntry, + entryGlobalName: remoteInfo.globalName, + }, + ]); + } else if ( + !('entry' in remote) || + !remote.entry.includes(MANIFEST_EXT) + ) { + const { hostGlobalSnapshot, remoteSnapshot } = + hostInstance.snapshotHandler.getGlobalRemoteInfo(remoteInfo); + logger.debug( + 'find hostGlobalSnapshot: ', + JSON.stringify(hostGlobalSnapshot), + ); + logger.debug('find remoteSnapshot: ', JSON.stringify(remoteSnapshot)); + + if (!hostGlobalSnapshot || !remoteSnapshot) { + if ('version' in remote) { + // @ts-ignore + delete remote.version; + } + // @ts-ignore + remote.entry = remoteEntry; + remote.entryGlobalName = remoteInfo.globalName; + } + } + } catch (e) { + ctx.status(500); + return ctx.text( + `failed to fetch ${remoteInfo.name} data, error:\n ${e}`, + ); + } + } + + const dataFetchItem = dataFetchMap[dataFetchId]; + logger.debug('fetch data from server, dataFetchItem: ', dataFetchItem); + if (dataFetchItem) { + const callFetchDataPromise = fetchData(dataFetchId, { + ...params, + isDowngrade: !remoteInfo, + }); + const wrappedPromise = wrapSetTimeout( + callFetchDataPromise, + 20000, + dataFetchId, + ); + if (wrappedPromise) { + const res = await wrappedPromise; + logger.log('fetch data from server, dataFetchItem res: ', res); + return ctx.json(res); + } + } + + const remoteId = dataFetchId.split(SEPARATOR)[0]; + const hostInstance = globalThis.__FEDERATION__.__INSTANCES__[0]; + if (!hostInstance) { + throw new Error('host instance not found!'); + } + const dataFetchFn = await loadDataFetchModule(hostInstance, remoteId); + const data = await dataFetchFn({ ...params, isDowngrade: !remoteInfo }); + logger.log('fetch data from server, loadDataFetchModule res: ', data); + return ctx.json(data); + } catch (e) { + logger.error('server plugin data fetch error: ', e); + ctx.status(500); + return ctx.text(`failed to fetch ${remoteInfo.name} data, error:\n ${e}`); + } +}; + +export default dataFetchServerMiddleware; diff --git a/packages/react/src/module/data-fetch/inject-data-fetch.ts b/packages/react/src/module/data-fetch/inject-data-fetch.ts new file mode 100644 index 00000000000..bc654551df6 --- /dev/null +++ b/packages/react/src/module/data-fetch/inject-data-fetch.ts @@ -0,0 +1,109 @@ +import { + DATA_FETCH_FUNCTION, + DOWNGRADE_KEY, + FS_HREF, + MF_DATA_FETCH_STATUS, + MF_DATA_FETCH_TYPE, +} from '../constant'; +import logger from '../logger'; +import { + dataFetchFunctionOptions, + MF_DATA_FETCH_MAP_VALUE_PROMISE_SET, +} from '../types'; +import { + callAllDowngrade, + callDowngrade, + getDataFetchItem, + getDataFetchMap, + getDowngradeTag, + initDataFetchMap, +} from '../utils'; + +const dataFetchFunction = async function (options: dataFetchFunctionOptions) { + const [id, data, downgrade] = options; + logger.debug('==========call data fetch function!'); + if (data) { + if (!id) { + throw new Error('id is required!'); + } + if (!getDataFetchMap()) { + initDataFetchMap(); + } + const dataFetchItem = getDataFetchItem(id); + if (dataFetchItem) { + dataFetchItem[1]?.[1]?.(data); + dataFetchItem[2] = MF_DATA_FETCH_STATUS.LOADED; + return; + } + if (!dataFetchItem) { + const dataFetchMap = getDataFetchMap(); + let res: MF_DATA_FETCH_MAP_VALUE_PROMISE_SET[1]; + let rej: MF_DATA_FETCH_MAP_VALUE_PROMISE_SET[2]; + const p = new Promise((resolve, reject) => { + res = resolve; + rej = reject; + }); + + dataFetchMap[id] = [ + [ + async () => async () => { + return ''; + }, + MF_DATA_FETCH_TYPE.FETCH_SERVER, + ], + [p, res, rej], + MF_DATA_FETCH_STATUS.LOADED, + ]; + res && res(data); + return; + } + } + + if (downgrade) { + const mfDowngrade = getDowngradeTag(); + if (!mfDowngrade) { + globalThis[DOWNGRADE_KEY] = id ? [id] : true; + } else if (Array.isArray(mfDowngrade) && id && !mfDowngrade.includes(id)) { + mfDowngrade.push(id); + } + } + + const mfDowngrade = getDowngradeTag(); + + if (typeof mfDowngrade === 'boolean') { + return callAllDowngrade(); + } + if (Array.isArray(mfDowngrade)) { + if (!id) { + globalThis[DOWNGRADE_KEY] = true; + return callAllDowngrade(); + } + + if (!mfDowngrade.includes(id)) { + mfDowngrade.push(id); + } + + return callDowngrade(id); + } +}; + +export function injectDataFetch() { + globalThis[DATA_FETCH_FUNCTION] ||= []; + const dataFetch = globalThis[DATA_FETCH_FUNCTION]; + + //@ts-ignore + if (dataFetch.push === dataFetchFunction) { + return; + } + + if (typeof window === 'undefined') { + return; + } + + globalThis[FS_HREF] = window.location.href; + + //@ts-ignore + dataFetch.push = dataFetchFunction; +} + +export { dataFetchFunction }; diff --git a/packages/modernjs/src/cli/mfRuntimePlugins/auto-fetch-data.ts b/packages/react/src/module/data-fetch/runtime-plugin.ts similarity index 88% rename from packages/modernjs/src/cli/mfRuntimePlugins/auto-fetch-data.ts rename to packages/react/src/module/data-fetch/runtime-plugin.ts index 259ee4c9142..74c8cc95101 100644 --- a/packages/modernjs/src/cli/mfRuntimePlugins/auto-fetch-data.ts +++ b/packages/react/src/module/data-fetch/runtime-plugin.ts @@ -4,18 +4,19 @@ import { getDataFetchItem, getDataFetchMap, isCSROnly, -} from '../../utils'; -import logger from '../../logger'; -import { getDataFetchMapKey, isDataLoaderExpose, loadDataFetchModule, -} from '../../utils/dataFetch'; -import { MF_DATA_FETCH_TYPE, MF_DATA_FETCH_STATUS } from '../../constant'; -import { DATA_FETCH_CLIENT_SUFFIX } from '@module-federation/rsbuild-plugin/constant'; +} from '../utils'; +import logger from '../logger'; +import { + MF_DATA_FETCH_TYPE, + MF_DATA_FETCH_STATUS, + DATA_FETCH_CLIENT_SUFFIX, +} from '../constant'; -import type { MF_DATA_FETCH_MAP_VALUE } from '../../interfaces/global'; -import type { FederationRuntimePlugin } from '@module-federation/enhanced/runtime'; +import type { MF_DATA_FETCH_MAP_VALUE } from '../types'; +import type { FederationRuntimePlugin } from '@module-federation/runtime'; const autoFetchData: () => FederationRuntimePlugin = () => ({ name: 'auto-fetch-data-plugin', diff --git a/packages/react/src/module/index.ts b/packages/react/src/module/index.ts new file mode 100644 index 00000000000..2b08dfcb7df --- /dev/null +++ b/packages/react/src/module/index.ts @@ -0,0 +1,35 @@ +import autoFetchDataPlugin from './data-fetch/runtime-plugin'; + +export type { DataFetchParams, NoSSRRemoteInfo } from './types'; +export { ERROR_TYPE } from './constant'; +export type { + CreateRemoteComponentOptions, + IProps as CollectSSRAssetsOptions, +} from './createRemoteComponent'; + +// avoid import react directly https://github.com/web-infra-dev/modern.js/issues/7096 +export const kit = { + get createRemoteSSRComponent(): typeof import('./createRemoteComponent').createRemoteSSRComponent { + return require('./createRemoteComponent').createRemoteSSRComponent; + }, + get createRemoteComponent(): typeof import('./createRemoteComponent').createRemoteComponent { + return require('./createRemoteComponent').createRemoteComponent; + }, + get collectSSRAssets(): typeof import('./createRemoteComponent').collectSSRAssets { + return require('./createRemoteComponent').collectSSRAssets; + }, + get wrapNoSSR(): typeof import('./wrapNoSSR').wrapNoSSR { + return require('./wrapNoSSR').wrapNoSSR; + }, + get injectDataFetch(): typeof import('./data-fetch/inject-data-fetch').injectDataFetch { + return require('./data-fetch/inject-data-fetch').injectDataFetch; + }, + get callDataFetch(): typeof import('./data-fetch/call-data-fetch').callDataFetch { + return require('./data-fetch/call-data-fetch').callDataFetch; + }, + get setSSREnv(): typeof import('./utils').setSSREnv { + return require('./utils').setSSREnv; + }, +}; + +export { autoFetchDataPlugin }; diff --git a/packages/react/src/module/logger.ts b/packages/react/src/module/logger.ts new file mode 100644 index 00000000000..c1be3252163 --- /dev/null +++ b/packages/react/src/module/logger.ts @@ -0,0 +1,6 @@ +import { createLogger } from '@module-federation/sdk'; +import { PLUGIN_IDENTIFIER } from './constant'; + +const logger = createLogger(PLUGIN_IDENTIFIER); + +export default logger; diff --git a/packages/react/src/module/types.ts b/packages/react/src/module/types.ts new file mode 100644 index 00000000000..5da868a0719 --- /dev/null +++ b/packages/react/src/module/types.ts @@ -0,0 +1,49 @@ +import { MF_DATA_FETCH_TYPE, MF_DATA_FETCH_STATUS } from './constant'; + +export type dataFetchFunctionOptions = [ + id?: string, + data?: unknown, + downgrade?: boolean, +]; + +declare global { + var _mfSSRDowngrade: string[] | true | undefined; + var __MF_DATA_FETCH_MAP__: MF_DATA_FETCH_MAP | undefined; + var FEDERATION_SERVER_QUERY: Record | undefined; + var FEDERATION_SSR: boolean | undefined; + var _mfFSHref: string | undefined; + var _mfDataFetch: Array | undefined; +} + +export type DataFetchParams = { + isDowngrade: boolean; +} & Record; +export type DataFetch = (params: DataFetchParams) => Promise; + +// loading, resolve, reject +export type MF_DATA_FETCH_MAP_VALUE_PROMISE_SET = [ + Promise, + ((data: unknown) => void)?, + ((err: unknown) => void)?, +]; +export type MF_DATA_FETCH_MAP_VALUE = [ + [ + // getDataFetchGetter + () => Promise>, + MF_DATA_FETCH_TYPE, + // getDataFetchPromise + Promise>?, + ], + MF_DATA_FETCH_MAP_VALUE_PROMISE_SET?, + MF_DATA_FETCH_STATUS?, +]; +export type MF_DATA_FETCH_MAP = Record; +export type MF_SSR_DOWNGRADE = string[] | true | undefined; + +export type NoSSRRemoteInfo = { + name: string; + version: string; + ssrPublicPath: string; + ssrRemoteEntry: string; + globalName: string; +}; diff --git a/packages/modernjs/src/utils/dataFetch.ts b/packages/react/src/module/utils.ts similarity index 56% rename from packages/modernjs/src/utils/dataFetch.ts rename to packages/react/src/module/utils.ts index bca456a7300..d4333401cf6 100644 --- a/packages/modernjs/src/utils/dataFetch.ts +++ b/packages/react/src/module/utils.ts @@ -1,24 +1,24 @@ import { isBrowserEnv, composeKeyWithSeparator } from '@module-federation/sdk'; -import { isCSROnly } from '../utils'; -import logger from '../logger'; -import { callDowngrade, getDowngradeTag } from '../ssr-runtime/downgrade'; +import logger from './logger'; import { DOWNGRADE_KEY, MF_DATA_FETCH_STATUS, WRAP_DATA_FETCH_ID_IDENTIFIER, -} from '../constant'; -import { - DATA_FETCH_CLIENT_SUFFIX, + DATA_FETCH_QUERY, + MF_DATA_FETCH_TYPE, DATA_FETCH_IDENTIFIER, -} from '@module-federation/rsbuild-plugin/constant'; + DATA_FETCH_CLIENT_SUFFIX, +} from './constant'; import type { GlobalModuleInfo } from '@module-federation/sdk'; import type { DataFetchParams, MF_DATA_FETCH_MAP, NoSSRRemoteInfo, -} from '../interfaces/global'; -import type { FederationHost } from '@module-federation/enhanced/runtime'; + MF_SSR_DOWNGRADE, + MF_DATA_FETCH_MAP_VALUE_PROMISE_SET, +} from './types'; +import type { FederationHost } from '@module-federation/runtime'; export const getDataFetchInfo = ({ name, @@ -219,3 +219,137 @@ export function isDataLoaderExpose(exposeKey: string) { exposeKey.endsWith(DATA_FETCH_CLIENT_SUFFIX) ); } + +export function getDowngradeTag() { + return globalThis[DOWNGRADE_KEY] as MF_SSR_DOWNGRADE; +} + +export function callAllDowngrade() { + const dataFetchMap = getDataFetchMap(); + if (!dataFetchMap) { + return; + } + Object.keys(dataFetchMap).forEach((key) => { + callDowngrade(key); + }); +} + +export async function callDowngrade( + id: string, + params?: DataFetchParams, + remoteInfo?: NoSSRRemoteInfo, +) { + const dataFetchMap = getDataFetchMap(); + if (!dataFetchMap) { + return; + } + const mfDataFetch = dataFetchMap[id]; + if (mfDataFetch?.[2] === MF_DATA_FETCH_STATUS.AWAIT) { + mfDataFetch[2] = MF_DATA_FETCH_STATUS.LOADING; + let promise: MF_DATA_FETCH_MAP_VALUE_PROMISE_SET[0]; + let res: MF_DATA_FETCH_MAP_VALUE_PROMISE_SET[1]; + let rej: MF_DATA_FETCH_MAP_VALUE_PROMISE_SET[2]; + if (mfDataFetch[1]) { + promise = mfDataFetch[1][0]; + res = mfDataFetch[1][1]; + rej = mfDataFetch[1][2]; + } else { + promise = new Promise((resolve, reject) => { + res = resolve; + rej = reject; + }); + mfDataFetch[1] = [promise, res, rej]; + } + const dataFetchType = mfDataFetch[0][1]; + if (dataFetchType === MF_DATA_FETCH_TYPE.FETCH_CLIENT) { + try { + mfDataFetch[0][0]().then((getDataFetchFn) => { + return getDataFetchFn({ + ...params, + isDowngrade: true, + }).then((data) => { + mfDataFetch[2] = MF_DATA_FETCH_STATUS.LOADED; + res && res(data); + }); + }); + } catch (e) { + mfDataFetch[2] = MF_DATA_FETCH_STATUS.ERROR; + rej && rej(e); + } + } else if (dataFetchType === MF_DATA_FETCH_TYPE.FETCH_SERVER) { + try { + const currentUrl = new URL(window.location.href); + currentUrl.searchParams.set(DATA_FETCH_QUERY, encodeURIComponent(id)); + if (params) { + currentUrl.searchParams.set( + 'params', + encodeURIComponent(JSON.stringify(params)), + ); + } + if (remoteInfo) { + currentUrl.searchParams.set( + 'remoteInfo', + encodeURIComponent(JSON.stringify(remoteInfo)), + ); + } + const fetchServerQuery = globalThis.FEDERATION_SERVER_QUERY; + if (fetchServerQuery && typeof fetchServerQuery === 'object') { + Object.keys(fetchServerQuery).forEach((key) => { + currentUrl.searchParams.set( + key, + JSON.stringify(fetchServerQuery[key]), + ); + }); + } + const fetchUrl = currentUrl.toString(); + const data = await fetch(fetchUrl).then((res) => res.json()); + mfDataFetch[2] = MF_DATA_FETCH_STATUS.LOADED; + res && res(data); + } catch (e) { + mfDataFetch[2] = MF_DATA_FETCH_STATUS.ERROR; + rej && rej(e); + } + } + + return promise; + } +} + +export function isCSROnly() { + // @ts-ignore modern.js will inject window._SSR_DATA if enable ssr + return window._SSR_DATA === undefined; +} + +export function setSSREnv({ + fetchServerQuery, +}: { + fetchServerQuery?: Record; +}) { + globalThis.FEDERATION_SSR = true; + globalThis.FEDERATION_SERVER_QUERY = fetchServerQuery; +} + +export function getLoadedRemoteInfos( + id: string, + instance: FederationHost | null, +) { + if (!instance) { + return; + } + const { name, expose } = instance.remoteHandler.idToRemoteMap[id] || {}; + if (!name) { + return; + } + const module = instance.moduleCache.get(name); + if (!module) { + return; + } + const { remoteSnapshot } = instance.snapshotHandler.getGlobalRemoteInfo( + module.remoteInfo, + ); + return { + ...module.remoteInfo, + snapshot: remoteSnapshot, + expose, + }; +} diff --git a/packages/modernjs/src/runtime/wrapNoSSR.tsx b/packages/react/src/module/wrapNoSSR.tsx similarity index 100% rename from packages/modernjs/src/runtime/wrapNoSSR.tsx rename to packages/react/src/module/wrapNoSSR.tsx diff --git a/packages/react/tsconfig.json b/packages/react/tsconfig.json new file mode 100644 index 00000000000..072b194b07a --- /dev/null +++ b/packages/react/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2015", + "lib": ["DOM", "ESNext"], + "allowJs": true, + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "experimentalDecorators": true, + "resolveJsonModule": true, + "moduleResolution": "node", + "declaration": false, + "jsx": "preserve", + "baseUrl": "./", + "paths": {}, + "noImplicitAny": false + }, + "include": ["src"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 041f9a02698..422205f13b9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2238,7 +2238,7 @@ importers: version: 5.4.18(@types/node@18.16.9)(less@4.3.0)(stylus@0.64.0) vite-plugin-dts: specifier: ^4.3.0 - version: 4.3.0(@types/node@18.16.9)(rollup@4.40.0)(typescript@5.5.2)(vite@5.4.18) + version: 4.5.4(@types/node@18.16.9)(rollup@4.40.0)(typescript@5.5.2)(vite@5.4.18) packages/bridge/bridge-react-webpack-plugin: dependencies: @@ -2781,6 +2781,9 @@ importers: '@module-federation/node': specifier: workspace:* version: link:../node + '@module-federation/react': + specifier: workspace:* + version: link:../react '@module-federation/rsbuild-plugin': specifier: workspace:* version: link:../rsbuild-plugin @@ -2962,6 +2965,34 @@ importers: specifier: ^5.40.0 version: 5.93.0(@swc/core@1.7.26)(esbuild@0.25.0)(webpack-cli@5.1.4) + packages/react: + dependencies: + '@module-federation/sdk': + specifier: workspace:* + version: link:../sdk + '@swc/helpers': + specifier: ^0.5.17 + version: 0.5.17 + devDependencies: + '@modern-js/module-tools': + specifier: 2.67.6 + version: 2.67.6(typescript@5.7.3) + '@module-federation/runtime': + specifier: workspace:* + version: link:../runtime + '@types/react': + specifier: 18.2.79 + version: 18.2.79 + hono: + specifier: 3.12.12 + version: 3.12.12 + react: + specifier: 18.3.1 + version: 18.3.1 + typescript: + specifier: ^5.2.2 + version: 5.7.3 + packages/retry-plugin: dependencies: '@module-federation/sdk': @@ -3213,7 +3244,7 @@ packages: react: '>=16.0.0' react-dom: '>=16.0.0' dependencies: - '@babel/runtime': 7.26.0 + '@babel/runtime': 7.25.7 '@emotion/hash': 0.8.0 '@emotion/unitless': 0.7.5 classnames: 2.5.1 @@ -3618,7 +3649,7 @@ packages: '@babel/traverse': 7.27.1 '@babel/types': 7.27.1 convert-source-map: 1.9.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 lodash: 4.17.21 @@ -3666,7 +3697,7 @@ packages: '@babel/traverse': 7.27.1 '@babel/types': 7.27.1 convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -3689,7 +3720,7 @@ packages: '@babel/traverse': 7.26.9 '@babel/types': 7.27.0 convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -3711,7 +3742,7 @@ packages: '@babel/traverse': 7.27.1 '@babel/types': 7.27.1 convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -3990,7 +4021,7 @@ packages: '@babel/core': 7.26.10 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -4532,7 +4563,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.26.10 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-export-default-from': 7.24.7(@babel/core@7.26.10) dev: true @@ -4565,7 +4596,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.26.10 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-partial-application': 7.24.7(@babel/core@7.26.10) dev: true @@ -4586,7 +4617,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.26.10 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-pipeline-operator': 7.24.7(@babel/core@7.26.10) dev: true @@ -4728,7 +4759,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.26.10 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.27.1 dev: true /@babel/plugin-syntax-flow@7.25.7(@babel/core@7.26.10): @@ -4996,7 +5027,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.26.10 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.27.1 dev: true /@babel/plugin-syntax-pipeline-operator@7.24.7(@babel/core@7.26.10): @@ -5006,7 +5037,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.26.10 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.27.1 dev: true /@babel/plugin-syntax-pipeline-operator@7.25.7(@babel/core@7.26.10): @@ -5016,7 +5047,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.26.10 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.27.1 dev: true /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.25.2): @@ -5643,7 +5674,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.27.1 dev: true /@babel/plugin-transform-react-jsx-source@7.24.7(@babel/core@7.26.0): @@ -5653,7 +5684,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.27.1 dev: true /@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.25.2): @@ -5756,7 +5787,7 @@ packages: dependencies: '@babel/core': 7.26.10 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-plugin-utils': 7.27.1 babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.26.10) babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.26.10) babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.26.10) @@ -6170,7 +6201,7 @@ packages: '@babel/parser': 7.27.2 '@babel/template': 7.25.9 '@babel/types': 7.27.1 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -6184,7 +6215,7 @@ packages: '@babel/parser': 7.27.2 '@babel/template': 7.26.9 '@babel/types': 7.27.1 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -6198,7 +6229,7 @@ packages: '@babel/parser': 7.27.2 '@babel/template': 7.27.0 '@babel/types': 7.27.1 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -6213,7 +6244,7 @@ packages: '@babel/parser': 7.27.2 '@babel/template': 7.27.2 '@babel/types': 7.27.1 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -8691,7 +8722,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -8708,7 +8739,7 @@ packages: engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: ajv: 6.12.6 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -8797,7 +8828,7 @@ packages: deprecated: Use @eslint/config-array instead dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -8808,7 +8839,7 @@ packages: deprecated: Use @eslint/config-array instead dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -9544,6 +9575,16 @@ packages: - '@types/node' dev: true + /@microsoft/api-extractor-model@7.30.6(@types/node@18.16.9): + resolution: {integrity: sha512-znmFn69wf/AIrwHya3fxX6uB5etSIn6vg4Q4RB/tb5VDDs1rqREc+AvMC/p19MUN13CZ7+V/8pkYPTj7q8tftg==} + dependencies: + '@microsoft/tsdoc': 0.15.1 + '@microsoft/tsdoc-config': 0.17.1 + '@rushstack/node-core-library': 5.13.1(@types/node@18.16.9) + transitivePeerDependencies: + - '@types/node' + dev: true + /@microsoft/api-extractor@7.47.11(@types/node@16.11.68): resolution: {integrity: sha512-lrudfbPub5wzBhymfFtgZKuBvXxoSIAdrvS2UbHjoMT2TjIEddq6Z13pcve7A03BAouw0x8sW8G4txdgfiSwpQ==} hasBin: true @@ -9586,6 +9627,27 @@ packages: - '@types/node' dev: true + /@microsoft/api-extractor@7.52.8(@types/node@18.16.9): + resolution: {integrity: sha512-cszYIcjiNscDoMB1CIKZ3My61+JOhpERGlGr54i6bocvGLrcL/wo9o+RNXMBrb7XgLtKaizZWUpqRduQuHQLdg==} + hasBin: true + dependencies: + '@microsoft/api-extractor-model': 7.30.6(@types/node@18.16.9) + '@microsoft/tsdoc': 0.15.1 + '@microsoft/tsdoc-config': 0.17.1 + '@rushstack/node-core-library': 5.13.1(@types/node@18.16.9) + '@rushstack/rig-package': 0.5.3 + '@rushstack/terminal': 0.15.3(@types/node@18.16.9) + '@rushstack/ts-command-line': 5.0.1(@types/node@18.16.9) + lodash: 4.17.21 + minimatch: 3.0.8 + resolve: 1.22.8 + semver: 7.5.4 + source-map: 0.6.1 + typescript: 5.8.2 + transitivePeerDependencies: + - '@types/node' + dev: true + /@microsoft/tsdoc-config@0.17.0: resolution: {integrity: sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==} dependencies: @@ -9595,10 +9657,23 @@ packages: resolve: 1.22.8 dev: true + /@microsoft/tsdoc-config@0.17.1: + resolution: {integrity: sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw==} + dependencies: + '@microsoft/tsdoc': 0.15.1 + ajv: 8.12.0 + jju: 1.4.0 + resolve: 1.22.8 + dev: true + /@microsoft/tsdoc@0.15.0: resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==} dev: true + /@microsoft/tsdoc@0.15.1: + resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} + dev: true + /@modern-js-app/eslint-config@2.54.6(@swc/helpers@0.5.13)(typescript@5.0.4): resolution: {integrity: sha512-2mA5jIo6pRDTBCNZsWp8pKr5Do4PH/kQieyBGAsm6OcOJoCf7rQ8bpHDYwkPdEOmBWIm8MsSlYTwQ0Vrk52gaA==} peerDependencies: @@ -10101,7 +10176,7 @@ packages: '@ampproject/remapping': 2.3.0 '@ast-grep/napi': 0.35.0 '@babel/core': 7.26.10 - '@babel/types': 7.27.0 + '@babel/types': 7.27.1 '@modern-js/core': 2.67.6 '@modern-js/plugin': 2.67.6 '@modern-js/plugin-changeset': 2.67.6 @@ -10143,7 +10218,7 @@ packages: '@ampproject/remapping': 2.3.0 '@ast-grep/napi': 0.35.0 '@babel/core': 7.26.10 - '@babel/types': 7.27.0 + '@babel/types': 7.27.1 '@modern-js/core': 2.67.6 '@modern-js/plugin': 2.67.6 '@modern-js/plugin-changeset': 2.67.6 @@ -10172,6 +10247,48 @@ packages: - supports-color dev: true + /@modern-js/module-tools@2.67.6(typescript@5.7.3): + resolution: {integrity: sha512-3ywJTXAq7PUt+k9JsasbXeFDUQCzGG4oSZekREKcL7CfKVFr4cNusLOX8qlx05Dnu3771ahnApgzbA7Vkoctfg==} + engines: {node: '>=16.0.0'} + hasBin: true + peerDependencies: + typescript: ^4 || ^5 + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@ampproject/remapping': 2.3.0 + '@ast-grep/napi': 0.35.0 + '@babel/core': 7.26.10 + '@babel/types': 7.27.1 + '@modern-js/core': 2.67.6 + '@modern-js/plugin': 2.67.6 + '@modern-js/plugin-changeset': 2.67.6 + '@modern-js/plugin-i18n': 2.67.6 + '@modern-js/swc-plugins': 0.6.11(@swc/helpers@0.5.17) + '@modern-js/types': 2.67.6 + '@modern-js/utils': 2.67.6 + '@rollup/pluginutils': 4.2.1 + '@swc/helpers': 0.5.17 + convert-source-map: 1.9.0 + enhanced-resolve: 5.17.1 + esbuild: 0.19.2 + magic-string: 0.30.17 + postcss: 8.4.38 + postcss-modules: 4.3.1(postcss@8.4.38) + safe-identifier: 0.4.2 + source-map: 0.7.4 + style-inject: 0.3.0 + sucrase: 3.29.0 + tapable: 2.2.1 + terser: 5.37.0 + tsconfig-paths-webpack-plugin: 4.1.0 + typescript: 5.7.3 + transitivePeerDependencies: + - debug + - supports-color + dev: true + /@modern-js/node-bundle-require@2.65.1: resolution: {integrity: sha512-XpEkciVEfDbkkLUI662ZFlI9tXsUQtLXk4NRJDBGosNnk9uL2XszmC8sKsdCSLK8AYuPW2w6MTVWuJsOR0EU8A==} dependencies: @@ -12021,7 +12138,7 @@ packages: '@open-draft/until': 1.0.3 '@types/debug': 4.1.12 '@xmldom/xmldom': 0.8.10 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) headers-polyfill: 3.2.5 outvariant: 1.4.3 strict-event-emitter: 0.2.8 @@ -16221,7 +16338,7 @@ packages: '@rsbuild/core': 1.3.20 deepmerge: 4.3.1 loader-utils: 2.0.4 - postcss: 8.5.3 + postcss: 8.5.4 reduce-configs: 1.1.0 sass-embedded: 1.89.0 dev: true @@ -16444,7 +16561,7 @@ packages: '@rspack/core': 0.7.5(@swc/helpers@0.5.3) caniuse-lite: 1.0.30001667 html-webpack-plugin: /html-rspack-plugin@5.7.2(@rspack/core@0.7.5) - postcss: 8.4.38 + postcss: 8.4.47 optionalDependencies: fsevents: 2.3.3 transitivePeerDependencies: @@ -17537,6 +17654,25 @@ packages: resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} dev: true + /@rushstack/node-core-library@5.13.1(@types/node@18.16.9): + resolution: {integrity: sha512-5yXhzPFGEkVc9Fu92wsNJ9jlvdwz4RNb2bMso+/+TH0nMm1jDDDsOIf4l8GAkPxGuwPw5DH24RliWVfSPhlW/Q==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@types/node': 18.16.9 + ajv: 8.13.0 + ajv-draft-04: 1.0.0(ajv@8.13.0) + ajv-formats: 3.0.1(ajv@8.13.0) + fs-extra: 11.3.0 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.8 + semver: 7.5.4 + dev: true + /@rushstack/node-core-library@5.9.0(@types/node@16.11.68): resolution: {integrity: sha512-MMsshEWkTbXqxqFxD4gcIUWQOCeBChlGczdZbHfqmNZQFLHB3yWxDFSMHFUdu2/OB9NUk7Awn5qRL+rws4HQNg==} peerDependencies: @@ -17608,6 +17744,19 @@ packages: supports-color: 8.1.1 dev: true + /@rushstack/terminal@0.15.3(@types/node@18.16.9): + resolution: {integrity: sha512-DGJ0B2Vm69468kZCJkPj3AH5nN+nR9SPmC0rFHtzsS4lBQ7/dgOwtwVxYP7W9JPDMuRBkJ4KHmWKr036eJsj9g==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@rushstack/node-core-library': 5.13.1(@types/node@18.16.9) + '@types/node': 18.16.9 + supports-color: 8.1.1 + dev: true + /@rushstack/ts-command-line@4.23.0(@types/node@16.11.68): resolution: {integrity: sha512-jYREBtsxduPV6ptNq8jOKp9+yx0ld1Tb/Tkdnlj8gTjazl1sF3DwX2VbluyYrNd0meWIL0bNeer7WDf5tKFjaQ==} dependencies: @@ -17630,6 +17779,17 @@ packages: - '@types/node' dev: true + /@rushstack/ts-command-line@5.0.1(@types/node@18.16.9): + resolution: {integrity: sha512-bsbUucn41UXrQK7wgM8CNM/jagBytEyJqXw/umtI8d68vFm1Jwxh1OtLrlW7uGZgjCWiiPH6ooUNa1aVsuVr3Q==} + dependencies: + '@rushstack/terminal': 0.15.3(@types/node@18.16.9) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + dev: true + /@sec-ant/readable-stream@0.4.1: resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} dev: true @@ -17664,7 +17824,7 @@ packages: conventional-changelog-writer: 8.0.1 conventional-commits-filter: 5.0.0 conventional-commits-parser: 6.1.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) import-from-esm: 2.0.0 lodash-es: 4.17.21 micromatch: 4.0.8 @@ -17731,7 +17891,7 @@ packages: '@octokit/plugin-throttling': 9.4.0(@octokit/core@6.1.4) '@semantic-release/error': 4.0.0 aggregate-error: 5.0.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) dir-glob: 3.0.1 globby: 14.1.0 http-proxy-agent: 7.0.2 @@ -17800,7 +17960,7 @@ packages: conventional-changelog-writer: 8.0.1 conventional-commits-filter: 5.0.0 conventional-commits-parser: 6.1.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) get-stream: 7.0.1 import-from-esm: 2.0.0 into-stream: 7.0.0 @@ -18996,7 +19156,7 @@ packages: typescript: '>= 3.x' webpack: '>= 4' dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) endent: 2.1.0 find-cache-dir: 3.3.2 flat-cache: 3.2.0 @@ -19015,7 +19175,7 @@ packages: typescript: '>= 4.x' webpack: '>= 4' dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) endent: 2.1.0 find-cache-dir: 3.3.2 flat-cache: 3.2.0 @@ -19034,7 +19194,7 @@ packages: typescript: '>= 4.x' webpack: '>= 4' dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) endent: 2.1.0 find-cache-dir: 3.3.2 flat-cache: 3.2.0 @@ -19504,7 +19664,7 @@ packages: '@swc-node/sourcemap-support': 0.5.1 '@swc/core': 1.7.26(@swc/helpers@0.5.13) colorette: 2.0.20 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) oxc-resolver: 5.2.0 pirates: 4.0.7 tslib: 2.8.1 @@ -20022,8 +20182,8 @@ packages: /@types/babel__core@7.20.5: resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} dependencies: - '@babel/parser': 7.26.9 - '@babel/types': 7.27.0 + '@babel/parser': 7.27.2 + '@babel/types': 7.27.1 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.6 @@ -20916,7 +21076,7 @@ packages: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(typescript@5.0.4) '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.0.4) - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) eslint: 8.57.1 graphemer: 1.4.0 ignore: 5.3.2 @@ -20968,7 +21128,7 @@ packages: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.0.4) - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) eslint: 8.57.1 typescript: 5.0.4 transitivePeerDependencies: @@ -20989,7 +21149,7 @@ packages: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.3) '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) eslint: 8.57.1 typescript: 5.7.3 transitivePeerDependencies: @@ -21010,7 +21170,7 @@ packages: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) eslint: 9.0.0 typescript: 5.4.5 transitivePeerDependencies: @@ -21090,7 +21250,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.0.4) '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.0.4) - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) eslint: 8.57.1 tsutils: 3.21.0(typescript@5.0.4) typescript: 5.0.4 @@ -21110,7 +21270,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.7.3) '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.7.3) - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) eslint: 8.57.1 ts-api-utils: 1.3.0(typescript@5.7.3) typescript: 5.7.3 @@ -21129,7 +21289,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 8.8.0(typescript@5.7.3) '@typescript-eslint/utils': 8.8.0(eslint@8.57.1)(typescript@5.7.3) - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) ts-api-utils: 1.3.0(typescript@5.7.3) typescript: 5.7.3 transitivePeerDependencies: @@ -21173,7 +21333,7 @@ packages: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.3 @@ -21194,7 +21354,7 @@ packages: dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -21216,7 +21376,7 @@ packages: dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -21238,7 +21398,7 @@ packages: dependencies: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 @@ -21260,7 +21420,7 @@ packages: dependencies: '@typescript-eslint/types': 8.14.0 '@typescript-eslint/visitor-keys': 8.14.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 @@ -21282,7 +21442,7 @@ packages: dependencies: '@typescript-eslint/types': 8.8.0 '@typescript-eslint/visitor-keys': 8.8.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 @@ -21631,7 +21791,7 @@ packages: '@verdaccio/loaders': 8.0.0-next-8.6 '@verdaccio/signature': 8.0.0-next-8.7 '@verdaccio/utils': 8.1.0-next-8.15 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) lodash: 4.17.21 verdaccio-htpasswd: 13.0.0-next-8.15 transitivePeerDependencies: @@ -21650,7 +21810,7 @@ packages: dependencies: '@verdaccio/core': 8.0.0-next-8.15 '@verdaccio/utils': 8.1.0-next-8.15 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) js-yaml: 4.1.0 lodash: 4.17.21 minimatch: 7.4.6 @@ -21684,7 +21844,7 @@ packages: resolution: {integrity: sha512-yuqD8uAZJcgzuNHjV6C438UNT5r2Ai9+SnUlO34AHZdWSYcluO3Zj5R3p5uf+C7YPCE31pUD27wBU74xVbUoBw==} engines: {node: '>=18'} dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) lodash: 4.17.21 transitivePeerDependencies: - supports-color @@ -21711,7 +21871,7 @@ packages: '@verdaccio/core': 8.0.0-next-8.15 '@verdaccio/logger-prettify': 8.0.0-next-8.2 colorette: 2.0.20 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -21742,7 +21902,7 @@ packages: '@verdaccio/core': 8.0.0-next-8.15 '@verdaccio/url': 13.0.0-next-8.15 '@verdaccio/utils': 8.1.0-next-8.15 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) express: 4.21.2 express-rate-limit: 5.5.1 lodash: 4.17.21 @@ -21760,7 +21920,7 @@ packages: engines: {node: '>=18'} dependencies: '@verdaccio/config': 8.0.0-next-8.15 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) jsonwebtoken: 9.0.2 transitivePeerDependencies: - supports-color @@ -21776,7 +21936,7 @@ packages: '@verdaccio/core': 8.0.0-next-8.15 '@verdaccio/url': 13.0.0-next-8.15 '@verdaccio/utils': 8.1.0-next-8.15 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) gunzip-maybe: 1.4.2 lodash: 4.17.21 tar-stream: 3.1.7 @@ -21791,7 +21951,7 @@ packages: engines: {node: '>=18'} dependencies: '@verdaccio/core': 8.0.0-next-8.15 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) lodash: 4.17.21 validator: 13.12.0 transitivePeerDependencies: @@ -22193,7 +22353,7 @@ packages: '@vue/shared': 3.5.13 estree-walker: 2.0.2 magic-string: 0.30.17 - postcss: 8.5.3 + postcss: 8.5.4 source-map-js: 1.2.1 dev: true @@ -22257,6 +22417,25 @@ packages: path-browserify: 1.0.1 typescript: 5.5.2 + /@vue/language-core@2.2.0(typescript@5.5.2): + resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@volar/language-core': 2.4.13 + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.13 + alien-signals: 0.4.14 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + typescript: 5.5.2 + dev: true + /@vue/language-core@2.2.10(typescript@5.7.3): resolution: {integrity: sha512-+yNoYx6XIKuAO8Mqh1vGytu8jkFEOH5C8iOv3i8Z/65A7x9iAOXA97Q+PqZ3nlm2lxf5rOJuIGI/wDtx/riNYw==} peerDependencies: @@ -23018,7 +23197,7 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -23026,7 +23205,7 @@ packages: resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} engines: {node: '>= 14'} dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: true @@ -23167,6 +23346,10 @@ packages: uri-js: 4.4.1 dev: false + /alien-signals@0.4.14: + resolution: {integrity: sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==} + dev: true + /alien-signals@1.0.13: resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} @@ -25570,6 +25753,10 @@ packages: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} dev: true + /confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + dev: true + /config-chain@1.1.13: resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} dependencies: @@ -26866,7 +27053,6 @@ packages: dependencies: ms: 2.1.3 supports-color: 8.1.1 - dev: true /debug@4.4.0(supports-color@9.3.1): resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} @@ -26879,6 +27065,7 @@ packages: dependencies: ms: 2.1.3 supports-color: 9.3.1 + dev: true /decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} @@ -27123,7 +27310,7 @@ packages: hasBin: true dependencies: address: 1.2.2 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -27477,7 +27664,6 @@ packages: dependencies: graceful-fs: 4.2.11 tapable: 2.2.1 - dev: false /enquirer@2.3.6: resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} @@ -27869,7 +28055,7 @@ packages: peerDependencies: esbuild: '>=0.12 <1' dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) esbuild: 0.17.19 transitivePeerDependencies: - supports-color @@ -27880,7 +28066,7 @@ packages: peerDependencies: esbuild: '>=0.12 <1' dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) esbuild: 0.18.20 transitivePeerDependencies: - supports-color @@ -27891,7 +28077,7 @@ packages: peerDependencies: esbuild: '>=0.12 <1' dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) esbuild: 0.23.0 transitivePeerDependencies: - supports-color @@ -27901,7 +28087,7 @@ packages: peerDependencies: esbuild: '>=0.12 <1' dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) esbuild: 0.24.0 transitivePeerDependencies: - supports-color @@ -27912,7 +28098,7 @@ packages: peerDependencies: esbuild: '>=0.12 <1' dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) esbuild: 0.25.0 transitivePeerDependencies: - supports-color @@ -28300,8 +28486,8 @@ packages: optional: true dependencies: '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.0(supports-color@9.3.1) - enhanced-resolve: 5.17.1 + debug: 4.4.0(supports-color@8.1.1) + enhanced-resolve: 5.18.1 eslint: 9.0.0 eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.0.0) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-typescript@3.6.3)(eslint@9.0.0) @@ -28469,7 +28655,7 @@ packages: eslint-import-resolver-node: 0.3.9 eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) hasown: 2.0.2 - is-core-module: 2.16.1 + is-core-module: 2.15.1 is-glob: 4.0.3 minimatch: 3.1.2 object.fromentries: 2.0.8 @@ -28506,7 +28692,7 @@ packages: eslint-import-resolver-node: 0.3.9 eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.0.0) hasown: 2.0.2 - is-core-module: 2.16.1 + is-core-module: 2.15.1 is-glob: 4.0.3 minimatch: 3.1.2 object.fromentries: 2.0.8 @@ -28869,7 +29055,7 @@ packages: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -28915,7 +29101,7 @@ packages: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) escape-string-regexp: 4.0.0 eslint-scope: 8.3.0 eslint-visitor-keys: 4.2.0 @@ -29336,6 +29522,10 @@ packages: transitivePeerDependencies: - supports-color + /exsolve@1.0.5: + resolution: {integrity: sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==} + dev: true + /ext-list@2.2.2: resolution: {integrity: sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==} engines: {node: '>=0.10.0'} @@ -29893,7 +30083,7 @@ packages: debug: optional: true dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -30026,15 +30216,6 @@ packages: mime-types: 2.1.35 dev: true - /form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - dev: true - /form-data@4.0.1: resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} engines: {node: '>= 6'} @@ -31471,7 +31652,7 @@ packages: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: true @@ -31481,7 +31662,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: true @@ -31509,7 +31690,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@types/http-proxy': 1.17.15 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) http-proxy: 1.18.1(debug@4.4.0) is-glob: 4.0.3 is-plain-object: 5.0.0 @@ -31580,7 +31761,7 @@ packages: engines: {node: '>= 6.0.0'} dependencies: agent-base: 5.1.1 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: true @@ -31590,26 +31771,16 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.4.0(supports-color@9.3.1) - transitivePeerDependencies: - - supports-color - - /https-proxy-agent@7.0.5: - resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} - engines: {node: '>= 14'} - dependencies: - agent-base: 7.1.1 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color - dev: true /https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: true @@ -31765,7 +31936,7 @@ packages: resolution: {integrity: sha512-YVt14UZCgsX1vZQ3gKjkWVdBdHQ6eu3MPU1TBgL1H5orXe2+jWD006WCPPtOuwlQm10NuzOW5WawiF1Q9veW8g==} engines: {node: '>=18.20'} dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) import-meta-resolve: 4.1.0 transitivePeerDependencies: - supports-color @@ -32614,7 +32785,7 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -32626,7 +32797,7 @@ packages: engines: {node: '>=10'} dependencies: '@jridgewell/trace-mapping': 0.3.25 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -33439,10 +33610,10 @@ packages: cssstyle: 4.1.0 data-urls: 5.0.0 decimal.js: 10.4.3 - form-data: 4.0.0 + form-data: 4.0.2 html-encoding-sniffer: 4.0.0 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.5 + https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 nwsapi: 2.2.13 parse5: 7.1.2 @@ -33687,7 +33858,7 @@ packages: content-disposition: 0.5.4 content-type: 1.0.5 cookies: 0.9.1 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) delegates: 1.0.0 depd: 2.0.0 destroy: 1.2.0 @@ -33718,7 +33889,7 @@ packages: content-disposition: 0.5.4 content-type: 1.0.5 cookies: 0.9.1 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) delegates: 1.0.0 depd: 2.0.0 destroy: 1.2.0 @@ -33749,7 +33920,7 @@ packages: content-disposition: 0.5.4 content-type: 1.0.5 cookies: 0.9.1 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) delegates: 1.0.0 depd: 2.0.0 destroy: 1.2.0 @@ -34094,6 +34265,15 @@ packages: pkg-types: 1.2.1 dev: true + /local-pkg@1.1.1: + resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} + engines: {node: '>=14'} + dependencies: + mlly: 1.7.4 + pkg-types: 2.1.0 + quansync: 0.2.10 + dev: true + /locate-path@2.0.0: resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} engines: {node: '>=4'} @@ -35147,7 +35327,7 @@ packages: resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} dependencies: '@types/debug': 4.1.12 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -35452,7 +35632,7 @@ packages: dependencies: acorn: 8.14.0 pathe: 1.1.2 - pkg-types: 1.2.1 + pkg-types: 1.3.1 ufo: 1.5.4 dev: true @@ -35465,6 +35645,15 @@ packages: ufo: 1.5.4 dev: true + /mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + dependencies: + acorn: 8.14.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.5.4 + dev: true + /moment@2.30.1: resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} dev: false @@ -35626,7 +35815,7 @@ packages: resolution: {integrity: sha512-0mvZ1o5F0GStEzsZIrlGAYmLOtrILwMCh2vHAT1J2qZdyCqgMUo/5FBVk1B54pmCZCDxOS8mMm3MAIW5nCDL3w==} dependencies: '@vercel/nft': 0.27.3(encoding@0.1.13) - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) fs-extra: 11.3.0 mlly: 1.6.1 pkg-types: 1.2.1 @@ -36431,7 +36620,7 @@ packages: consola: 3.2.3 execa: 8.0.1 pathe: 1.1.2 - pkg-types: 1.2.1 + pkg-types: 1.3.1 ufo: 1.5.4 dev: true @@ -37155,6 +37344,10 @@ packages: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} dev: true + /pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + dev: true + /pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} dev: true @@ -37329,6 +37522,22 @@ packages: pathe: 1.1.2 dev: true + /pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + dependencies: + confbox: 0.1.8 + mlly: 1.7.4 + pathe: 2.0.3 + dev: true + + /pkg-types@2.1.0: + resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==} + dependencies: + confbox: 0.2.2 + exsolve: 1.0.5 + pathe: 2.0.3 + dev: true + /pkg-up@3.1.0: resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} engines: {node: '>=8'} @@ -38306,7 +38515,6 @@ packages: nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 - dev: false /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -38712,7 +38920,7 @@ packages: engines: {node: '>=8.16.0'} dependencies: '@types/mime-types': 2.1.4 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) extract-zip: 1.7.0 https-proxy-agent: 4.0.0 mime: 2.6.0 @@ -38743,6 +38951,10 @@ packages: dependencies: side-channel: 1.1.0 + /quansync@0.2.10: + resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} + dev: true + /querystring-es3@0.2.1: resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} engines: {node: '>=0.4.x'} @@ -42584,7 +42796,7 @@ packages: '@semantic-release/release-notes-generator': 14.0.3(semantic-release@24.2.3) aggregate-error: 5.0.0 cosmiconfig: 9.0.0(typescript@5.7.3) - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) env-ci: 11.1.0 execa: 9.5.2 figures: 6.1.0 @@ -42695,7 +42907,7 @@ packages: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -43244,7 +43456,7 @@ packages: /spdy-transport@3.0.0: resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==} dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) detect-node: 2.1.0 hpack.js: 2.1.6 obuf: 1.1.2 @@ -43257,7 +43469,7 @@ packages: resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==} engines: {node: '>=6.0.0'} dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) handle-thing: 2.0.1 http-deceiver: 1.2.7 select-hose: 2.0.0 @@ -43557,7 +43769,7 @@ packages: engines: {node: '>=8.0'} dependencies: date-format: 4.0.14 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) fs-extra: 8.1.0 transitivePeerDependencies: - supports-color @@ -44042,7 +44254,7 @@ packages: hasBin: true dependencies: '@adobe/css-tools': 4.3.3 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) glob: 10.4.5 sax: 1.4.1 source-map: 0.7.4 @@ -44109,6 +44321,7 @@ packages: /supports-color@9.3.1: resolution: {integrity: sha512-knBY82pjmnIzK3NifMo3RxEIRD9E0kIzV4BKcyTZ9+9kWgLMxd4PrsTSMoFQUabgRBbF8KOLRDCyKgNV+iK44Q==} engines: {node: '>=12'} + dev: true /supports-hyperlinks@3.2.0: resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} @@ -45234,7 +45447,7 @@ packages: webpack: ^5.0.0 dependencies: chalk: 4.1.2 - enhanced-resolve: 5.17.1 + enhanced-resolve: 5.18.1 micromatch: 4.0.8 semver: 7.6.3 typescript: 5.0.4 @@ -45249,7 +45462,7 @@ packages: webpack: ^5.0.0 dependencies: chalk: 4.1.2 - enhanced-resolve: 5.17.1 + enhanced-resolve: 5.18.1 micromatch: 4.0.8 semver: 7.6.3 typescript: 5.5.2 @@ -45280,7 +45493,7 @@ packages: webpack: ^5.0.0 dependencies: chalk: 4.1.2 - enhanced-resolve: 5.17.1 + enhanced-resolve: 5.18.1 micromatch: 4.0.8 semver: 7.6.3 source-map: 0.7.4 @@ -45433,7 +45646,7 @@ packages: engines: {node: '>=10.13.0'} dependencies: chalk: 4.1.2 - enhanced-resolve: 5.17.1 + enhanced-resolve: 5.18.1 tsconfig-paths: 4.2.0 dev: true @@ -45442,7 +45655,7 @@ packages: engines: {node: '>=10.13.0'} dependencies: chalk: 4.1.2 - enhanced-resolve: 5.17.1 + enhanced-resolve: 5.18.1 tapable: 2.2.1 tsconfig-paths: 4.2.0 dev: true @@ -45502,7 +45715,7 @@ packages: bundle-require: 4.2.1(esbuild@0.19.2) cac: 6.7.14 chokidar: 3.6.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) esbuild: 0.19.2 execa: 5.1.1 globby: 11.1.0 @@ -45544,7 +45757,7 @@ packages: cac: 6.7.14 chokidar: 4.0.1 consola: 3.2.3 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) esbuild: 0.24.0 joycon: 3.1.1 picocolors: 1.1.1 @@ -45779,6 +45992,12 @@ packages: engines: {node: '>=14.17'} hasBin: true + /typescript@5.8.2: + resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + /typical@4.0.0: resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==} engines: {node: '>=8'} @@ -46417,7 +46636,7 @@ packages: apache-md5: 1.1.8 bcryptjs: 2.4.3 core-js: 3.40.0 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) http-errors: 2.0.0 unix-crypt-td-js: 1.1.4 transitivePeerDependencies: @@ -46448,7 +46667,7 @@ packages: clipanion: 4.0.0-rc.4(typanion@3.14.0) compression: 1.8.0 cors: 2.8.5 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) envinfo: 7.14.0 express: 4.21.2 handlebars: 4.7.8 @@ -46551,7 +46770,7 @@ packages: hasBin: true dependencies: cac: 6.7.14 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) pathe: 1.1.2 picocolors: 1.1.1 vite: 5.4.18(@types/node@20.12.14)(less@4.3.0)(stylus@0.64.0) @@ -46573,7 +46792,7 @@ packages: hasBin: true dependencies: cac: 6.7.14 - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) pathe: 1.1.2 picocolors: 1.1.1 vite: 5.4.18(@types/node@18.16.9)(less@4.3.0)(stylus@0.64.0) @@ -46643,6 +46862,32 @@ packages: - supports-color dev: true + /vite-plugin-dts@4.5.4(@types/node@18.16.9)(rollup@4.40.0)(typescript@5.5.2)(vite@5.4.18): + resolution: {integrity: sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==} + peerDependencies: + typescript: '*' + vite: '*' + peerDependenciesMeta: + vite: + optional: true + dependencies: + '@microsoft/api-extractor': 7.52.8(@types/node@18.16.9) + '@rollup/pluginutils': 5.1.4(rollup@4.40.0) + '@volar/typescript': 2.4.13 + '@vue/language-core': 2.2.0(typescript@5.5.2) + compare-versions: 6.1.1 + debug: 4.4.0(supports-color@8.1.1) + kolorist: 1.8.0 + local-pkg: 1.1.1 + magic-string: 0.30.17 + typescript: 5.5.2 + vite: 5.4.18(@types/node@18.16.9)(less@4.3.0)(stylus@0.64.0) + transitivePeerDependencies: + - '@types/node' + - rollup + - supports-color + dev: true + /vite-tsconfig-paths@4.2.3(typescript@5.7.3)(vite@6.3.5): resolution: {integrity: sha512-xVsA2xe6QSlzBujtWF8q2NYexh7PAUYfzJ4C8Axpe/7d2pcERYxuxGgph9F4f0iQO36g5tyGq6eBUYIssdUrVw==} peerDependencies: @@ -46694,7 +46939,7 @@ packages: '@types/node': 16.11.68 esbuild: 0.21.5 less: 4.3.0 - postcss: 8.5.3 + postcss: 8.5.4 rollup: 4.40.0 stylus: 0.64.0 optionalDependencies: @@ -46776,7 +47021,7 @@ packages: '@types/node': 20.12.14 esbuild: 0.21.5 less: 4.3.0 - postcss: 8.5.3 + postcss: 8.5.4 rollup: 4.40.0 stylus: 0.64.0 optionalDependencies: @@ -46992,7 +47237,7 @@ packages: peerDependencies: eslint: '>=6.0.0' dependencies: - debug: 4.4.0(supports-color@9.3.1) + debug: 4.4.0(supports-color@8.1.1) eslint: 8.57.1 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 @@ -47854,7 +48099,7 @@ packages: acorn: 8.14.0 browserslist: 4.24.4 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.17.1 + enhanced-resolve: 5.18.1 es-module-lexer: 1.6.0 eslint-scope: 5.1.1 events: 3.3.0 @@ -47895,7 +48140,7 @@ packages: acorn: 8.14.0 browserslist: 4.24.4 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.17.1 + enhanced-resolve: 5.18.1 es-module-lexer: 1.6.0 eslint-scope: 5.1.1 events: 3.3.0 @@ -47936,7 +48181,7 @@ packages: acorn: 8.14.0 browserslist: 4.24.4 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.17.1 + enhanced-resolve: 5.18.1 es-module-lexer: 1.6.0 eslint-scope: 5.1.1 events: 3.3.0 From 9c8e31af0b9e65daaa6c5e061afa74b39527a917 Mon Sep 17 00:00:00 2001 From: 2heal1 Date: Mon, 16 Jun 2025 21:52:31 +0800 Subject: [PATCH 02/16] chore: ignore cache --- .github/workflows/build-and-test.yml | 2 +- .github/workflows/devtools.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 87ed38eed5c..14b67163349 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -56,7 +56,7 @@ jobs: run: nproc - name: Warm Nx Cache - run: npx nx run-many --targets=build --projects=tag:type:pkg --parallel=4 + run: npx nx run-many --targets=build --projects=tag:type:pkg --parallel=4 --skip-nx-cache - name: Run Build for All run: npx nx run-many --targets=build --projects=tag:type:pkg --parallel=4 --skip-nx-cache diff --git a/.github/workflows/devtools.yml b/.github/workflows/devtools.yml index fd263b433aa..bdcac4d5cf8 100644 --- a/.github/workflows/devtools.yml +++ b/.github/workflows/devtools.yml @@ -38,7 +38,7 @@ jobs: run: pnpm install - name: Run Affected Build - run: npx nx run-many --targets=build --projects=tag:type:pkg + run: npx nx run-many --targets=build --projects=tag:type:pkg --skip-nx-cache - name: Configuration xvfb shell: bash From eb0d1dc80ee60a2ec874314ef323214624e6aed2 Mon Sep 17 00:00:00 2001 From: 2heal1 Date: Wed, 18 Jun 2025 16:56:24 +0800 Subject: [PATCH 03/16] refactor: rename createRemoteComponent --- .changeset/breezy-lemons-grin.md | 5 + .changeset/config.json | 3 +- .changeset/curly-insects-wonder.md | 5 + .changeset/curly-pillows-give.md | 5 + .changeset/hip-hornets-exercise.md | 5 + .changeset/spicy-parents-greet.md | 6 - .changeset/tender-rocks-leave.md | 5 + .../host/src/routes/basic/page.tsx | 9 +- .../host/src/routes/client-downgrade/page.tsx | 6 +- .../host/src/routes/csr/page.tsx | 9 +- .../host/src/routes/server-downgrade/page.tsx | 6 +- .../src/components/Content.tsx | 6 +- .../host/src/routes/dynamic-remote/page.tsx | 6 +- .../nested-remote/src/routes/page.tsx | 6 +- apps/router-demo/router-host-2000/src/App.tsx | 14 +- .../router-host-2000/src/pages/Home.tsx | 4 +- .../router-host-v5-2200/src/App.tsx | 8 +- .../router-host-vue3-2100/src/router.ts | 2 +- .../docs/en/guide/framework/modernjs.mdx | 48 ++-- .../docs/en/practice/bridge/index.mdx | 12 +- .../docs/en/practice/bridge/react-bridge.mdx | 56 ++-- .../docs/en/practice/bridge/vue-bridge.mdx | 16 +- .../frameworks/modern/dynamic-remote.mdx | 9 +- .../en/practice/frameworks/modern/index.mdx | 6 +- .../docs/zh/guide/framework/modernjs.mdx | 48 ++-- .../docs/zh/practice/bridge/index.mdx | 11 +- .../docs/zh/practice/bridge/react-bridge.mdx | 56 ++-- .../docs/zh/practice/bridge/vue-bridge.mdx | 16 +- .../frameworks/modern/dynamic-remote.mdx | 9 +- .../zh/practice/frameworks/modern/index.mdx | 6 +- .../bridge-react/__tests__/bridge.spec.tsx | 14 +- packages/bridge/bridge-react/package.json | 43 ++- packages/bridge/bridge-react/src/index.ts | 22 +- .../bridge-react/src/lazy}/AwaitDataFetch.tsx | 0 .../bridge-react/src/lazy}/constant.ts | 0 .../src/lazy/createLazyComponent.tsx} | 18 +- .../src/lazy}/data-fetch/call-data-fetch.ts | 0 .../data-fetch-server-middleware.ts | 0 .../bridge-react/src/lazy/data-fetch/index.ts | 2 + .../src/lazy}/data-fetch/inject-data-fetch.ts | 0 .../src/lazy}/data-fetch/runtime-plugin.ts | 0 .../bridge/bridge-react/src/lazy/index.ts | 18 ++ .../bridge-react/src/lazy}/logger.ts | 0 .../bridge-react/src/lazy}/types.ts | 0 .../bridge-react/src/lazy}/utils.ts | 0 .../bridge-react/src/lazy/wrapNoSSR.tsx | 10 + .../bridge-react/src/remote/component.tsx | 6 +- .../bridge/bridge-react/src/remote/create.tsx | 21 +- packages/bridge/bridge-react/vite.config.ts | 13 + packages/bridge/vue3-bridge/src/create.ts | 30 +- packages/bridge/vue3-bridge/src/index.ts | 2 +- packages/bridge/vue3-bridge/src/remoteApp.tsx | 13 +- packages/modernjs/package.json | 9 +- .../modernjs/src/cli/configPlugin.spec.ts | 8 +- packages/modernjs/src/cli/configPlugin.ts | 4 +- .../cli/server/data-fetch-server-plugin.ts | 2 +- packages/modernjs/src/react/index.ts | 49 ++++ packages/modernjs/src/runtime/index.ts | 59 ---- .../modernjs/src/ssr-runtime/devPlugin.tsx | 2 +- .../injectDataFetchFunctionPlugin.tsx | 7 +- packages/react/.eslintrc.json | 41 --- packages/react/CHANGELOG.md | 1 - packages/react/LICENSE | 21 -- packages/react/README.md | 1 - packages/react/modern.config.ts | 6 - packages/react/package.json | 85 ------ packages/react/project.json | 27 -- packages/react/src/index.ts | 27 -- packages/react/src/module/index.ts | 35 --- packages/react/src/module/wrapNoSSR.tsx | 10 - packages/react/tsconfig.json | 21 -- pnpm-lock.yaml | 264 +++++++----------- 72 files changed, 539 insertions(+), 755 deletions(-) create mode 100644 .changeset/breezy-lemons-grin.md create mode 100644 .changeset/curly-insects-wonder.md create mode 100644 .changeset/curly-pillows-give.md create mode 100644 .changeset/hip-hornets-exercise.md delete mode 100644 .changeset/spicy-parents-greet.md create mode 100644 .changeset/tender-rocks-leave.md rename packages/{react/src/module => bridge/bridge-react/src/lazy}/AwaitDataFetch.tsx (100%) rename packages/{react/src/module => bridge/bridge-react/src/lazy}/constant.ts (100%) rename packages/{react/src/module/createRemoteComponent.tsx => bridge/bridge-react/src/lazy/createLazyComponent.tsx} (95%) rename packages/{react/src/module => bridge/bridge-react/src/lazy}/data-fetch/call-data-fetch.ts (100%) rename packages/{react/src/module => bridge/bridge-react/src/lazy}/data-fetch/data-fetch-server-middleware.ts (100%) create mode 100644 packages/bridge/bridge-react/src/lazy/data-fetch/index.ts rename packages/{react/src/module => bridge/bridge-react/src/lazy}/data-fetch/inject-data-fetch.ts (100%) rename packages/{react/src/module => bridge/bridge-react/src/lazy}/data-fetch/runtime-plugin.ts (100%) create mode 100644 packages/bridge/bridge-react/src/lazy/index.ts rename packages/{react/src/module => bridge/bridge-react/src/lazy}/logger.ts (100%) rename packages/{react/src/module => bridge/bridge-react/src/lazy}/types.ts (100%) rename packages/{react/src/module => bridge/bridge-react/src/lazy}/utils.ts (100%) create mode 100644 packages/bridge/bridge-react/src/lazy/wrapNoSSR.tsx create mode 100644 packages/modernjs/src/react/index.ts delete mode 100644 packages/react/.eslintrc.json delete mode 100644 packages/react/CHANGELOG.md delete mode 100644 packages/react/LICENSE delete mode 100644 packages/react/README.md delete mode 100644 packages/react/modern.config.ts delete mode 100644 packages/react/package.json delete mode 100644 packages/react/project.json delete mode 100644 packages/react/src/index.ts delete mode 100644 packages/react/src/module/index.ts delete mode 100644 packages/react/src/module/wrapNoSSR.tsx delete mode 100644 packages/react/tsconfig.json diff --git a/.changeset/breezy-lemons-grin.md b/.changeset/breezy-lemons-grin.md new file mode 100644 index 00000000000..389846d7a9d --- /dev/null +++ b/.changeset/breezy-lemons-grin.md @@ -0,0 +1,5 @@ +--- +'@module-federation/bridge-react': patch +--- + +feat(bridge-react): export createLazyCompoent api diff --git a/.changeset/config.json b/.changeset/config.json index 83b093f29db..6a62d9a7350 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -27,8 +27,7 @@ "@module-federation/inject-external-runtime-core-plugin", "@module-federation/runtime-core", "create-module-federation", - "@module-federation/cli", - "@module-federation/react" + "@module-federation/cli" ] ], "ignorePatterns": ["^alpha|^beta"], diff --git a/.changeset/curly-insects-wonder.md b/.changeset/curly-insects-wonder.md new file mode 100644 index 00000000000..67413e0d0af --- /dev/null +++ b/.changeset/curly-insects-wonder.md @@ -0,0 +1,5 @@ +--- +'@module-federation/modern-js': patch +--- + +refactor(modern-js-plugin): add subpath react to export createLazyCompoent and wrapNoSSR apis diff --git a/.changeset/curly-pillows-give.md b/.changeset/curly-pillows-give.md new file mode 100644 index 00000000000..e6ad4e09837 --- /dev/null +++ b/.changeset/curly-pillows-give.md @@ -0,0 +1,5 @@ +--- +'@module-federation/bridge-vue3': minor +--- + +refactor(vue3-bridge): rename createRemoteComponent as createRemoteAppComponent diff --git a/.changeset/hip-hornets-exercise.md b/.changeset/hip-hornets-exercise.md new file mode 100644 index 00000000000..e57b68dd904 --- /dev/null +++ b/.changeset/hip-hornets-exercise.md @@ -0,0 +1,5 @@ +--- +'@module-federation/bridge-react': minor +--- + +refactor(bridge-react): rename createRemoteComponent as createRemoteAppComponent diff --git a/.changeset/spicy-parents-greet.md b/.changeset/spicy-parents-greet.md deleted file mode 100644 index 91f0b96d049..00000000000 --- a/.changeset/spicy-parents-greet.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@module-federation/react': patch -'@module-federation/modern-js': patch ---- - -chore(react): export createRemoteComponent and related react utils diff --git a/.changeset/tender-rocks-leave.md b/.changeset/tender-rocks-leave.md new file mode 100644 index 00000000000..92cda74e3f0 --- /dev/null +++ b/.changeset/tender-rocks-leave.md @@ -0,0 +1,5 @@ +--- +'@module-federation/modern-js': minor +--- + +refactor(modern-js-plugin): deprecate createRemoteComponent and createRemoteSSRComponent diff --git a/apps/modern-component-data-fetch/host/src/routes/basic/page.tsx b/apps/modern-component-data-fetch/host/src/routes/basic/page.tsx index 03de3de3524..b6d4034ed47 100644 --- a/apps/modern-component-data-fetch/host/src/routes/basic/page.tsx +++ b/apps/modern-component-data-fetch/host/src/routes/basic/page.tsx @@ -1,8 +1,9 @@ -import { kit, ERROR_TYPE } from '@module-federation/modern-js/runtime'; +import { + createLazyComponent, + ERROR_TYPE, +} from '@module-federation/modern-js/react'; -const { createRemoteComponent } = kit; - -const Basic = createRemoteComponent({ +const Basic = createLazyComponent({ loader: () => { return import('remote/BasicComponent'); }, diff --git a/apps/modern-component-data-fetch/host/src/routes/client-downgrade/page.tsx b/apps/modern-component-data-fetch/host/src/routes/client-downgrade/page.tsx index b01971f8aed..2dad137ec3e 100644 --- a/apps/modern-component-data-fetch/host/src/routes/client-downgrade/page.tsx +++ b/apps/modern-component-data-fetch/host/src/routes/client-downgrade/page.tsx @@ -1,8 +1,6 @@ -import { kit } from '@module-federation/modern-js/runtime'; +import { createLazyComponent } from '@module-federation/modern-js/react'; -const { createRemoteComponent } = kit; - -const ClientDowngrade = createRemoteComponent({ +const ClientDowngrade = createLazyComponent({ loader: () => { return import('remote/ClientDowngrade'); }, diff --git a/apps/modern-component-data-fetch/host/src/routes/csr/page.tsx b/apps/modern-component-data-fetch/host/src/routes/csr/page.tsx index 80fed2d9778..81c88d47b0d 100644 --- a/apps/modern-component-data-fetch/host/src/routes/csr/page.tsx +++ b/apps/modern-component-data-fetch/host/src/routes/csr/page.tsx @@ -1,8 +1,9 @@ -import { kit } from '@module-federation/modern-js/runtime'; +import { + createLazyComponent, + wrapNoSSR, +} from '@module-federation/modern-js/react'; -const { createRemoteComponent, wrapNoSSR } = kit; - -const CsrWithFetchDataFromServerComponent = wrapNoSSR(createRemoteComponent)({ +const CsrWithFetchDataFromServerComponent = wrapNoSSR(createLazyComponent)({ loader: () => { return import('provider-csr'); }, diff --git a/apps/modern-component-data-fetch/host/src/routes/server-downgrade/page.tsx b/apps/modern-component-data-fetch/host/src/routes/server-downgrade/page.tsx index d4d2a5661c7..4a44e7a31da 100644 --- a/apps/modern-component-data-fetch/host/src/routes/server-downgrade/page.tsx +++ b/apps/modern-component-data-fetch/host/src/routes/server-downgrade/page.tsx @@ -1,8 +1,6 @@ -import { kit } from '@module-federation/modern-js/runtime'; +import { createLazyComponent } from '@module-federation/modern-js/react'; -const { createRemoteComponent } = kit; - -const ServerDowngrade = createRemoteComponent({ +const ServerDowngrade = createLazyComponent({ loader: () => { return import('remote/ServerDowngrade'); }, diff --git a/apps/modernjs-ssr/dynamic-nested-remote/src/components/Content.tsx b/apps/modernjs-ssr/dynamic-nested-remote/src/components/Content.tsx index 312936b2d32..7d15ec26f64 100644 --- a/apps/modernjs-ssr/dynamic-nested-remote/src/components/Content.tsx +++ b/apps/modernjs-ssr/dynamic-nested-remote/src/components/Content.tsx @@ -3,12 +3,10 @@ import Button from 'antd/lib/button'; import { registerRemotes, loadRemote, - kit, } from '@module-federation/modern-js/runtime'; +import { createLazyComponent } from '@module-federation/modern-js/react'; import stuff from './stuff.module.css'; -const { createRemoteSSRComponent } = kit; - registerRemotes([ { name: 'dynamic_remote', @@ -16,7 +14,7 @@ registerRemotes([ }, ]); -const RemoteSSRComponent = createRemoteSSRComponent({ +const RemoteSSRComponent = createLazyComponent({ loader: () => loadRemote('dynamic_remote'), loading: 'loading...', fallback: ({ error }) => { diff --git a/apps/modernjs-ssr/host/src/routes/dynamic-remote/page.tsx b/apps/modernjs-ssr/host/src/routes/dynamic-remote/page.tsx index d95ab03769b..d7b149ade63 100644 --- a/apps/modernjs-ssr/host/src/routes/dynamic-remote/page.tsx +++ b/apps/modernjs-ssr/host/src/routes/dynamic-remote/page.tsx @@ -2,10 +2,8 @@ import React, { useState, Suspense } from 'react'; import { loadRemote, registerRemotes, - kit, } from '@module-federation/modern-js/runtime'; - -const { createRemoteSSRComponent } = kit; +import { createLazyComponent } from '@module-federation/modern-js/react'; registerRemotes([ { @@ -14,7 +12,7 @@ registerRemotes([ }, ]); -const RemoteSSRComponent = createRemoteSSRComponent({ +const RemoteSSRComponent = createLazyComponent({ loader: () => loadRemote('dynamic_remote'), loading: 'loading...', fallback: ({ error }) => { diff --git a/apps/modernjs-ssr/nested-remote/src/routes/page.tsx b/apps/modernjs-ssr/nested-remote/src/routes/page.tsx index 84b8509ef14..d5967725f6b 100644 --- a/apps/modernjs-ssr/nested-remote/src/routes/page.tsx +++ b/apps/modernjs-ssr/nested-remote/src/routes/page.tsx @@ -1,11 +1,9 @@ -import { kit } from '@module-federation/modern-js/runtime'; +import { createLazyComponent } from '@module-federation/modern-js/react'; import Content from '../components/Content'; import './index.css'; -const { createRemoteSSRComponent } = kit; - -const RemoteSSRComponent = createRemoteSSRComponent({ +const RemoteSSRComponent = createLazyComponent({ loader: () => import('remote/Button'), loading: 'loading...', export: 'Button', diff --git a/apps/router-demo/router-host-2000/src/App.tsx b/apps/router-demo/router-host-2000/src/App.tsx index 5412248dd30..562ab57da1a 100644 --- a/apps/router-demo/router-host-2000/src/App.tsx +++ b/apps/router-demo/router-host-2000/src/App.tsx @@ -7,7 +7,7 @@ import React, { import { Route, Routes, useLocation } from 'react-router-dom'; import { init, loadRemote } from '@module-federation/enhanced/runtime'; import { RetryPlugin } from '@module-federation/retry-plugin'; -import { createRemoteComponent } from '@module-federation/bridge-react'; +import { createRemoteAppComponent } from '@module-federation/bridge-react'; import Navigation from './navigation'; import Detail from './pages/Detail'; import Home from './pages/Home'; @@ -67,13 +67,13 @@ const FallbackErrorComp = (info: any) => { const FallbackComp =
loading...
; -const Remote1App = createRemoteComponent({ +const Remote1App = createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app'), fallback: FallbackErrorComp, loading: FallbackComp, }); -const Remote5App = createRemoteComponent({ +const Remote5App = createRemoteAppComponent({ loader: () => loadRemote('remote5/export-app'), fallback: FallbackErrorComp, loading: FallbackComp, @@ -136,26 +136,26 @@ const Remote1AppWithErrorBoundary = React.forwardRef((props, ref) => ( )); -const Remote2App = createRemoteComponent({ +const Remote2App = createRemoteAppComponent({ loader: () => import('remote2/export-app'), export: 'provider', fallback: FallbackErrorComp, loading: FallbackComp, }); -const Remote3App = createRemoteComponent({ +const Remote3App = createRemoteAppComponent({ loader: () => loadRemote('remote3/export-app'), fallback: FallbackErrorComp, loading: FallbackComp, }); -const RemoteRenderErrorApp = createRemoteComponent({ +const RemoteRenderErrorApp = createRemoteAppComponent({ loader: () => loadRemote('remote-render-error/export-app'), fallback: FallbackErrorComp, loading: FallbackComp, }) as ForwardRefExoticComponent; -const RemoteResourceErrorApp = createRemoteComponent({ +const RemoteResourceErrorApp = createRemoteAppComponent({ loader: () => loadRemote('remote-resource-error/export-app'), fallback: FallbackErrorComp, loading: FallbackComp, diff --git a/apps/router-demo/router-host-2000/src/pages/Home.tsx b/apps/router-demo/router-host-2000/src/pages/Home.tsx index e31d64c2bf5..c4a281906fc 100644 --- a/apps/router-demo/router-host-2000/src/pages/Home.tsx +++ b/apps/router-demo/router-host-2000/src/pages/Home.tsx @@ -3,7 +3,7 @@ import { Space, Table, Tag } from 'antd'; import type { TableProps } from 'antd'; import type React from 'react'; import { init, loadRemote } from '@module-federation/enhanced/runtime'; -import { createRemoteComponent } from '@module-federation/bridge-react'; +import { createRemoteAppComponent } from '@module-federation/bridge-react'; interface DataType { key: string; @@ -86,7 +86,7 @@ const data: DataType[] = [ }, ]; -const Remote1Button = createRemoteComponent({ +const Remote1Button = createRemoteAppComponent({ loader: () => loadRemote('remote1/export-button'), // @ts-ignore fallback: null, diff --git a/apps/router-demo/router-host-v5-2200/src/App.tsx b/apps/router-demo/router-host-v5-2200/src/App.tsx index 9b7200465a3..bdac28f68a1 100644 --- a/apps/router-demo/router-host-v5-2200/src/App.tsx +++ b/apps/router-demo/router-host-v5-2200/src/App.tsx @@ -4,7 +4,7 @@ import './App.css'; import Navigation from './navigation'; import Home from './pages/Home'; import { loadRemote } from '@module-federation/enhanced/runtime'; -import { createRemoteComponent } from '@module-federation/bridge-react'; +import { createRemoteAppComponent } from '@module-federation/bridge-react'; const FallbackErrorComp = (info: any) => { return
{info?.error?.message}
; @@ -12,13 +12,13 @@ const FallbackErrorComp = (info: any) => { const FallbackComp =
loading
; -const Remote1App = createRemoteComponent({ +const Remote1App = createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app'), fallback: FallbackErrorComp, loading: FallbackComp, }); -const Remote2App = createRemoteComponent({ +const Remote2App = createRemoteAppComponent({ // @ts-ignore loader: () => import('remote2/export-app'), export: 'provider', @@ -26,7 +26,7 @@ const Remote2App = createRemoteComponent({ loading: FallbackComp, }); -const Remote3App = createRemoteComponent({ +const Remote3App = createRemoteAppComponent({ loader: () => loadRemote('remote3/export-app'), fallback: FallbackErrorComp, loading: FallbackComp, diff --git a/apps/router-demo/router-host-vue3-2100/src/router.ts b/apps/router-demo/router-host-vue3-2100/src/router.ts index 450339df79f..a1a30cc29b9 100644 --- a/apps/router-demo/router-host-vue3-2100/src/router.ts +++ b/apps/router-demo/router-host-vue3-2100/src/router.ts @@ -8,7 +8,7 @@ import Detail from '@/pages/Detail.vue'; import { loadRemote, init } from '@module-federation/enhanced/runtime'; import * as bridge from '@module-federation/bridge-vue3'; -const Remote2 = bridge.createRemoteComponent({ +const Remote2 = bridge.createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app'), }); diff --git a/apps/website-new/docs/en/guide/framework/modernjs.mdx b/apps/website-new/docs/en/guide/framework/modernjs.mdx index ded63d08eec..c6ac94b3edb 100644 --- a/apps/website-new/docs/en/guide/framework/modernjs.mdx +++ b/apps/website-new/docs/en/guide/framework/modernjs.mdx @@ -191,14 +191,12 @@ export default Index; #### Consumer -In the consumer, we need to use `createRemoteComponent` to load the remote component and fetch data. +In the consumer, we need to use `createLazyComponent` to load the remote component and fetch data. ```tsx -import { kit, ERROR_TYPE } from '@module-federation/modern-js/runtime'; +import { createLazyComponent, ERROR_TYPE } from '@module-federation/modern-js/react'; -const { createRemoteComponent } = kit; - -const List = createRemoteComponent({ +const List = createLazyComponent({ loader: () => { return import('remote/List'); }, @@ -236,7 +234,7 @@ By default, parameters are passed to the loader function. The type is `DataFetch - `isDowngrade` (boolean): Indicates whether the current execution context is in downgrade mode. For example, if Server-Side Rendering (SSR) fails and falls back to Client-Side Rendering (CSR), a request will be re-initiated to the server to call the loader function, and this value will be `true`. -In addition to the default parameters, you can also pass the [dataFetchParams](#datafetchparams) field in `createRemoteComponent`. This field will be passed through to the loader function. +In addition to the default parameters, you can also pass the [dataFetchParams](#datafetchparams) field in `createLazyComponent`. This field will be passed through to the loader function. #### Return Value @@ -304,21 +302,21 @@ In addition to exporting [MF Runtime](../basic/runtime), `@module-federation/mod To prevent conflicts with Shared modules, you need to import them as follows: ```ts -import { kit } from '@module-federation/modern-js/runtime'; -const { loadRemote ,createRemoteComponent, createRemoteSSRComponent, wrapNoSSR } = kit; +import { loadRemote } from '@module-federation/modern-js/runtime'; +import { createLazyComponent, wrapNoSSR } from '@module-federation/modern-js/react'; ``` -### createRemoteComponent +### createLazyComponent import Collapse from '@components/Collapse' ```ts -declare function createRemoteComponent( - props: CreateRemoteComponentOptions +declare function createLazyComponent( + props: CreateLazyComponentOptions ): (props: ComponentType) => React.JSX.Element; -type CreateRemoteComponentOptions = { +type CreateLazyComponentOptions = { loader: () => Promise; loading: React.ReactNode; fallback: ReactNode | ((errorInfo: ErrorInfo) => ReactNode); @@ -353,11 +351,9 @@ This function supports loading components and also provides the following capabi ```tsx import React, { FC, memo, useEffect } from 'react'; -import { kit, ERROR_TYPE } from '@module-federation/modern-js/runtime'; - -const { createRemoteComponent } = kit; +import { createLazyComponent, ERROR_TYPE } from '@module-federation/modern-js/react'; -const RemoteComponent = createRemoteComponent({ +const LazyComponent = createLazyComponent({ loader: () => import('remote/Image'), loading:
loading...
, fallback: ({error,errorType,dataFetchMapKey}) => { @@ -374,7 +370,7 @@ const RemoteComponent = createRemoteComponent({ const App: FC = () => { return <> - + ; }; export default App; @@ -420,19 +416,13 @@ If the remote component is a named export, you can use this parameter to specify If the remote component has a data fetching function, setting this will pass it to the data fetching function. -### createRemoteSSRComponent - -:::danger Note -This function will be deprecated. It is recommended to use [createRemoteComponent](#createremotecomponent). -::: - ### wrapNoSSR ```ts declare function wrapNoSSR( - createComponentFn: typeof createRemoteComponent, -) : (options: CreateRemoteComponentOptions) => (props: ComponentType) => React.JSX.Element + createLazyComponentFn: typeof createLazyComponent, +) : (options: CreateLazyComponentOptions) => (props: ComponentType) => React.JSX.Element ``` @@ -441,11 +431,9 @@ Wraps a component so that it does not render in SSR scenarios. Usage example: ```tsx -import { kit } from '@module-federation/modern-js/runtime'; - -const { createRemoteComponent, wrapNoSSR } = kit; +import { createLazyComponent, wrapNoSSR } from '@module-federation/modern-js/react'; -const RemoteComponent = wrapNoSSR(createRemoteComponent)({ +const LazyComponent = wrapNoSSR(createLazyComponent)({ loader: () => { return import('remote/Content'); }, @@ -465,7 +453,7 @@ const Index = (): JSX.Element => {

The component will be render in csr.

- + ); }; diff --git a/apps/website-new/docs/en/practice/bridge/index.mdx b/apps/website-new/docs/en/practice/bridge/index.mdx index 03fd2d0c0fc..c6cfd5eb14c 100644 --- a/apps/website-new/docs/en/practice/bridge/index.mdx +++ b/apps/website-new/docs/en/practice/bridge/index.mdx @@ -27,11 +27,13 @@ This toolkit provides two APIs: > Used to create React application-type module exports. If your application is React-based and you want it to be loaded as an application-type module by another MF application, you should use this to create standard-compliant exports for your application. -- createRemoteComponent +- createRemoteAppComponent + +> Used to load application-type modules in a React application. The loaded module must be wrapped by `createBridgeComponent`. `createRemoteAppComponent` will automatically create a rendering context in your application to ensure the module works properly. -> Used to load application-type modules in a React application. The loaded module must be wrapped by `createBridgeComponent`. `createRemoteComponent` will automatically create a rendering context in your application to ensure the module works properly. +- createRemoteComponent -For usage of `@module-federation/bridge-react`, see [Host demo](https://github.com/module-federation/core/tree/main/apps/router-demo/router-host-2000) and [Remote demo](https://github.com/module-federation/core/tree/main/apps/router-demo/router-remote2-2002). +> It will be deprecated, please use `createRemoteAppComponent` instead. ### @module-federation/bridge-vue3 @@ -43,9 +45,9 @@ This toolkit provides two APIs: > Used to create Vue application-type module exports. If your application is Vue v3-based and you want it to be loaded as an application-type module by another MF application, you should use this to create standard-compliant exports for your application. -- createRemoteComponent +- createRemoteAppComponent -> Used to load application-type modules in a Vue application. The loaded module must be wrapped by `createBridgeComponent`. `createRemoteComponent` will automatically create a rendering context in your application to ensure the module works properly. +> Used to load application-type modules in a Vue application. The loaded module must be wrapped by `createBridgeComponent`. `createRemoteAppComponent` will automatically create a rendering context in your application to ensure the module works properly. ## FAQ diff --git a/apps/website-new/docs/en/practice/bridge/react-bridge.mdx b/apps/website-new/docs/en/practice/bridge/react-bridge.mdx index 5f55234874f..af7dab26783 100644 --- a/apps/website-new/docs/en/practice/bridge/react-bridge.mdx +++ b/apps/website-new/docs/en/practice/bridge/react-bridge.mdx @@ -2,7 +2,7 @@ `@module-federation/bridge-react` provides bridge utility functions for React applications: - `createBridgeComponent`: Used for exporting application-level modules, suitable for producers to wrap modules exported as application types -- `createRemoteComponent`: Used for loading application-level modules, suitable for consumers to load modules as application types +- `createRemoteAppComponent`: Used for loading application-level modules, suitable for consumers to load modules as application types ### React Version Compatibility @@ -118,11 +118,11 @@ export default defineConfig({ }); ``` -- Step 2: In the host application, we need to use `createRemoteComponent` to load the remote application. +- Step 2: In the host application, we need to use `createRemoteAppComponent` to load the remote application. ```tsx // ./src/App.tsx -import { createRemoteComponent } from '@module-federation/bridge-react'; +import { createRemoteAppComponent } from '@module-federation/bridge-react'; import { loadRemote } from '@module-federation/runtime'; // Define FallbackError component @@ -141,8 +141,8 @@ const FallbackErrorComp = ({ error }: { error: Error }) => { // Define FallbackLoading component const FallbackComp =
loading...
; -// Use createRemoteComponent to create remote component -const Remote1App = createRemoteComponent({ +// Use createRemoteAppComponent to create remote component +const Remote1App = createRemoteAppComponent({ // loader is used to load remote modules, e.g.: loadRemote('remote1/export-app'), import('remote1/export-app') loader: () => loadRemote('remote1/export-app'), // fallback is used for displaying components when remote module loading fails @@ -177,10 +177,10 @@ const App = () => { :::info -1. The remote module exported by `createRemoteComponent` will automatically use the react-bridge loading protocol to load the module, +1. The remote module exported by `createRemoteAppComponent` will automatically use the react-bridge loading protocol to load the module, making cross-framework rendering of applications possible. -2. Additionally, `createRemoteComponent` will automatically handle module loading, module destruction, error handling, loading, routing, and other logic, +2. Additionally, `createRemoteAppComponent` will automatically handle module loading, module destruction, error handling, loading, routing, and other logic, allowing developers to focus solely on how to use the remote component. ::: @@ -210,8 +210,8 @@ function createBridgeComponent( interface ProviderFnParams { /** Root component to be remotely loaded */ rootComponent: React.ComponentType; - - /** + + /** * Custom render function for custom rendering logic * @param App - React element * @param id - DOM element or string ID @@ -221,8 +221,8 @@ interface ProviderFnParams { App: React.ReactElement, id?: HTMLElement | string, ) => RootType | Promise; - - /** + + /** * Custom createRoot function for React 18 and above * @param container - DOM container * @param options - CreateRoot options @@ -232,7 +232,7 @@ interface ProviderFnParams { container: Element | DocumentFragment, options?: CreateRootOptions, ) => Root; - + /** * Default options for createRoot in React 18 and 19 * These options will be used when creating a root unless overridden by rootOptions in render params @@ -246,9 +246,9 @@ interface ProviderFnParams { } ``` -#### createRemoteComponent +#### createRemoteAppComponent -`createRemoteComponent` is used to load remote React components. +`createRemoteAppComponent` is used to load remote React components. ```tsx /** @@ -256,7 +256,7 @@ interface ProviderFnParams { * @param options - Remote component configuration options * @returns Returns a React component that can receive props and render remote component */ -function createRemoteComponent( +function createRemoteAppComponent( options: RemoteComponentParams ): React.ForwardRefExoticComponent< React.PropsWithoutRef & React.RefAttributes @@ -269,19 +269,19 @@ interface RemoteComponentParams< T = Record, E extends keyof T = keyof T > { - /** + /** * Function to load remote module * Example: () => loadRemote('remote1/export-app') or () => import('remote1/export-app') */ loader: () => Promise; - + /** Component displayed when loading remote module */ loading: React.ReactNode; - + /** Error component displayed when loading or rendering remote module fails */ fallback: React.ComponentType<{ error: Error }>; - - /** + + /** * Specify module export name * Default is 'default' */ @@ -295,18 +295,18 @@ interface RemoteComponentProps> { /** Properties passed to remote component */ props?: T; - /** + /** * Memory route configuration, used to control child application routing as memoryRouter * Will not directly display URL in browser address bar */ memoryRoute?: { entryPath: string }; - + /** Base path name */ basename?: string; - + /** Style */ style?: React.CSSProperties; - + /** Class name */ className?: string; } @@ -323,7 +323,7 @@ export const provider = createBridgeComponent({ }); // host -const Remote1App = createRemoteComponent({ +const Remote1App = createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app'), export: 'provider', // Specify to use provider export fallback: FallbackErrorComp, @@ -385,15 +385,15 @@ export default createBridgeComponent({ ```tsx // In the consumer application -const RemoteApp = createRemoteComponent({ +const RemoteApp = createRemoteAppComponent({ url: 'http://localhost:3001/remoteEntry.js', scope: 'remote', module: './App', }); // Pass rootOptions when rendering - { diff --git a/apps/website-new/docs/en/practice/bridge/vue-bridge.mdx b/apps/website-new/docs/en/practice/bridge/vue-bridge.mdx index 92a92f4c39b..22dea28a186 100644 --- a/apps/website-new/docs/en/practice/bridge/vue-bridge.mdx +++ b/apps/website-new/docs/en/practice/bridge/vue-bridge.mdx @@ -1,6 +1,6 @@ # Vue Bridge (for Vue v3) -`@module-federation/bridge-vue3` provides a `bridge` utility function for Vue V3 applications. The provided `createBridgeComponent` can be used to export application-level modules, and `createRemoteComponent` can be used to load application-level modules. +`@module-federation/bridge-vue3` provides a `bridge` utility function for Vue V3 applications. The provided `createBridgeComponent` can be used to export application-level modules, and `createRemoteAppComponent` can be used to load application-level modules. ### Installation @@ -17,7 +17,7 @@ import { PackageManagerTabs } from '@theme'; ### Type ```tsx -function createRemoteComponent( +function createRemoteAppComponent( options: { // Function to load remote application, e.g., loadRemote('remote1/export-app') or import('remote1/export-app') loader: () => Promise; @@ -117,7 +117,7 @@ export default defineConfig({ // ./src/router.ts import * as bridge from '@module-federation/bridge-vue3'; -const Remote2 = bridge.createRemoteComponent({ loader: () => loadRemote('remote1/export-app'), rootAttrs: {class: 'root-element-class'} }); +const Remote2 = bridge.createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app'), rootAttrs: {class: 'root-element-class'} }); const router = createRouter({ history: createWebHistory(), @@ -133,10 +133,10 @@ export default router; ### Parameters -#### createRemoteComponent +#### createRemoteAppComponent ```tsx -function createRemoteComponent( +function createRemoteAppComponent( options: { // Function to load remote application, e.g., loadRemote('remote1/export-app') or import('remote1/export-app') loader: () => Promise; @@ -155,7 +155,7 @@ function createRemoteComponent( ```tsx -const Remote1App = createRemoteComponent({ loader: () => loadRemote('remote1/export-app') }); +const Remote1App = createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app') }); ``` * `options` @@ -178,7 +178,7 @@ export const provider = createBridgeComponent({ }); // host -const Remote1App = createRemoteComponent({ +const Remote1App = createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app'), export: 'provider' }); @@ -191,7 +191,7 @@ const Remote1App = createRemoteComponent({ ```tsx import * as bridge from '@module-federation/bridge-vue3'; -const Remote2 = bridge.createRemoteComponent({ loader: () => loadRemote('remote1/export-app'), rootAttrs: {class: 'root-element-class'} }); +const Remote2 = bridge.createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app'), rootAttrs: {class: 'root-element-class'} }); const router = createRouter({ history: createWebHistory(), diff --git a/apps/website-new/docs/en/practice/frameworks/modern/dynamic-remote.mdx b/apps/website-new/docs/en/practice/frameworks/modern/dynamic-remote.mdx index 28a88de4c40..2c1036f0ba0 100644 --- a/apps/website-new/docs/en/practice/frameworks/modern/dynamic-remote.mdx +++ b/apps/website-new/docs/en/practice/frameworks/modern/dynamic-remote.mdx @@ -147,16 +147,15 @@ export const loader = async ({ request }: LoaderFunctionArgs): Promise import('remote/Image'), loading: 'loading...', export: 'default', @@ -176,7 +175,7 @@ const Index = () => { const DynamicRemoteSSRComponents = dataLoader.providerList.map(item => { const { id } = item; - const Com = createRemoteSSRComponent({ + const Com = createLazyComponent({ loader: () => loadRemote(id), loading: 'loading...', fallback: ({ error }) => { diff --git a/apps/website-new/docs/en/practice/frameworks/modern/index.mdx b/apps/website-new/docs/en/practice/frameworks/modern/index.mdx index 7c6fc66a798..c08082f42e6 100644 --- a/apps/website-new/docs/en/practice/frameworks/modern/index.mdx +++ b/apps/website-new/docs/en/practice/frameworks/modern/index.mdx @@ -254,12 +254,10 @@ This is because the producer's style files cannot be injected into the correspon This issue can be solved by using the [createremotessrcomponent](../../../guide/framework/modernjs#createremotessrcomponent) provided by `@module-federation/modern-js`. ```tsx title='page.tsx' -import { kit } from '@module-federation/modern-js/runtime' +import { createLazyComponent } from '@module-federation/modern-js/react' import './index.css'; -const { createRemoteSSRComponent } = kit; - -const RemoteSSRComponent = createRemoteSSRComponent({ +const RemoteSSRComponent = createLazyComponent({ loader: () => import('remote/Image'), loading: 'loading...', export: 'default', diff --git a/apps/website-new/docs/zh/guide/framework/modernjs.mdx b/apps/website-new/docs/zh/guide/framework/modernjs.mdx index ec25577541e..bc3fd65c533 100644 --- a/apps/website-new/docs/zh/guide/framework/modernjs.mdx +++ b/apps/website-new/docs/zh/guide/framework/modernjs.mdx @@ -192,14 +192,12 @@ export default Index; #### 消费者 -在消费者中,我们需要通过 `createRemoteComponent` 来加载远程组件,并获取数据。 +在消费者中,我们需要通过 `createLazyComponent` 来加载远程组件,并获取数据。 ```tsx -import { kit, ERROR_TYPE } from '@module-federation/modern-js/runtime'; +import { createLazyComponent, ERROR_TYPE } from '@module-federation/modern-js/react'; -const { createRemoteComponent } = kit; - -const List = createRemoteComponent({ +const List = createLazyComponent({ loader: () => { return import('remote/List'); }, @@ -237,7 +235,7 @@ export default Index; - `isDowngrade` (boolean): 表示当前执行上下文是否处于降级模式。例如,在服务端渲染 (SSR) 失败,在客户端渲染(CSR)中会重新往服务端发起请求,调用 loader 函数,此时该值为 `true`。 -除了默认的参数以外,还可以在 `createRemoteComponent` 中传递 [dataFetchParams](#datafetchparams) 字段,该字段会被透传给 loader 函数。 +除了默认的参数以外,还可以在 `createLazyComponent` 中传递 [dataFetchParams](#datafetchparams) 字段,该字段会被透传给 loader 函数。 #### 返回值 @@ -306,21 +304,21 @@ export async function loader({ params }) { 为防止与 Shared 冲突,需要通过下列方式引用。 ```ts -import { kit } from '@module-federation/modern-js/runtime'; -const { loadRemote ,createRemoteComponent, createRemoteSSRComponent, wrapNoSSR } = kit; +import { loadRemote } from '@module-federation/modern-js/runtime'; +import { createLazyComponent, wrapNoSSR } from '@module-federation/modern-js/react'; ``` -### createRemoteComponent +### createLazyComponent import Collapse from '@components/Collapse' ```ts -declare function createRemoteComponent( - props: CreateRemoteComponentOptions +declare function createLazyComponent( + props: CreateLazyComponentOptions ): (props: ComponentType) => React.JSX.Element; -type CreateRemoteComponentOptions = { +type CreateLazyComponentOptions = { loader: () => Promise; loading: React.ReactNode; fallback: ReactNode | ((errorInfo: ErrorInfo) => ReactNode); @@ -355,11 +353,9 @@ type ErrorInfo = { ```tsx import React, { FC, memo, useEffect } from 'react'; -import { kit, ERROR_TYPE } from '@module-federation/modern-js/runtime'; - -const { createRemoteComponent } = kit; +import { createLazyComponent, ERROR_TYPE } from '@module-federation/modern-js/react'; -const RemoteComponent = createRemoteComponent({ +const LazyComponent = createLazyComponent({ loader: () => import('remote/Image'), loading:
loading...
, fallback: ({error,errorType,dataFetchMapKey}) => { @@ -376,7 +372,7 @@ const RemoteComponent = createRemoteComponent({ const App: FC = () => { return <> - + ; }; export default App; @@ -422,19 +418,13 @@ export default App; 如果远程组件存在数据获取函数,设置后会传递给数据获取函数。 -### createRemoteSSRComponent - -:::danger 注意 -此函数将被废弃。推荐使用 [createRemoteComponent](#createremotecomponent) -::: - ### wrapNoSSR ```ts declare function wrapNoSSR( - createComponentFn: typeof createRemoteComponent, -) : (options: CreateRemoteComponentOptions) => (props: ComponentType) => React.JSX.Element + createLazyComponentFn: typeof createLazyComponent, +) : (options: CreateLazyComponentOptions) => (props: ComponentType) => React.JSX.Element ``` @@ -443,11 +433,9 @@ declare function wrapNoSSR( 使用示例: ```tsx -import { kit } from '@module-federation/modern-js/runtime'; - -const { createRemoteComponent, wrapNoSSR } = kit; +import { createLazyComponent, wrapNoSSR } from '@module-federation/modern-js/runtime'; -const RemoteComponent = wrapNoSSR(createRemoteComponent)({ +const LazyComponent = wrapNoSSR(createLazyComponent)({ loader: () => { return import('remote/Content'); }, @@ -467,7 +455,7 @@ const Index = (): JSX.Element => {

The component will be render in csr.

- + ); }; diff --git a/apps/website-new/docs/zh/practice/bridge/index.mdx b/apps/website-new/docs/zh/practice/bridge/index.mdx index cec9757060c..bce977ce218 100644 --- a/apps/website-new/docs/zh/practice/bridge/index.mdx +++ b/apps/website-new/docs/zh/practice/bridge/index.mdx @@ -28,12 +28,15 @@ > 用于创建 React 应用类型模块导出,如果你的应用是 React 类型 且希望作为应用类型模块被另一个 MF 应用加载,那么你应该使用它为你的应用创造符合规范的导出。 -- createRemoteComponent +- createRemoteAppComponent -> 用于在 React 应用中加载应用类型模块,所加载的模块必须被 `createBridgeComponent` 所包裹,`createRemoteComponent` 将自动在你的应用中创建渲染上下文以保证模块能正常工作。 +> 用于在 React 应用中加载应用类型模块,所加载的模块必须被 `createBridgeComponent` 所包裹,`createRemoteAppComponent` 将自动在你的应用中创建渲染上下文以保证模块能正常工作。 `@module-federation/bridge-react` 的使用见 [Host demo](https://github.com/module-federation/core/tree/main/apps/router-demo/router-host-2000)、[Remote demo](https://github.com/module-federation/core/tree/main/apps/router-demo/router-remote2-2002)。 +- createRemoteComponent + +> 此 API 即将废弃,请使用 `createRemoteAppComponent` 代替。 ### @module-federation/bridge-vue3 @@ -45,9 +48,9 @@ > 用于创建 Vue 应用类型模块导出,如果你的应用是 Vue v3 类型 且希望作为应用类型模块被另一个 MF 应用加载,那么你应该使用它为你的应用创造符合规范的导出。 -- createRemoteComponent +- createRemoteAppComponent -> 用于在 Vue 应用中加载应用类型模块,所加载的模块必须被 `createBridgeComponent` 所包裹,`createRemoteComponent` 将自动在你的应用中创建渲染上下文以保证模块能正常工作。 +> 用于在 Vue 应用中加载应用类型模块,所加载的模块必须被 `createBridgeComponent` 所包裹,`createRemoteAppComponent` 将自动在你的应用中创建渲染上下文以保证模块能正常工作。 ## FAQ diff --git a/apps/website-new/docs/zh/practice/bridge/react-bridge.mdx b/apps/website-new/docs/zh/practice/bridge/react-bridge.mdx index a28c8d4261f..ae4956f04ef 100644 --- a/apps/website-new/docs/zh/practice/bridge/react-bridge.mdx +++ b/apps/website-new/docs/zh/practice/bridge/react-bridge.mdx @@ -2,7 +2,7 @@ `@module-federation/bridge-react` 提供了用于 React 应用的 bridge 工具函数: - `createBridgeComponent`:用于导出应用级别模块,适用于生产者包装其作为应用类型导出的模块 -- `createRemoteComponent`:用于加载应用级别模块,适用于消费者加载作为应用类型加载的模块 +- `createRemoteAppComponent`:用于加载应用级别模块,适用于消费者加载作为应用类型加载的模块 ## React 版本兼容性 @@ -130,11 +130,11 @@ export default defineConfig({ **步骤 2**: 加载远程应用 -在消费者项目中,我们需要使用 `createRemoteComponent` 来加载应用类型模块: +在消费者项目中,我们需要使用 `createRemoteAppComponent` 来加载应用类型模块: ```tsx // ./src/App.tsx -import { createRemoteComponent } from '@module-federation/bridge-react'; +import { createRemoteAppComponent } from '@module-federation/bridge-react'; import { loadRemote } from '@module-federation/runtime'; // 定义错误回退组件 @@ -153,8 +153,8 @@ const FallbackErrorComp = ({ error }) => { // 定义加载中组件 const FallbackComp =
加载中...
; -// 使用 createRemoteComponent 创建远程组件 -const Remote1App = createRemoteComponent({ +// 使用 createRemoteAppComponent 创建远程组件 +const Remote1App = createRemoteAppComponent({ // loader 用于加载远程模块,例如:loadRemote('remote1/export-app'),import('remote1/export-app') loader: () => loadRemote('remote1/export-app'), // fallback 用于在远程模块加载失败时显示的组件 @@ -191,8 +191,8 @@ const App = () => { **关于远程组件加载** -1. 通过 `createRemoteComponent` 导出的远程模块将自动使用 react-bridge 加载协议加载模块,使得应用的跨框架渲染成为可能。 -2. 此外,`createRemoteComponent` 将自动处理模块加载、模块销毁、错误处理、加载中、路由等逻辑,让开发者只需要关注如何使用远程组件。 +1. 通过 `createRemoteAppComponent` 导出的远程模块将自动使用 react-bridge 加载协议加载模块,使得应用的跨框架渲染成为可能。 +2. 此外,`createRemoteAppComponent` 将自动处理模块加载、模块销毁、错误处理、加载中、路由等逻辑,让开发者只需要关注如何使用远程组件。 ::: @@ -221,8 +221,8 @@ function createBridgeComponent( interface ProviderFnParams { /** 要远程加载的根组件 */ rootComponent: React.ComponentType; - - /** + + /** * 自定义渲染函数,用于自定义渲染逻辑 * @param App - React 元素 * @param id - DOM 元素或字符串 ID @@ -232,8 +232,8 @@ interface ProviderFnParams { App: React.ReactElement, id?: HTMLElement | string, ) => RootType | Promise; - - /** + + /** * 自定义 createRoot 函数,用于 React 18 及以上版本 * @param container - DOM 容器 * @param options - CreateRoot 选项 @@ -243,7 +243,7 @@ interface ProviderFnParams { container: Element | DocumentFragment, options?: CreateRootOptions, ) => Root; - + /** * React 18 和 19 的 createRoot 默认选项 * 这些选项将在创建根节点时使用,除非在渲染参数中被 rootOptions 覆盖 @@ -257,9 +257,9 @@ interface ProviderFnParams { } ``` -### createRemoteComponent +### createRemoteAppComponent -`createRemoteComponent` 用于加载远程 React 组件。 +`createRemoteAppComponent` 用于加载远程 React 组件。 ```tsx /** @@ -267,7 +267,7 @@ interface ProviderFnParams { * @param options - 远程组件配置选项 * @returns 返回一个可以接收 props 并渲染远程组件的 React 组件 */ -function createRemoteComponent( +function createRemoteAppComponent( options: RemoteComponentParams ): React.ForwardRefExoticComponent< React.PropsWithoutRef & React.RefAttributes @@ -280,19 +280,19 @@ interface RemoteComponentParams< T = Record, E extends keyof T = keyof T > { - /** + /** * 加载远程模块的函数 * 例如:() => loadRemote('remote1/export-app') 或 () => import('remote1/export-app') */ loader: () => Promise; - + /** 加载远程模块时显示的组件 */ loading: React.ReactNode; - + /** 加载或渲染远程模块失败时显示的错误组件 */ fallback: React.ComponentType<{ error: Error }>; - - /** + + /** * 指定模块导出名称 * 默认为 'default' */ @@ -306,18 +306,18 @@ interface RemoteComponentProps> { /** 传递给远程组件的属性 */ props?: T; - /** + /** * 内存路由配置,用于将子应用路由作为 memoryRouter 控制 * 不会直接在浏览器地址栏中显示 URL */ memoryRoute?: { entryPath: string }; - + /** 基础路径名 */ basename?: string; - + /** 样式 */ style?: React.CSSProperties; - + /** 类名 */ className?: string; } @@ -334,7 +334,7 @@ export const provider = createBridgeComponent({ }); // 宿主应用 -const Remote1App = createRemoteComponent({ +const Remote1App = createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app'), export: 'provider', // 指定使用 provider 导出 fallback: FallbackErrorComp, @@ -396,15 +396,15 @@ export default createBridgeComponent({ ```tsx // 在消费者应用中 -const RemoteApp = createRemoteComponent({ +const RemoteApp = createRemoteAppComponent({ url: 'http://localhost:3001/remoteEntry.js', scope: 'remote', module: './App', }); // 在渲染时传递 rootOptions - { diff --git a/apps/website-new/docs/zh/practice/bridge/vue-bridge.mdx b/apps/website-new/docs/zh/practice/bridge/vue-bridge.mdx index a6960a06c71..c008ba4e567 100644 --- a/apps/website-new/docs/zh/practice/bridge/vue-bridge.mdx +++ b/apps/website-new/docs/zh/practice/bridge/vue-bridge.mdx @@ -1,6 +1,6 @@ # Vue Bridge(for Vue v3) -`@module-federation/bridge-vue3` 提供了用于 Vue V3 应用的 `bridge` 工具函数,其提供的 `createBridgeComponent` 可用于导出应用级别模块,`createRemoteComponent` 用于加载应用级别模块。[Demo](https://github.com/module-federation/core/tree/main/apps/router-demo) +`@module-federation/bridge-vue3` 提供了用于 Vue V3 应用的 `bridge` 工具函数,其提供的 `createBridgeComponent` 可用于导出应用级别模块,`createRemoteAppComponent` 用于加载应用级别模块。[Demo](https://github.com/module-federation/core/tree/main/apps/router-demo) ### 安装 @@ -18,7 +18,7 @@ import { PackageManagerTabs } from '@theme'; ### 类型 ```tsx -function createRemoteComponent( +function createRemoteAppComponent( options: { // Function to load remote application, e.g., loadRemote('remote1/export-app') or import('remote1/export-app') loader: () => Promise; @@ -119,7 +119,7 @@ export default defineConfig({ // ./src/router.ts import * as bridge from '@module-federation/bridge-vue3'; -const Remote1 = bridge.createRemoteComponent({ +const Remote1 = bridge.createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app'), }); @@ -137,10 +137,10 @@ export default router; ### 方法 -#### createRemoteComponent +#### createRemoteAppComponent ```tsx -function createRemoteComponent( +function createRemoteAppComponent( options: { // Function to load remote application, e.g., loadRemote('remote1/export-app') or import('remote1/export-app') loader: () => Promise; @@ -159,7 +159,7 @@ function createRemoteComponent( ```tsx -const Remote1App = createRemoteComponent({ loader: () => loadRemote('remote1/export-app') }); +const Remote1App = createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app') }); ``` * `options` @@ -182,7 +182,7 @@ export const provider = createBridgeComponent({ }); // host -const Remote1App = createRemoteComponent({ +const Remote1App = createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app'), export: 'provider' }); @@ -195,7 +195,7 @@ const Remote1App = createRemoteComponent({ ```tsx import * as bridge from '@module-federation/bridge-vue3'; -const Remote2 = bridge.createRemoteComponent({ loader: () => loadRemote('remote1/export-app'), rootAttrs: {class: 'root-element-class'} }); +const Remote2 = bridge.createRemoteAppComponent({ loader: () => loadRemote('remote1/export-app'), rootAttrs: {class: 'root-element-class'} }); const router = createRouter({ history: createWebHistory(), diff --git a/apps/website-new/docs/zh/practice/frameworks/modern/dynamic-remote.mdx b/apps/website-new/docs/zh/practice/frameworks/modern/dynamic-remote.mdx index a8a1b1b0895..e28c71aeb72 100644 --- a/apps/website-new/docs/zh/practice/frameworks/modern/dynamic-remote.mdx +++ b/apps/website-new/docs/zh/practice/frameworks/modern/dynamic-remote.mdx @@ -144,16 +144,15 @@ export const loader = async ({ request }: LoaderFunctionArgs): Promise import('remote/Image'), loading: 'loading...', export: 'default', @@ -173,7 +172,7 @@ const Index = () => { const DynamicRemoteSSRComponents = dataLoader.providerList.map(item => { const { id } = item; - const Com = createRemoteSSRComponent({ + const Com = createLazyComponent({ loader: () => loadRemote(id), loading: 'loading...', fallback: ({ error }) => { diff --git a/apps/website-new/docs/zh/practice/frameworks/modern/index.mdx b/apps/website-new/docs/zh/practice/frameworks/modern/index.mdx index 43116228018..c90b8ddf3e8 100644 --- a/apps/website-new/docs/zh/practice/frameworks/modern/index.mdx +++ b/apps/website-new/docs/zh/practice/frameworks/modern/index.mdx @@ -257,12 +257,10 @@ export default Index; 修改消费者引用生产者处的代码(`src/routes/page.tsx`): ```tsx title='page.tsx' -import { kit } from '@module-federation/modern-js/runtime' +import { createLazyComponent } from '@module-federation/modern-js/react' import './index.css'; -const { createRemoteSSRComponent } = kit; - -const RemoteSSRComponent = createRemoteSSRComponent({ +const RemoteSSRComponent = createLazyComponent({ loader: () => import('remote/Image'), loading: 'loading...', export: 'default', diff --git a/packages/bridge/bridge-react/__tests__/bridge.spec.tsx b/packages/bridge/bridge-react/__tests__/bridge.spec.tsx index b09fbdf6314..9e29a1b59a2 100644 --- a/packages/bridge/bridge-react/__tests__/bridge.spec.tsx +++ b/packages/bridge/bridge-react/__tests__/bridge.spec.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { assert, describe, it } from 'vitest'; -import { createBridgeComponent, createRemoteComponent } from '../src'; +import { createBridgeComponent, createRemoteAppComponent } from '../src'; import { act, fireEvent, @@ -44,14 +44,14 @@ describe('bridge', () => { expect(document.querySelector('#container')!.innerHTML).toContain(''); }); - it('createRemoteComponent', async () => { + it('createRemoteAppComponent', async () => { function Component({ props }: { props?: Record }) { return
life cycle render {props?.msg}
; } const BridgeComponent = createBridgeComponent({ rootComponent: Component, }); - const RemoteComponent = createRemoteComponent({ + const RemoteComponent = createRemoteAppComponent({ loader: async () => { return { default: BridgeComponent, @@ -71,7 +71,7 @@ describe('bridge', () => { expect(getHtml(container)).toMatch('hello world'); }); - it('createRemoteComponent and obtain ref property', async () => { + it('createRemoteAppComponent and obtain ref property', async () => { const ref = { current: null, }; @@ -82,7 +82,7 @@ describe('bridge', () => { const BridgeComponent = createBridgeComponent({ rootComponent: Component, }); - const RemoteComponent = createRemoteComponent({ + const RemoteComponent = createRemoteAppComponent({ loader: async () => { return { default: BridgeComponent, @@ -103,7 +103,7 @@ describe('bridge', () => { expect(ref.current).not.toBeNull(); }); - it('createRemoteComponent with custom createRoot prop', async () => { + it('createRemoteAppComponent with custom createRoot prop', async () => { const renderMock = vi.fn(); function Component({ props }: { props?: Record }) { @@ -118,7 +118,7 @@ describe('bridge', () => { }; }, }); - const RemoteComponent = createRemoteComponent({ + const RemoteComponent = createRemoteAppComponent({ loader: async () => { return { default: BridgeComponent, diff --git a/packages/bridge/bridge-react/package.json b/packages/bridge/bridge-react/package.json index f9b86a09693..2b0f8e6450a 100644 --- a/packages/bridge/bridge-react/package.json +++ b/packages/bridge/bridge-react/package.json @@ -11,7 +11,6 @@ "url": "https://github.com/module-federation/core", "directory": "packages/bridge-react" }, - "type": "module", "main": "./dist/index.cjs.js", "module": "./dist/index.es.js", "types": "./dist/index.d.ts", @@ -51,8 +50,47 @@ "import": "./dist/router-v6.es.js", "require": "./dist/router-v6.cjs.js" }, + "./data-fetch-runtime-plugin": { + "types": "./dist/data-fetch-runtime-plugin.d.ts", + "import": "./dist/data-fetch-runtime-plugin.es.js", + "require": "./dist/data-fetch-runtime-plugin.cjs.js" + }, + "./lazy-utils": { + "types": "./dist/lazy-utils.d.ts", + "import": "./dist/lazy-utils.es.js", + "require": "./dist/lazy-utils.cjs.js" + }, + "./data-fetch-utils": { + "types": "./dist/data-fetch-utils.d.ts", + "import": "./dist/data-fetch-utils.es.js", + "require": "./dist/data-fetch-utils.cjs.js" + }, + "./data-fetch-server-middleware": { + "types": "./dist/data-fetch-server-middleware.d.ts", + "import": "./dist/data-fetch-server-middleware.es.js", + "require": "./dist/data-fetch-server-middleware.cjs.js" + }, "./*": "./*" }, + "typesVersions": { + "*": { + ".": [ + "./dist/types/index.d.ts" + ], + "data-fetch-runtime-plugin": [ + "./dist/lazy-utils.d.ts" + ], + "lazy-utils": [ + "./dist/lazy-utils.d.ts" + ], + "data-fetch-utils": [ + "./dist/data-fetch-utils.d.ts" + ], + "data-fetch-server-middleware": [ + "./dist/data-fetch-server-middleware.d.ts" + ] + } + }, "scripts": { "dev": "vite", "build": "vite build", @@ -82,6 +120,7 @@ "typescript": "^5.2.2", "vite": "^5.4.18", "vite-plugin-dts": "^4.3.0", - "@module-federation/runtime": "workspace:*" + "@module-federation/runtime": "workspace:*", + "hono": "3.12.12" } } diff --git a/packages/bridge/bridge-react/src/index.ts b/packages/bridge/bridge-react/src/index.ts index ef312515bc2..e9094bd6c84 100644 --- a/packages/bridge/bridge-react/src/index.ts +++ b/packages/bridge/bridge-react/src/index.ts @@ -3,7 +3,21 @@ * This file provides support for React 16 and 17 versions, using the traditional ReactDOM.render API */ export { createBridgeComponent } from './provider/versions/legacy'; -export { createRemoteComponent } from './remote/create'; +export { + createRemoteComponent, + createRemoteAppComponent, +} from './remote/create'; +export { + ERROR_TYPE, + createLazyComponent, + collectSSRAssets, + wrapNoSSR, + injectDataFetch, + callDataFetch, + setSSREnv, + autoFetchDataPlugin, +} from './lazy'; + export type { CreateRootOptions, Root } from './provider/versions/legacy'; export type { ProviderParams, @@ -12,3 +26,9 @@ export type { DestroyParams, RenderParams, } from './types'; +export type { + DataFetchParams, + NoSSRRemoteInfo, + CollectSSRAssetsOptions, + CreateLazyComponentOptions, +} from './lazy'; diff --git a/packages/react/src/module/AwaitDataFetch.tsx b/packages/bridge/bridge-react/src/lazy/AwaitDataFetch.tsx similarity index 100% rename from packages/react/src/module/AwaitDataFetch.tsx rename to packages/bridge/bridge-react/src/lazy/AwaitDataFetch.tsx diff --git a/packages/react/src/module/constant.ts b/packages/bridge/bridge-react/src/lazy/constant.ts similarity index 100% rename from packages/react/src/module/constant.ts rename to packages/bridge/bridge-react/src/lazy/constant.ts diff --git a/packages/react/src/module/createRemoteComponent.tsx b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx similarity index 95% rename from packages/react/src/module/createRemoteComponent.tsx rename to packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx index f70a5a845db..3a19eb74d48 100644 --- a/packages/react/src/module/createRemoteComponent.tsx +++ b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx @@ -29,7 +29,7 @@ export type IProps = { runtime: typeof import('@module-federation/runtime'); }; -export type CreateRemoteComponentOptions = { +export type CreateLazyComponentOptions = { loader: () => Promise; loading: React.ReactNode; fallback: ReactNode | ((errorInfo: ErrorInfo) => ReactNode); @@ -189,8 +189,8 @@ function getServerNeedRemoteInfo( return; } -export function createRemoteComponent( - options: CreateRemoteComponentOptions, +export function createLazyComponent( + options: CreateLazyComponentOptions, ) { const { runtime } = options; if (!runtime?.getInstance) { @@ -388,15 +388,3 @@ export function createRemoteComponent( } }; } - -/** - * @deprecated createRemoteSSRComponent is deprecated, please use createRemoteComponent instead! - */ -export function createRemoteSSRComponent( - options: CreateRemoteComponentOptions, -) { - logger.warn( - 'createRemoteSSRComponent is deprecated, please use createRemoteComponent instead!', - ); - return createRemoteComponent(options); -} diff --git a/packages/react/src/module/data-fetch/call-data-fetch.ts b/packages/bridge/bridge-react/src/lazy/data-fetch/call-data-fetch.ts similarity index 100% rename from packages/react/src/module/data-fetch/call-data-fetch.ts rename to packages/bridge/bridge-react/src/lazy/data-fetch/call-data-fetch.ts diff --git a/packages/react/src/module/data-fetch/data-fetch-server-middleware.ts b/packages/bridge/bridge-react/src/lazy/data-fetch/data-fetch-server-middleware.ts similarity index 100% rename from packages/react/src/module/data-fetch/data-fetch-server-middleware.ts rename to packages/bridge/bridge-react/src/lazy/data-fetch/data-fetch-server-middleware.ts diff --git a/packages/bridge/bridge-react/src/lazy/data-fetch/index.ts b/packages/bridge/bridge-react/src/lazy/data-fetch/index.ts new file mode 100644 index 00000000000..54f27098440 --- /dev/null +++ b/packages/bridge/bridge-react/src/lazy/data-fetch/index.ts @@ -0,0 +1,2 @@ +export { callDataFetch } from './call-data-fetch'; +export { injectDataFetch } from './inject-data-fetch'; diff --git a/packages/react/src/module/data-fetch/inject-data-fetch.ts b/packages/bridge/bridge-react/src/lazy/data-fetch/inject-data-fetch.ts similarity index 100% rename from packages/react/src/module/data-fetch/inject-data-fetch.ts rename to packages/bridge/bridge-react/src/lazy/data-fetch/inject-data-fetch.ts diff --git a/packages/react/src/module/data-fetch/runtime-plugin.ts b/packages/bridge/bridge-react/src/lazy/data-fetch/runtime-plugin.ts similarity index 100% rename from packages/react/src/module/data-fetch/runtime-plugin.ts rename to packages/bridge/bridge-react/src/lazy/data-fetch/runtime-plugin.ts diff --git a/packages/bridge/bridge-react/src/lazy/index.ts b/packages/bridge/bridge-react/src/lazy/index.ts new file mode 100644 index 00000000000..d9d4a9a4481 --- /dev/null +++ b/packages/bridge/bridge-react/src/lazy/index.ts @@ -0,0 +1,18 @@ +import autoFetchDataPlugin from './data-fetch/runtime-plugin'; + +export { ERROR_TYPE } from './constant'; +export type { DataFetchParams, NoSSRRemoteInfo } from './types'; +export type { + CreateLazyComponentOptions, + IProps as CollectSSRAssetsOptions, +} from './createLazyComponent'; + +export { createLazyComponent, collectSSRAssets } from './createLazyComponent'; + +export { wrapNoSSR } from './wrapNoSSR'; + +export { injectDataFetch, callDataFetch } from './data-fetch'; + +export { setSSREnv } from './utils'; + +export { autoFetchDataPlugin }; diff --git a/packages/react/src/module/logger.ts b/packages/bridge/bridge-react/src/lazy/logger.ts similarity index 100% rename from packages/react/src/module/logger.ts rename to packages/bridge/bridge-react/src/lazy/logger.ts diff --git a/packages/react/src/module/types.ts b/packages/bridge/bridge-react/src/lazy/types.ts similarity index 100% rename from packages/react/src/module/types.ts rename to packages/bridge/bridge-react/src/lazy/types.ts diff --git a/packages/react/src/module/utils.ts b/packages/bridge/bridge-react/src/lazy/utils.ts similarity index 100% rename from packages/react/src/module/utils.ts rename to packages/bridge/bridge-react/src/lazy/utils.ts diff --git a/packages/bridge/bridge-react/src/lazy/wrapNoSSR.tsx b/packages/bridge/bridge-react/src/lazy/wrapNoSSR.tsx new file mode 100644 index 00000000000..de61d36476c --- /dev/null +++ b/packages/bridge/bridge-react/src/lazy/wrapNoSSR.tsx @@ -0,0 +1,10 @@ +import { createLazyComponent } from './createLazyComponent'; +import type { CreateLazyComponentOptions } from './createLazyComponent'; + +export function wrapNoSSR( + createLazyComponentFn: typeof createLazyComponent, +) { + return (options: Omit, 'noSSR'>) => { + return createLazyComponentFn({ ...options, noSSR: true }); + }; +} diff --git a/packages/bridge/bridge-react/src/remote/component.tsx b/packages/bridge/bridge-react/src/remote/component.tsx index 9112d9bb650..7f617131f8a 100644 --- a/packages/bridge/bridge-react/src/remote/component.tsx +++ b/packages/bridge/bridge-react/src/remote/component.tsx @@ -48,7 +48,7 @@ const RemoteAppWrapper = forwardRef(function ( return () => { if (providerInfoRef.current?.destroy) { LoggerInstance.debug( - `createRemoteComponent LazyComponent destroy >>>`, + `createRemoteAppComponent LazyComponent destroy >>>`, { moduleName, basename, dom: renderDom.current }, ); @@ -171,7 +171,7 @@ export function withRouterData< } } - LoggerInstance.debug(`createRemoteComponent withRouterData >>>`, { + LoggerInstance.debug(`createRemoteAppComponent withRouterData >>>`, { ...props, basename, routerContextVal, @@ -185,7 +185,7 @@ export function withRouterData< useEffect(() => { if (pathname !== '' && pathname !== location.pathname) { LoggerInstance.debug( - `createRemoteComponent dispatchPopstateEnv >>>`, + `createRemoteAppComponent dispatchPopstateEnv >>>`, { name: props.name, pathname: location.pathname, diff --git a/packages/bridge/bridge-react/src/remote/create.tsx b/packages/bridge/bridge-react/src/remote/create.tsx index 42a4c064f68..38bfcf490fc 100644 --- a/packages/bridge/bridge-react/src/remote/create.tsx +++ b/packages/bridge/bridge-react/src/remote/create.tsx @@ -16,7 +16,7 @@ function createLazyRemoteComponent< >(info: LazyRemoteComponentInfo) { const exportName = info?.export || 'default'; return React.lazy(async () => { - LoggerInstance.debug(`createRemoteComponent LazyComponent create >>>`, { + LoggerInstance.debug(`createRemoteAppComponent LazyComponent create >>>`, { lazyComponent: info.loader, exportName, }); @@ -26,7 +26,7 @@ function createLazyRemoteComponent< // @ts-ignore const moduleName = m && m[Symbol.for('mf_module_id')]; LoggerInstance.debug( - `createRemoteComponent LazyComponent loadRemote info >>>`, + `createRemoteAppComponent LazyComponent loadRemote info >>>`, { name: moduleName, module: m, exportName }, ); @@ -55,7 +55,7 @@ function createLazyRemoteComponent< }; } else { LoggerInstance.debug( - `createRemoteComponent LazyComponent module not found >>>`, + `createRemoteAppComponent LazyComponent module not found >>>`, { name: moduleName, module: m, exportName }, ); throw Error( @@ -70,7 +70,7 @@ function createLazyRemoteComponent< }); } -export function createRemoteComponent< +export function createRemoteAppComponent< T = Record, E extends keyof T = keyof T, >(info: LazyRemoteComponentInfo) { @@ -87,3 +87,16 @@ export function createRemoteComponent< ); }); } + +/** + * @deprecated createRemoteAppComponent is deprecated, please use createRemoteAppComponent instead! + */ +export function createRemoteComponent< + T = Record, + E extends keyof T = keyof T, +>(info: LazyRemoteComponentInfo) { + LoggerInstance.warn( + `createRemoteAppComponent is deprecated, please use createRemoteAppComponent instead!`, + ); + return createRemoteAppComponent(info); +} diff --git a/packages/bridge/bridge-react/vite.config.ts b/packages/bridge/bridge-react/vite.config.ts index 4f69518cfc3..adf17bac3c3 100644 --- a/packages/bridge/bridge-react/vite.config.ts +++ b/packages/bridge/bridge-react/vite.config.ts @@ -26,6 +26,19 @@ export default defineConfig({ 'router-v6': path.resolve(__dirname, 'src/router/v6.tsx'), v18: path.resolve(__dirname, 'src/v18.ts'), v19: path.resolve(__dirname, 'src/v19.ts'), + 'data-fetch-runtime-plugin': path.resolve( + __dirname, + 'src/lazy/data-fetch/runtime-plugin.ts', + ), + 'data-fetch-server-middleware': path.resolve( + __dirname, + 'src/lazy/data-fetch/data-fetch-server-middleware.ts', + ), + 'lazy-utils': path.resolve(__dirname, 'src/lazy/utils.ts'), + 'data-fetch-utils': path.resolve( + __dirname, + 'src/lazy/data-fetch/index.ts', + ), }, formats: ['cjs', 'es'], fileName: (format, entryName) => `${entryName}.${format}.js`, diff --git a/packages/bridge/vue3-bridge/src/create.ts b/packages/bridge/vue3-bridge/src/create.ts index 756d80ff4f6..af6e5018f46 100644 --- a/packages/bridge/vue3-bridge/src/create.ts +++ b/packages/bridge/vue3-bridge/src/create.ts @@ -5,7 +5,7 @@ import { LoggerInstance } from './utils.js'; declare const __APP_VERSION__: string; -export function createRemoteComponent(info: { +export function createRemoteAppComponent(info: { loader: () => Promise; export?: string; asyncComponentOptions?: Omit; @@ -29,17 +29,20 @@ export function createRemoteComponent(info: { } const exportName = info?.export || 'default'; - LoggerInstance.debug(`createRemoteComponent LazyComponent create >>>`, { - basename, - info, - }); + LoggerInstance.debug( + `createRemoteAppComponent LazyComponent create >>>`, + { + basename, + info, + }, + ); const module: any = await info.loader(); const moduleName = module && module[Symbol.for('mf_module_id')]; const exportFn = module[exportName]; LoggerInstance.debug( - `createRemoteComponent LazyComponent loadRemote info >>>`, + `createRemoteAppComponent LazyComponent loadRemote info >>>`, { moduleName, module, exportName, basename, route }, ); @@ -59,3 +62,18 @@ export function createRemoteComponent(info: { }, }); } + +/** + * @deprecated createRemoteAppComponent is deprecated, please use createRemoteAppComponent instead! + */ +export function createRemoteComponent(info: { + loader: () => Promise; + export?: string; + asyncComponentOptions?: Omit; + rootAttrs?: Record; +}) { + LoggerInstance.warn( + 'createRemoteAppComponent is deprecated, please use createRemoteAppComponent instead!', + ); + return createRemoteAppComponent(info); +} diff --git a/packages/bridge/vue3-bridge/src/index.ts b/packages/bridge/vue3-bridge/src/index.ts index 7212a3c8f5c..4e2180a4708 100644 --- a/packages/bridge/vue3-bridge/src/index.ts +++ b/packages/bridge/vue3-bridge/src/index.ts @@ -1,3 +1,3 @@ export { createBridgeComponent } from './provider'; -export { createRemoteComponent } from './create'; +export { createRemoteComponent, createRemoteAppComponent } from './create'; 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 417f12758e7..68b4a959222 100644 --- a/packages/bridge/vue3-bridge/src/remoteApp.tsx +++ b/packages/bridge/vue3-bridge/src/remoteApp.tsx @@ -43,7 +43,7 @@ export default defineComponent({ hashRoute: props.hashRoute, }; LoggerInstance.debug( - `createRemoteComponent LazyComponent render >>>`, + `createRemoteAppComponent LazyComponent render >>>`, renderProps, ); @@ -67,7 +67,7 @@ export default defineComponent({ // dispatchPopstateEnv if (pathname.value !== '' && pathname.value !== newPath) { LoggerInstance.debug( - `createRemoteComponent dispatchPopstateEnv >>>`, + `createRemoteAppComponent dispatchPopstateEnv >>>`, { ...props, pathname: route.path, @@ -84,9 +84,12 @@ export default defineComponent({ }); onBeforeUnmount(() => { - LoggerInstance.debug(`createRemoteComponent LazyComponent destroy >>>`, { - ...props, - }); + LoggerInstance.debug( + `createRemoteAppComponent LazyComponent destroy >>>`, + { + ...props, + }, + ); watchStopHandle(); hostInstance?.bridgeHook?.lifecycle?.beforeBridgeDestroy?.emit({ diff --git a/packages/modernjs/package.json b/packages/modernjs/package.json index 859428af46e..031789973a8 100644 --- a/packages/modernjs/package.json +++ b/packages/modernjs/package.json @@ -27,6 +27,10 @@ "types": "./dist/types/runtime/index.d.ts", "default": "./dist/esm/runtime/index.js" }, + "./react": { + "types": "./dist/types/react/index.d.ts", + "default": "./dist/esm/react/index.js" + }, "./ssr-dev-plugin": { "types": "./dist/types/ssr-runtime/devPlugin.d.ts", "default": "./dist/esm/ssr-runtime/devPlugin.js" @@ -77,6 +81,9 @@ "runtime": [ "./dist/types/runtime/index.d.ts" ], + "react": [ + "./dist/types/react/index.d.ts" + ], "config-plugin": [ "./dist/types/cli/configPlugin.d.ts" ], @@ -111,7 +118,7 @@ "@modern-js/utils": "2.67.5", "@modern-js/node-bundle-require": "2.67.6", "@module-federation/rsbuild-plugin": "workspace:*", - "@module-federation/react": "workspace:*", + "@module-federation/bridge-react": "workspace:*", "fs-extra": "11.3.0", "lru-cache": "10.4.3", "@module-federation/enhanced": "workspace:*", diff --git a/packages/modernjs/src/cli/configPlugin.spec.ts b/packages/modernjs/src/cli/configPlugin.spec.ts index 08b3f6e5516..30d0d170194 100644 --- a/packages/modernjs/src/cli/configPlugin.spec.ts +++ b/packages/modernjs/src/cli/configPlugin.spec.ts @@ -34,7 +34,9 @@ describe('patchMFConfig', async () => { remoteType: 'script', runtimePlugins: [ require.resolve('@module-federation/modern-js/shared-strategy'), - require.resolve('@module-federation/react/data-fetch-runtime-plugin'), + require.resolve( + '@module-federation/bridge-react/data-fetch-runtime-plugin', + ), require.resolve('@module-federation/node/runtimePlugin'), require.resolve('@module-federation/modern-js/inject-node-fetch'), ], @@ -65,7 +67,9 @@ describe('patchMFConfig', async () => { remoteType: 'script', runtimePlugins: [ require.resolve('@module-federation/modern-js/shared-strategy'), - require.resolve('@module-federation/react/data-fetch-runtime-plugin'), + require.resolve( + '@module-federation/bridge-react/data-fetch-runtime-plugin', + ), ], shared: { react: { diff --git a/packages/modernjs/src/cli/configPlugin.ts b/packages/modernjs/src/cli/configPlugin.ts index ae16a07da73..7b118db7703 100644 --- a/packages/modernjs/src/cli/configPlugin.ts +++ b/packages/modernjs/src/cli/configPlugin.ts @@ -170,7 +170,9 @@ export const patchMFConfig = ( ); injectRuntimePlugins( - require.resolve('@module-federation/react/data-fetch-runtime-plugin'), + require.resolve( + '@module-federation/bridge-react/data-fetch-runtime-plugin', + ), runtimePlugins, ); diff --git a/packages/modernjs/src/cli/server/data-fetch-server-plugin.ts b/packages/modernjs/src/cli/server/data-fetch-server-plugin.ts index dac15473dfb..46952e729ad 100644 --- a/packages/modernjs/src/cli/server/data-fetch-server-plugin.ts +++ b/packages/modernjs/src/cli/server/data-fetch-server-plugin.ts @@ -1,4 +1,4 @@ -import dataFetchMiddleWare from '@module-federation/react/data-fetch-server-middleware'; +import dataFetchMiddleWare from '@module-federation/bridge-react/data-fetch-server-middleware'; import type { ServerPlugin } from '@modern-js/server-runtime'; diff --git a/packages/modernjs/src/react/index.ts b/packages/modernjs/src/react/index.ts new file mode 100644 index 00000000000..30505d01317 --- /dev/null +++ b/packages/modernjs/src/react/index.ts @@ -0,0 +1,49 @@ +import * as mfRuntime from '@module-federation/enhanced/runtime'; +// eslint-disable-next-line @nx/enforce-module-boundaries +import { + ERROR_TYPE, + createLazyComponent as rawCreateLazyComponent, + collectSSRAssets as rawCollectSsrAssets, + injectDataFetch, +} from '@module-federation/bridge-react'; + +import type { + CollectSSRAssetsOptions, + CreateLazyComponentOptions, +} from '@module-federation/bridge-react'; + +export { ERROR_TYPE }; + +type NewCreateLazyComponentOptions = Omit< + CreateLazyComponentOptions, + 'runtime' +>; +type NewCreateLazyComponent = ( + options: NewCreateLazyComponentOptions, +) => ReturnType>; + +export const createLazyComponent: NewCreateLazyComponent = (options) => { + return rawCreateLazyComponent({ ...options, runtime: mfRuntime }); +}; + +export const collectSSRAssets: ( + options: Omit, +) => ReturnType = ( + options: Omit, +) => { + return rawCollectSsrAssets({ ...options, runtime: mfRuntime }); +}; + +export function wrapNoSSR( + createLazyComponentFn: typeof createLazyComponent, +): ( + options: Omit, 'noSSR'>, +) => ReturnType> { + return (options: Omit, 'noSSR'>) => { + return createLazyComponentFn({ ...options, noSSR: true }); + }; +} + +export { injectDataFetch }; + +export type { DataFetchParams } from '@module-federation/bridge-react'; diff --git a/packages/modernjs/src/runtime/index.ts b/packages/modernjs/src/runtime/index.ts index 06d8ab1dd78..532254ed0fc 100644 --- a/packages/modernjs/src/runtime/index.ts +++ b/packages/modernjs/src/runtime/index.ts @@ -1,60 +1 @@ -import * as mfRuntime from '@module-federation/enhanced/runtime'; -// eslint-disable-next-line @nx/enforce-module-boundaries -import { kit as rawKit, ERROR_TYPE } from '@module-federation/react/pure'; - -import type { - CollectSSRAssetsOptions, - CreateRemoteComponentOptions, -} from '@module-federation/react/pure'; - export * from '@module-federation/enhanced/runtime'; - -export { ERROR_TYPE }; - -type NewCreateRemoteComponentOptions = Omit< - CreateRemoteComponentOptions, - 'runtime' ->; -type NewCreateRemoteComponent = ( - options: NewCreateRemoteComponentOptions, -) => ReturnType< - typeof import('@module-federation/react/pure').kit.createRemoteSSRComponent< - T, - E - > ->; - -export const kit = { - get createRemoteSSRComponent(): NewCreateRemoteComponent { - const { createRemoteSSRComponent } = rawKit; - return (options) => - createRemoteSSRComponent({ ...options, runtime: mfRuntime }); - }, - get createRemoteComponent(): NewCreateRemoteComponent { - const { createRemoteComponent } = rawKit; - return (options) => - createRemoteComponent({ ...options, runtime: mfRuntime }); - }, - get collectSSRAssets(): ( - options: Omit, - ) => ReturnType< - typeof import('@module-federation/react/pure').kit.collectSSRAssets - > { - const { collectSSRAssets } = rawKit; - return (options) => collectSSRAssets({ ...options, runtime: mfRuntime }); - }, - get wrapNoSSR(): ( - createComponentFn: NewCreateRemoteComponent, - ) => ( - options: Omit, 'noSSR'>, - ) => ReturnType { - return (createComponentFn) => { - return (options) => createComponentFn({ ...options, noSSR: true }); - }; - }, - get injectDataFetch(): typeof import('@module-federation/react/pure').kit.injectDataFetch { - return require('@module-federation/react/pure').kit.injectDataFetch; - }, -}; - -export type { DataFetchParams } from '@module-federation/react/pure'; diff --git a/packages/modernjs/src/ssr-runtime/devPlugin.tsx b/packages/modernjs/src/ssr-runtime/devPlugin.tsx index de78ada8249..a2c8ec8b086 100644 --- a/packages/modernjs/src/ssr-runtime/devPlugin.tsx +++ b/packages/modernjs/src/ssr-runtime/devPlugin.tsx @@ -1,6 +1,6 @@ import type { RuntimePluginFuture } from '@modern-js/runtime'; import { SSRLiveReload } from './SSRLiveReload'; -import { flushDataFetch } from '@module-federation/react/data-fetch-utils'; +import { flushDataFetch } from '@module-federation/bridge-react/lazy-utils'; export const mfSSRDevPlugin = (): RuntimePluginFuture => ({ name: '@module-federation/modern-js', diff --git a/packages/modernjs/src/ssr-runtime/injectDataFetchFunctionPlugin.tsx b/packages/modernjs/src/ssr-runtime/injectDataFetchFunctionPlugin.tsx index f454174ff35..245003391fd 100644 --- a/packages/modernjs/src/ssr-runtime/injectDataFetchFunctionPlugin.tsx +++ b/packages/modernjs/src/ssr-runtime/injectDataFetchFunctionPlugin.tsx @@ -1,6 +1,9 @@ -import { kit } from '@module-federation/react/pure'; +import { + callDataFetch, + injectDataFetch, +} from '@module-federation/bridge-react/data-fetch-utils'; +import { setSSREnv } from '@module-federation/bridge-react/lazy-utils'; -const { callDataFetch, injectDataFetch, setSSREnv } = kit; import type { RuntimePluginFuture } from '@modern-js/runtime'; export const injectDataFetchFunctionPlugin = ({ diff --git a/packages/react/.eslintrc.json b/packages/react/.eslintrc.json deleted file mode 100644 index 5c3013868ca..00000000000 --- a/packages/react/.eslintrc.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "extends": ["../../.eslintrc.json"], - "ignorePatterns": [ - "!**/*", - "**/*.d.ts", - "**/vite.config.*.timestamp*", - "**/vitest.config.*.timestamp*" - ], - "overrides": [ - { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": { - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/ban-ts-comment": "warn", - "@typescript-eslint/no-var-requires": 0, - "@typescript-eslint/no-restricted-imports": [ - "error", - { - "paths": [ - { - "name": "webpack", - "message": "Please use require(normalizeWebpackPath('webpack')) instead.", - "allowTypeImports": true - } - ], - "patterns": [ - { - "group": ["webpack/lib/*"], - "message": "Please use require(normalizeWebpackPath('webpack')) instead.", - "allowTypeImports": true - } - ] - } - ] - } - }, - { - "files": ["*.js", "*.jsx"] - } - ] -} diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md deleted file mode 100644 index fa8f0625cb5..00000000000 --- a/packages/react/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -# @module-federation/react diff --git a/packages/react/LICENSE b/packages/react/LICENSE deleted file mode 100644 index 45036bbb708..00000000000 --- a/packages/react/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025-present zhanghang(2heal1) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/packages/react/README.md b/packages/react/README.md deleted file mode 100644 index 2b3ce667a4d..00000000000 --- a/packages/react/README.md +++ /dev/null @@ -1 +0,0 @@ -# React diff --git a/packages/react/modern.config.ts b/packages/react/modern.config.ts deleted file mode 100644 index a7a46250653..00000000000 --- a/packages/react/modern.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { moduleTools, defineConfig } from '@modern-js/module-tools'; - -export default defineConfig({ - buildPreset: 'modern-js-universal', - plugins: [moduleTools()], -}); diff --git a/packages/react/package.json b/packages/react/package.json deleted file mode 100644 index cb6ac03e754..00000000000 --- a/packages/react/package.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "name": "@module-federation/react", - "version": "0.15.0", - "publishConfig": { - "access": "public" - }, - "files": [ - "dist/" - ], - "author": "hanric ", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/module-federation/core", - "directory": "packages/react" - }, - "main": "./dist/cjs/index.js", - "module": "./dist/esm/index.js", - "types": "./dist/types/index.d.ts", - "exports": { - ".": { - "types": "./dist/types/index.d.ts", - "import": "./dist/esm/index.js", - "require": "./dist/cjs/index.js" - }, - "./data-fetch-runtime-plugin": { - "types": "./dist/types/module/data-fetch/runtime-plugin.d.ts", - "import": "./dist/esm/module/data-fetch/runtime-plugin.js", - "require": "./dist/cjs/module/data-fetch/runtime-plugin.js" - }, - "./data-fetch-utils": { - "types": "./dist/types/module/utils.d.ts", - "import": "./dist/esm/module/utils.js", - "require": "./dist/cjs/module/utils.js" - }, - "./data-fetch-server-middleware": { - "types": "./dist/types/module/data-fetch/data-fetch-server-middleware.d.ts", - "import": "./dist/esm/module/data-fetch/data-fetch-server-middleware.js", - "require": "./dist/cjs/module/data-fetch/data-fetch-server-middleware.js" - }, - "./pure": { - "types": "./dist/types/module/index.d.ts", - "import": "./dist/esm/module/index.js", - "require": "./dist/cjs/module/index.js" - }, - "./*": "./*" - }, - "typesVersions": { - "*": { - ".": [ - "./dist/types/index.d.ts" - ], - "data-fetch-runtime-plugin": [ - "./dist/types/module/data-fetch/runtime-plugin.d.ts" - ], - "data-fetch-utils": [ - "./dist/types/module/utils.d.ts" - ], - "data-fetch-server-middleware": [ - "./dist/types/module/data-fetch/data-fetch-server-middleware.d.ts" - ], - "pure": [ - "./dist/types/module/index.d.ts" - ] - } - }, - "scripts": { - "build": "modern-module build" - }, - "dependencies": { - "@module-federation/sdk": "workspace:*", - "@swc/helpers": "^0.5.17" - }, - "peerDependencies": { - "react": ">=17" - }, - "devDependencies": { - "@types/react": "18.2.79", - "react": "18.3.1", - "typescript": "^5.2.2", - "@modern-js/module-tools": "2.67.6", - "@module-federation/runtime": "workspace:*", - "hono": "3.12.12" - } -} diff --git a/packages/react/project.json b/packages/react/project.json deleted file mode 100644 index a4e09aff327..00000000000 --- a/packages/react/project.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "react", - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "packages/react/src", - "projectType": "library", - "tags": ["type:pkg"], - "targets": { - "build": { - "executor": "nx:run-commands", - "outputs": ["{projectRoot}/packages/modernjs/dist"], - "dependsOn": [ - { - "target": "build", - "dependencies": true - } - ], - "options": { - "parallel": false, - "commands": [ - "pnpm i", - "cd packages/react; pnpm run build || (sleep 2 && pnpm run build)", - "cp packages/react/LICENSE packages/react/dist" - ] - } - } - } -} diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts deleted file mode 100644 index 059e653ee31..00000000000 --- a/packages/react/src/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { kit, ERROR_TYPE, autoFetchDataPlugin } from './module'; -export type { - DataFetchParams, - NoSSRRemoteInfo, - CollectSSRAssetsOptions, - CreateRemoteComponentOptions, -} from './module'; - -const { - createRemoteSSRComponent, - createRemoteComponent, - collectSSRAssets, - wrapNoSSR, - injectDataFetch, - callDataFetch, -} = kit; - -export { - createRemoteSSRComponent, - createRemoteComponent, - collectSSRAssets, - wrapNoSSR, - injectDataFetch, - callDataFetch, - ERROR_TYPE, - autoFetchDataPlugin, -}; diff --git a/packages/react/src/module/index.ts b/packages/react/src/module/index.ts deleted file mode 100644 index 2b08dfcb7df..00000000000 --- a/packages/react/src/module/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -import autoFetchDataPlugin from './data-fetch/runtime-plugin'; - -export type { DataFetchParams, NoSSRRemoteInfo } from './types'; -export { ERROR_TYPE } from './constant'; -export type { - CreateRemoteComponentOptions, - IProps as CollectSSRAssetsOptions, -} from './createRemoteComponent'; - -// avoid import react directly https://github.com/web-infra-dev/modern.js/issues/7096 -export const kit = { - get createRemoteSSRComponent(): typeof import('./createRemoteComponent').createRemoteSSRComponent { - return require('./createRemoteComponent').createRemoteSSRComponent; - }, - get createRemoteComponent(): typeof import('./createRemoteComponent').createRemoteComponent { - return require('./createRemoteComponent').createRemoteComponent; - }, - get collectSSRAssets(): typeof import('./createRemoteComponent').collectSSRAssets { - return require('./createRemoteComponent').collectSSRAssets; - }, - get wrapNoSSR(): typeof import('./wrapNoSSR').wrapNoSSR { - return require('./wrapNoSSR').wrapNoSSR; - }, - get injectDataFetch(): typeof import('./data-fetch/inject-data-fetch').injectDataFetch { - return require('./data-fetch/inject-data-fetch').injectDataFetch; - }, - get callDataFetch(): typeof import('./data-fetch/call-data-fetch').callDataFetch { - return require('./data-fetch/call-data-fetch').callDataFetch; - }, - get setSSREnv(): typeof import('./utils').setSSREnv { - return require('./utils').setSSREnv; - }, -}; - -export { autoFetchDataPlugin }; diff --git a/packages/react/src/module/wrapNoSSR.tsx b/packages/react/src/module/wrapNoSSR.tsx deleted file mode 100644 index 4f1fc00b1be..00000000000 --- a/packages/react/src/module/wrapNoSSR.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { createRemoteComponent } from './createRemoteComponent'; -import type { CreateRemoteComponentOptions } from './createRemoteComponent'; - -export function wrapNoSSR( - createComponentFn: typeof createRemoteComponent, -) { - return (options: Omit, 'noSSR'>) => { - return createComponentFn({ ...options, noSSR: true }); - }; -} diff --git a/packages/react/tsconfig.json b/packages/react/tsconfig.json deleted file mode 100644 index 072b194b07a..00000000000 --- a/packages/react/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2015", - "lib": ["DOM", "ESNext"], - "allowJs": true, - "module": "commonjs", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "experimentalDecorators": true, - "resolveJsonModule": true, - "moduleResolution": "node", - "declaration": false, - "jsx": "preserve", - "baseUrl": "./", - "paths": {}, - "noImplicitAny": false - }, - "include": ["src"] -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 422205f13b9..1ad8b34d7a1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2218,6 +2218,9 @@ importers: '@vitejs/plugin-vue-jsx': specifier: ^4.0.0 version: 4.0.1(vite@5.4.18)(vue@3.5.13) + hono: + specifier: 3.12.12 + version: 3.12.12 jsdom: specifier: ^24.1.0 version: 24.1.3 @@ -2772,6 +2775,9 @@ importers: '@modern-js/utils': specifier: 2.67.5 version: 2.67.5 + '@module-federation/bridge-react': + specifier: workspace:* + version: link:../bridge/bridge-react '@module-federation/cli': specifier: workspace:* version: link:../cli @@ -2781,9 +2787,6 @@ importers: '@module-federation/node': specifier: workspace:* version: link:../node - '@module-federation/react': - specifier: workspace:* - version: link:../react '@module-federation/rsbuild-plugin': specifier: workspace:* version: link:../rsbuild-plugin @@ -2965,34 +2968,6 @@ importers: specifier: ^5.40.0 version: 5.93.0(@swc/core@1.7.26)(esbuild@0.25.0)(webpack-cli@5.1.4) - packages/react: - dependencies: - '@module-federation/sdk': - specifier: workspace:* - version: link:../sdk - '@swc/helpers': - specifier: ^0.5.17 - version: 0.5.17 - devDependencies: - '@modern-js/module-tools': - specifier: 2.67.6 - version: 2.67.6(typescript@5.7.3) - '@module-federation/runtime': - specifier: workspace:* - version: link:../runtime - '@types/react': - specifier: 18.2.79 - version: 18.2.79 - hono: - specifier: 3.12.12 - version: 3.12.12 - react: - specifier: 18.3.1 - version: 18.3.1 - typescript: - specifier: ^5.2.2 - version: 5.7.3 - packages/retry-plugin: dependencies: '@module-federation/sdk': @@ -3649,7 +3624,7 @@ packages: '@babel/traverse': 7.27.1 '@babel/types': 7.27.1 convert-source-map: 1.9.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) gensync: 1.0.0-beta.2 json5: 2.2.3 lodash: 4.17.21 @@ -3697,7 +3672,7 @@ packages: '@babel/traverse': 7.27.1 '@babel/types': 7.27.1 convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -3720,7 +3695,7 @@ packages: '@babel/traverse': 7.26.9 '@babel/types': 7.27.0 convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -3742,7 +3717,7 @@ packages: '@babel/traverse': 7.27.1 '@babel/types': 7.27.1 convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -4021,7 +3996,7 @@ packages: '@babel/core': 7.26.10 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -6201,7 +6176,7 @@ packages: '@babel/parser': 7.27.2 '@babel/template': 7.25.9 '@babel/types': 7.27.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -6215,7 +6190,7 @@ packages: '@babel/parser': 7.27.2 '@babel/template': 7.26.9 '@babel/types': 7.27.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -6229,7 +6204,7 @@ packages: '@babel/parser': 7.27.2 '@babel/template': 7.27.0 '@babel/types': 7.27.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -6244,7 +6219,7 @@ packages: '@babel/parser': 7.27.2 '@babel/template': 7.27.2 '@babel/types': 7.27.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -8722,7 +8697,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -8739,7 +8714,7 @@ packages: engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: ajv: 6.12.6 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -8828,7 +8803,7 @@ packages: deprecated: Use @eslint/config-array instead dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -8839,7 +8814,7 @@ packages: deprecated: Use @eslint/config-array instead dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -10247,48 +10222,6 @@ packages: - supports-color dev: true - /@modern-js/module-tools@2.67.6(typescript@5.7.3): - resolution: {integrity: sha512-3ywJTXAq7PUt+k9JsasbXeFDUQCzGG4oSZekREKcL7CfKVFr4cNusLOX8qlx05Dnu3771ahnApgzbA7Vkoctfg==} - engines: {node: '>=16.0.0'} - hasBin: true - peerDependencies: - typescript: ^4 || ^5 - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@ampproject/remapping': 2.3.0 - '@ast-grep/napi': 0.35.0 - '@babel/core': 7.26.10 - '@babel/types': 7.27.1 - '@modern-js/core': 2.67.6 - '@modern-js/plugin': 2.67.6 - '@modern-js/plugin-changeset': 2.67.6 - '@modern-js/plugin-i18n': 2.67.6 - '@modern-js/swc-plugins': 0.6.11(@swc/helpers@0.5.17) - '@modern-js/types': 2.67.6 - '@modern-js/utils': 2.67.6 - '@rollup/pluginutils': 4.2.1 - '@swc/helpers': 0.5.17 - convert-source-map: 1.9.0 - enhanced-resolve: 5.17.1 - esbuild: 0.19.2 - magic-string: 0.30.17 - postcss: 8.4.38 - postcss-modules: 4.3.1(postcss@8.4.38) - safe-identifier: 0.4.2 - source-map: 0.7.4 - style-inject: 0.3.0 - sucrase: 3.29.0 - tapable: 2.2.1 - terser: 5.37.0 - tsconfig-paths-webpack-plugin: 4.1.0 - typescript: 5.7.3 - transitivePeerDependencies: - - debug - - supports-color - dev: true - /@modern-js/node-bundle-require@2.65.1: resolution: {integrity: sha512-XpEkciVEfDbkkLUI662ZFlI9tXsUQtLXk4NRJDBGosNnk9uL2XszmC8sKsdCSLK8AYuPW2w6MTVWuJsOR0EU8A==} dependencies: @@ -12138,7 +12071,7 @@ packages: '@open-draft/until': 1.0.3 '@types/debug': 4.1.12 '@xmldom/xmldom': 0.8.10 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) headers-polyfill: 3.2.5 outvariant: 1.4.3 strict-event-emitter: 0.2.8 @@ -16305,6 +16238,18 @@ packages: - webpack-hot-middleware dev: true + /@rsbuild/plugin-react@1.3.2(@rsbuild/core@1.3.20): + resolution: {integrity: sha512-H4blXmgvVOrQlVy4ZfJ5IGfQIF5uKwtkGzwVnEsn1HN7DRRI9VlFrcuXj6+e3GigvYxg6TDHAAUJi6FoIGbnKQ==} + peerDependencies: + '@rsbuild/core': 1.x + dependencies: + '@rsbuild/core': 1.3.20 + '@rspack/plugin-react-refresh': 1.4.3(react-refresh@0.17.0) + react-refresh: 0.17.0 + transitivePeerDependencies: + - webpack-hot-middleware + dev: true + /@rsbuild/plugin-react@1.3.2(@rsbuild/core@1.3.22): resolution: {integrity: sha512-H4blXmgvVOrQlVy4ZfJ5IGfQIF5uKwtkGzwVnEsn1HN7DRRI9VlFrcuXj6+e3GigvYxg6TDHAAUJi6FoIGbnKQ==} peerDependencies: @@ -16389,7 +16334,7 @@ packages: '@rsbuild/core': 1.x dependencies: '@rsbuild/core': 1.3.20 - '@rsbuild/plugin-react': 1.3.1(@rsbuild/core@1.3.20) + '@rsbuild/plugin-react': 1.3.2(@rsbuild/core@1.3.20) '@svgr/core': 8.1.0(typescript@5.0.4) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0) '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0)(typescript@5.0.4) @@ -16407,7 +16352,7 @@ packages: '@rsbuild/core': 1.x dependencies: '@rsbuild/core': 1.3.20 - '@rsbuild/plugin-react': 1.3.1(@rsbuild/core@1.3.20) + '@rsbuild/plugin-react': 1.3.2(@rsbuild/core@1.3.20) '@svgr/core': 8.1.0(typescript@5.5.2) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0) '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0)(typescript@5.5.2) @@ -17824,7 +17769,7 @@ packages: conventional-changelog-writer: 8.0.1 conventional-commits-filter: 5.0.0 conventional-commits-parser: 6.1.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) import-from-esm: 2.0.0 lodash-es: 4.17.21 micromatch: 4.0.8 @@ -17891,7 +17836,7 @@ packages: '@octokit/plugin-throttling': 9.4.0(@octokit/core@6.1.4) '@semantic-release/error': 4.0.0 aggregate-error: 5.0.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) dir-glob: 3.0.1 globby: 14.1.0 http-proxy-agent: 7.0.2 @@ -17960,7 +17905,7 @@ packages: conventional-changelog-writer: 8.0.1 conventional-commits-filter: 5.0.0 conventional-commits-parser: 6.1.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) get-stream: 7.0.1 import-from-esm: 2.0.0 into-stream: 7.0.0 @@ -19156,7 +19101,7 @@ packages: typescript: '>= 3.x' webpack: '>= 4' dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) endent: 2.1.0 find-cache-dir: 3.3.2 flat-cache: 3.2.0 @@ -19175,7 +19120,7 @@ packages: typescript: '>= 4.x' webpack: '>= 4' dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) endent: 2.1.0 find-cache-dir: 3.3.2 flat-cache: 3.2.0 @@ -19194,7 +19139,7 @@ packages: typescript: '>= 4.x' webpack: '>= 4' dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) endent: 2.1.0 find-cache-dir: 3.3.2 flat-cache: 3.2.0 @@ -19664,7 +19609,7 @@ packages: '@swc-node/sourcemap-support': 0.5.1 '@swc/core': 1.7.26(@swc/helpers@0.5.13) colorette: 2.0.20 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) oxc-resolver: 5.2.0 pirates: 4.0.7 tslib: 2.8.1 @@ -21076,7 +21021,7 @@ packages: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(typescript@5.0.4) '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.0.4) - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) eslint: 8.57.1 graphemer: 1.4.0 ignore: 5.3.2 @@ -21128,7 +21073,7 @@ packages: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.0.4) - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) eslint: 8.57.1 typescript: 5.0.4 transitivePeerDependencies: @@ -21149,7 +21094,7 @@ packages: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.3) '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) eslint: 8.57.1 typescript: 5.7.3 transitivePeerDependencies: @@ -21170,7 +21115,7 @@ packages: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) eslint: 9.0.0 typescript: 5.4.5 transitivePeerDependencies: @@ -21250,7 +21195,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.0.4) '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.0.4) - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) eslint: 8.57.1 tsutils: 3.21.0(typescript@5.0.4) typescript: 5.0.4 @@ -21270,7 +21215,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.7.3) '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@5.7.3) - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) eslint: 8.57.1 ts-api-utils: 1.3.0(typescript@5.7.3) typescript: 5.7.3 @@ -21289,7 +21234,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 8.8.0(typescript@5.7.3) '@typescript-eslint/utils': 8.8.0(eslint@8.57.1)(typescript@5.7.3) - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) ts-api-utils: 1.3.0(typescript@5.7.3) typescript: 5.7.3 transitivePeerDependencies: @@ -21333,7 +21278,7 @@ packages: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.3 @@ -21354,7 +21299,7 @@ packages: dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -21376,7 +21321,7 @@ packages: dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -21398,7 +21343,7 @@ packages: dependencies: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 @@ -21420,7 +21365,7 @@ packages: dependencies: '@typescript-eslint/types': 8.14.0 '@typescript-eslint/visitor-keys': 8.14.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 @@ -21442,7 +21387,7 @@ packages: dependencies: '@typescript-eslint/types': 8.8.0 '@typescript-eslint/visitor-keys': 8.8.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 @@ -21791,7 +21736,7 @@ packages: '@verdaccio/loaders': 8.0.0-next-8.6 '@verdaccio/signature': 8.0.0-next-8.7 '@verdaccio/utils': 8.1.0-next-8.15 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) lodash: 4.17.21 verdaccio-htpasswd: 13.0.0-next-8.15 transitivePeerDependencies: @@ -21810,7 +21755,7 @@ packages: dependencies: '@verdaccio/core': 8.0.0-next-8.15 '@verdaccio/utils': 8.1.0-next-8.15 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) js-yaml: 4.1.0 lodash: 4.17.21 minimatch: 7.4.6 @@ -21844,7 +21789,7 @@ packages: resolution: {integrity: sha512-yuqD8uAZJcgzuNHjV6C438UNT5r2Ai9+SnUlO34AHZdWSYcluO3Zj5R3p5uf+C7YPCE31pUD27wBU74xVbUoBw==} engines: {node: '>=18'} dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) lodash: 4.17.21 transitivePeerDependencies: - supports-color @@ -21871,7 +21816,7 @@ packages: '@verdaccio/core': 8.0.0-next-8.15 '@verdaccio/logger-prettify': 8.0.0-next-8.2 colorette: 2.0.20 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) transitivePeerDependencies: - supports-color @@ -21902,7 +21847,7 @@ packages: '@verdaccio/core': 8.0.0-next-8.15 '@verdaccio/url': 13.0.0-next-8.15 '@verdaccio/utils': 8.1.0-next-8.15 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) express: 4.21.2 express-rate-limit: 5.5.1 lodash: 4.17.21 @@ -21920,7 +21865,7 @@ packages: engines: {node: '>=18'} dependencies: '@verdaccio/config': 8.0.0-next-8.15 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) jsonwebtoken: 9.0.2 transitivePeerDependencies: - supports-color @@ -21936,7 +21881,7 @@ packages: '@verdaccio/core': 8.0.0-next-8.15 '@verdaccio/url': 13.0.0-next-8.15 '@verdaccio/utils': 8.1.0-next-8.15 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) gunzip-maybe: 1.4.2 lodash: 4.17.21 tar-stream: 3.1.7 @@ -21951,7 +21896,7 @@ packages: engines: {node: '>=18'} dependencies: '@verdaccio/core': 8.0.0-next-8.15 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) lodash: 4.17.21 validator: 13.12.0 transitivePeerDependencies: @@ -23197,7 +23142,7 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) transitivePeerDependencies: - supports-color @@ -23205,7 +23150,7 @@ packages: resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} engines: {node: '>= 14'} dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) transitivePeerDependencies: - supports-color dev: true @@ -27053,6 +26998,7 @@ packages: dependencies: ms: 2.1.3 supports-color: 8.1.1 + dev: true /debug@4.4.0(supports-color@9.3.1): resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} @@ -27065,7 +27011,6 @@ packages: dependencies: ms: 2.1.3 supports-color: 9.3.1 - dev: true /decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} @@ -27310,7 +27255,7 @@ packages: hasBin: true dependencies: address: 1.2.2 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) transitivePeerDependencies: - supports-color @@ -28055,7 +28000,7 @@ packages: peerDependencies: esbuild: '>=0.12 <1' dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) esbuild: 0.17.19 transitivePeerDependencies: - supports-color @@ -28066,7 +28011,7 @@ packages: peerDependencies: esbuild: '>=0.12 <1' dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) esbuild: 0.18.20 transitivePeerDependencies: - supports-color @@ -28077,7 +28022,7 @@ packages: peerDependencies: esbuild: '>=0.12 <1' dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) esbuild: 0.23.0 transitivePeerDependencies: - supports-color @@ -28087,7 +28032,7 @@ packages: peerDependencies: esbuild: '>=0.12 <1' dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) esbuild: 0.24.0 transitivePeerDependencies: - supports-color @@ -28098,7 +28043,7 @@ packages: peerDependencies: esbuild: '>=0.12 <1' dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) esbuild: 0.25.0 transitivePeerDependencies: - supports-color @@ -28486,7 +28431,7 @@ packages: optional: true dependencies: '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) enhanced-resolve: 5.18.1 eslint: 9.0.0 eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.0.0) @@ -29055,7 +29000,7 @@ packages: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -29101,7 +29046,7 @@ packages: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) escape-string-regexp: 4.0.0 eslint-scope: 8.3.0 eslint-visitor-keys: 4.2.0 @@ -30083,7 +30028,7 @@ packages: debug: optional: true dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -31652,7 +31597,7 @@ packages: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) transitivePeerDependencies: - supports-color dev: true @@ -31662,7 +31607,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) transitivePeerDependencies: - supports-color dev: true @@ -31690,7 +31635,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@types/http-proxy': 1.17.15 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) http-proxy: 1.18.1(debug@4.4.0) is-glob: 4.0.3 is-plain-object: 5.0.0 @@ -31761,7 +31706,7 @@ packages: engines: {node: '>= 6.0.0'} dependencies: agent-base: 5.1.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) transitivePeerDependencies: - supports-color dev: true @@ -31771,7 +31716,7 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) transitivePeerDependencies: - supports-color @@ -31780,7 +31725,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) transitivePeerDependencies: - supports-color dev: true @@ -31936,7 +31881,7 @@ packages: resolution: {integrity: sha512-YVt14UZCgsX1vZQ3gKjkWVdBdHQ6eu3MPU1TBgL1H5orXe2+jWD006WCPPtOuwlQm10NuzOW5WawiF1Q9veW8g==} engines: {node: '>=18.20'} dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) import-meta-resolve: 4.1.0 transitivePeerDependencies: - supports-color @@ -32785,7 +32730,7 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -32797,7 +32742,7 @@ packages: engines: {node: '>=10'} dependencies: '@jridgewell/trace-mapping': 0.3.25 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -33858,7 +33803,7 @@ packages: content-disposition: 0.5.4 content-type: 1.0.5 cookies: 0.9.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) delegates: 1.0.0 depd: 2.0.0 destroy: 1.2.0 @@ -33889,7 +33834,7 @@ packages: content-disposition: 0.5.4 content-type: 1.0.5 cookies: 0.9.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) delegates: 1.0.0 depd: 2.0.0 destroy: 1.2.0 @@ -33920,7 +33865,7 @@ packages: content-disposition: 0.5.4 content-type: 1.0.5 cookies: 0.9.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) delegates: 1.0.0 depd: 2.0.0 destroy: 1.2.0 @@ -35327,7 +35272,7 @@ packages: resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} dependencies: '@types/debug': 4.1.12 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -35815,7 +35760,7 @@ packages: resolution: {integrity: sha512-0mvZ1o5F0GStEzsZIrlGAYmLOtrILwMCh2vHAT1J2qZdyCqgMUo/5FBVk1B54pmCZCDxOS8mMm3MAIW5nCDL3w==} dependencies: '@vercel/nft': 0.27.3(encoding@0.1.13) - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) fs-extra: 11.3.0 mlly: 1.6.1 pkg-types: 1.2.1 @@ -38920,7 +38865,7 @@ packages: engines: {node: '>=8.16.0'} dependencies: '@types/mime-types': 2.1.4 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) extract-zip: 1.7.0 https-proxy-agent: 4.0.0 mime: 2.6.0 @@ -42796,7 +42741,7 @@ packages: '@semantic-release/release-notes-generator': 14.0.3(semantic-release@24.2.3) aggregate-error: 5.0.0 cosmiconfig: 9.0.0(typescript@5.7.3) - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) env-ci: 11.1.0 execa: 9.5.2 figures: 6.1.0 @@ -42907,7 +42852,7 @@ packages: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -43456,7 +43401,7 @@ packages: /spdy-transport@3.0.0: resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==} dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) detect-node: 2.1.0 hpack.js: 2.1.6 obuf: 1.1.2 @@ -43469,7 +43414,7 @@ packages: resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==} engines: {node: '>=6.0.0'} dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) handle-thing: 2.0.1 http-deceiver: 1.2.7 select-hose: 2.0.0 @@ -43769,7 +43714,7 @@ packages: engines: {node: '>=8.0'} dependencies: date-format: 4.0.14 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) fs-extra: 8.1.0 transitivePeerDependencies: - supports-color @@ -44254,7 +44199,7 @@ packages: hasBin: true dependencies: '@adobe/css-tools': 4.3.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) glob: 10.4.5 sax: 1.4.1 source-map: 0.7.4 @@ -44321,7 +44266,6 @@ packages: /supports-color@9.3.1: resolution: {integrity: sha512-knBY82pjmnIzK3NifMo3RxEIRD9E0kIzV4BKcyTZ9+9kWgLMxd4PrsTSMoFQUabgRBbF8KOLRDCyKgNV+iK44Q==} engines: {node: '>=12'} - dev: true /supports-hyperlinks@3.2.0: resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} @@ -45715,7 +45659,7 @@ packages: bundle-require: 4.2.1(esbuild@0.19.2) cac: 6.7.14 chokidar: 3.6.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) esbuild: 0.19.2 execa: 5.1.1 globby: 11.1.0 @@ -45757,7 +45701,7 @@ packages: cac: 6.7.14 chokidar: 4.0.1 consola: 3.2.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) esbuild: 0.24.0 joycon: 3.1.1 picocolors: 1.1.1 @@ -46636,7 +46580,7 @@ packages: apache-md5: 1.1.8 bcryptjs: 2.4.3 core-js: 3.40.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) http-errors: 2.0.0 unix-crypt-td-js: 1.1.4 transitivePeerDependencies: @@ -46667,7 +46611,7 @@ packages: clipanion: 4.0.0-rc.4(typanion@3.14.0) compression: 1.8.0 cors: 2.8.5 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) envinfo: 7.14.0 express: 4.21.2 handlebars: 4.7.8 @@ -46770,7 +46714,7 @@ packages: hasBin: true dependencies: cac: 6.7.14 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) pathe: 1.1.2 picocolors: 1.1.1 vite: 5.4.18(@types/node@20.12.14)(less@4.3.0)(stylus@0.64.0) @@ -46792,7 +46736,7 @@ packages: hasBin: true dependencies: cac: 6.7.14 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) pathe: 1.1.2 picocolors: 1.1.1 vite: 5.4.18(@types/node@18.16.9)(less@4.3.0)(stylus@0.64.0) @@ -46876,7 +46820,7 @@ packages: '@volar/typescript': 2.4.13 '@vue/language-core': 2.2.0(typescript@5.5.2) compare-versions: 6.1.1 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) kolorist: 1.8.0 local-pkg: 1.1.1 magic-string: 0.30.17 @@ -47237,7 +47181,7 @@ packages: peerDependencies: eslint: '>=6.0.0' dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.0(supports-color@9.3.1) eslint: 8.57.1 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 From f5565c77ab158a9c2b635de7c1f0fc9a57f29753 Mon Sep 17 00:00:00 2001 From: 2heal1 Date: Mon, 23 Jun 2025 14:45:14 +0800 Subject: [PATCH 04/16] fix: use the same loader --- .../src/lazy/createLazyComponent.tsx | 75 +++---------------- 1 file changed, 12 insertions(+), 63 deletions(-) diff --git a/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx index 3a19eb74d48..f36545412f0 100644 --- a/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx +++ b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx @@ -1,6 +1,6 @@ -import React, { ReactNode, useEffect, useState } from 'react'; +import React, { ReactNode } from 'react'; import logger from './logger'; -import { AwaitDataFetch, transformError } from './AwaitDataFetch'; +import { AwaitDataFetch } from './AwaitDataFetch'; import { fetchData, getDataFetchItem, @@ -324,67 +324,16 @@ export function createLazyComponent( return (props: ComponentType) => { const { key, ...args } = props; - if (globalThis.FEDERATION_SSR && !options.noSSR) { - const { key, ...args } = props; - return ( - - {/* @ts-ignore */} - {(data) => } - - ); - } else { - // Client-side rendering logic - const [data, setData] = useState(null); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - - useEffect(() => { - let isMounted = true; - const fetchDataAsync = async () => { - try { - setLoading(true); - const result = await getData(options.noSSR); - if (isMounted) { - setData(result); - } - } catch (e: any) { - if (isMounted) { - setError(transformError(e)); - } - } finally { - if (isMounted) { - setLoading(false); - } - } - }; - - fetchDataAsync(); - - return () => { - isMounted = false; - }; - }, []); - - if (loading) { - return <>{options.loading}; - } - - if (error) { - return ( - <> - {typeof options.fallback === 'function' - ? options.fallback(error) - : options.fallback} - - ); - } - // @ts-ignore - return ; - } + return ( + + {/* @ts-ignore */} + {(data) => } + + ); }; } From 52781fc58d123a644f64e2ad8bc124df53c811e5 Mon Sep 17 00:00:00 2001 From: 2heal1 Date: Tue, 24 Jun 2025 14:55:44 +0800 Subject: [PATCH 05/16] chore: apply injectDataFetch in runtime plugin --- packages/bridge/bridge-react/src/index.ts | 1 - .../bridge-react/src/lazy/data-fetch/runtime-plugin.ts | 2 ++ packages/modernjs/src/react/index.ts | 3 --- .../src/ssr-runtime/injectDataFetchFunctionPlugin.tsx | 6 +----- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/bridge/bridge-react/src/index.ts b/packages/bridge/bridge-react/src/index.ts index e9094bd6c84..673a76ade49 100644 --- a/packages/bridge/bridge-react/src/index.ts +++ b/packages/bridge/bridge-react/src/index.ts @@ -12,7 +12,6 @@ export { createLazyComponent, collectSSRAssets, wrapNoSSR, - injectDataFetch, callDataFetch, setSSREnv, autoFetchDataPlugin, diff --git a/packages/bridge/bridge-react/src/lazy/data-fetch/runtime-plugin.ts b/packages/bridge/bridge-react/src/lazy/data-fetch/runtime-plugin.ts index 74c8cc95101..4ce27b9e08b 100644 --- a/packages/bridge/bridge-react/src/lazy/data-fetch/runtime-plugin.ts +++ b/packages/bridge/bridge-react/src/lazy/data-fetch/runtime-plugin.ts @@ -1,3 +1,4 @@ +import { injectDataFetch } from './inject-data-fetch'; import { getDataFetchInfo, initDataFetchMap, @@ -22,6 +23,7 @@ const autoFetchData: () => FederationRuntimePlugin = () => ({ name: 'auto-fetch-data-plugin', beforeInit(args) { initDataFetchMap(); + injectDataFetch(); return args; }, afterLoadSnapshot(args) { diff --git a/packages/modernjs/src/react/index.ts b/packages/modernjs/src/react/index.ts index 30505d01317..497b387b447 100644 --- a/packages/modernjs/src/react/index.ts +++ b/packages/modernjs/src/react/index.ts @@ -4,7 +4,6 @@ import { ERROR_TYPE, createLazyComponent as rawCreateLazyComponent, collectSSRAssets as rawCollectSsrAssets, - injectDataFetch, } from '@module-federation/bridge-react'; import type { @@ -44,6 +43,4 @@ export function wrapNoSSR( }; } -export { injectDataFetch }; - export type { DataFetchParams } from '@module-federation/bridge-react'; diff --git a/packages/modernjs/src/ssr-runtime/injectDataFetchFunctionPlugin.tsx b/packages/modernjs/src/ssr-runtime/injectDataFetchFunctionPlugin.tsx index 245003391fd..0c3c15628aa 100644 --- a/packages/modernjs/src/ssr-runtime/injectDataFetchFunctionPlugin.tsx +++ b/packages/modernjs/src/ssr-runtime/injectDataFetchFunctionPlugin.tsx @@ -1,7 +1,4 @@ -import { - callDataFetch, - injectDataFetch, -} from '@module-federation/bridge-react/data-fetch-utils'; +import { callDataFetch } from '@module-federation/bridge-react/data-fetch-utils'; import { setSSREnv } from '@module-federation/bridge-react/lazy-utils'; import type { RuntimePluginFuture } from '@modern-js/runtime'; @@ -16,7 +13,6 @@ export const injectDataFetchFunctionPlugin = ({ setup: (api) => { api.onBeforeRender(async () => { setSSREnv({ fetchServerQuery }); - injectDataFetch(); await callDataFetch(); }); From 7f67062fe05bec68ca679609e6929f5c7343f327 Mon Sep 17 00:00:00 2001 From: 2heal1 Date: Tue, 24 Jun 2025 15:51:52 +0800 Subject: [PATCH 06/16] chore: pass instance instead of runtime --- .../host/src/routes/basic/page.tsx | 2 + .../host/src/routes/client-downgrade/page.tsx | 2 + .../host/src/routes/csr/page.tsx | 2 + .../host/src/routes/server-downgrade/page.tsx | 2 + .../src/components/Content.tsx | 2 + .../host/src/routes/dynamic-remote/page.tsx | 2 + .../nested-remote/src/routes/page.tsx | 2 + .../docs/en/guide/framework/modernjs.mdx | 9 +++- .../frameworks/modern/dynamic-remote.mdx | 4 +- .../en/practice/frameworks/modern/index.mdx | 2 + .../docs/zh/guide/framework/modernjs.mdx | 9 +++- .../frameworks/modern/dynamic-remote.mdx | 4 +- .../zh/practice/frameworks/modern/index.mdx | 2 + .../src/lazy/createLazyComponent.tsx | 18 ++++---- packages/modernjs/src/react/index.ts | 46 ++----------------- 15 files changed, 52 insertions(+), 56 deletions(-) diff --git a/apps/modern-component-data-fetch/host/src/routes/basic/page.tsx b/apps/modern-component-data-fetch/host/src/routes/basic/page.tsx index b6d4034ed47..424e7373b64 100644 --- a/apps/modern-component-data-fetch/host/src/routes/basic/page.tsx +++ b/apps/modern-component-data-fetch/host/src/routes/basic/page.tsx @@ -1,9 +1,11 @@ +import { getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent, ERROR_TYPE, } from '@module-federation/modern-js/react'; const Basic = createLazyComponent({ + instance: getInstance(), loader: () => { return import('remote/BasicComponent'); }, diff --git a/apps/modern-component-data-fetch/host/src/routes/client-downgrade/page.tsx b/apps/modern-component-data-fetch/host/src/routes/client-downgrade/page.tsx index 2dad137ec3e..e3875a85a9a 100644 --- a/apps/modern-component-data-fetch/host/src/routes/client-downgrade/page.tsx +++ b/apps/modern-component-data-fetch/host/src/routes/client-downgrade/page.tsx @@ -1,6 +1,8 @@ +import { getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent } from '@module-federation/modern-js/react'; const ClientDowngrade = createLazyComponent({ + instance: getInstance(), loader: () => { return import('remote/ClientDowngrade'); }, diff --git a/apps/modern-component-data-fetch/host/src/routes/csr/page.tsx b/apps/modern-component-data-fetch/host/src/routes/csr/page.tsx index 81c88d47b0d..4757dc23ea1 100644 --- a/apps/modern-component-data-fetch/host/src/routes/csr/page.tsx +++ b/apps/modern-component-data-fetch/host/src/routes/csr/page.tsx @@ -1,9 +1,11 @@ +import { getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent, wrapNoSSR, } from '@module-federation/modern-js/react'; const CsrWithFetchDataFromServerComponent = wrapNoSSR(createLazyComponent)({ + instance: getInstance(), loader: () => { return import('provider-csr'); }, diff --git a/apps/modern-component-data-fetch/host/src/routes/server-downgrade/page.tsx b/apps/modern-component-data-fetch/host/src/routes/server-downgrade/page.tsx index 4a44e7a31da..721d2305947 100644 --- a/apps/modern-component-data-fetch/host/src/routes/server-downgrade/page.tsx +++ b/apps/modern-component-data-fetch/host/src/routes/server-downgrade/page.tsx @@ -1,6 +1,8 @@ +import { getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent } from '@module-federation/modern-js/react'; const ServerDowngrade = createLazyComponent({ + instance: getInstance(), loader: () => { return import('remote/ServerDowngrade'); }, diff --git a/apps/modernjs-ssr/dynamic-nested-remote/src/components/Content.tsx b/apps/modernjs-ssr/dynamic-nested-remote/src/components/Content.tsx index 7d15ec26f64..4c811e8e6ad 100644 --- a/apps/modernjs-ssr/dynamic-nested-remote/src/components/Content.tsx +++ b/apps/modernjs-ssr/dynamic-nested-remote/src/components/Content.tsx @@ -1,6 +1,7 @@ import React from 'react'; import Button from 'antd/lib/button'; import { + getInstance, registerRemotes, loadRemote, } from '@module-federation/modern-js/runtime'; @@ -15,6 +16,7 @@ registerRemotes([ ]); const RemoteSSRComponent = createLazyComponent({ + instance: getInstance(), loader: () => loadRemote('dynamic_remote'), loading: 'loading...', fallback: ({ error }) => { diff --git a/apps/modernjs-ssr/host/src/routes/dynamic-remote/page.tsx b/apps/modernjs-ssr/host/src/routes/dynamic-remote/page.tsx index d7b149ade63..f53a8164863 100644 --- a/apps/modernjs-ssr/host/src/routes/dynamic-remote/page.tsx +++ b/apps/modernjs-ssr/host/src/routes/dynamic-remote/page.tsx @@ -1,5 +1,6 @@ import React, { useState, Suspense } from 'react'; import { + getInstance, loadRemote, registerRemotes, } from '@module-federation/modern-js/runtime'; @@ -13,6 +14,7 @@ registerRemotes([ ]); const RemoteSSRComponent = createLazyComponent({ + instance: getInstance(), loader: () => loadRemote('dynamic_remote'), loading: 'loading...', fallback: ({ error }) => { diff --git a/apps/modernjs-ssr/nested-remote/src/routes/page.tsx b/apps/modernjs-ssr/nested-remote/src/routes/page.tsx index d5967725f6b..a40ffd61f0e 100644 --- a/apps/modernjs-ssr/nested-remote/src/routes/page.tsx +++ b/apps/modernjs-ssr/nested-remote/src/routes/page.tsx @@ -1,9 +1,11 @@ +import { getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent } from '@module-federation/modern-js/react'; import Content from '../components/Content'; import './index.css'; const RemoteSSRComponent = createLazyComponent({ + instance: getInstance(), loader: () => import('remote/Button'), loading: 'loading...', export: 'Button', diff --git a/apps/website-new/docs/en/guide/framework/modernjs.mdx b/apps/website-new/docs/en/guide/framework/modernjs.mdx index c6ac94b3edb..5b388dfe19e 100644 --- a/apps/website-new/docs/en/guide/framework/modernjs.mdx +++ b/apps/website-new/docs/en/guide/framework/modernjs.mdx @@ -194,9 +194,11 @@ export default Index; In the consumer, we need to use `createLazyComponent` to load the remote component and fetch data. ```tsx +import { getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent, ERROR_TYPE } from '@module-federation/modern-js/react'; const List = createLazyComponent({ + instance: getInstance(), loader: () => { return import('remote/List'); }, @@ -302,7 +304,7 @@ In addition to exporting [MF Runtime](../basic/runtime), `@module-federation/mod To prevent conflicts with Shared modules, you need to import them as follows: ```ts -import { loadRemote } from '@module-federation/modern-js/runtime'; +import { loadRemote, getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent, wrapNoSSR } from '@module-federation/modern-js/react'; ``` @@ -317,6 +319,7 @@ declare function createLazyComponent( ): (props: ComponentType) => React.JSX.Element; type CreateLazyComponentOptions = { + instance: ReturnType; loader: () => Promise; loading: React.ReactNode; fallback: ReactNode | ((errorInfo: ErrorInfo) => ReactNode); @@ -351,9 +354,11 @@ This function supports loading components and also provides the following capabi ```tsx import React, { FC, memo, useEffect } from 'react'; +import { getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent, ERROR_TYPE } from '@module-federation/modern-js/react'; const LazyComponent = createLazyComponent({ + instance: getInstance(), loader: () => import('remote/Image'), loading:
loading...
, fallback: ({error,errorType,dataFetchMapKey}) => { @@ -431,9 +436,11 @@ Wraps a component so that it does not render in SSR scenarios. Usage example: ```tsx +import { getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent, wrapNoSSR } from '@module-federation/modern-js/react'; const LazyComponent = wrapNoSSR(createLazyComponent)({ + instance: getInstance(), loader: () => { return import('remote/Content'); }, diff --git a/apps/website-new/docs/en/practice/frameworks/modern/dynamic-remote.mdx b/apps/website-new/docs/en/practice/frameworks/modern/dynamic-remote.mdx index 2c1036f0ba0..7d12548f33a 100644 --- a/apps/website-new/docs/en/practice/frameworks/modern/dynamic-remote.mdx +++ b/apps/website-new/docs/en/practice/frameworks/modern/dynamic-remote.mdx @@ -147,7 +147,7 @@ export const loader = async ({ request }: LoaderFunctionArgs): Promise import('remote/Image'), loading: 'loading...', export: 'default', @@ -176,6 +177,7 @@ const Index = () => { const DynamicRemoteSSRComponents = dataLoader.providerList.map(item => { const { id } = item; const Com = createLazyComponent({ + instance: getInstance(), loader: () => loadRemote(id), loading: 'loading...', fallback: ({ error }) => { diff --git a/apps/website-new/docs/en/practice/frameworks/modern/index.mdx b/apps/website-new/docs/en/practice/frameworks/modern/index.mdx index c08082f42e6..c9cbe541bdd 100644 --- a/apps/website-new/docs/en/practice/frameworks/modern/index.mdx +++ b/apps/website-new/docs/en/practice/frameworks/modern/index.mdx @@ -254,10 +254,12 @@ This is because the producer's style files cannot be injected into the correspon This issue can be solved by using the [createremotessrcomponent](../../../guide/framework/modernjs#createremotessrcomponent) provided by `@module-federation/modern-js`. ```tsx title='page.tsx' +import { getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent } from '@module-federation/modern-js/react' import './index.css'; const RemoteSSRComponent = createLazyComponent({ + instance: getInstance(), loader: () => import('remote/Image'), loading: 'loading...', export: 'default', diff --git a/apps/website-new/docs/zh/guide/framework/modernjs.mdx b/apps/website-new/docs/zh/guide/framework/modernjs.mdx index bc3fd65c533..8a6cd932ab9 100644 --- a/apps/website-new/docs/zh/guide/framework/modernjs.mdx +++ b/apps/website-new/docs/zh/guide/framework/modernjs.mdx @@ -195,9 +195,11 @@ export default Index; 在消费者中,我们需要通过 `createLazyComponent` 来加载远程组件,并获取数据。 ```tsx +import { getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent, ERROR_TYPE } from '@module-federation/modern-js/react'; const List = createLazyComponent({ + instance: getInstance(), loader: () => { return import('remote/List'); }, @@ -304,7 +306,7 @@ export async function loader({ params }) { 为防止与 Shared 冲突,需要通过下列方式引用。 ```ts -import { loadRemote } from '@module-federation/modern-js/runtime'; +import { loadRemote, getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent, wrapNoSSR } from '@module-federation/modern-js/react'; ``` @@ -319,6 +321,7 @@ declare function createLazyComponent( ): (props: ComponentType) => React.JSX.Element; type CreateLazyComponentOptions = { + instance: ReturnType; loader: () => Promise; loading: React.ReactNode; fallback: ReactNode | ((errorInfo: ErrorInfo) => ReactNode); @@ -353,9 +356,11 @@ type ErrorInfo = { ```tsx import React, { FC, memo, useEffect } from 'react'; +import { getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent, ERROR_TYPE } from '@module-federation/modern-js/react'; const LazyComponent = createLazyComponent({ + instance: getInstance(), loader: () => import('remote/Image'), loading:
loading...
, fallback: ({error,errorType,dataFetchMapKey}) => { @@ -433,9 +438,11 @@ declare function wrapNoSSR( 使用示例: ```tsx +import { getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent, wrapNoSSR } from '@module-federation/modern-js/runtime'; const LazyComponent = wrapNoSSR(createLazyComponent)({ + instance: getInstance(), loader: () => { return import('remote/Content'); }, diff --git a/apps/website-new/docs/zh/practice/frameworks/modern/dynamic-remote.mdx b/apps/website-new/docs/zh/practice/frameworks/modern/dynamic-remote.mdx index e28c71aeb72..649b8e44960 100644 --- a/apps/website-new/docs/zh/practice/frameworks/modern/dynamic-remote.mdx +++ b/apps/website-new/docs/zh/practice/frameworks/modern/dynamic-remote.mdx @@ -144,7 +144,7 @@ export const loader = async ({ request }: LoaderFunctionArgs): Promise import('remote/Image'), loading: 'loading...', export: 'default', @@ -173,6 +174,7 @@ const Index = () => { const DynamicRemoteSSRComponents = dataLoader.providerList.map(item => { const { id } = item; const Com = createLazyComponent({ + instance: getInstance(), loader: () => loadRemote(id), loading: 'loading...', fallback: ({ error }) => { diff --git a/apps/website-new/docs/zh/practice/frameworks/modern/index.mdx b/apps/website-new/docs/zh/practice/frameworks/modern/index.mdx index c90b8ddf3e8..6e7408f1b91 100644 --- a/apps/website-new/docs/zh/practice/frameworks/modern/index.mdx +++ b/apps/website-new/docs/zh/practice/frameworks/modern/index.mdx @@ -257,10 +257,12 @@ export default Index; 修改消费者引用生产者处的代码(`src/routes/page.tsx`): ```tsx title='page.tsx' +import { getInstance } from '@module-federation/modern-js/runtime'; import { createLazyComponent } from '@module-federation/modern-js/react' import './index.css'; const RemoteSSRComponent = createLazyComponent({ + instance: getInstance(), loader: () => import('remote/Image'), loading: 'loading...', export: 'default', diff --git a/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx index f36545412f0..dd12e298982 100644 --- a/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx +++ b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx @@ -20,23 +20,23 @@ import { import type { ErrorInfo } from './AwaitDataFetch'; import type { DataFetchParams, NoSSRRemoteInfo } from './types'; -import type { FederationHost } from '@module-federation/runtime'; +import type { FederationHost, getInstance } from '@module-federation/runtime'; export type IProps = { id: string; + instance: ReturnType; injectScript?: boolean; injectLink?: boolean; - runtime: typeof import('@module-federation/runtime'); }; export type CreateLazyComponentOptions = { loader: () => Promise; + instance: ReturnType; loading: React.ReactNode; fallback: ReactNode | ((errorInfo: ErrorInfo) => ReactNode); export?: E; dataFetchParams?: DataFetchParams; noSSR?: boolean; - runtime: typeof import('@module-federation/runtime'); }; type ReactKey = { key?: React.Key | null }; @@ -89,7 +89,7 @@ export function collectSSRAssets(options: IProps) { } = typeof options === 'string' ? { id: options } : options; const links: React.ReactNode[] = []; const scripts: React.ReactNode[] = []; - const instance = options.runtime.getInstance(); + const instance = options.instance; if (!instance || (!injectLink && !injectScript)) { return [...scripts, ...links]; } @@ -192,10 +192,10 @@ function getServerNeedRemoteInfo( export function createLazyComponent( options: CreateLazyComponentOptions, ) { - const { runtime } = options; - if (!runtime?.getInstance) { + const { instance } = options; + if (!instance) { throw new Error( - 'runtime is required if used in "@module-federation/bridge-react"!', + 'instance is required if used in "@module-federation/bridge-react"!', ); } type ComponentType = T[E] extends (...args: any) => any @@ -219,7 +219,6 @@ export function createLazyComponent( const getData = async (noSSR?: boolean) => { let loadedRemoteInfo: ReturnType; let moduleId: string; - const instance = runtime.getInstance(); try { const m = await callLoader(); moduleId = m && m[Symbol.for('mf_module_id')]; @@ -271,7 +270,6 @@ export function createLazyComponent( const LazyComponent = React.lazy(async () => { const m = await callLoader(); const moduleId = m && m[Symbol.for('mf_module_id')]; - const instance = runtime.getInstance()!; const loadedRemoteInfo = getLoadedRemoteInfos(moduleId, instance); loadedRemoteInfo?.snapshot; const dataFetchMapKey = loadedRemoteInfo @@ -289,7 +287,7 @@ export function createLazyComponent( const assets = collectSSRAssets({ id: moduleId, - runtime, + instance, }); const Com = m[exportName] as React.FC; diff --git a/packages/modernjs/src/react/index.ts b/packages/modernjs/src/react/index.ts index 497b387b447..a4b887223d0 100644 --- a/packages/modernjs/src/react/index.ts +++ b/packages/modernjs/src/react/index.ts @@ -1,46 +1,8 @@ -import * as mfRuntime from '@module-federation/enhanced/runtime'; -// eslint-disable-next-line @nx/enforce-module-boundaries -import { +export { ERROR_TYPE, - createLazyComponent as rawCreateLazyComponent, - collectSSRAssets as rawCollectSsrAssets, + createLazyComponent, + collectSSRAssets, + wrapNoSSR, } from '@module-federation/bridge-react'; -import type { - CollectSSRAssetsOptions, - CreateLazyComponentOptions, -} from '@module-federation/bridge-react'; - -export { ERROR_TYPE }; - -type NewCreateLazyComponentOptions = Omit< - CreateLazyComponentOptions, - 'runtime' ->; -type NewCreateLazyComponent = ( - options: NewCreateLazyComponentOptions, -) => ReturnType>; - -export const createLazyComponent: NewCreateLazyComponent = (options) => { - return rawCreateLazyComponent({ ...options, runtime: mfRuntime }); -}; - -export const collectSSRAssets: ( - options: Omit, -) => ReturnType = ( - options: Omit, -) => { - return rawCollectSsrAssets({ ...options, runtime: mfRuntime }); -}; - -export function wrapNoSSR( - createLazyComponentFn: typeof createLazyComponent, -): ( - options: Omit, 'noSSR'>, -) => ReturnType> { - return (options: Omit, 'noSSR'>) => { - return createLazyComponentFn({ ...options, noSSR: true }); - }; -} - export type { DataFetchParams } from '@module-federation/bridge-react'; From 2096b66a79b4b9ef0e797059e676ea825b3658e4 Mon Sep 17 00:00:00 2001 From: 2heal1 Date: Tue, 24 Jun 2025 22:22:12 +0800 Subject: [PATCH 07/16] feat: add prefetch and cache api --- .../components/BasicComponent/index.data.ts | 6 +- packages/bridge/bridge-react/package.json | 3 +- packages/bridge/bridge-react/src/index.ts | 10 + .../src/lazy/createLazyComponent.tsx | 4 +- .../bridge-react/src/lazy/data-fetch/cache.ts | 296 ++++++++++++++++++ .../data-fetch-server-middleware.ts | 7 +- .../bridge-react/src/lazy/data-fetch/index.ts | 13 + .../src/lazy/data-fetch/prefetch.ts | 97 ++++++ .../bridge/bridge-react/src/lazy/index.ts | 15 +- .../bridge/bridge-react/src/lazy/types.ts | 26 ++ .../bridge/bridge-react/src/lazy/utils.ts | 27 +- packages/bridge/bridge-react/tsconfig.json | 2 +- packages/modernjs/src/react/index.ts | 14 +- packages/runtime-core/src/helpers.ts | 8 +- packages/runtime/src/helpers.ts | 9 +- pnpm-lock.yaml | 72 +---- 16 files changed, 524 insertions(+), 85 deletions(-) create mode 100644 packages/bridge/bridge-react/src/lazy/data-fetch/cache.ts create mode 100644 packages/bridge/bridge-react/src/lazy/data-fetch/prefetch.ts diff --git a/apps/modern-component-data-fetch/provider/src/components/BasicComponent/index.data.ts b/apps/modern-component-data-fetch/provider/src/components/BasicComponent/index.data.ts index 5586247ab1c..e3ce4738e26 100644 --- a/apps/modern-component-data-fetch/provider/src/components/BasicComponent/index.data.ts +++ b/apps/modern-component-data-fetch/provider/src/components/BasicComponent/index.data.ts @@ -1,8 +1,10 @@ +import { cache } from '@module-federation/modern-js/react'; + export type Data = { data: string; }; -export const fetchData = async (): Promise => { +export const fetchData = cache(async (): Promise => { return new Promise((resolve) => { setTimeout(() => { resolve({ @@ -10,4 +12,4 @@ export const fetchData = async (): Promise => { }); }, 1000); }); -}; +}); diff --git a/packages/bridge/bridge-react/package.json b/packages/bridge/bridge-react/package.json index 2b0f8e6450a..eba28407211 100644 --- a/packages/bridge/bridge-react/package.json +++ b/packages/bridge/bridge-react/package.json @@ -99,7 +99,8 @@ "dependencies": { "@module-federation/bridge-shared": "workspace:*", "@module-federation/sdk": "workspace:*", - "react-error-boundary": "^4.1.2" + "react-error-boundary": "^4.1.2", + "lru-cache": "^10.4.3" }, "peerDependencies": { "react": ">=16.9.0", diff --git a/packages/bridge/bridge-react/src/index.ts b/packages/bridge/bridge-react/src/index.ts index 673a76ade49..3da407c8672 100644 --- a/packages/bridge/bridge-react/src/index.ts +++ b/packages/bridge/bridge-react/src/index.ts @@ -15,6 +15,14 @@ export { callDataFetch, setSSREnv, autoFetchDataPlugin, + CacheSize, + CacheTime, + configureCache, + generateKey, + cache, + revalidateTag, + clearStore, + prefetch, } from './lazy'; export type { CreateRootOptions, Root } from './provider/versions/legacy'; @@ -30,4 +38,6 @@ export type { NoSSRRemoteInfo, CollectSSRAssetsOptions, CreateLazyComponentOptions, + CacheStatus, + CacheStatsInfo, } from './lazy'; diff --git a/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx index dd12e298982..4ec12eaa451 100644 --- a/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx +++ b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx @@ -194,9 +194,7 @@ export function createLazyComponent( ) { const { instance } = options; if (!instance) { - throw new Error( - 'instance is required if used in "@module-federation/bridge-react"!', - ); + throw new Error('instance is required for createLazyComponent!'); } type ComponentType = T[E] extends (...args: any) => any ? Parameters[0] extends undefined diff --git a/packages/bridge/bridge-react/src/lazy/data-fetch/cache.ts b/packages/bridge/bridge-react/src/lazy/data-fetch/cache.ts new file mode 100644 index 00000000000..377ec86c482 --- /dev/null +++ b/packages/bridge/bridge-react/src/lazy/data-fetch/cache.ts @@ -0,0 +1,296 @@ +import { LRUCache } from 'lru-cache'; +import { getDataFetchCache } from '../utils'; + +import type { + CacheConfig, + CacheItem, + DataFetch, + DataFetchParams, +} from '../types'; + +export const CacheSize = { + KB: 1024, + MB: 1024 * 1024, + GB: 1024 * 1024 * 1024, +} as const; + +export const CacheTime = { + SECOND: 1000, + MINUTE: 60 * 1000, + HOUR: 60 * 60 * 1000, + DAY: 24 * 60 * 60 * 1000, + WEEK: 7 * 24 * 60 * 60 * 1000, + MONTH: 30 * 24 * 60 * 60 * 1000, +} as const; + +export type CacheStatus = 'hit' | 'stale' | 'miss'; + +export interface CacheStatsInfo { + status: CacheStatus; + key: string | symbol; + params: DataFetchParams; + result: any; +} + +interface CacheOptions { + tag?: string | string[]; + maxAge?: number; + revalidate?: number; + getKey?: (...args: Args) => string; + customKey?: (options: { + params: Args; + fn: (...args: Args) => any; + generatedKey: string; + }) => string | symbol; + onCache?: (info: CacheStatsInfo) => boolean; +} + +function getTagKeyMap() { + const dataFetchCache = getDataFetchCache(); + if (!dataFetchCache || !dataFetchCache.tagKeyMap) { + const tagKeyMap = new Map>(); + globalThis.__MF_DATA_FETCH_CACHE__ ||= {}; + globalThis.__MF_DATA_FETCH_CACHE__.tagKeyMap = tagKeyMap; + return tagKeyMap; + } + return dataFetchCache.tagKeyMap; +} + +function addTagKeyRelation(tag: string, key: string) { + const tagKeyMap = getTagKeyMap(); + let keys = tagKeyMap.get(tag); + if (!keys) { + keys = new Set(); + tagKeyMap.set(tag, keys); + } + keys.add(key); +} + +function getCacheConfig() { + const dataFetchCache = getDataFetchCache(); + if (!dataFetchCache || !dataFetchCache.cacheConfig) { + const cacheConfig: CacheConfig = { + maxSize: CacheSize.GB, + }; + globalThis.__MF_DATA_FETCH_CACHE__ ||= {}; + globalThis.__MF_DATA_FETCH_CACHE__.cacheConfig = cacheConfig; + return cacheConfig; + } + return dataFetchCache.cacheConfig; +} + +export function configureCache(config: CacheConfig): void { + const cacheConfig = getCacheConfig(); + Object.assign(cacheConfig, config); +} + +function getLRUCache() { + const dataFetchCache = getDataFetchCache(); + const cacheConfig = getCacheConfig(); + + if (!dataFetchCache || !dataFetchCache.cacheStore) { + const cacheStore = new LRUCache>>({ + maxSize: cacheConfig.maxSize ?? CacheSize.GB, + sizeCalculation: (value: Map>): number => { + if (!value.size) { + return 1; + } + + let size = 0; + for (const [k, item] of value.entries()) { + size += k.length * 2; + size += estimateObjectSize(item.data); + size += 8; + } + return size; + }, + updateAgeOnGet: true, + updateAgeOnHas: true, + }); + globalThis.__MF_DATA_FETCH_CACHE__ ||= {}; + globalThis.__MF_DATA_FETCH_CACHE__.cacheStore = cacheStore; + return cacheStore; + } + + return dataFetchCache.cacheStore; +} + +function estimateObjectSize(data: unknown): number { + const type = typeof data; + + if (type === 'number') return 8; + if (type === 'boolean') return 4; + if (type === 'string') return Math.max((data as string).length * 2, 1); + if (data === null || data === undefined) return 1; + + if (ArrayBuffer.isView(data)) { + return Math.max(data.byteLength, 1); + } + + if (Array.isArray(data)) { + return Math.max( + data.reduce((acc, item) => acc + estimateObjectSize(item), 0), + 1, + ); + } + + if (data instanceof Map || data instanceof Set) { + return 1024; + } + + if (data instanceof Date) { + return 8; + } + + if (type === 'object') { + return Math.max( + Object.entries(data).reduce( + (acc, [key, value]) => acc + key.length * 2 + estimateObjectSize(value), + 0, + ), + 1, + ); + } + + return 1; +} + +export function generateKey(dataFetchOptions: DataFetchParams): string { + return JSON.stringify(dataFetchOptions, (_, value) => { + if (value && typeof value === 'object' && !Array.isArray(value)) { + return Object.keys(value) + .sort() + .reduce((result: Record, key) => { + result[key] = value[key]; + return result; + }, {}); + } + return value; + }); +} + +export function cache( + fn: DataFetch, + options?: CacheOptions, +): DataFetch { + const { + tag = 'default', + maxAge = CacheTime.MINUTE * 5, + revalidate = 0, + onCache, + getKey, + } = options || {}; + + const tags = Array.isArray(tag) ? tag : [tag]; + + return async (dataFetchOptions) => { + // if downgrade, skip cache + if (dataFetchOptions.isDowngrade || !dataFetchOptions._id) { + return fn(dataFetchOptions); + } + const store = getLRUCache(); + + const now = Date.now(); + const storeKey = dataFetchOptions._id; + const cacheKey = getKey + ? getKey(dataFetchOptions) + : generateKey(dataFetchOptions); + + tags.forEach((t) => addTagKeyRelation(t, cacheKey)); + + let cacheStore = store.get(cacheKey); + if (!cacheStore) { + cacheStore = new Map(); + } + + const cached = cacheStore.get(storeKey); + if (cached) { + const age = now - cached.timestamp; + + if (age < maxAge) { + if (onCache) { + const useCache = onCache({ + status: 'hit', + key: cacheKey, + params: dataFetchOptions, + result: cached.data, + }); + if (!useCache) { + return fn(dataFetchOptions); + } + } + return cached.data; + } + + if (revalidate > 0 && age < maxAge + revalidate) { + if (onCache) { + onCache({ + status: 'stale', + key: cacheKey, + params: dataFetchOptions, + result: cached.data, + }); + } + + if (!cached.isRevalidating) { + cached.isRevalidating = true; + Promise.resolve().then(async () => { + try { + const newData = await fn(dataFetchOptions); + cacheStore!.set(storeKey, { + data: newData, + timestamp: Date.now(), + isRevalidating: false, + }); + + store.set(cacheKey, cacheStore!); + } catch (error) { + cached.isRevalidating = false; + console.error('Background revalidation failed:', error); + } + }); + } + return cached.data; + } + } + + const data = await fn(dataFetchOptions); + cacheStore.set(storeKey, { + data, + timestamp: now, + isRevalidating: false, + }); + store.set(cacheKey, cacheStore); + + if (onCache) { + onCache({ + status: 'miss', + key: cacheKey, + params: dataFetchOptions, + result: data, + }); + } + + return data; + }; +} + +export function revalidateTag(tag: string): void { + const tagKeyMap = getTagKeyMap(); + const keys = tagKeyMap.get(tag); + const lruCache = getLRUCache(); + if (keys) { + keys.forEach((key) => { + lruCache?.delete(key); + }); + } +} + +export function clearStore(): void { + const lruCache = getLRUCache(); + const tagKeyMap = getTagKeyMap(); + + lruCache?.clear(); + delete globalThis.__MF_DATA_FETCH_CACHE__?.cacheStore; + tagKeyMap.clear(); +} diff --git a/packages/bridge/bridge-react/src/lazy/data-fetch/data-fetch-server-middleware.ts b/packages/bridge/bridge-react/src/lazy/data-fetch/data-fetch-server-middleware.ts index d314665e0eb..511fd72cbf5 100644 --- a/packages/bridge/bridge-react/src/lazy/data-fetch/data-fetch-server-middleware.ts +++ b/packages/bridge/bridge-react/src/lazy/data-fetch/data-fetch-server-middleware.ts @@ -159,6 +159,7 @@ const dataFetchServerMiddleware: MiddlewareHandler = async (ctx, next) => { const callFetchDataPromise = fetchData(dataFetchId, { ...params, isDowngrade: !remoteInfo, + _id: dataFetchId, }); const wrappedPromise = wrapSetTimeout( callFetchDataPromise, @@ -178,7 +179,11 @@ const dataFetchServerMiddleware: MiddlewareHandler = async (ctx, next) => { throw new Error('host instance not found!'); } const dataFetchFn = await loadDataFetchModule(hostInstance, remoteId); - const data = await dataFetchFn({ ...params, isDowngrade: !remoteInfo }); + const data = await dataFetchFn({ + ...params, + isDowngrade: !remoteInfo, + _id: dataFetchId, + }); logger.log('fetch data from server, loadDataFetchModule res: ', data); return ctx.json(data); } catch (e) { diff --git a/packages/bridge/bridge-react/src/lazy/data-fetch/index.ts b/packages/bridge/bridge-react/src/lazy/data-fetch/index.ts index 54f27098440..1c696537ae7 100644 --- a/packages/bridge/bridge-react/src/lazy/data-fetch/index.ts +++ b/packages/bridge/bridge-react/src/lazy/data-fetch/index.ts @@ -1,2 +1,15 @@ export { callDataFetch } from './call-data-fetch'; export { injectDataFetch } from './inject-data-fetch'; +export { + CacheSize, + CacheTime, + configureCache, + generateKey, + cache, + revalidateTag, + clearStore, +} from './cache'; + +export type { CacheStatus, CacheStatsInfo } from './cache'; + +export { prefetch } from './prefetch'; diff --git a/packages/bridge/bridge-react/src/lazy/data-fetch/prefetch.ts b/packages/bridge/bridge-react/src/lazy/data-fetch/prefetch.ts new file mode 100644 index 00000000000..92cf45748b0 --- /dev/null +++ b/packages/bridge/bridge-react/src/lazy/data-fetch/prefetch.ts @@ -0,0 +1,97 @@ +import type { getInstance } from '@module-federation/runtime'; +import { + getDataFetchInfo, + getDataFetchMap, + getDataFetchMapKey, +} from '../utils'; +import helpers from '@module-federation/runtime/helpers'; +import { DataFetchParams } from '../types'; + +type PrefetchOptions = { + id: string; + instance: ReturnType; + dataFetchParams?: DataFetchParams; + preloadComponentResource?: boolean; +}; + +export async function prefetch(options: PrefetchOptions) { + const { instance, id, dataFetchParams, preloadComponentResource } = options; + if (!id) { + throw new Error('id is required for prefetch!'); + } + if (!instance) { + throw new Error('instance is required for prefetch!'); + } + const matchedRemoteInfo = helpers.utils.matchRemoteWithNameAndExpose( + instance.options.remotes, + id, + ); + if (!matchedRemoteInfo) { + throw new Error(`Can not found '${id}' in instance.options.remotes!`); + } + const { remote, expose } = matchedRemoteInfo; + const { remoteSnapshot, globalSnapshot } = + await instance.snapshotHandler.loadRemoteSnapshotInfo({ + moduleInfo: remote, + }); + + if (preloadComponentResource) { + const remoteInfo = helpers.utils.getRemoteInfo(remote); + + instance.remoteHandler.hooks.lifecycle.generatePreloadAssets.emit({ + origin: instance, + preloadOptions: { + remote, + preloadConfig: { + nameOrAlias: remote.name, + exposes: [expose], + }, + }, + remote, + remoteInfo, + globalSnapshot, + remoteSnapshot, + }); + } + + const dataFetchMap = getDataFetchMap(); + if (!dataFetchMap) { + return; + } + const dataFetchInfo = getDataFetchInfo({ + name: remote.name, + alias: remote.alias, + id, + remoteSnapshot, + }); + + const dataFetchMapKey = getDataFetchMapKey(dataFetchInfo, { + name: instance.name, + version: instance.options.version, + }); + + if (!dataFetchMapKey) { + return; + } + + const dataFetchItem = dataFetchMap[dataFetchMapKey]; + if (!dataFetchItem) { + return; + } + + const [getDataFetchGetter, _type, getDataFetchPromise] = dataFetchItem[0]; + + if (!getDataFetchPromise) { + if (!getDataFetchGetter) { + return; + } + const _getDataFetchPromise = getDataFetchGetter(); + + _getDataFetchPromise.then((dataFetchFn) => { + return dataFetchFn({ + ...dataFetchParams, + isDowngrade: false, + }); + }); + } +} diff --git a/packages/bridge/bridge-react/src/lazy/index.ts b/packages/bridge/bridge-react/src/lazy/index.ts index d9d4a9a4481..ee03156077c 100644 --- a/packages/bridge/bridge-react/src/lazy/index.ts +++ b/packages/bridge/bridge-react/src/lazy/index.ts @@ -11,8 +11,21 @@ export { createLazyComponent, collectSSRAssets } from './createLazyComponent'; export { wrapNoSSR } from './wrapNoSSR'; -export { injectDataFetch, callDataFetch } from './data-fetch'; +export { + injectDataFetch, + callDataFetch, + CacheSize, + CacheTime, + configureCache, + generateKey, + cache, + revalidateTag, + clearStore, + prefetch, +} from './data-fetch'; export { setSSREnv } from './utils'; export { autoFetchDataPlugin }; + +export type { CacheStatus, CacheStatsInfo } from './data-fetch'; diff --git a/packages/bridge/bridge-react/src/lazy/types.ts b/packages/bridge/bridge-react/src/lazy/types.ts index 5da868a0719..36a4da055f9 100644 --- a/packages/bridge/bridge-react/src/lazy/types.ts +++ b/packages/bridge/bridge-react/src/lazy/types.ts @@ -1,4 +1,5 @@ import { MF_DATA_FETCH_TYPE, MF_DATA_FETCH_STATUS } from './constant'; +import type { LRUCache } from 'lru-cache'; export type dataFetchFunctionOptions = [ id?: string, @@ -13,10 +14,18 @@ declare global { var FEDERATION_SSR: boolean | undefined; var _mfFSHref: string | undefined; var _mfDataFetch: Array | undefined; + var __MF_DATA_FETCH_CACHE__: MF_DATA_FETCH_CACHE | undefined; +} + +export interface CacheItem { + data: T; + timestamp: number; + isRevalidating?: boolean; } export type DataFetchParams = { isDowngrade: boolean; + _id?: string; } & Record; export type DataFetch = (params: DataFetchParams) => Promise; @@ -30,6 +39,7 @@ export type MF_DATA_FETCH_MAP_VALUE = [ [ // getDataFetchGetter () => Promise>, + // data fetch type MF_DATA_FETCH_TYPE, // getDataFetchPromise Promise>?, @@ -47,3 +57,19 @@ export type NoSSRRemoteInfo = { ssrRemoteEntry: string; globalName: string; }; + +export interface CacheConfig { + maxSize?: number; + unstable_shouldDisable?: ({ + request, + }: { + request: Request; + }) => boolean | Promise; +} + +// key is the id, default is the same with dataFetchMapId, but it can be custom by passing dataFetchParams.id +export type MF_DATA_FETCH_CACHE = { + cacheStore?: LRUCache>>; + tagKeyMap?: Map>; + cacheConfig?: CacheConfig; +}; diff --git a/packages/bridge/bridge-react/src/lazy/utils.ts b/packages/bridge/bridge-react/src/lazy/utils.ts index d4333401cf6..7c80ce98a39 100644 --- a/packages/bridge/bridge-react/src/lazy/utils.ts +++ b/packages/bridge/bridge-react/src/lazy/utils.ts @@ -17,8 +17,10 @@ import type { NoSSRRemoteInfo, MF_SSR_DOWNGRADE, MF_DATA_FETCH_MAP_VALUE_PROMISE_SET, + MF_DATA_FETCH_CACHE, } from './types'; import type { FederationHost } from '@module-federation/runtime'; +import { clearStore } from './data-fetch/cache'; export const getDataFetchInfo = ({ name, @@ -83,9 +85,14 @@ export function getDataFetchMap() { return globalThis.__MF_DATA_FETCH_MAP__ as MF_DATA_FETCH_MAP; } +export function getDataFetchCache() { + return globalThis.__MF_DATA_FETCH_CACHE__ as MF_DATA_FETCH_CACHE; +} + export const flushDataFetch = () => { globalThis.__MF_DATA_FETCH_MAP__ = {}; globalThis[DOWNGRADE_KEY] = undefined; + clearStore(); }; export function setDataFetchItemLoadedStatus(id: string) { @@ -137,7 +144,10 @@ export async function fetchData( if (!fetchDataFn) { return; } - return fetchDataFn(params); + return fetchDataFn({ + ...params, + _id: id, + }); }; if (isBrowserEnv()) { const dataFetchItem = getDataFetchItem(id); @@ -158,13 +168,11 @@ export async function fetchData( } const mfDowngrade = getDowngradeTag(); - if (mfDowngrade) { - if (typeof mfDowngrade === 'boolean') { - return callDowngrade(id, { ...params, isDowngrade: true }); - } - if (mfDowngrade.includes(id)) { - return callDowngrade(id, { ...params, isDowngrade: true }); - } + if ( + mfDowngrade && + (typeof mfDowngrade === 'boolean' || mfDowngrade.includes(id)) + ) { + return callDowngrade(id, { ...params, isDowngrade: true }); } let res; @@ -263,10 +271,11 @@ export async function callDowngrade( const dataFetchType = mfDataFetch[0][1]; if (dataFetchType === MF_DATA_FETCH_TYPE.FETCH_CLIENT) { try { - mfDataFetch[0][0]().then((getDataFetchFn) => { + mfDataFetch[0][0]().then(async (getDataFetchFn) => { return getDataFetchFn({ ...params, isDowngrade: true, + _id: id, }).then((data) => { mfDataFetch[2] = MF_DATA_FETCH_STATUS.LOADED; res && res(data); diff --git a/packages/bridge/bridge-react/tsconfig.json b/packages/bridge/bridge-react/tsconfig.json index 0d9967f6a9e..0846dd1f090 100644 --- a/packages/bridge/bridge-react/tsconfig.json +++ b/packages/bridge/bridge-react/tsconfig.json @@ -9,7 +9,7 @@ "declarationDir": "./dist/types", "rootDir": "./src", "module": "commonjs", - "target": "es5", + "target": "es2015", /* Linting */ "noUnusedLocals": true, diff --git a/packages/modernjs/src/react/index.ts b/packages/modernjs/src/react/index.ts index a4b887223d0..e2540e2e2df 100644 --- a/packages/modernjs/src/react/index.ts +++ b/packages/modernjs/src/react/index.ts @@ -3,6 +3,18 @@ export { createLazyComponent, collectSSRAssets, wrapNoSSR, + CacheSize, + CacheTime, + configureCache, + generateKey, + cache, + revalidateTag, + clearStore, + prefetch, } from '@module-federation/bridge-react'; -export type { DataFetchParams } from '@module-federation/bridge-react'; +export type { + DataFetchParams, + CacheStatus, + CacheStatsInfo, +} from '@module-federation/bridge-react'; diff --git a/packages/runtime-core/src/helpers.ts b/packages/runtime-core/src/helpers.ts index 8f4560bb3ba..e8fc734ae03 100644 --- a/packages/runtime-core/src/helpers.ts +++ b/packages/runtime-core/src/helpers.ts @@ -18,7 +18,8 @@ import { Global, } from './global'; import { getRegisteredShare, getGlobalShareScope } from './utils/share'; - +import { getRemoteInfo, matchRemoteWithNameAndExpose } from './utils'; +import { preloadAssets } from './utils/preload'; interface IShareUtils { getRegisteredShare: typeof getRegisteredShare; getGlobalShareScope: typeof getGlobalShareScope; @@ -71,6 +72,11 @@ const GlobalUtils: IGlobalUtils = { export default { global: GlobalUtils, share: ShareUtils, + utils: { + matchRemoteWithNameAndExpose, + preloadAssets, + getRemoteInfo, + }, }; export type { IGlobalUtils, IShareUtils }; diff --git a/packages/runtime/src/helpers.ts b/packages/runtime/src/helpers.ts index ee21f6d2e5d..5a252c2846f 100644 --- a/packages/runtime/src/helpers.ts +++ b/packages/runtime/src/helpers.ts @@ -1,14 +1,21 @@ import { helpers } from '@module-federation/runtime-core'; import { getGlobalFederationInstance } from './utils'; + export type { IGlobalUtils, IShareUtils, } from '@module-federation/runtime-core'; export default { + ...helpers, global: { ...helpers.global, getGlobalFederationInstance, }, - share: helpers.share, +} as { + global: typeof helpers.global & { + getGlobalFederationInstance: typeof getGlobalFederationInstance; + }; + share: typeof helpers.share; + utils: typeof helpers.utils; }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1ad8b34d7a1..fdbca7307dc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2193,6 +2193,9 @@ importers: '@module-federation/sdk': specifier: workspace:* version: link:../../sdk + lru-cache: + specifier: ^10.4.3 + version: 10.4.3 react-error-boundary: specifier: ^4.1.2 version: 4.1.2(react@18.3.1) @@ -9867,9 +9870,9 @@ packages: tsconfig-paths: optional: true dependencies: - '@babel/parser': 7.27.2 - '@babel/traverse': 7.27.1 - '@babel/types': 7.27.1 + '@babel/parser': 7.27.0 + '@babel/traverse': 7.27.0 + '@babel/types': 7.27.0 '@modern-js/core': 2.67.6 '@modern-js/node-bundle-require': 2.67.6 '@modern-js/plugin': 2.67.6 @@ -9878,9 +9881,9 @@ packages: '@modern-js/plugin-v2': 2.67.6(react-dom@18.3.1)(react@18.3.1) '@modern-js/prod-server': 2.67.6(react-dom@18.3.1)(react@18.3.1) '@modern-js/rsbuild-plugin-esbuild': 2.67.6(@swc/core@1.7.26)(webpack-cli@5.1.4) - '@modern-js/server': 2.67.6(@babel/traverse@7.27.1)(@rsbuild/core@1.3.20)(react-dom@18.3.1)(react@18.3.1) + '@modern-js/server': 2.67.6(@babel/traverse@7.27.0)(@rsbuild/core@1.3.20)(react-dom@18.3.1)(react@18.3.1) '@modern-js/server-core': 2.67.6(react-dom@18.3.1)(react@18.3.1) - '@modern-js/server-utils': 2.67.6(@babel/traverse@7.27.1)(@rsbuild/core@1.3.20) + '@modern-js/server-utils': 2.67.6(@babel/traverse@7.27.0)(@rsbuild/core@1.3.20) '@modern-js/types': 2.67.6 '@modern-js/uni-builder': 2.67.6(@rspack/core@1.3.9)(esbuild@0.17.19)(styled-components@6.1.8)(typescript@5.0.4)(webpack-cli@5.1.4) '@modern-js/utils': 2.67.6 @@ -10654,26 +10657,6 @@ packages: - supports-color dev: true - /@modern-js/server-utils@2.67.6(@babel/traverse@7.27.1)(@rsbuild/core@1.3.20): - resolution: {integrity: sha512-q411M9JQjZ9NTeK6GgCjp4QbPlKegaVGqtaeJs1s3vLdwk4Rswdb+0ZK9EhisAoYkeh+ZtmUGRoHJEN6J//7xw==} - dependencies: - '@babel/core': 7.26.10 - '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.10) - '@babel/preset-env': 7.26.0(@babel/core@7.26.10) - '@babel/preset-react': 7.26.3(@babel/core@7.26.10) - '@babel/preset-typescript': 7.26.0(@babel/core@7.26.10) - '@modern-js/babel-compiler': 2.67.6 - '@modern-js/babel-plugin-module-resolver': 2.67.6 - '@modern-js/babel-preset': 2.67.6(@rsbuild/core@1.3.20) - '@modern-js/utils': 2.67.6 - '@swc/helpers': 0.5.17 - babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.26.10)(@babel/traverse@7.27.1) - transitivePeerDependencies: - - '@babel/traverse' - - '@rsbuild/core' - - supports-color - dev: true - /@modern-js/server@2.67.5(@babel/traverse@7.27.1)(@rsbuild/core@1.3.20)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-EeItN3EdOekrfm4Q1Ikzbg2WmeMTmyejuR7dx3dyXLMiM71471Y4MVi/lfDfKH2q8OUhXJpKbsToHaePi6Pnqg==} peerDependencies: @@ -10752,45 +10735,6 @@ packages: - utf-8-validate dev: true - /@modern-js/server@2.67.6(@babel/traverse@7.27.1)(@rsbuild/core@1.3.20)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-Qh7cojbn50tdRrlQhYeEfirEXgUcJo7k711uArXptZP7avaGi5I+Zop1VLnyflUkof+ljdrcFuOXzAIIMa9yXQ==} - peerDependencies: - devcert: ^1.2.2 - ts-node: ^10.1.0 - tsconfig-paths: '>= 3.0.0 || >= 4.0.0' - peerDependenciesMeta: - devcert: - optional: true - ts-node: - optional: true - tsconfig-paths: - optional: true - dependencies: - '@babel/core': 7.26.10 - '@babel/register': 7.25.7(@babel/core@7.26.10) - '@modern-js/runtime-utils': 2.67.6(react-dom@18.3.1)(react@18.3.1) - '@modern-js/server-core': 2.67.6(react-dom@18.3.1)(react@18.3.1) - '@modern-js/server-utils': 2.67.6(@babel/traverse@7.27.1)(@rsbuild/core@1.3.20) - '@modern-js/types': 2.67.6 - '@modern-js/utils': 2.67.6 - '@swc/helpers': 0.5.17 - axios: 1.8.2 - connect-history-api-fallback: 2.0.0 - http-compression: 1.0.6 - minimatch: 3.1.2 - path-to-regexp: 6.3.0 - ws: 8.18.0 - transitivePeerDependencies: - - '@babel/traverse' - - '@rsbuild/core' - - bufferutil - - debug - - react - - react-dom - - supports-color - - utf-8-validate - dev: true - /@modern-js/storybook-builder@2.67.6(@rspack/core@1.3.9)(@types/react-dom@18.3.0)(@types/react@18.2.79)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1)(react@18.3.1)(styled-components@6.1.8)(typescript@5.0.4)(webpack-cli@5.1.4)(webpack@5.98.0): resolution: {integrity: sha512-oHxbtDX7l5dlv9CCJmAhw+Bhxvh3jsa7CcJFxRYDGa7RITZfCGw7ZUaP+I1uIwvWd50PIt25XilRZFIR6kyk1g==} engines: {node: '>=16.0.0'} From 7f7ec0c48947163ca5770b94e76b9bc922400951 Mon Sep 17 00:00:00 2001 From: 2heal1 Date: Wed, 25 Jun 2025 12:48:49 +0800 Subject: [PATCH 08/16] fix: support ssr cache --- .../host/src/routes/layout.tsx | 13 +++++++++ .../provider-csr/package.json | 1 + .../provider-csr/src/index.data.ts | 6 ++-- .../components/BasicComponent/index.data.ts | 1 + .../data-fetch-server-middleware.ts | 28 +++++++++---------- .../src/lazy/data-fetch/prefetch.ts | 26 +++++++++++------ .../bridge/bridge-react/src/lazy/utils.ts | 20 ++++++++++--- pnpm-lock.yaml | 3 ++ 8 files changed, 70 insertions(+), 28 deletions(-) diff --git a/apps/modern-component-data-fetch/host/src/routes/layout.tsx b/apps/modern-component-data-fetch/host/src/routes/layout.tsx index 25ce86d7e1a..89889106d3b 100644 --- a/apps/modern-component-data-fetch/host/src/routes/layout.tsx +++ b/apps/modern-component-data-fetch/host/src/routes/layout.tsx @@ -1,6 +1,19 @@ import React from 'react'; import { Outlet, useNavigate, useLocation } from '@modern-js/runtime/router'; import { Layout, Menu } from 'antd'; +import { getInstance } from '@module-federation/modern-js/runtime'; +import { prefetch } from '@module-federation/modern-js/react'; + +console.log('layout'); +prefetch({ + id: 'remote/BasicComponent', + instance: getInstance(), +}); + +prefetch({ + id: 'provider-csr', + instance: getInstance(), +}); const { Header, Content } = Layout; diff --git a/apps/modern-component-data-fetch/provider-csr/package.json b/apps/modern-component-data-fetch/provider-csr/package.json index beee230d6b9..5ef916dfc48 100644 --- a/apps/modern-component-data-fetch/provider-csr/package.json +++ b/apps/modern-component-data-fetch/provider-csr/package.json @@ -8,6 +8,7 @@ "build:watch": "rslib build --watch" }, "devDependencies": { + "@module-federation/bridge-react": "workspace:*", "@module-federation/enhanced": "workspace:*", "@module-federation/rsbuild-plugin": "workspace:*", "@module-federation/storybook-addon": "workspace:*", diff --git a/apps/modern-component-data-fetch/provider-csr/src/index.data.ts b/apps/modern-component-data-fetch/provider-csr/src/index.data.ts index 9cbe4997e71..4a1391087d5 100644 --- a/apps/modern-component-data-fetch/provider-csr/src/index.data.ts +++ b/apps/modern-component-data-fetch/provider-csr/src/index.data.ts @@ -1,8 +1,10 @@ +import { cache } from '@module-federation/bridge-react'; export type Data = { data: string; }; -export const fetchData = async (): Promise => { +export const fetchData = cache(async (): Promise => { + console.log(`[ csr provider - server ] fetch data: ${new Date()}`); return new Promise((resolve) => { setTimeout(() => { resolve({ @@ -10,4 +12,4 @@ export const fetchData = async (): Promise => { }); }, 1000); }); -}; +}); diff --git a/apps/modern-component-data-fetch/provider/src/components/BasicComponent/index.data.ts b/apps/modern-component-data-fetch/provider/src/components/BasicComponent/index.data.ts index e3ce4738e26..bf4230c2149 100644 --- a/apps/modern-component-data-fetch/provider/src/components/BasicComponent/index.data.ts +++ b/apps/modern-component-data-fetch/provider/src/components/BasicComponent/index.data.ts @@ -5,6 +5,7 @@ export type Data = { }; export const fetchData = cache(async (): Promise => { + console.log('provder-server called'); return new Promise((resolve) => { setTimeout(() => { resolve({ diff --git a/packages/bridge/bridge-react/src/lazy/data-fetch/data-fetch-server-middleware.ts b/packages/bridge/bridge-react/src/lazy/data-fetch/data-fetch-server-middleware.ts index 511fd72cbf5..0054a0c473a 100644 --- a/packages/bridge/bridge-react/src/lazy/data-fetch/data-fetch-server-middleware.ts +++ b/packages/bridge/bridge-react/src/lazy/data-fetch/data-fetch-server-middleware.ts @@ -53,12 +53,12 @@ const getDecodeQuery = (url: URL, name: string) => { const dataFetchServerMiddleware: MiddlewareHandler = async (ctx, next) => { let url: URL; - let dataFetchId: string | null; + let dataFetchKey: string | null; let params: Record; let remoteInfo: NoSSRRemoteInfo; try { url = new URL(ctx.req.url); - dataFetchId = getDecodeQuery(url, DATA_FETCH_QUERY); + dataFetchKey = getDecodeQuery(url, DATA_FETCH_QUERY); params = JSON.parse(getDecodeQuery(url, 'params') || '{}'); const remoteInfoQuery = getDecodeQuery(url, 'remoteInfo'); remoteInfo = remoteInfoQuery ? JSON.parse(remoteInfoQuery) : null; @@ -67,10 +67,10 @@ const dataFetchServerMiddleware: MiddlewareHandler = async (ctx, next) => { return next(); } - if (!dataFetchId) { + if (!dataFetchKey) { return next(); } - logger.log('fetch data from server, dataFetchId: ', dataFetchId); + logger.log('fetch data from server, dataFetchKey: ', dataFetchKey); logger.debug( 'fetch data from server, moduleInfo: ', globalThis.__FEDERATION__?.moduleInfo, @@ -80,25 +80,25 @@ const dataFetchServerMiddleware: MiddlewareHandler = async (ctx, next) => { if (!dataFetchMap) { initDataFetchMap(); } - const fetchDataPromise = dataFetchMap[dataFetchId]?.[1]; + const fetchDataPromise = dataFetchMap[dataFetchKey]?.[1]; logger.debug( 'fetch data from server, fetchDataPromise: ', fetchDataPromise, ); if ( fetchDataPromise && - dataFetchMap[dataFetchId]?.[2] !== MF_DATA_FETCH_STATUS.ERROR + dataFetchMap[dataFetchKey]?.[2] !== MF_DATA_FETCH_STATUS.ERROR ) { const targetPromise = fetchDataPromise[0]; // Ensure targetPromise is thenable - const wrappedPromise = wrapSetTimeout(targetPromise, 20000, dataFetchId); + const wrappedPromise = wrapSetTimeout(targetPromise, 20000, dataFetchKey); if (wrappedPromise) { const res = await wrappedPromise; logger.log('fetch data from server, fetchDataPromise res: ', res); return ctx.json(res); } logger.error( - `Expected a Promise from fetchDataPromise[0] for dataFetchId ${dataFetchId}, but received:`, + `Expected a Promise from fetchDataPromise[0] for dataFetchKey ${dataFetchKey}, but received:`, targetPromise, 'Will try call new dataFetch again...', ); @@ -153,18 +153,18 @@ const dataFetchServerMiddleware: MiddlewareHandler = async (ctx, next) => { } } - const dataFetchItem = dataFetchMap[dataFetchId]; + const dataFetchItem = dataFetchMap[dataFetchKey]; logger.debug('fetch data from server, dataFetchItem: ', dataFetchItem); if (dataFetchItem) { - const callFetchDataPromise = fetchData(dataFetchId, { + const callFetchDataPromise = fetchData(dataFetchKey, { ...params, isDowngrade: !remoteInfo, - _id: dataFetchId, + _id: dataFetchKey, }); const wrappedPromise = wrapSetTimeout( callFetchDataPromise, 20000, - dataFetchId, + dataFetchKey, ); if (wrappedPromise) { const res = await wrappedPromise; @@ -173,7 +173,7 @@ const dataFetchServerMiddleware: MiddlewareHandler = async (ctx, next) => { } } - const remoteId = dataFetchId.split(SEPARATOR)[0]; + const remoteId = dataFetchKey.split(SEPARATOR)[0]; const hostInstance = globalThis.__FEDERATION__.__INSTANCES__[0]; if (!hostInstance) { throw new Error('host instance not found!'); @@ -182,7 +182,7 @@ const dataFetchServerMiddleware: MiddlewareHandler = async (ctx, next) => { const data = await dataFetchFn({ ...params, isDowngrade: !remoteInfo, - _id: dataFetchId, + _id: dataFetchKey, }); logger.log('fetch data from server, loadDataFetchModule res: ', data); return ctx.json(data); diff --git a/packages/bridge/bridge-react/src/lazy/data-fetch/prefetch.ts b/packages/bridge/bridge-react/src/lazy/data-fetch/prefetch.ts index 92cf45748b0..749bf90184c 100644 --- a/packages/bridge/bridge-react/src/lazy/data-fetch/prefetch.ts +++ b/packages/bridge/bridge-react/src/lazy/data-fetch/prefetch.ts @@ -3,9 +3,11 @@ import { getDataFetchInfo, getDataFetchMap, getDataFetchMapKey, + isServerEnv, } from '../utils'; import helpers from '@module-federation/runtime/helpers'; import { DataFetchParams } from '../types'; +import { MF_DATA_FETCH_TYPE } from '../constant'; type PrefetchOptions = { id: string; @@ -33,6 +35,8 @@ export async function prefetch(options: PrefetchOptions) { const { remoteSnapshot, globalSnapshot } = await instance.snapshotHandler.loadRemoteSnapshotInfo({ moduleInfo: remote, + id, + expose, }); if (preloadComponentResource) { @@ -79,19 +83,25 @@ export async function prefetch(options: PrefetchOptions) { return; } - const [getDataFetchGetter, _type, getDataFetchPromise] = dataFetchItem[0]; + const [getDataFetchGetter, type, getDataFetchPromise] = dataFetchItem[0]; + if (type === MF_DATA_FETCH_TYPE.FETCH_CLIENT && !isServerEnv()) { + return; + } + + let _getDataFetchPromise = getDataFetchPromise; if (!getDataFetchPromise) { if (!getDataFetchGetter) { return; } - const _getDataFetchPromise = getDataFetchGetter(); + _getDataFetchPromise = getDataFetchGetter(); + } - _getDataFetchPromise.then((dataFetchFn) => { - return dataFetchFn({ - ...dataFetchParams, - isDowngrade: false, - }); + _getDataFetchPromise!.then((dataFetchFn) => { + return dataFetchFn({ + ...dataFetchParams, + _id: dataFetchMapKey, + isDowngrade: false, }); - } + }); } diff --git a/packages/bridge/bridge-react/src/lazy/utils.ts b/packages/bridge/bridge-react/src/lazy/utils.ts index 7c80ce98a39..c32d8ab8e4f 100644 --- a/packages/bridge/bridge-react/src/lazy/utils.ts +++ b/packages/bridge/bridge-react/src/lazy/utils.ts @@ -1,4 +1,8 @@ -import { isBrowserEnv, composeKeyWithSeparator } from '@module-federation/sdk'; +import { + isBrowserEnv, + composeKeyWithSeparator, + SEPARATOR, +} from '@module-federation/sdk'; import logger from './logger'; import { DOWNGRADE_KEY, @@ -45,17 +49,20 @@ export const getDataFetchInfo = ({ const expose = id.replace(nameOrAlias, ''); let dataFetchName = ''; let dataFetchId = ''; + let dataFetchKey = ''; if (expose.startsWith('/')) { dataFetchName = `${expose.slice(1)}.${DATA_FETCH_IDENTIFIER}`; dataFetchId = `${id}.${DATA_FETCH_IDENTIFIER}`; + dataFetchKey = `${name}${expose}.${DATA_FETCH_IDENTIFIER}`; } else if (expose === '') { dataFetchName = DATA_FETCH_IDENTIFIER; dataFetchId = `${id}/${DATA_FETCH_IDENTIFIER}`; + dataFetchKey = `${name}/${DATA_FETCH_IDENTIFIER}`; } else { return; } - if (!dataFetchName || !dataFetchId) { + if (!dataFetchName || !dataFetchId || !dataFetchKey) { return; } @@ -70,6 +77,7 @@ export const getDataFetchInfo = ({ return { dataFetchName, dataFetchId, + dataFetchKey, }; }; @@ -197,9 +205,9 @@ export function getDataFetchMapKey( return; } - const { dataFetchId } = dataFetchInfo; + const { dataFetchKey } = dataFetchInfo; - return composeKeyWithSeparator(dataFetchId, hostInfo.name, hostInfo.version); + return composeKeyWithSeparator(dataFetchKey, hostInfo.name, hostInfo.version); } export async function loadDataFetchModule( @@ -329,6 +337,10 @@ export function isCSROnly() { return window._SSR_DATA === undefined; } +export function isServerEnv() { + return typeof window === 'undefined'; +} + export function setSSREnv({ fetchServerQuery, }: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fdbca7307dc..531b7038e27 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -899,6 +899,9 @@ importers: apps/modern-component-data-fetch/provider-csr: devDependencies: + '@module-federation/bridge-react': + specifier: workspace:* + version: link:../../../packages/bridge/bridge-react '@module-federation/enhanced': specifier: workspace:* version: link:../../../packages/enhanced From 1c6cfcf818305c6e0acc0f5e1e36f2c9719b9e1f Mon Sep 17 00:00:00 2001 From: 2heal1 Date: Thu, 26 Jun 2025 10:17:12 +0800 Subject: [PATCH 09/16] fix: no intercept --- .../bridge/bridge-react/src/lazy/data-fetch/prefetch.ts | 9 ++------- .../bridge-react/src/lazy/data-fetch/runtime-plugin.ts | 3 ++- packages/bridge/bridge-react/src/lazy/utils.ts | 6 +----- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/packages/bridge/bridge-react/src/lazy/data-fetch/prefetch.ts b/packages/bridge/bridge-react/src/lazy/data-fetch/prefetch.ts index 749bf90184c..b6db22372e6 100644 --- a/packages/bridge/bridge-react/src/lazy/data-fetch/prefetch.ts +++ b/packages/bridge/bridge-react/src/lazy/data-fetch/prefetch.ts @@ -3,11 +3,9 @@ import { getDataFetchInfo, getDataFetchMap, getDataFetchMapKey, - isServerEnv, } from '../utils'; import helpers from '@module-federation/runtime/helpers'; import { DataFetchParams } from '../types'; -import { MF_DATA_FETCH_TYPE } from '../constant'; type PrefetchOptions = { id: string; @@ -83,11 +81,8 @@ export async function prefetch(options: PrefetchOptions) { return; } - const [getDataFetchGetter, type, getDataFetchPromise] = dataFetchItem[0]; - - if (type === MF_DATA_FETCH_TYPE.FETCH_CLIENT && !isServerEnv()) { - return; - } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [getDataFetchGetter, _type, getDataFetchPromise] = dataFetchItem[0]; let _getDataFetchPromise = getDataFetchPromise; if (!getDataFetchPromise) { diff --git a/packages/bridge/bridge-react/src/lazy/data-fetch/runtime-plugin.ts b/packages/bridge/bridge-react/src/lazy/data-fetch/runtime-plugin.ts index 4ce27b9e08b..48c46253602 100644 --- a/packages/bridge/bridge-react/src/lazy/data-fetch/runtime-plugin.ts +++ b/packages/bridge/bridge-react/src/lazy/data-fetch/runtime-plugin.ts @@ -8,6 +8,7 @@ import { getDataFetchMapKey, isDataLoaderExpose, loadDataFetchModule, + isServerEnv, } from '../utils'; import logger from '../logger'; import { @@ -80,7 +81,7 @@ const autoFetchData: () => FederationRuntimePlugin = () => ({ : MF_DATA_FETCH_TYPE.FETCH_CLIENT; let finalDataFetchId = dataFetchId; - if (typeof window !== 'undefined') { + if (!isServerEnv()) { finalDataFetchId = downgradeType === MF_DATA_FETCH_TYPE.FETCH_CLIENT ? hasDataFetchClient diff --git a/packages/bridge/bridge-react/src/lazy/utils.ts b/packages/bridge/bridge-react/src/lazy/utils.ts index c32d8ab8e4f..4a03992519f 100644 --- a/packages/bridge/bridge-react/src/lazy/utils.ts +++ b/packages/bridge/bridge-react/src/lazy/utils.ts @@ -1,8 +1,4 @@ -import { - isBrowserEnv, - composeKeyWithSeparator, - SEPARATOR, -} from '@module-federation/sdk'; +import { isBrowserEnv, composeKeyWithSeparator } from '@module-federation/sdk'; import logger from './logger'; import { DOWNGRADE_KEY, From 63c40741a9250a0eb7739ce1a08a18f945885987 Mon Sep 17 00:00:00 2001 From: 2heal1 Date: Mon, 30 Jun 2025 10:46:47 +0800 Subject: [PATCH 10/16] fix: csr should load data in useEffect --- .../src/lazy/createLazyComponent.tsx | 78 +++++++++++++++---- 1 file changed, 64 insertions(+), 14 deletions(-) diff --git a/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx index 4ec12eaa451..c127cc3b02d 100644 --- a/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx +++ b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx @@ -1,6 +1,6 @@ -import React, { ReactNode } from 'react'; +import React, { ReactNode, useState, useEffect } from 'react'; import logger from './logger'; -import { AwaitDataFetch } from './AwaitDataFetch'; +import { AwaitDataFetch, transformError } from './AwaitDataFetch'; import { fetchData, getDataFetchItem, @@ -186,7 +186,7 @@ function getServerNeedRemoteInfo( globalName: loadedRemoteInfo.entryGlobalName, }; } - return; + return undefined; } export function createLazyComponent( @@ -241,7 +241,7 @@ export function createLazyComponent( id: moduleId, remoteSnapshot: loadedRemoteInfo.snapshot, }), - { name: instance!.name, version: instance?.options.version }, + { name: instance.name, version: instance.options.version }, ); logger.debug('getData dataFetchMapKey: ', dataFetchMapKey); if (!dataFetchMapKey) { @@ -319,17 +319,67 @@ export function createLazyComponent( }); return (props: ComponentType) => { + // eslint-disable-next-line max-lines const { key, ...args } = props; + if (globalThis.FEDERATION_SSR && !options.noSSR) { + return ( + + {/* @ts-expect-error ignore */} + {(data) => } + + ); + } else { + // Client-side rendering logic + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); - return ( - - {/* @ts-ignore */} - {(data) => } - - ); + useEffect(() => { + let isMounted = true; + const fetchDataAsync = async () => { + try { + setLoading(true); + const result = await getData(options.noSSR); + if (isMounted) { + setData(result); + } + } catch (e) { + if (isMounted) { + setError(transformError(e as Error)); + } + } finally { + if (isMounted) { + setLoading(false); + } + } + }; + + fetchDataAsync(); + + return () => { + isMounted = false; + }; + }, []); + + if (loading) { + return <>{options.loading}; + } + + if (error) { + return ( + <> + {typeof options.fallback === 'function' + ? options.fallback(error) + : options.fallback} + + ); + } + // @ts-expect-error ignore + return ; + } }; } From 38f664c950d9a1473ab12efd7c4f6b9ab6830c22 Mon Sep 17 00:00:00 2001 From: 2heal1 Date: Mon, 30 Jun 2025 20:41:13 +0800 Subject: [PATCH 11/16] chore: only noSSR use effect --- packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx index c127cc3b02d..f27e20a794a 100644 --- a/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx +++ b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx @@ -315,13 +315,13 @@ export function createLazyComponent( exportName, )}`, ); + // eslint-disable-next-line max-lines } }); return (props: ComponentType) => { - // eslint-disable-next-line max-lines const { key, ...args } = props; - if (globalThis.FEDERATION_SSR && !options.noSSR) { + if (!options.noSSR) { return ( Date: Mon, 30 Jun 2025 20:47:04 +0800 Subject: [PATCH 12/16] feat: add cacheData option --- .../bridge-react/src/lazy/createLazyComponent.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx index f27e20a794a..57769aa7ecc 100644 --- a/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx +++ b/packages/bridge/bridge-react/src/lazy/createLazyComponent.tsx @@ -37,6 +37,7 @@ export type CreateLazyComponentOptions = { export?: E; dataFetchParams?: DataFetchParams; noSSR?: boolean; + cacheData?: boolean; }; type ReactKey = { key?: React.Key | null }; @@ -192,10 +193,12 @@ function getServerNeedRemoteInfo( export function createLazyComponent( options: CreateLazyComponentOptions, ) { - const { instance } = options; + const { instance, cacheData } = options; if (!instance) { throw new Error('instance is required for createLazyComponent!'); } + let dataCache: unknown = null; + type ComponentType = T[E] extends (...args: any) => any ? Parameters[0] extends undefined ? ReactKey @@ -257,6 +260,7 @@ export function createLazyComponent( ); setDataFetchItemLoadedStatus(dataFetchMapKey); logger.debug('get data res: \n', data); + dataCache = data; return data; } catch (err) { const errMsg = `${DATA_FETCH_ERROR_PREFIX}${wrapDataFetchId(dataFetchMapKey)}${err}`; @@ -321,6 +325,10 @@ export function createLazyComponent( return (props: ComponentType) => { const { key, ...args } = props; + if (cacheData && dataCache) { + // @ts-expect-error ignore + return ; + } if (!options.noSSR) { return ( Date: Fri, 4 Jul 2025 14:31:01 +0800 Subject: [PATCH 13/16] feat: add delayLoading --- .../bridge-react/src/lazy/AwaitDataFetch.tsx | 45 +++++++++++++++++-- .../src/lazy/createLazyComponent.tsx | 17 +++++-- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/packages/bridge/bridge-react/src/lazy/AwaitDataFetch.tsx b/packages/bridge/bridge-react/src/lazy/AwaitDataFetch.tsx index f1e41af8d6a..a520e99601e 100644 --- a/packages/bridge/bridge-react/src/lazy/AwaitDataFetch.tsx +++ b/packages/bridge/bridge-react/src/lazy/AwaitDataFetch.tsx @@ -1,4 +1,10 @@ -import React, { MutableRefObject, ReactNode, Suspense, useRef } from 'react'; +import React, { + MutableRefObject, + ReactNode, + Suspense, + useRef, + useState, +} from 'react'; import logger from './logger'; import { DATA_FETCH_ERROR_PREFIX, @@ -63,6 +69,7 @@ export const transformError = (err: string | Error): ErrorInfo => { export interface AwaitProps { resolve: T | Promise; loading?: ReactNode; + delayLoading?: number; errorElement?: ReactNode | ((errorInfo: ErrorInfo) => ReactNode); children: (data: T) => ReactNode; params?: DataFetchParams; @@ -82,6 +89,7 @@ export function AwaitDataFetch({ errorElement = DefaultErrorElement, children, params, + delayLoading, }: AwaitProps) { const dataRef = useRef(); const data = dataRef.current || resolve; @@ -92,7 +100,8 @@ export function AwaitDataFetch({ params={params} loading={loading} errorElement={errorElement} - // @ts-ignore + delayLoading={delayLoading} + // @ts-expect-error resolve={getData} > {children} @@ -100,14 +109,43 @@ export function AwaitDataFetch({ ); } +export const DelayedLoading = ({ + delayLoading, + children, +}: { + delayLoading?: number; + children: ReactNode; +}) => { + const [show, setShow] = useState(false); + const timerSet = useRef(false); + + if (!delayLoading) { + return children; + } + + if (typeof window !== 'undefined' && !show && !timerSet.current) { + timerSet.current = true; + setTimeout(() => { + setShow(true); + }, delayLoading); + } + + return show ? children : null; +}; + function AwaitSuspense({ resolve, children, loading = DefaultLoading, errorElement = DefaultErrorElement, + delayLoading, }: AwaitErrorHandlerProps) { return ( - + {loading} + } + > {children} @@ -132,6 +170,7 @@ function ResolveAwait({ {globalThis.FEDERATION_SSR && (