Other

This section is a collection of common issues related to the implementation of Module Federation in general(not specific error code). The main goal is to provide additional context and solution paths for beginners not familiar with the fundamental ways of how Module Federation is working at its core.

Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

Error Message

Browser Error Message

Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

You might have mismatching versions of React and the renderer (such as React DOM)

You might be breaking the Rules of Hooks

You might have more than one copy of React in the same app

Browser Error Message

Uncaught TypeError: Cannot read properties on null (reading useState)

Solution

This error is a React multi-instance problem, which usually occurs when react does not reuse the same instance. This problem can be avoided by setting shared and setting singleton: true singleton mode.

modern.config.js
{
    ...
    new ModuleFederationPlugin({
            ...,
         // Default basic configuration
         // shared: [
         //   'react',
         //   'react-dom',
         //   'my-custom-module'
         // ]

         // Configuration with more specificity
            shared: {
                react: { singleton: true, },
                'react-dom': { singleton: true, },
                'my-custom-module': { singleton: true, },
                ...
            },
        })
      ])
  }

Unable to compile federated types, Error: compile TS failed

Error Message

Browser Error Message

Unable to compile federated types, Error: compile TS failed, the original command is 'npx tsc --project file-path.json'.

Browser Error Message

Error: ENOENT: no such file or directory, open 'project-path/rspack_hmr/application-name/dist/@mf-types.zip'

Solution

  1. Execute npx tsc --project file-path.json according to the error message to solve all type problems encountered.
  2. Check your ModuleFederationPlugin config field exposes:
[modern|rspack|rsbuild|webpack].config.[js,ts]
new ModuleFederationPlugin({
    ...
    // Make sure both key and value start with "./"
    exposes: { './Foo': './src/<path-to-file>/Foo.tsx' },
    ...
  })

HMR failed

CORS warn

When exposes is set in the project, it will be regarded as a producer. To ensure that the producer resources can be loaded normally by consumers, @module-federation/modern-js and @module-federation/rsbuild-plugin will set Access-Control-Allow-Origin to * and issue a warning at the same time.

Solutions

  • [Modern.js]: Set devServer.headers value to the specified domain whitelist instead of *

  • [Rsbuild]: Set server.cors.origin value to the specified domain whitelist instead of *

A preload for 'http://resource-url' is found, but is not used because the request credentials mode does not match. Consider taking a look at crossorigin attribute.

Reason

When the producer URL is a manifest, loading this producer module will automatically preload the corresponding resources. If the above warning occurs, it is because the default preload does not configure credentials, while the actual load remote script carries the corresponding credentials, causing the preload to fail.

Solution

Add a runtime plugin via runtimePlugins and configure the crossorigin attribute in the createLink hook. Its value needs to be consistent with the actual load script.

For example, to modify the crossorigin attribute of the preloaded link to anonymous:

runtimePlugin.ts
import { ModuleFederationRuntimePlugin } from '@module-federation/runtime/types';

export default function MFLinkPlugin(): ModuleFederationRuntimePlugin {
  return {
    name: 'link-plugin',
    createLink({ url }) {
      const link = document.createElement('link');
      link.setAttribute('href', url);
      link.setAttribute('rel', 'preload');
      link.setAttribute('as', 'script');
      link.setAttribute('crossorigin', 'anonymous');
      return link
    }
  };
}

Problem: esm remoteEntry.js usage in var host environment

Problem

There are some cases when your host application is written with ModuleFederationPlugin and you want to use esm (e.g. vite) in your remote application. And your host application doesn't support esm remote loading (e.g. your host doesn't use promise new Promise workaround).

In this case you are not able to load remote esm application without changing the host application.

Error Message

Browser Error Message

Uncaught SyntaxError: Cannot use import statement outside a module

Solution

If you are not able (or don't want) to rewrite your host var environment to support esm remote import, you can write a little "var" layer on the remote's side.

In you remote (vite) app create a new workaround file public/varRemoteEntry.js:

// public/varRemoteEntry.js
var remote; // name of remote app
remote = (function () {
  function getScriptUrl() {
    return document.currentScript.src
  }

  const entry = `${getScriptUrl()}/../remoteEntry.js` // path to esm remoteEntry.js

  return {
    get: (...args) => import(entry).then(m => m.get(...args)),
    init: (...args) => import(entry).then(m => m.init(...args)),
  };
})();

Update remotes config in your host (webpack) app:

new ModuleFederationPlugin({
  // ... webpack module federation config
  remotes: {
-    remote: 'remote@http://localhost:3001/remoteEntry.js',
+    remote: 'remote@http://localhost:3001/varRemoteEntry.js',
  }
})

Now you are able to import modules from remote (esm) in your host (var) application:

const App = await import('remote/App')