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

Tho*_*ock 185 package-managers node.js npm

例如,为什么Grunt插件将其对grunt的依赖定义为" 对等依赖 "?

为什么插件不能将Grunt作为grunt-plug/node_modules中的依赖?

此处描述了对等依赖关系:https://nodejs.org/en/blog/npm/peer-dependencies/

但我真的不明白.

我正在使用AppGyver Steroids,它使用Grunt任务将我的源文件构建到/ dist /文件夹中,以便在本地设备上提供.我在npm和grunt都很新,所以我想完全理解发生了什么.

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

[rootfolder] /package.json告诉npm它取决于grunt-steroids用于开发的npm包:

  "devDependencies": {
    "grunt-steroids": "0.x"
  },
Run Code Online (Sandbox Code Playgroud)

好的.在[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"
  },
Run Code Online (Sandbox Code Playgroud)

" dependencies "包安装在[rootfolder]/node_modules/grunt-steroids/node_modules中,这对我来说是合乎逻辑的.

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

但后来我们有了" peerDependencies ".

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

Sti*_*itt 366

TL; DR:*) peerDependencies用于向消费代码公开(并且预期由消费代码使用)的依赖项,而不是未公开的"私有"依赖项,并且仅是实现细节.

问题对等依赖关系解决了

npm的模块系统是分层的.更简单场景的一大优势是,当你安装一个npm软件包时,该软件包会带来它自己的依赖项,因此它可以开箱即用.

但问题出现在:

  • 您的项目和您正在使用的某个模块都依赖于同一个其他模块.
  • 这三个模块必须相互通信.

假设您正在构建YourCoolProject并正在使用JacksModule 1.0JillsModule 2.0.我们假设这JacksModule也取决于JillsModule,但是在不同的版本上,比方说1.0.只要这两个版本不符合,就没有问题.在表面下JacksModule使用的事实JillsModule只是一个实现细节.我们捆绑JillsModule两次,但是当我们获得开箱即用的稳定软件时,这是一个很小的代价.

但现在让我们假设以某种方式JacksModule暴露其依赖性JillsModule.它接受一个对象JillsClass new JillsClass,例如......当我们创建一个库的2.0使用版本jacksFunction并将其传递给它时会发生jillsObject instanceof JillsClass什么?一切都会破裂!简单的事情想false会突然返回jillsObject,因为JillsClass实际上是一个实例另一个 2.0peerDependencies版本.

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

他们告诉npm

我需要这个软件包,但我需要的是项目的一部分版本,而不是我的模块私有版本.

当npm看到您的软件包被安装到没有该依赖项的项目中,或者它具有不兼容的版本时,它将在安装过程中警告用户.

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

  • 在构建要由其他项目使用的库时,以及
  • 这个库正在使用其他一些库,
  • 您期望/需要用户也可以使用其他库

常见场景是大型框架的插件.想想Gulp,Grunt,Babel,Mocha等等.如果你编写一个Gulp插件,你希望该插件能够与用户项目所使用的Gulp相同,而不是使用你自己的私有版本的Gulp.


*)太长; 没看过.用于表示没有读过(长)文本

  • 我可以想象人们创建的Grunt插件是Grunt的粉丝:)因此,对于他们来说,在他们的插件构建过程中使用Grunt似乎很自然。他们用来创建它的构建过程?将其添加为开发依赖项可以使他们解耦。基本上有两个阶段:构建时间和运行时间。在构建期间需要开发依赖项。运行时需要常规和对等依赖项。当然有了依赖的依赖,一切都会很快变得混乱:) (4认同)
  • 我注意到一件重要的事情,但在任何地方都没有提到,当我们构建插件时,对于对等依赖项,我们是否应该有一个包依赖项的副本?在 OP 示例中,我们可以看到 `"grunt": "0.4.4"` 在 devDependencies 和 peerDependencies 中都存在,并且在那里有一个副本对我来说确实有意义,因为这意味着我需要那个 `grunt ` 包供我自己使用,而且我的库的用户可以使用他们自己的版本,只要它尊重 peerDependencies 版本锁。那是对的吗?或者 OP 示例是一个非常糟糕的示例? (3认同)
  • @tonix 或者第三个选项:克隆 `JacksModule` 存储库,将其升级为依赖于 `JillsModule ^2.0.0` 并向项目维护人员提供 PR。首先提交一个错误,说明此依赖项已过时,您希望帮助更新它,这可能会有所帮助。如果你做了一个好的 PR,大多数库维护者都会合并它并感谢你。如果维护者没有反应,您可以将您的分叉发布到您名下的 NPM 命名空间,然后使用您的分叉。无论如何,都有解决方案,但“peerDependency”本身并不能解决它。 (2认同)

Fer*_* To 24

我建议你先重新阅读这篇文章.这有点令人困惑,但winston-mail的例子向您展示了答案原因:

例如,让我们假装winston-mail 0.2.3在其"依赖关系"哈希中指定"winston":"0.5.x",因为这是它测试的最新版本.作为应用程序开发人员,您需要最新和最好的东西,所以你查找最新版本的winston和winston-mail,将它们放在你的package.json中

{
  "dependencies": {  
    "winston": "0.6.2",  
    "winston-mail": "0.2.3"  
  }  
}
Run Code Online (Sandbox Code Playgroud)

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

??? winston@0.6.2  
??? winston-mail@0.2.3                
  ??? winston@0.5.11
Run Code Online (Sandbox Code Playgroud)

在这种情况下,可能有一个包的多个版本会导致一些问题.peerDependencies允许npm开发人员确保用户具有特定模块(在根文件夹中).但是你的说法是正确的,即描述一个特定版本的软件包会导致使用其他版本的其他软件包出现问题.正如文章所述,这个问题与npm开发人员有关

一条建议:与常规依赖项不同,对等依赖项要求应该是宽松的.您不应将对等依赖项锁定到特定的修补程序版本.

因此,开发人员应该遵循semver来定义peerDependencies.您应该在github上为grunt-steriods包打开一个问题...


Chr*_*kar 9

peerDependencies 用最简单的示例进行解释:

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


{
  "name": "foo"
  "peerDependencies": {
    "react": "^16.0.0"
  }
}
Run Code Online (Sandbox Code Playgroud)

在myPackage中运行npm install会抛出错误,因为它试图安装React版本^15.0.0AND foo并且仅与React兼容^16.0.0

没有安装peerDependencies。