Skip to content

Instantly share code, notes, and snippets.

@marcosmapf
Created August 10, 2022 14:34
Show Gist options
  • Save marcosmapf/4ab9c30dfd78656bb4d6c4ca33e239e3 to your computer and use it in GitHub Desktop.
Save marcosmapf/4ab9c30dfd78656bb4d6c4ca33e239e3 to your computer and use it in GitHub Desktop.

Revisions

  1. marcosmapf created this gist Aug 10, 2022.
    64 changes: 64 additions & 0 deletions federatedApp.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,64 @@
    type FederatedAppRender = (props?: any) => void

    export interface FederatedAppList {
    [key: string]: () => Promise<FederatedAppRender>
    }
    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<FederatedAppRender> => {
    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