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/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/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/.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 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..ad3c3fd73fb 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,7 @@ -import { kit, ERROR_TYPE } from '@module-federation/modern-js/runtime'; +import { getInstance } from '@module-federation/modern-js/runtime'; +import { ERROR_TYPE } from '@module-federation/modern-js/react'; -const { createRemoteComponent } = kit; - -const Basic = createRemoteComponent({ +const Basic = getInstance()!.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..32ae80ad2fe 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 { getInstance } from '@module-federation/modern-js/runtime'; -const { createRemoteComponent } = kit; - -const ClientDowngrade = createRemoteComponent({ +const ClientDowngrade = getInstance()!.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..261093cd4d2 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,9 @@ -import { kit } from '@module-federation/modern-js/runtime'; +import { getInstance } from '@module-federation/modern-js/runtime'; -const { createRemoteComponent, wrapNoSSR } = kit; - -const CsrWithFetchDataFromServerComponent = wrapNoSSR(createRemoteComponent)({ +const CsrWithFetchDataFromServerComponent = getInstance()!.createLazyComponent({ + noSSR: true, loader: () => { + console.log('calling'); return import('provider-csr'); }, loading: 'loading...', 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..ec55820a6b4 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,18 @@ 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 { lazyLoadComponentPlugin } from '@module-federation/modern-js/react'; + +getInstance()!.registerPlugins([lazyLoadComponentPlugin()]); +console.log('layout'); +getInstance()!.prefetch({ + id: 'remote/BasicComponent', +}); + +getInstance()!.prefetch({ + id: 'provider-csr', +}); const { Header, Content } = Layout; 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..cae8591ba5a 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 { getInstance } from '@module-federation/modern-js/runtime'; -const { createRemoteComponent } = kit; - -const ServerDowngrade = createRemoteComponent({ +const ServerDowngrade = getInstance()!.createLazyComponent({ loader: () => { return import('remote/ServerDowngrade'); }, 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/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 5586247ab1c..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 @@ -1,8 +1,11 @@ +import { cache } from '@module-federation/modern-js/react'; + export type Data = { data: string; }; -export const fetchData = async (): Promise => { +export const fetchData = cache(async (): Promise => { + console.log('provder-server called'); return new Promise((resolve) => { setTimeout(() => { resolve({ @@ -10,4 +13,4 @@ export const fetchData = async (): Promise => { }); }, 1000); }); -}; +}); 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..bdbfe4644c2 100644 --- a/apps/modernjs-ssr/dynamic-nested-remote/src/components/Content.tsx +++ b/apps/modernjs-ssr/dynamic-nested-remote/src/components/Content.tsx @@ -1,13 +1,14 @@ import React from 'react'; import Button from 'antd/lib/button'; import { + getInstance, registerRemotes, loadRemote, - kit, } from '@module-federation/modern-js/runtime'; +import { lazyLoadComponentPlugin } from '@module-federation/modern-js/react'; import stuff from './stuff.module.css'; -const { createRemoteSSRComponent } = kit; +getInstance()!.registerPlugins([lazyLoadComponentPlugin()]); registerRemotes([ { @@ -16,7 +17,7 @@ registerRemotes([ }, ]); -const RemoteSSRComponent = createRemoteSSRComponent({ +const RemoteSSRComponent = getInstance()!.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..6f54211172a 100644 --- a/apps/modernjs-ssr/host/src/routes/dynamic-remote/page.tsx +++ b/apps/modernjs-ssr/host/src/routes/dynamic-remote/page.tsx @@ -1,12 +1,10 @@ import React, { useState, Suspense } from 'react'; import { + getInstance, loadRemote, registerRemotes, - kit, } from '@module-federation/modern-js/runtime'; -const { createRemoteSSRComponent } = kit; - registerRemotes([ { name: 'dynamic_remote', @@ -14,7 +12,7 @@ registerRemotes([ }, ]); -const RemoteSSRComponent = createRemoteSSRComponent({ +const RemoteSSRComponent = getInstance()!.createLazyComponent({ loader: () => loadRemote('dynamic_remote'), loading: 'loading...', fallback: ({ error }) => { diff --git a/apps/modernjs-ssr/host/src/routes/layout.tsx b/apps/modernjs-ssr/host/src/routes/layout.tsx index 6cd5fc73bcb..ae85bd69429 100644 --- a/apps/modernjs-ssr/host/src/routes/layout.tsx +++ b/apps/modernjs-ssr/host/src/routes/layout.tsx @@ -1,9 +1,11 @@ import React from 'react'; import { Outlet, useNavigate } from '@modern-js/runtime/router'; import { Layout, Menu } from 'antd'; - +import { lazyLoadComponentPlugin } from '@module-federation/modern-js/react'; +import { getInstance } from '@module-federation/modern-js/runtime'; const { Header, Content } = Layout; +getInstance()!.registerPlugins([lazyLoadComponentPlugin()]); const App: React.FC = () => { const navi = useNavigate(); diff --git a/apps/modernjs-ssr/nested-remote/src/routes/page.tsx b/apps/modernjs-ssr/nested-remote/src/routes/page.tsx index 84b8509ef14..1dfb9347068 100644 --- a/apps/modernjs-ssr/nested-remote/src/routes/page.tsx +++ b/apps/modernjs-ssr/nested-remote/src/routes/page.tsx @@ -1,11 +1,12 @@ -import { kit } from '@module-federation/modern-js/runtime'; +import { getInstance } from '@module-federation/modern-js/runtime'; +import { lazyLoadComponentPlugin } from '@module-federation/modern-js/react'; import Content from '../components/Content'; import './index.css'; -const { createRemoteSSRComponent } = kit; +getInstance()!.registerPlugins([lazyLoadComponentPlugin()]); -const RemoteSSRComponent = createRemoteSSRComponent({ +const RemoteSSRComponent = getInstance()!.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 5286aeb6ad3..816fe54dc93 100644 --- a/apps/website-new/docs/en/guide/framework/modernjs.mdx +++ b/apps/website-new/docs/en/guide/framework/modernjs.mdx @@ -191,14 +191,14 @@ 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 { getInstance } 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({ + instance: getInstance(), loader: () => { return import('remote/List'); }, @@ -236,7 +236,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 +304,22 @@ In addition to exporting [MF Runtime](../basic/runtime/runtime-api), `@module-fe 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, getInstance } 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 = { + instance: ReturnType; loader: () => Promise; loading: React.ReactNode; fallback: ReactNode | ((errorInfo: ErrorInfo) => ReactNode); @@ -353,11 +354,11 @@ 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 { getInstance } from '@module-federation/modern-js/runtime'; +import { createLazyComponent, ERROR_TYPE } from '@module-federation/modern-js/react'; -const RemoteComponent = createRemoteComponent({ +const LazyComponent = createLazyComponent({ + instance: getInstance(), loader: () => import('remote/Image'), loading:
loading...
, fallback: ({error,errorType,dataFetchMapKey}) => { @@ -374,7 +375,7 @@ const RemoteComponent = createRemoteComponent({ const App: FC = () => { return <> - + ; }; export default App; @@ -420,19 +421,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 +436,11 @@ 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 { getInstance } from '@module-federation/modern-js/runtime'; +import { createLazyComponent, wrapNoSSR } from '@module-federation/modern-js/react'; -const RemoteComponent = wrapNoSSR(createRemoteComponent)({ +const LazyComponent = wrapNoSSR(createLazyComponent)({ + instance: getInstance(), loader: () => { return import('remote/Content'); }, @@ -465,7 +460,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 f54930b89f1..b2dd3adc1d9 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..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,16 +147,16 @@ export const loader = async ({ request }: LoaderFunctionArgs): Promise import('remote/Image'), loading: 'loading...', export: 'default', @@ -176,7 +176,8 @@ const Index = () => { const DynamicRemoteSSRComponents = dataLoader.providerList.map(item => { const { id } = item; - const Com = createRemoteSSRComponent({ + 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 7c6fc66a798..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,12 +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 { kit } from '@module-federation/modern-js/runtime' +import { getInstance } 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({ + 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 55305dfbe1b..624bb5d6dc0 100644 --- a/apps/website-new/docs/zh/guide/framework/modernjs.mdx +++ b/apps/website-new/docs/zh/guide/framework/modernjs.mdx @@ -192,14 +192,14 @@ export default Index; #### 消费者 -在消费者中,我们需要通过 `createRemoteComponent` 来加载远程组件,并获取数据。 +在消费者中,我们需要通过 `createLazyComponent` 来加载远程组件,并获取数据。 ```tsx -import { kit, ERROR_TYPE } from '@module-federation/modern-js/runtime'; +import { getInstance } 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({ + instance: getInstance(), loader: () => { return import('remote/List'); }, @@ -237,7 +237,7 @@ export default Index; - `isDowngrade` (boolean): 表示当前执行上下文是否处于降级模式。例如,在服务端渲染 (SSR) 失败,在客户端渲染(CSR)中会重新往服务端发起请求,调用 loader 函数,此时该值为 `true`。 -除了默认的参数以外,还可以在 `createRemoteComponent` 中传递 [dataFetchParams](#datafetchparams) 字段,该字段会被透传给 loader 函数。 +除了默认的参数以外,还可以在 `createLazyComponent` 中传递 [dataFetchParams](#datafetchparams) 字段,该字段会被透传给 loader 函数。 #### 返回值 @@ -306,21 +306,22 @@ export async function loader({ params }) { 为防止与 Shared 冲突,需要通过下列方式引用。 ```ts -import { kit } from '@module-federation/modern-js/runtime'; -const { loadRemote ,createRemoteComponent, createRemoteSSRComponent, wrapNoSSR } = kit; +import { loadRemote, getInstance } 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 = { + instance: ReturnType; loader: () => Promise; loading: React.ReactNode; fallback: ReactNode | ((errorInfo: ErrorInfo) => ReactNode); @@ -355,11 +356,11 @@ type ErrorInfo = { ```tsx import React, { FC, memo, useEffect } from 'react'; -import { kit, ERROR_TYPE } from '@module-federation/modern-js/runtime'; - -const { createRemoteComponent } = kit; +import { getInstance } from '@module-federation/modern-js/runtime'; +import { createLazyComponent, ERROR_TYPE } from '@module-federation/modern-js/react'; -const RemoteComponent = createRemoteComponent({ +const LazyComponent = createLazyComponent({ + instance: getInstance(), loader: () => import('remote/Image'), loading:
loading...
, fallback: ({error,errorType,dataFetchMapKey}) => { @@ -376,7 +377,7 @@ const RemoteComponent = createRemoteComponent({ const App: FC = () => { return <> - + ; }; export default App; @@ -422,19 +423,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 +438,11 @@ declare function wrapNoSSR( 使用示例: ```tsx -import { kit } from '@module-federation/modern-js/runtime'; - -const { createRemoteComponent, wrapNoSSR } = kit; +import { getInstance } from '@module-federation/modern-js/runtime'; +import { createLazyComponent, wrapNoSSR } from '@module-federation/modern-js/runtime'; -const RemoteComponent = wrapNoSSR(createRemoteComponent)({ +const LazyComponent = wrapNoSSR(createLazyComponent)({ + instance: getInstance(), loader: () => { return import('remote/Content'); }, @@ -467,7 +462,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 e009a9d8d04..eb82a0ba177 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..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,16 +144,16 @@ export const loader = async ({ request }: LoaderFunctionArgs): Promise import('remote/Image'), loading: 'loading...', export: 'default', @@ -173,7 +173,8 @@ const Index = () => { const DynamicRemoteSSRComponents = dataLoader.providerList.map(item => { const { id } = item; - const Com = createRemoteSSRComponent({ + 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 43116228018..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,12 +257,12 @@ export default Index; 修改消费者引用生产者处的代码(`src/routes/page.tsx`): ```tsx title='page.tsx' -import { kit } from '@module-federation/modern-js/runtime' +import { getInstance } 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({ + instance: getInstance(), 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 acf51b4684f..edc39092111 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" }, + "./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" + }, + "./lazy-load-component-plugin": { + "types": "./dist/lazy-load-component-plugin.d.ts", + "import": "./dist/lazy-load-component-plugin.es.js", + "require": "./dist/lazy-load-component-plugin.cjs.js" + }, "./*": "./*" }, + "typesVersions": { + "*": { + ".": [ + "./dist/types/index.d.ts" + ], + "lazy-load-component-plugin": [ + "./dist/lazy-load-component-plugin.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", @@ -61,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", @@ -82,6 +121,8 @@ "typescript": "^5.2.2", "vite": "^5.4.18", "vite-plugin-dts": "^4.3.0", - "@module-federation/runtime": "workspace:*" + "@module-federation/runtime": "workspace:*", + "@module-federation/runtime-core": "workspace:*", + "hono": "3.12.12" } } diff --git a/packages/bridge/bridge-react/src/.eslintrc.js b/packages/bridge/bridge-react/src/.eslintrc.js deleted file mode 100644 index fafc0032305..00000000000 --- a/packages/bridge/bridge-react/src/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// eslint-disable-next-line import/no-commonjs -module.exports = { - root: true, - extends: ['@modern-js-app'], - parserOptions: { - tsconfigRootDir: __dirname, - project: ['../tsconfig.json'], - }, -}; diff --git a/packages/bridge/bridge-react/src/index.ts b/packages/bridge/bridge-react/src/index.ts index ef312515bc2..4e04c1011f3 100644 --- a/packages/bridge/bridge-react/src/index.ts +++ b/packages/bridge/bridge-react/src/index.ts @@ -3,7 +3,30 @@ * 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, + callDataFetch, + setSSREnv, + autoFetchDataPlugin, + CacheSize, + CacheTime, + configureCache, + generateKey, + cache, + revalidateTag, + clearStore, + prefetch, +} from './lazy'; + +export { lazyLoadComponentPlugin } from './plugins/lazy-load-component-plugin'; + export type { CreateRootOptions, Root } from './provider/versions/legacy'; export type { ProviderParams, @@ -12,3 +35,11 @@ export type { DestroyParams, RenderParams, } from './types'; +export type { + DataFetchParams, + NoSSRRemoteInfo, + CollectSSRAssetsOptions, + CreateLazyComponentOptions, + CacheStatus, + CacheStatsInfo, +} from './lazy'; diff --git a/packages/modernjs/src/runtime/AwaitDataFetch.tsx b/packages/bridge/bridge-react/src/lazy/AwaitDataFetch.tsx similarity index 81% rename from packages/modernjs/src/runtime/AwaitDataFetch.tsx rename to packages/bridge/bridge-react/src/lazy/AwaitDataFetch.tsx index 821b05154c5..a520e99601e 100644 --- a/packages/modernjs/src/runtime/AwaitDataFetch.tsx +++ b/packages/bridge/bridge-react/src/lazy/AwaitDataFetch.tsx @@ -1,14 +1,20 @@ -import React, { MutableRefObject, ReactNode, Suspense, useRef } from 'react'; -import logger from '../logger'; +import React, { + MutableRefObject, + ReactNode, + Suspense, + useRef, + useState, +} from 'react'; +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 ( @@ -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 && (