You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js模块联邦开发报错:TypeError: dispatcher is null及Hook调用异常

问题排查:Next.js模块联邦开发中的多错误问题

遇到的错误现象

  • 多次代码重建后触发 TypeError: dispatcher is null
  • 浏览器控制台弹出 Invalid hook call 警告,提示Hook只能在函数组件内部调用,可能原因包括React与渲染器版本不匹配、违反Hook规则、存在多份React副本
  • 浏览器控制台出现 Warning: Cannot update a component (HotReload) while rendering a different component (wL) 警告
  • VSCode终端显示 No ModuleFederationPlugin(s) found

相关代码

page.js

/// <reference types="@module-federation/nextjs-mf/src/include-defaults" />
'use client'

import dynamic from "next/dynamic"

const Footer = dynamic(() => import("container/App"), { ssr: false });

export default function Home() {
  return (
    <>
      <h1>
        Welcome to the Shop app port: 3001
      </h1>
      {Footer ? <Footer /> : <div>Loading...</div>}
    </>
  )
}

next.config.js

const NextFederationPlugin = require("@module-federation/nextjs-mf");
const path = require("path");
const webpack = require('webpack');

const shared = ["react", "react-dom", "next/dynamic"]
const ASSET_PATH = process.env.ASSET_PATH || '/';


module.exports = {
  reactStrictMode: true,
  pageExtensions: ['mdx', 'md', 'jsx', 'js', 'tsx', 'ts'],

  experimental: {
    isrMemoryCacheSize: 0,
    appDir: true,
  },

  webpack(config, options) {
    const { isServer } = options;

    config.plugins.push(
      new NextFederationPlugin({
        name: "web-fs",
        remotes: {
          container: `container@https://xx-xx-xx-xx.xx.com.br/_next/static/chunks/remoteEntry.js?v=${Date.now()}`
        },
        filename: 'static/chunks/remoteEntry.js',
        shared: shared,
      }),
      new webpack.DefinePlugin({
        'use client': JSON.stringify(true)
      })
    );

    const fileLoaderRule = config.module.rules.find((rule) =>
      rule.test?.test?.(".svg")
    );

    config.module.rules.push(
      {
        ...fileLoaderRule,
        test: /\.svg$/i,
        resourceQuery: /url/,
      },
      {
        test: /\.svg$/i,
        issuer: /\.[jt]sx?$/,
        resourceQuery: { not: /url/ },
        use: ["@svgr/webpack"],
      }
    );

    fileLoaderRule.exclude = /\.svg$/i;

    return config;
  },
};

layout.tsx

/// <reference types="@module-federation/nextjs-mf/src/include-defaults" />
'use client'

import "./globals.css";
import { Inter } from "@next/font/google";
import Providers from "./components/Providers";
import CheckLogin from "./components/CheckLogin";
import Footer from "./components/Footer";
import { Suspense } from "react";

export const metadata = {
  title: "Web Feature Store",
};

const inter = Inter({ subsets: ["latin"] });

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  console.log("layout");
  return (
    <html lang="pt">
      <body className={inter.className}>
        <Providers>
          <CheckLogin />
          {children}
        </Providers>

        <br />
        <footer>
          <Footer />
        </footer>
      </body>
    </html>
  );
}

providers.tsx

"use client";

import { SessionProvider } from "next-auth/react";
import React, { ReactNode } from "react";

interface Props {
  children: ReactNode;
}

const Providers = (props: Props) => {
  console.log("providers");
  return <SessionProvider>{props.children}</SessionProvider>;
};

export default Providers;

package.json

{
  "name": "web-feature-store-v2",
  "version": "0.1.0",
  "private": false,
  "scripts": {
    "dev": "next dev -p 3000",
    "build": "next build && npx tailwind -i app/globals.css -o app/tailwind.css",
    "start": "next start -p 3000",
    "lint": "next lint"
  },
  "resolutions": {
    "webpack": "5.1.3"
  },
  "dependencies": {
    "@chakra-ui/react": "2.6.1",
    "@emotion/react": "11.10.6",
    "@emotion/styled": "11.10.6",
    "@google-cloud/storage": "^7.5.0",
    "@module-federation/nextjs-mf": "6.7.1",
    "@mui/icons-material": "^5.14.1",
    "@mui/material": "^5.14.2",
    "@mui/x-data-grid": "^6.10.2",
    "@next-tools/dynamic": "^0.0.11",
    "@next/font": "13.1.0",
    "@radix-ui/colors": "^3.0.0-rc.4",
    "@radix-ui/primitive": "^1.0.1",
    "@radix-ui/react-checkbox": "^1.0.4",
    "@radix-ui/react-dropdown-menu": "^2.0.5",
    "@react-oauth/google": "^0.11.1",
    "@reduxjs/toolkit": "^1.9.5",
    "@tanstack/react-query": "^4.33.0",
    "@tanstack/react-table": "^8.9.7",
    "@types/chart.js": "^2.9.40",
    "@types/node": "20.4.5",
    "@types/react": "18.2.17",
    "@types/react-dom": "18.2.7",
    "axios": "^1.4.0",
    "bootstrap": "^5.3.1",
    "chart.js": "^4.4.0",
    "class-variance-authority": "^0.7.0",
    "clsx": "^2.0.0",
    "dotenv": "^16.3.1",
    "encoding": "^0.1.13",
    "env-cmd": "^10.1.0",
    "eslint": "8.46.0",
    "eslint-config-next": "13.4.12",
    "external-remotes-plugin": "^1.0.0",
    "framer-motion": "^10.16.2",
    "fs": "^0.0.1-security",
    "lib-utils-ts": "^2.0.4-stable",
    "lucide-react": "^0.274.0",
    "net": "^1.0.2",
    "next": "13.1.6",
    "next-auth": "^4.24.7",
    "next-external-remotes-plugin": "^1.0.4",
    "react": "^18.2.0",
    "react-bootstrap": "^2.8.0",
    "react-chartjs-2": "^5.2.0",
    "react-dom": "^18.2.0",
    "react-modal": "^3.16.1",
    "react-redux": "^8.1.2",
    "reactjs-popup": "^2.0.6",
    "reactstrap": "^9.2.0",
    "sharp": "^0.32.4",
    "tailwind-merge": "^1.14.0",
    "tailwindcss-animate": "^1.0.7",
    "typescript": "5.1.6",
    "webpack": "^5.75.0",
    "yarn": "^1.22.22"
  },
  "devDependencies": {
    "@faker-js/faker": "^8.0.2",
    "@types/react-modal": "^3.16.0",
    "autoprefixer": "^10.4.14",
    "json-loader": "^0.5.7",
    "postcss": "^8.4.27",
    "react-router-dom": "^6.14.2",
    "tailwindcss": "^3.3.3"
  },
  "browser": {
    "child_process": false,
    "fs": false,
    "tls": false
  }
}

问题修复方案

1. 解决多份React副本与Hook调用错误

  • 原因:shared配置为数组形式,未强制单例,导致主/远程应用加载多份React;错误通过DefinePlugin定义use client,破坏React运行时机制
  • 修复:
    • 修改shared为对象配置,强制单例并指定版本:
      const shared = {
        react: { singleton: true, requiredVersion: "^18.2.0" },
        "react-dom": { singleton: true, requiredVersion: "^18.2.0" },
        "next/dynamic": { singleton: true }
      };
      
    • 移除new webpack.DefinePlugin({ 'use client': JSON.stringify(true) }),use client是Next.js原生指令,无需额外定义

2. 修复No ModuleFederationPlugin(s) found警告

  • 原因:Next.js 13 App Router下,服务端不需要生成remoteEntry,插件全局添加导致服务端识别异常
  • 修复:在webpack配置中仅客户端添加插件:
    if (!isServer) {
      config.plugins.push(
        new NextFederationPlugin({
          name: "web-fs",
          remotes: {
            container: `container@https://xx-xx-xx-xx.xx.com.br/_next/static/chunks/remoteEntry.js?v=${Date.now()}`
          },
          filename: 'static/chunks/remoteEntry.js',
          shared: shared,
        })
      );
    }
    

3. 修复动态组件加载与HotReload警告

  • 原因:动态组件Footer是构造函数,永远为真,手动条件判断无效;热重载时组件更新时机冲突
  • 修复:用Suspense包裹动态组件替代手动Loading:
    export default function Home() {
      return (
        <>
          <h1>Welcome to the Shop app port: 3001</h1>
          <Suspense fallback={<div>Loading...</div>}>
            <Footer />
          </Suspense>
        </>
      )
    }
    

4. 修复webpack版本冲突

  • 原因:resolutions强制webpack@5.1.3与dependencies中webpack@5.75.0冲突,导致插件加载异常
  • 修复:删除resolutions中的webpack配置,运行yarn install重新安装依赖

内容的提问来源于stack exchange,提问作者douglas siqueira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 01:32:04