如何处理 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:
- You might have mismatching versions of React and the renderer (such as React DOM)
- You might be breaking the Rules of Hooks
- 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
中删除 react
和 react-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 库:
- A yarn monorepo 通过提升对根的依赖性,使这个问题更容易处理。
- Publish your library to either github or the npm repository 以便将其安装到您的应用中。
这看起来与您用来构建项目的教程相同。
我有一个正在处理的 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:
- You might have mismatching versions of React and the renderer (such as React DOM)
- You might be breaking the Rules of Hooks
- 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
中删除 react
和 react-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 库:
- A yarn monorepo 通过提升对根的依赖性,使这个问题更容易处理。
- Publish your library to either github or the npm repository 以便将其安装到您的应用中。
这看起来与您用来构建项目的教程相同。