type FederatedAppRender = (props?: any) => void export interface FederatedAppList { [key: string]: () => Promise } export interface FederatedApp { render?: FederatedAppRender root: HTMLElement } const handleFederatedApp = (appList?: FederatedAppList) => { const getAppRoot = (appName: string) => { return window[appName]?.root as HTMLElement } const setAppRoot = (appName: string, rootElement: HTMLElement) => { if (!window[appName]) { window[appName] = {} } window[appName].root = rootElement } const isAppInsideShadowRoot = (appName: string) => { return getAppRoot(appName) instanceof ShadowRoot } /** * Returns the render function of a Module Federation container * Module federation containers are automatically added to the window object upon module loading. * This module loading occurs if there is an async definition of module (appList) provided to this function or if the module is loaded in any way */ const getRenderFederatedApp = async (appName: string, appModule: string): Promise => { try { const factory = await window[appName]?.get?.(appModule) if (factory) { const { default: render } = factory() return render } const appImportFunction = appList?.[appName] if (appImportFunction) { return await appImportFunction() } throw new Error(`Missing federated module render function for app: ${appName}`) } catch (error) { const errorMessage = `App ${appName} was not imported correctly, check the module import key or the module entrypoint file.` console.error(`${errorMessage} \n\n`, error) Promise.reject(error) } return Promise.reject(new Error()) } return { getRenderFederatedApp, getAppRoot, isAppInsideShadowRoot, setAppRoot } } export default handleFederatedApp