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

基于Material UI的TS组件库无法在Next.js应用中使用

React/MUI组件库在Next.js中触发React.createElement错误的解决方案

问题背景

我开发了一个基于React 18、MUI 5和Emotion的组件库,将核心依赖声明为peerDependencies以实现包体积优化和共享ThemeProvider:

"peerDependencies": {
  "@emotion/react": "^11.10.5",
  "@emotion/styled": "^11.10.5",
  "@mui/icons-material": "^5.10.15",
  "@mui/material": "^5.10.15",
  "react": "18.2.0",
  "react-dom": "18.2.0"
}

Rollup配置中已将这些依赖设为外部依赖,避免打包进组件库:

external: [
  'react',
  'react-dom',
  /@emotion\/.*/,
  /@mui\/.*/,
],
output: [
  {
    file: 'dist/index.cjs.min.js',
    format: 'cjs',
    sourcemap: true,
    plugins: [terser()],
  },
  {
    file: 'dist/index.esm.min.js',
    format: 'esm',
    sourcemap: true,
    plugins: [terser()],
  },
],
plugins: [
  resolve({ browser: true }),
  // 其他插件省略
  typescript({ tsconfig: './tsconfig.json' }),
],

组件库已发布到npm,在Storybook和纯React应用中使用正常,但在Next.js 13 + Webpack 5项目中运行dev命令时,只要组件库引入MUI组件(如Paper)就会触发React.createElement错误,仅含纯div的测试组件能正常运行。尝试修改tsconfig、调整peerDependencies范围均无效。

核心原因

Next.js的Webpack 5模块解析逻辑与组件库的Rollup打包输出存在冲突,导致React/MUI/Emotion模块被重复加载:

  • 组件库压缩后的ES模块可能干扰Next.js的tree-shaking和模块解析,使得应用和组件库加载了不同实例的React或MUI组件,触发React的"不同实例"错误(React要求全局仅能有一个实例)。
  • MUI依赖的Emotion样式系统在Next.js的SSR/CSR混合环境下,因模块解析路径不一致,导致样式注入逻辑异常,进而引发React.createElement调用失败。

解决步骤

1. 强制Next.js统一模块解析路径

在next.config.js中添加Webpack配置,强制让Next.js从项目根目录的node_modules加载核心依赖,避免组件库加载独立的依赖实例:

const path = require('path');

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  webpack: (config, { isServer }) => {
    // 统一React、MUI、Emotion的模块解析路径
    config.resolve.alias = {
      ...config.resolve.alias,
      'react': path.resolve(__dirname, './node_modules/react'),
      'react-dom': path.resolve(__dirname, './node_modules/react-dom'),
      '@mui/material': path.resolve(__dirname, './node_modules/@mui/material'),
      '@emotion/react': path.resolve(__dirname, './node_modules/@emotion/react'),
      '@emotion/styled': path.resolve(__dirname, './node_modules/@emotion/styled'),
    };

    // 服务端与客户端保持一致的模块加载
    if (!isServer) {
      config.externals = [...(config.externals || []), {
        react: 'React',
        'react-dom': 'ReactDOM',
      }];
    }

    return config;
  },
};

module.exports = nextConfig;

2. 调整组件库的Rollup输出配置

确保组件库的ES模块符合Next.js的优化要求:

  • 移除ES模块的terser压缩(让Next.js自行处理代码优化):
output: [
  {
    file: 'dist/index.cjs.min.js',
    format: 'cjs',
    sourcemap: true,
    plugins: [terser()],
  },
  {
    file: 'dist/index.esm.js', // 不压缩ES模块
    format: 'esm',
    sourcemap: true,
  },
],
  • 在组件库的package.json中明确指定模块入口:
{
  "main": "dist/index.cjs.min.js",
  "module": "dist/index.esm.js",
  "types": "dist/index.d.ts"
}

3. 验证并统一依赖版本

确保Next.js项目中的依赖版本与组件库的peerDependencies范围完全匹配,示例package.json依赖:

"dependencies": {
  "@emotion/react": "^11.10.5",
  "@emotion/styled": "^11.10.5",
  "@mui/icons-material": "^5.10.15",
  "@mui/material": "^5.10.15",
  "react": "18.2.0",
  "react-dom": "18.2.0",
  "next": "13.4.x"
}

运行以下命令检查并清理重复依赖:

npm ls react # 检查是否存在多个React实例
npm dedupe # 合并重复依赖

4. 临时排查:禁用Strict Mode

若问题仍存在,可临时关闭React Strict Mode验证是否为严格模式兼容性问题:

const nextConfig = {
  reactStrictMode: false,
  // 其他配置...
};

注:此为临时排查手段,建议排查完成后恢复严格模式。

内容的提问来源于stack exchange,提问作者Selena Mallet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 22:20:21