其他

本节收集了与“模块联邦”实现相关的常见问题(非特定错误代码)。 主要目标是为不熟悉“模块联邦”实现原理的初学者提供额外的上下文和解决方案路径

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:

错误信息

浏览器错误信息

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

浏览器错误信息

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

解决方案

该错误为 React 多实例问题,通常出现在 react 没有复用同一个实例的场景。 可以通过设置 shared 并且设置 singleton: true 单例模式 来避免此问题。

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, },
                ...
            },
        })
      ])
  }

HMR 失效

CORS 警告

当项目中设置了 exposes ,会被视为生产者,为保证生产者资源能正常被消费者加载,@module-federation/modern-js@module-federation/rsbuild-plugin 会设置 Access-Control-Allow-Origin* ,并同时发出警告。

解决方案

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.

原因

当生产者 url 为 manifest 时,加载此生产者模块会自动预加载相应的资源。如果出现上述警告,是因为默认预加载不会配置 credentials ,而实际的 load remote script 携带了对应的 credentials ,导致预加载失败。

解决方案

通过 runtimePlugins 添加运行时插件,在 createLink hook 中配置 crossorigin 属性,其值需要和实际 load script 保持一致。

例如需要修改预加载 link 的 crossorigin 属性为 anonymous

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

export default function MFLinkPlugin(): FederationRuntimePlugin {
  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
    }
  };
}