import React, { forwardRef } from 'react'; import { ErrorBoundary, ErrorBoundaryPropsWithComponent, } from 'react-error-boundary'; import { LoggerInstance } from './utils'; import RemoteApp from './remote'; import type { ProviderParams } from '@module-federation/bridge-shared'; export interface RenderFnParams extends ProviderParams { dom?: any; } interface RemoteModule { provider: () => { render: (info: RenderFnParams) => void; destroy: (info: { dom: any }) => void; }; } type LazyRemoteComponentInfo = { loader: () => Promise; loading: React.ReactNode; fallback: ErrorBoundaryPropsWithComponent['FallbackComponent']; export?: E; }; function createLazyRemoteComponent( info: LazyRemoteComponentInfo, ) { const exportName = info?.export || 'default'; return React.lazy(async () => { LoggerInstance.log(`createRemoteComponent LazyComponent create >>>`, { lazyComponent: info.loader, exportName, }); try { const m = (await info.loader()) as RemoteModule; // @ts-ignore const moduleName = m && m[Symbol.for('mf_module_id')]; LoggerInstance.log( `createRemoteComponent LazyComponent loadRemote info >>>`, { name: moduleName, module: m, exportName }, ); // @ts-ignore const exportFn = m[exportName]; if (exportName in m && typeof exportFn === 'function') { const RemoteAppComponent = forwardRef< HTMLDivElement, { basename?: ProviderParams['basename']; memoryRoute?: ProviderParams['memoryRoute']; } >((props, ref) => { return ( ); }); return { default: RemoteAppComponent, }; } else { LoggerInstance.log( `createRemoteComponent LazyComponent module not found >>>`, { name: moduleName, module: m, exportName }, ); throw Error( `Make sure that ${moduleName} has the correct export when export is ${String( exportName, )}`, ); } } catch (error) { throw error; } }); } export function createRemoteComponent( info: LazyRemoteComponentInfo, ) { type ExportType = T[E] extends (...args: any) => any ? ReturnType : never; type RawComponentType = '__BRIDGE_FN__' extends keyof ExportType ? ExportType['__BRIDGE_FN__'] extends (...args: any) => any ? Parameters[0] : {} : {}; return forwardRef( (props, ref) => { const LazyComponent = createLazyRemoteComponent(info); return ( ); }, ); }