Bridge Overview

Introduction

The MF bridge is a utility function provided by Module Federation to help users load application-level modules through Module Federation. It automatically provides the necessary application lifecycle functions render and destroy required by the provider function and ensures compatibility with different framework versions. Additionally, it allows proper routing collaboration between applications.

Toolkits

@module-federation/bridge-react

The @module-federation/bridge-react toolkit is a bridge utility function package provided by MF for React v18 applications. The exported createBridgeComponent can be used for exporting modules in React v18 applications. Usage examples of @module-federation/bridge-react can be found in the Host demo and Remote demo.

@module-federation/bridge-vue3

The @module-federation/bridge-vue3 toolkit is a bridge utility function package provided by MF for Vue v3 applications. The exported createBridgeComponent can be used for exporting modules in Vue v3 sub-applications. Usage examples of @module-federation/bridge-vue3 can be found in the Host demo and Remote demo.

FAQ

Why Bridge?

Bridge is mainly used to solve two problems:

  • Cross-application framework (React, Vue) loading and rendering
  • Support for loading modules with routes (routes can work together properly)

These two problems are important features in the "micro-frontend framework".

How to solve it if the corresponding framework bridge is not provided?

Currently, Module Federation provides official bridge toolkits. If you need bridge toolkits for other frameworks, you can provide feedback via issue or refer to the existing Bridge to implement it yourself.

The implementation of Bridge is very simple. The core is based on DOM rendering. Here is the pseudocode:

Export module

export default function () {
  const rootMap = new Map<any, ReactDOM.Root>();
  return {
    render(info: { dom: HTMLElement; basename?: string; memoryRoute?: { entryPath: string; } }) {
      const root = ReactDOM.createRoot(info.dom);
      rootMap.set(info.dom, root);
      root.render(<App />);
    },
    destroy(info: { dom: HTMLElement }) {
      const root = rootMap.get(info.dom);
      root?.unmount();
    },
  };
}

Load module

const LazyComponent = React.lazy(async () => {
  const m = await loadRemote('remote1/export-app');
  return {
    default: () => {
      const rootRef = useRef(null);
      const providerInfoRef = useRef<any>(null);

      useEffect(() => {
        const providerReturn = providerInfo();
        providerInfoRef.current = providerReturn;
        providerReturn.render(renderProps);

        return () => {
          providerInfoRef.current?.destroy({
            dom: renderDom.current,
          });
        };
      }, []);
      return <div ref={rootRef}></div>;
    },
  };
});

function Component() {
  return (
    <React.Suspense fallback={<div>loading</div>}>
      <LazyComponent />
    </React.Suspense>
  );
}