为什么在npm中对插件使用对等依赖?

例如,为什么一个Grunt插件将它对Grunt的依赖定义为“同行的依赖性”?

为什么插件不能在grunt-plug / node_modules中把Grunt作为自己的依赖项?

对等依赖关系描述在这里:https://nodejs.org/en/blog/npm/peer-dependencies/

但我不太明白。

< em > < / em >例子

我正在使用AppGyver类固醇,目前使用Grunt任务将我的源文件构建到/dist/文件夹中,以在本地设备上提供服务。我是npm的新手,所以我想完全理解发生了什么。

到目前为止,我得到了这个:

[rootfolder] / package.json告诉npm它依赖于grunt-steroids npm包进行开发:

  "devDependencies": {
"grunt-steroids": "0.x"
},

好的。在(rootfolder)中运行npm install会检测依赖并在[rootfolder] / node_modules / grunt-steroids中安装grunt-steroids。

然后Npm读取[rootfolder] / node_modules / grunt-steroids / package.json,这样它就可以安装grunt-steroids自己的依赖项:

"devDependencies": {
"grunt-contrib-nodeunit": "0.3.0",
"grunt": "0.4.4"
},
"dependencies": {
"wrench": "1.5.4",
"chalk": "0.3.0",
"xml2js": "0.4.1",
"lodash": "2.4.1"
},
"peerDependencies": {
"grunt": "0.4.4",
"grunt-contrib-copy": "0.5.0",
"grunt-contrib-clean": "0.5.0",
"grunt-contrib-concat": "0.4.0",
"grunt-contrib-coffee": "0.10.1",
"grunt-contrib-sass": "0.7.3",
"grunt-extend-config": "0.9.2"
},

依赖关系”包被安装到[rootfolder] / node_modules / grunt-steroids / node_modules中,这对我来说是合乎逻辑的。

devDependencies”没有安装,我确信这是由npm检测控制的,我只是试图使用grunt-steroids,而不是在它上面开发。

但是我们有“peerDependencies”。

这些安装在[rootfolder] / node_modules,我不明白为什么在那里而不是在[rootfolder] / node_modules / grunt-steroids / node_modules,以避免与其他grunt插件(或其他)的冲突?

110342 次浏览

我建议你先把文章再读一遍。这有点令人困惑,但winston-mail的例子告诉了你为什么:

例如,让我们假设winston-mail@0.2.3在它的"dependencies"对象中指定了"winston": "0.5.x",因为这是它测试的最新版本。作为一个应用程序开发人员,你想要最新最好的东西,所以你查找winstonwinston-mail的最新版本,并把它们放在你的包中。json作为

{
"dependencies": {
"winston": "0.6.2",
"winston-mail": "0.2.3"
}
}

但是现在,运行npm install会导致意外的依赖关系图

├── winston@0.6.2
└─┬ winston-mail@0.2.3
└── winston@0.5.11

在这种情况下,一个包可能有多个版本,这将导致一些问题。对等依赖允许npm开发人员确保用户拥有特定的模块(在根文件夹中)。但是您的观点是正确的,描述一个特定版本的包将导致使用其他版本的其他包出现问题。正如文章所述,这个问题与npm开发人员有关

一条建议:对等依赖需求,不像那些常规依赖,应该宽大处理. 0。您不应该将您的对等依赖关系锁定到特定的补丁版本。

因此,开发人员应该遵循semver来定义peerDependencies。你应该在GitHub上为咕噜类固醇包打开一个问题…

TL;博士: peerDependencies用于向消费代码公开(并期望被使用)的依赖项,而“private"依赖项则没有公开,只是一个实现细节。

对等依赖解决的问题

NPM的模块系统是分层的。对于更简单的场景,一个很大的优势是当你安装一个npm包时,这个包自带它自己的依赖关系,所以它可以开箱即用。

但问题出现在:

  • 您的项目和正在使用的某些模块都依赖于另一个模块。
  • 这三个模块必须相互通信。

在示例

假设你正在构建YourCoolProject,并且同时使用了JacksModule 1.0JillsModule 2.0。让我们假设JacksModule也依赖于JillsModule,但依赖于不同的版本,比如1.0。只要这两个版本不满足,就没有问题。事实上,JacksModule在表面之下使用JillsModule只是一个实现细节。我们将JillsModule捆绑两次,但当我们获得稳定的软件时,这是一个很小的代价。

但是现在如果JacksModule以某种方式暴露了它对JillsModule的依赖呢?它接受JillsClass的实例,例如…当我们使用库的2.0版本创建new JillsClass并将其传递给jacksFunction时,会发生什么?一切都会乱套的!像jillsObject instanceof JillsClass这样简单的东西会突然返回false,因为jillsObject实际上是JillsModule1 JillsClass的实例,即2.0版本。

对等依赖如何解决这个问题

它们告诉npm

我需要这个包,但我需要的版本,这是部分

.项目,而不是模块的私有版本

当npm看到你的包被安装到一个有依赖或者有不兼容的版本依赖的项目中时,它会在安装过程中警告用户。

什么时候应该使用对等依赖关系?

  • 当你构建一个供其他项目使用的库时,而且 .
  • 这个库正在使用另一个库而且
  • 您期望/需要用户也使用其他库

常见的场景是大型框架的插件。比如Gulp, Grunt, Babel, Mocha等。如果你写了一个Gulp插件,你希望这个插件与用户的项目使用的是同一个Gulp,而不是你自己的Gulp私有版本。

peerDependencies用最简单的例子解释:

{
"name": "myPackage",
"dependencies": {
"foo": "^4.0.0",
"react": "^15.0.0"
}
}




{
"name": "foo"
"peerDependencies": {
"react": "^16.0.0"
}
}

在myPackage中运行npm install会抛出一个错误,因为它正在尝试安装仅与React ^16.0.0兼容的^15.0.0foo版本的React。

peerDependencies未安装。