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

自研React组件库用Emotion遇无效Hook调用及Vite环境报错

React组件库构建问题:Hook调用警告与Vite环境错误

背景信息

自研React组件库采用Emotion作为样式方案,已确保项目及组件库的react、react-dom版本均为18.3.1,核心依赖版本如下:

{
  "@emotion/css": "^11.13.5",
  "@emotion/react": "^11.14.0",
  "react": "^18.3.1",
  "react-dom": "^18.3.1"
}

问题1:Parcel构建时的Hook调用警告

使用Parcel构建测试页面,浏览器控制台抛出警告:

Button.tsx:41 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:

  1. React与渲染器(如React DOM)版本不匹配
  2. 违反Hooks规则
  3. 应用中存在多份React副本

相关代码

Button组件(第41行调用useContext):

import { css } from "@emotion/css";
// [...]
import { ThemeContext } from "../theme";

// [...]

export function Button(options: ButtonOptions)
{
    // 第41行
    const theme = useContext(ThemeContext);

    const newStyle: React.CSSProperties = {};

    // 省略样式赋值逻辑
    // [...]

    let className: string = "";

    const padding = "0.7rem 1rem";

    switch (options.variant ?? "secondary")
    {
        case "secondary":
        {
            className = css `
                /* CSS样式 */
            `;
            break;
        }
        case "primary":
        {
            className = css `
                /* CSS样式 */
            `;
            break;
        }
        case "danger":
        {
            className = css `
                /* CSS样式 */
            `;
            break;
        }
        case "outline":
        {
            const dark = Color(theme.colors.background).isDark();
            const color = dark ? "#fff" : "#000";
            const hoverBg = dark ? "rgba(255, 255, 255, 0.4)" : "rgba(0, 0, 0, 0.4)";
            const pressedCharColor = dark ? "#000" : "#fff";

            className = css `
                /* CSS样式 */
            `;
            break;
        }
        case "outline-primary":
        {
            const dark = Color(theme.colors.background).isDark();
            const color = dark ? "#fff" : "#000";
            const bg = dark ? "rgba(255, 255, 255, 0.4)" : "rgba(0, 0, 0, 0.4)";
            const hoverBg = dark ? "rgba(255, 255, 255, 0.6)" : "rgba(0, 0, 0, 0.6)";
            const pressedCharColor = dark ? "#000" : "#fff";

            className = css `
                /* CSS样式 */
            `;
            break;
        }
    }

    return <button className={className} style={newStyle} type={options.type ?? "button"} disabled={options.disabled ?? false} autoFocus={options.autoFocus ?? false}>{options.children}</button>;
}

ThemeContext定义:

// [...]

export const ThemeContext: React.Context<Theme> = createContext(lightTheme);

排查与解决

尽管你确认了版本一致,但本地引用组件库(@hydroper/metrocomponents": "file:..")大概率导致项目和组件库加载了两份独立的React副本,这是Hook警告的核心诱因。

解决步骤:

  1. 统一React依赖路径:
    • 在组件库的package.json中将react、react-dom设为peerDependencies,避免重复安装;
    • 或使用npm link将组件库的React实例链接到项目的React包,确保两者共享同一实例。
  2. 确认组件调用方式:确保Button是以React组件形式使用(即<Button />),而非普通函数调用(Button()),后者会直接触发Hook调用错误。

问题2:Vite构建时的process未定义错误

切换到Vite构建后,控制台抛出错误:

assert.js?v=00bb3fe6:1843 Uncaught ReferenceError: process is not defined

项目配置(package.json)

{
  "name": "demo",
  "type": "module",
  "devDependencies": {
    "@types/react-dom": "^18.3.1",
    "@vitejs/plugin-react": "^4.3.4",
    "typescript": "~5.7.2",
    "vite": "^6.1.0"
  },
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "@emotion/css": "^11.13.5",
    "@emotion/react": "^11.14.0",
    "@fontsource/open-sans": "^5.1.1",
    "@hydroper/metrocomponents": "file:..",
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  }
}

排查与解决

Vite默认不会在浏览器环境注入process对象,而@emotion/css的部分内部逻辑依赖了process.env,因此触发报错。

解决步骤:

  1. 在Vite中模拟process变量:
    在vite.config.ts中添加define配置,注入必要的process变量:
    import { defineConfig } from 'vite';
    import react from '@vitejs/plugin-react';
    
    export default defineConfig({
      plugins: [react()],
      define: {
        'process.env': {},
        // 若需要特定变量,比如NODE_ENV,可设置为:
        // 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
      }
    });
    
  2. 切换到Emotion的JSX语法:
    改用@emotion/react的JSX pragma替代@emotion/css,这种方式更贴合React生态,也能避免对process的依赖。修改组件代码:
    /** @jsxImportSource @emotion/react */
    import { css } from '@emotion/react';
    
    // 组件内样式定义改为:
    const buttonStyle = css`
      /* 样式内容 */
    `;
    
  3. 升级Emotion版本:检查是否有更新的Emotion版本修复了process依赖问题,尝试升级@emotion/css和@emotion/react到最新稳定版。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 10:34:51