Runtime Access

TIP

Before reading this chapter, it is assumed that you already understand:

Currently, Module Federation provides two ways to register and load modules:

  • One is to declare it in the build plugin (usually in the module-federation.config.ts file)

  • The other way is to directly register and load modules through the runtime API.

The two modes are not conflicting and can be used together. You can flexibly choose the module registration method and timing according to your actual scenario.


The differences between registering modules at runtime and registering modules in the build configuration are as follows:

Registering modules at runtimeRegistering modules in the plugin
Can be used without the build plugin, and pure runtime can be used directly for module registration and loading in projects like webpack4The build plugin needs to be webpack5 or above
Supports dynamic module registrationDoes not support dynamic module registration
Does not support loading modules with import syntaxSupports loading modules with import synchronous syntax
Supports loading modules with loadRemoteSupports loading modules with loadRemote
Setting shared must provide specific version and instance informationSetting shared only requires configuring rules, without providing specific version and instance information
shared dependencies can only be used externally, and external shared dependencies cannot be usedshared dependencies are shared bidirectionally according to specific rules
The loading process can be affected through the runtime's plugin mechanismCurrently does not support providing plugin to affect the loading process
Does not support remote type hintsSupports remote type hints

If the build plugin is used, an MF instance will be automatically created and stored in memory when the project starts. You can directly call methods of the MF instance via the .

import { loadRemote } from '@module-federation/enhanced/runtime';

loadRemote('remote1');

If the build plugin is not used, you need to manually create an MF instance before calling the corresponding API.

import { createInstance } from '@module-federation/enhanced/runtime';

const mf = createInstance({
  name: 'host',
  remotes: [
    {
      name: 'remote1',
      entry: 'http://localhost:2001/vmok-manifest.json',
    },
  ],
});

mf.loadRemote('remote1');
  • What is a ModuleFederation instance?

A ModuleFederation instance is an instance of the ModuleFederation class, which contains all the functionality of the ModuleFederation runtime.

You can enter __FEDERATION__.__INSTANCES__ in the console to view the created instances.

Installation

npm
yarn
pnpm
bun
npm add @module-federation/enhanced --save
Note:
  • In the following Federation Runtime examples, we all show cases that are detached from specific frameworks such as Modern.js, so the API will be exported from the initial @module-federation/enhanced/runtime package.

  • If your project is a Modern.js project and uses @module-federation/modern-js, the runtime should export the runtime API from @module-federation/modern-js/runtime. This ensures that the plugin and the runtime use the same runtime instance, ensuring that modules are loaded normally.

  • If your project is a Modern.js project but does not use @module-federation/modern-js, you should export the runtime API from @module-federation/enhanced/runtime. However, we recommend that you use @module-federation/modern-js for module registration and loading, which will allow you to enjoy more capabilities combined with the framework.

Module Registration

Build Plugin(Use build plugin)
Pure Runtime(Not use build plugin)
// If use build plugin, you can use `registerRemotes` directly.
import { registerRemotes } from '@module-federation/enhanced/runtime';

registerRemotes([
  {
      name: 'remote1',
      alias: 'remote-1',
      entry: 'http://localhost:3001/mf-manifest.json',
  }
]);

Module Loading

Build Plugin(Use build plugin)
Pure Runtime(Not use build plugin)
// If use build plugin, you can use `loadRemote` directly.
import { loadRemote } from '@module-federation/enhanced/runtime';
import React from 'react';

export default () => {
  const MyButton = React.lazy(() =>
    loadRemote('remote1').then(({ MyButton }) => {
      return {
        default: MyButton
      };
    }),
  );

  return (
    <React.Suspense fallback="Loading Button">
      <MyButton />
    </React.Suspense>
  );
}

Loading Anonymous Modules

Build Plugin(Use build plugin)
Pure Runtime(Not use build plugin)
// If use build plugin, you can use `loadRemote` directly.
import React from 'react';
import { loadRemote } from '@module-federation/enhanced/runtime';

const RemoteButton = React.lazy(() => loadRemote('provider/button'));
// 也可通过模块别名加载:
// const RemoteButton = React.lazy(() => loadRemote('remotes-1/button'));

export default () => {
  return (
    <React.Suspense fallback="Loading Button">
      <RemoteButton />
    </React.Suspense>
  );
}

Loading Named Modules

Build Plugin(Use build plugin)
Pure Runtime(Not use build plugin)
// If use build plugin, you can use `loadRemote` directly.
import React from 'react';
import { loadRemote } from '@module-federation/enhanced/runtime';

export default () => {
  const RemoteButton = React.lazy(() =>
    loadRemote('remote1/button').then(({ RemoteButton }) => {
      return {
        default: RemoteButton
      };
    }),
  );
  return (
    <React.Suspense fallback="Loading Button">
      <RemoteButton />
    </React.Suspense>
  );
}

Loading Utility Functions

Build Plugin(Use build plugin)
Pure Runtime(Not use build plugin)
// If use build plugin, you can use `loadRemote` directly.
import React from 'react';
import { loadRemote } from '@module-federation/enhanced/runtime';

// 加载 remote1 expose 的 util
loadRemote<{add: (...args: Array<number>)=> number }>("remote1/util").then((md)=>{
    md.add(1,2);
});