如何处理 NPM 包中的重复包?

How to handle duplicate packages from NPM package?

我有一个正在处理的 NPM 包,它具有 react 的依赖性。然后我有一个测试应用程序,其中 react 作为依赖项安装。当我将我的 npm 包导入测试应用程序时,出现以下错误:

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. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app

运行 npm ls react 在我的测试应用程序中表明我可能有 react:

的副本
test-app@0.1.0 
├─┬ @package-name/react@1.0.0 -> ./../package-name-react
│ ├─┬ react-dom@17.0.2
│ │ └── react@17.0.2 deduped
│ └── react@17.0.2 // <----------------
├─┬ next@12.1.0
│ ├── react@17.0.2 deduped
│ ├─┬ styled-jsx@5.0.0
│ │ └── react@17.0.2 deduped
│ └─┬ use-subscription@1.5.1
│   └── react@17.0.2 deduped
├─┬ react-dom@17.0.2
│ └── react@17.0.2 deduped
└── react@17.0.2 // <----------------

我的 npm 包的 package.json 看起来像这样:

{
  "name": "@package-name/react",
  "version": "1.0.0",
  "description": "",
  "main": "dist/cjs/index.js",
  "module": "dist/esm/index.js",
  "files": [
    "dist"
  ],
  "types": "dist/index.d.ts",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "clean": "rimraf dist",
    "build": "npm run clean && rollup -c"
  },
  "devDependencies": {
    "@rollup/plugin-commonjs": "^20.0.0",
    "@rollup/plugin-node-resolve": "^13.0.4",
    "@rollup/plugin-typescript": "^8.2.5",
    "rimraf": "^3.0.2",
    "rollup": "^2.56.2",
    "rollup-plugin-dts": "^3.0.2",
    "rollup-plugin-peer-deps-external": "^2.2.4",
    "rollup-plugin-postcss": "^4.0.1",
    "rollup-plugin-terser": "^7.0.2",
    "typescript": "^4.3.5"
  },
  "dependencies": {
    "socket.io-client": "^4.4.1"
  },
  "peerDependencies": {
    "react": "17.0.2",
    "react-dom": "17.0.2"
  }
}

当我从 peerDependencies 中删除 reactreact-dom 时,错误消失但会导致其他问题。这几乎就像 peerDependencies 正在安装并卷入我的包中。

现阶段我的包中的组件非常简单,如下所示:

const MyComponent  = ({ 
  children 
}) => {
  const [myValue, setValue] = useState(false);

  useEffect(() => {
    setFlagValue(true)
  }, []);

  return (
    <>
      {children}
    </>
  )
};

然后我在我的测试应用程序中使用这个包,如下所示:

import { MyComponent } from "package-name/react";

const MyApp = () => {
  <MyComponent>
    <div>Hello world</div>
  </MyComponent>
}

汇总配置:

import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import { terser } from 'rollup-plugin-terser';
import external from 'rollup-plugin-peer-deps-external';
import postcss from 'rollup-plugin-postcss';
import dts from 'rollup-plugin-dts';

const packageJson = require('./package.json');

export default [
    {
        input: 'src/index.ts',
        output: [
            {
                file: packageJson.main,
                format: 'cjs',
                sourcemap: true,
                name: 'react-ts-lib'
            },
            {
                file: packageJson.module,
                format: 'esm',
                sourcemap: true
            }
        ],
        plugins: [
            external(),
            resolve(),
            commonjs(),
            typescript({ tsconfig: './tsconfig.json' }),
            postcss(),
            terser()
        ],
    },
    {
        input: 'dist/esm/types/index.d.ts',
        output: [{ file: 'dist/index.d.ts', format: "esm" }],
        external: [/\.css$/],
        plugins: [dts()],
    },
]

从问题描述中看不清楚,但查看回购协议,我看到 package is installed locally.

"dependencies": {
  "next": "12.1.0",
  "react": "17.0.2",
  "react-dom": "17.0.2",
  "react-ts-lib": "file:../react-ts-lib"
},

这意味着 lib 代码仍然使用自己的 node_modules(本地安装)而不是 app 依赖项来解析 react

解决这个问题的一种方法是使用 create-react-library 之类的东西设置 lib 项目,它明确地解决了这个问题:

If you use react-hooks in your project, when you debug your example you may run into an exception Invalid Hook Call Warning. This issue explains the reason, your lib and example use a different instance, one solution is rewrite the react path in your example [app] package.json to 'file:../node_modules/react' or 'link:../node_modules/react'.

请注意,在您的情况下,您可以简单地将库 devDependencies 中的 react 的路径更改为指向应用程序的 react:

  "devDependencies": {
    "@rollup/plugin-commonjs": "^20.0.0",
    "@rollup/plugin-node-resolve": "^13.0.4",
    "@rollup/plugin-typescript": "^8.2.5",
    "@types/react": "^17.0.18",
    "react": "file:../my-app/node_modules/react",

或者反过来,取决于什么最有意义。


还有其他方法可以在本地开发 React 库: