在此之前我们需要知道,什么是依赖项?
依赖项是一个 npm 包,我们的包依赖于它才能运行。通常作为依赖项添加的一些流行包是 lodash、axios 和 moment。
场景
假设你正在创建一个 Vue 库,甚至只是一个导出某些函数的简单 JavaScript 文件。你的项目依赖于 npm 注册表中的包。这些包是项目的依赖项。你希望从项目创建自己的 npm 包。因此,你可以用 npm pack 从项目中生成 npm 包,还可以将其发布到 npm 仓库。
其他团队会将你的包作为依赖项添加到他们自己的项目中。我们在 package.json 中使用Dependencies和peerDependencies来告诉这些其他项目还需要添加哪些包才能使我们的包正常工作。
因此,在最基本的层面上,这就是Dependencies和peerDependencies的工作方式:
Dependencies
Dependencies(依赖项)列在项目中的 package.json 文件中。
如:
json
"dependencies": {
"lodash": "^4.17.11"
}
当我们在 dependencies 中添加包时,我们的意愿是:
- 我的代码需要此包才能运行。
- 如果此包在我的node_modules目录中尚不存在,则自动添加它。
- 添加包的依赖项中列出的包。这些包称为传递依赖项。
Peer Dependencies (对等依赖关系)
Peer Dependencies :对等依赖项列在 package.json 文件中的peerDependencies里面。
如:
json
"peerDependencies": {
"@angular/core": "^7.0.0"
}
当在peerDependencies 里面添加包时, 我们的意愿是:
- 我的代码与此版本的包兼容。
- 如果此包已存在于node_modules中,则不执行任何操作。
- 如果此包在 node_modules 目录中尚不存在,或者它是错误的版本,请不要添加它。但是,向用户显示未找到它的警告。(npm警告,yarn直接报错终止下载)
那么,某个 npm 包应该进入 dependencies 还是进入 peerDependencies ,该怎么判断呢?
我们通过一个示例来更好的理解:
示例
首先,我们创建一个简单的测试项目:
shell
mkdir conflict-test
cd conflict-test
npm init -y
然后,手动编辑package.json文件并添加了两个依赖项:
json
"dependencies": {
"todd-a": "^1.0.0",
"todd-b": "^1.0.0"
}
这些 todd-a 和 todd-b 包也有其自己的依赖项:
todd-a
json
"dependencies": {
"lodash": "^4.17.11",
"todd-child": "^1.0.0"
}
todd-b
json
"dependencies": {
"lodash": "^4.17.11",
"todd-child": "^2.0.0"
}
在这里需要注意到的是, todd-a 和 todd-b 使用相同的版本 lodash 。但是,它们的 todd-child 存在版本冲突:
- todd-a 使用 Todd-Child 版本 1.0.0
- todd-b 使用 Todd-Child 版本 2.0.0
看看 npm 如何处理这个版本冲突。
在我的 conflict-test主项目中 ,我运行 npm install .正如我们所期望的那样,npm 将 todd-a 和 todd-b 包安装在我们的 node_modules 文件夹中。它还添加它们所依赖的包(传递依赖项)。因此,运行 npm install 后,我们查看node_modules文件夹。它看起来像这样:
powershell
node_modules
├── lodash 4.17.11
├── todd-a 1.0.0
├── todd-b 1.0.0
│ └── node_modules
│ └── todd-child 2.0.0
└── todd-child 1.0.0
值得注意的是,我们的项目有一个 lodash 依赖项。但是,它有两个 todd-child 依赖项。并且注意, todd-b 获取自己的私有依赖项 todd-child 2.0.0 。
所以npm的冲突处理规则是:npm 通过添加冲突包的重复私有版本来处理版本冲突。
有时,拥有同一包的两个版本是可以的。但是,当同一代码库中有两个不同版本的包时,某些包会导致冲突。
例如,假设我们的组件库是使用 Vue2 创建的。当有人将其作为依赖项添加到他们的应用程序中时,我们不希望我们的npm包添加另一个完全不同的版本Vue,如Vue3
关键是:
我们不希望我们的库将另一个版本的包添加到node-modules中,因为该包可能与现有版本冲突并导致问题。
peerDependencies or dependencies?
因此,这给我们带来了依赖项的主要问题:
当我的包依赖于另一个包时,我应该把它放在 dependencies还是peerDependencies 中?
《准则》
当满足以下条件之一时,支持使用peerDependencies:
-
拥有包的多个副本会导致冲突
-
依赖项在您的界面中可见
-
你希望开发人员自己决定要安装的版本
让我们以react-dom 为例 。显然,如果您正在创建一个 react 库,react-dom将成为库界面中非常明显的部分。因此,它属于 peerDependencies .
见react-dom官方的package.json:github.com/facebook/re...
更多示例:
但是,也许你的库在内部使用 day.js 来处理一些与时间相关的输入。day.js很可能不会暴露在你的 react 组件的界面中。因此,它属于 dependencies .