如何解决我的 Vite 库(npm 包 - React 组件)抛出“无效的钩子调用...”的问题?

问题描述 投票:0回答:1

我已经构建了一个npm包,一个使用Vite及其库模式的可重用的ReactJS组件。它一直有效,直到一个多星期前,当我尝试运行本地开发服务器以通过 npm 符号链接添加一些新功能时。就在这时,它突然抛出了

Invalid hook call. Hooks can only be called inside of the body of a function component...

Error displayed in the devtools

作为我使用的库的初始指南这篇文章

我尝试过的解决方案:
  • 错误中描述的问题

    我做的第一件事是检查错误中描述的三个可能的原因。

    1. React 和 ReactDOM 是同一版本(版本.19.0.0)
    2. 我找不到任何违反“Hooks 规则”的钩子
    3. 我已经按照Duplicate React
    4. 部分中所述查找了重复的导出对象

    阅读类似情况时出现问题的一般原因似乎是使用 npm 链接或符号链接。但即使删除它后,错误仍然存在。

  • 检查早期的 git 版本

    由于当前的 git 版本无法工作,我尝试查看早期版本。但开发工具仍然显示该版本的相同错误。

  • 创建一个新的干净的Vite项目并安装我的npm包

    我还创建了一个单独的新的干净的Vite项目,我在其中安装了npm包。它显示错误。

  • 查看了帖子建议

    我已经浏览了此问题

    中链接的线程中的许多建议解决方案
    • 删除符号链接(从node_modules)
    • resolutions
      标志添加到 package.json
    • 将 React 和 ReactDOM 移动或添加到
      peerDependencies
缩小问题范围:

项目的主要部分是lib、src和dist文件夹。

  • lib - 包含库组件的所有逻辑
  • src - 演示页面,用于测试/实现库组件。
  • dist - 来自库组件“包”的转译代码。

Main project structure

💡因为我可以通过相对路径(来自lib文件夹)实现src文件夹中的组件,没有任何问题。 我最好的猜测是配置和 dist-folder 的某些内容导致了错误。

package.json

{
  "name": "react-sheet-modal",
  "private": false,
  "version": "1.0.11",
  "description": "An authentic modal sheet for ReactJs - Bringing the ()iOS experience to the web",
  "repository": {
    "url": "git+https://github.com/Colin-Farkas-Personal/React-Sheet-Modal.git"
  },
  "homepage": "https://github.com/Colin-Farkas-Personal/React-Sheet-Modal/blob/main/README.md",
  "keywords": [
    "ReactJs",
    "sheet",
    "modal"
  ],
  "author": {
    "name": "Colin Farkas",
    "email": "[email protected]"
  },
  "type": "module",
  "main": "dist/main.js",
  "module": "dist/main.js",
  "types": "dist/main.d.ts",
  "files": [
    "dist"
  ],
  "sideEffects": [
    "**/*.css"
  ],
  "scripts": {
    "dev": "vite",
    "dev:app1": "vite --mode app_1",
    "dev:app2": "vite --mode app_2",
    "build": "tsc -b ./tsconfig.lib.json && vite build",
    "build:watch": "tsc -b ./tsconfig.lib.json && vite build --watch",
    "lint": "eslint .",
    "preview": "vite preview",
    "prepublishOnly": "npm run build"
  },
  "peerDependencies": {
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  },
  "devDependencies": {
    "@eslint/js": "^9.13.0",
    "@types/node": "^22.9.3",
    "@types/react": "^18.3.11",
    "@types/react-dom": "^18.3.1",
    "@vitejs/plugin-react": "^4.3.3",
    "concurrently": "^9.1.0",
    "eslint": "^9.13.0",
    "eslint-plugin-react-hooks": "^5.0.0",
    "eslint-plugin-react-refresh": "^0.4.13",
    "globals": "^15.11.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "sass": "^1.83.0",
    "typescript": "~5.6.2",
    "typescript-eslint": "^8.10.0",
    "vite": "^5.4.9",
    "vite-plugin-dts": "^4.3.0",
    "vite-plugin-lib-inject-css": "^2.1.1",
    "vite-plugin-restart": "^0.4.2",
    "vite-plugin-svgr": "^4.3.0"
  }
}

vite.config.ts

import { resolve } from 'path';
import { defineConfig } from 'vite';
import dts from 'vite-plugin-dts';
import { libInjectCss } from 'vite-plugin-lib-inject-css';
import ViteRestart from 'vite-plugin-restart';
import svgr from 'vite-plugin-svgr';

export default defineConfig({
  plugins: [
    libInjectCss(),
    dts({
      tsconfigPath: resolve(__dirname, 'tsconfig.lib.json'),
    }),
    ViteRestart({
      restart: ['/lib/**'],
    }),
    svgr({
      svgrOptions: {
        ref: true,
        svgo: false,
        titleProp: true,
      },
      include: '**/*.svg',
    }),
  ],
  build: {
    copyPublicDir: false,
    lib: {
      entry: resolve(__dirname, 'lib/main.ts'),
      formats: ['es'],
    },
    rollupOptions: {
      output: {
        assetFileNames: 'assets/[name][extname]',
        entryFileNames: '[name].js',
      },
      external: ['react', 'react-dom'],
    },
  },
  resolve: {
    dedupe: ['react', 'react-dom'],
  },
});

tsconfig.app.json

{
  "compilerOptions": {
    "target": "ES6",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "Bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true,

    "types": ["vite/client"]
  },
  "include": ["src", "env.ts", "src/vite-env.d.ts"]
}

tsconfig.lib.json

{
  "extends": "./tsconfig.app.json",
  "include": ["lib"],
  "exclude": ["src"]
}
reactjs npm vite
1个回答
0
投票

我能够通过确保没有react/jsx-runtime实例被导入或捆绑到转译代码中来修复这个错误。

问题是 main.js 文件(在 dist 文件夹内)包含了 React/jsx-runtime,这会导致重复的 React 导出对象,因为开发环境也在使用 React。

我更新了 vite.config.ts 中的 rollupOptions 以正确排除 React/jsx-runtime 代码:

export default defineConfig({
  { ... }
  build: {
    copyPublicDir: false,
    lib: {
      entry: resolve(__dirname, './lib/main.ts'),
      formats: ['es'],
    },
    rollupOptions: {
      external: ['react', 'react/jsx-runtime'],
      output: {
        assetFileNames: 'assets/[name][extname]',
        entryFileNames: '[name].js',
      },
    },
  },
});
© www.soinside.com 2019 - 2024. All rights reserved.