希望通过此文阐明当你要使用 npm 的时候知道什么是
npm peerDependencies,弄明白什么时候以及为什么使用它。peerDependencies(翻译:“同行依赖”或“对等依赖”)是package.json文件中的peerDependencies属性对象(列表)。
为了更好的理解此文,你至少要先了解npm
本文内容:
- 首先,我们将准确比较
dependencies与peerDependencies的工作方式。 - 其次,我们将看到一些
dependencies与peerDependencies的示例。 - 然后,我们将研究 npm 如何处理版本冲突。
- 最后,通过上面的基础铺垫,我们将看看如何合理的使用
peerDependencies。
设想
为了保持真实性,假设您正在创建一个 Angular 库,甚至只是一个简单的 JavaScript 文件,其中导出了一些功能(函数)。
您的项目依赖于npm Registry中的软件包,这些软件包是您项目的dependencies依赖项。
你想从你的项目中创建你自己的 npm 包,所以你使用npm pack生成了一个 npm 包,你甚至想将它发布到npm Registry中。
团队中其他人想在他们项目中使用你的 npm 包作为他们项目的依赖。你在package.json使用dependencies和peerDependencies来告诉使用你的 npm 包的其他项目,要使你的 npm 包正常工作,则dependencies和peerDependencies中列出的包也需要安装。
因此,在最基本的层次上,这是dependencies与peerDependencies的工作方式:
Dependencies
Dependencies是package.json文件中的dependencies对象,当你添加一个 npm 包到dependencies对象中时,仿佛在说:
- 我的代码需要这个包才能运行。
- 如果该 npm 包在我的
node_modules目录中尚不存在,请自动添加。 - 此外,添加
dependencies中列出的 npm 包,这些 npm 包称为依赖项(transitive dependencies)。
peerDependencies
peerDependencies是package.json文件中的peerDependencies对象,当你添加一个 npm 包到peerDependencies对象中时,仿佛在说:
- 我的代码与此版本的 npm 包兼容。
- 如果此 npm 包已存在于
node_modules中,则什么也不用做。 - 如果该软件包在
node_modules目录中尚不存在或版本错误,请不要添加它。但是,需要向用户提示未找到该 npm 包的警告。
添加依赖
添加 dependencies
依赖包是我们使我们项目能够正常运行的一个 npm 包,通常作为dependencies添加的一些受欢迎的程序包有lodash、request和moment等等。
我们添加一个常规依赖项,如下所示:
1 | npm install lodash |
npm 将包名称和版本添加到我们项目的 package.json 文件中的dependencies对象中:
1 | "dependencies": { |
你们中的有些人可能还记得过去,我们不得不使用--save标志来更新 package.json 中的依赖项。值得庆幸的是,我们不再需要这样做了。
添加 peerDependencies
同行依赖包(peerDependencies)用于指定我们的程序包与 npm 程序包的特定版本兼容,Angular和React就是很好的例子。
要添加peerDependencies,您实际上需要手动修改package.json文件。例如,对于 Angular 组件库项目,我建议添加angular/core作为peerDependencies。因此,如果您想指定您的程序包是为 Angular 7 构建的,则可以包含以下内容:
1 | "peerDependencies": { |
关于冲突
我对某个 npm 包应该进入dependencies还是进入peerDependencies提出了很多疑问,做出此决定的关键在于了解 npm 如何处理版本冲突。
冲突测试
首先,我们创建一个简单的测试项目:conflict-test
我是这样创建的:
1 | md conflict-test |
然后,我手动编辑package.json文件并添加了两个依赖项:
1 | "dependencies": { |
这两个todd-a和todd-b软件包也具有它们自己的依赖项:
1 | // todd-a: |
我想让您注意的是,todd-a和todd-b使用的是lodash的相同版本。但是,它们对于todd-child有版本冲突:
todd-a使用todd-child版本1.0.0todd-b使用todd-child版本2.0.0
现在我知道,像我一样,您非常感兴趣,看看 npm 如何处理此版本冲突。在我的项目conflict-test中运行npm install,就像我们期望的那样,npm 在我们的node_modules文件夹中神奇地安装了todd-a和todd-b软件包。它还添加了它们所依赖的程序包(transitive dependencies)。因此,在运行npm install之后,我们来看一下node_modules文件夹。看起来像这样:
1 | node_modules |
有趣的是,我们的项目有一个lodash副本。但是,它有两个todd-child副本。请注意,todd-b获得了其自己的todd-child 2.0.0的专用副本。
因此:
npm 通过添加有冲突的程序包的重复私有版本来处理版本冲突。
peerDependencies
从我们对 npm 版本冲突的实验中可以看出,如果将软件包添加到依赖项中,则有可能最终将其复制到node_modules中。
有时,具有相同软件包的两个版本也可以。但是,在同一代码库中有两个不同版本的某些程序包会导致冲突。
例如,假设我们的组件库是使用Angular 5创建的。当有人将其添加为Angular 6应用的依赖项时,我们不希望我们的程序包添加另一个完全不同的angular/core版本。
关键是:当该程序包可能与现有版本冲突并导致问题时,我们不希望我们的库添加另一个版本的程序包到node-modules。
选择peerDependencies还是dependencies?
当我的程序包依赖于另一个程序包时,应该将其放在dependencies还是peerDependencies中?
好吧,就像大多数技术问题一样:看情况。
peerDependencies表示兼容性。例如,您将希望具体说明您的库与哪个版本的Angular兼容。
指导方案
当满足以下条件之一时,建议使用peerDependencies:
- 多个依赖包可能会导致冲突
- 依赖关系清晰明了
- 您希望开发人员决定要安装哪个版本
让我们以angular/core为例。显然,如果您正在创建 Angular Library,则angular/core将成为您的库界面中非常明显的一部分。因此,它属于peerDependencies。
但是,也许您的库在内部使用Moment.js来处理一些与时间相关的输入,Moment.js很可能不会在 Angular Services 或组件的界面中公开。因此,它属于dependencies。
Angular 作为依赖
假设您要在文档中指定您的库是一组 Angular 组件和服务,您可能会问以下问题:
我是否甚至需要将
angular/core指定为依赖项?如果有人在使用我的库,他们将已经有一个现有的 Angular 项目。
好问题!
是的,我们通常可以假设对于我们特定于 Angular 的库,Workspace 将已经有可用的 Angular 软件包。因此,从技术上讲,我们无需费心将它们添加到我们的依赖项列表中。
但是,我们确实想告诉开发人员我们的库与哪些 Angular 版本兼容。因此,我建议采用以下方法:
至少为peerDependencies添加兼容的 Angular 版本的angular/core。
这样,如果开发人员尝试在其 Angular 6 项目中使用 Angular 7 库,则会看到警告。不必添加其他 Angular 软件包。您可以假定它们是否具有angular/core,是否具有其他 Angular 库。
总结
如有疑问,您可能应该倾向于使用peerDependencies。这样,您的软件包的用户就可以选择添加哪些软件包。