Webpack 5 模块联合 - 远程模块中的挂钩 - 不起作用

Pit*_*sty 13 javascript typescript reactjs webpack

我试图在模块联合(webpack 5 功能)的帮助下在运行时获得一个动态系统。一切都很好,但是当我将钩子添加到“生产者”模块(主机应用程序从中动态导入组件的模块)时,我收到大量“无效的钩子规则”错误。

Warning: Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. You can only call Hooks at the top level of your React function. For more information, see [LINK RULES OF HOOKS]
Run Code Online (Sandbox Code Playgroud)
Warning: React has detected a change in the order of Hooks called by PluginHolder. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: [LINK RULES OF HOOKS]
Run Code Online (Sandbox Code Playgroud)

我已经使用了 externals 字段并在 html 文件中添加了 script 标签,我使用了共享选项来添加 singleton 字段: true 并指定了 React 和 React-dom 版本 每次控制台都会吐出大量错误

这是我直接从文档加载模块的方法

Warning: Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. You can only call Hooks at the top level of your React function. For more information, see [LINK RULES OF HOOKS]
Run Code Online (Sandbox Code Playgroud)

为了加载remoteEntry.js文件,我使用makeAsyncScriptLoader HOC和react-async-script,如下所示:

Warning: React has detected a change in the order of Hooks called by PluginHolder. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: [LINK RULES OF HOOKS]
Run Code Online (Sandbox Code Playgroud)

PluginHolder 是一个简单的组件,它包装了加载脚本中的加载模块(加载实际上已完成)

const loadComponent = (scope: string, module: string) => async (): Promise<any> => {
    // @ts-ignore
    await __webpack_init_sharing__('default');
    // @ts-ignore
    const container = window[scope];
    // @ts-ignore
    await container.init(__webpack_share_scopes__.default);
    // @ts-ignore
    const factory = await window[scope].get(module);
    return factory();
};
Run Code Online (Sandbox Code Playgroud)

最重要的是开胃菜:

const withScript = (name: string, url: string) => {
    const LoadingElement = () => {
        return <div>Loading...</div>;
    };

    return () => {
        const [scriptLoaded, setScriptLoaded] = useState<boolean>(false);

        const AsyncScriptLoader = makeAsyncScriptLoader(url, {
            globalName: name,
        })(LoadingElement);

        if (scriptLoaded) {
            return <PluginHolder name={name}/>;
        }

        return (
            <AsyncScriptLoader
                asyncScriptOnLoad={() => {
                    setScriptLoaded(true);
                }}
            />
        );
    };
};
Run Code Online (Sandbox Code Playgroud)

我不使用 React.Lazy 因为我无法使用 import()。更重要的是,在主机应用程序中,我在react和react-dom中设置了 field eager: true

我的 webpack.config.js (主机)如下:

 useEffect((): void => {
        (async () => {
            const c = await loadComponent(name, './Plugin')();
            setComponent(c.default);
        })();
    }, []);

 return cloneElement(component);
Run Code Online (Sandbox Code Playgroud)

还有第二个模块中的 webpack.config.js:

const [plugins, setPlugins] = useState<PluginFunc[]>([]);

    useEffect((): void => {
        pluginNames.forEach(desc => {
            const loaded = withScript(desc.name, desc.url);
            setPlugins([...plugins, loaded]);
        });
    }, []);
Run Code Online (Sandbox Code Playgroud)

您对此有任何经验或任何线索吗?我认为重点是 2 个应用程序使用 2 个 React 实例,但这些是我的猜测。我的配置有问题吗?

ano*_*ous 3

确保将共享依赖项添加到 webpack.config 文件中。

请参阅下面的示例:

  plugins: [
    new ModuleFederationPlugin(
      {
        name: 'MFE1',
        filename:
          'remoteEntry.js',

        exposes: {
          './Button':'./src/Button',
        },
        shared: { react: { singleton: true }, "react-dom": { singleton: true } },
      }
    ),
    new HtmlWebpackPlugin({
      template:
        './public/index.html',
    }),
  ],
};
Run Code Online (Sandbox Code Playgroud)

我使用此共享属性设置了主机和远程项目。当钩子破坏了我的主机应用程序时,为我修复了它。这是因为存在重复的react依赖项,无论版本是否相同,您都会收到此错误。