为什么在npm插件中使用对等依赖?
为什么在npm插件中使用对等依赖?
为什么一个Grunt插件会将其对grunt的依赖定义为peer dependencies?
为什么插件不能只将Grunt作为它自己在grunt-plug/node_modules中的依赖呢?
关于peer dependencies的描述可以在这里找到: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"
},
好的。在[rootfolder]中运行npm install会检测到这个依赖,并将grunt-steroids安装在[rootfolder]/node_modules/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"
},
"dependencies"的包被安装在[rootfolder]/node_modules/grunt-steroids/node_modules中,对我来说这是合理的。
"devDependencies"没有被安装,我确信这是由npm检测到我只是想使用grunt-steroids
,而不是在其上进行开发所控制的。
但是接下来是"peerDependencies"。
这些被安装在[rootfolder]/node_modules中,我不明白为什么不是在[rootfolder]/node_modules/grunt-steroids/node_modules中,这样就可以避免与其他grunt插件(或其他)的冲突了?
为什么在npm中使用对等依赖(peerDependencies)插件?
在使用npm安装插件时,可能会遇到peerDependencies的错误。这是因为插件的依赖关系与当前项目的依赖关系不匹配。解决这个问题的方法是使用peerDependencies。
peerDependencies是指在开发插件时,插件作者可以指定其插件所需的特定版本的依赖库。这样,在安装插件时,npm会检查项目的依赖关系,并确保与插件所需的依赖关系匹配。
例如,假设我们有一个名为myPackage的项目,其依赖关系如下:
{
"name": "myPackage",
"dependencies": {
"foo": "^4.0.0",
"react": "^15.0.0"
}
}
同时,我们有一个名为foo的插件,其peerDependencies指定了所需的React版本:
{
"name": "foo",
"peerDependencies": {
"react": "^16.0.0"
}
}
当我们在myPackage中运行npm install时,由于它尝试安装React版本^15.0.0和只与React ^16.0.0兼容的foo插件,将会抛出错误。此时,peerDependencies不会被安装。
有人可能会问,为什么不直接在foo插件的依赖关系中加入React 16呢?这样一来,就可以同时使用React 15和React 16,并且foo插件可以使用React 16,而myPackage可以使用React 15。
然而,React是一个在运行时启动的框架,为了在同一个页面上同时存在React 15和React 16,需要同时启动它们,这对终端用户来说将会非常沉重和问题重重。因此,如果foo插件可以同时使用React 15和React 16,它可以将peerDependency列为">=15 < 17"。
总之,使用peerDependencies可以确保插件的依赖关系与当前项目的依赖关系相匹配,避免了版本冲突和不兼容的问题。这对于保证项目的稳定性和正确性非常重要。
为了插件能够正常运行并防止出现版本冲突的问题,npm使用了peer dependencies。下面的内容解释了为什么使用peer dependencies以及解决方法。
在上述引用的例子中,winston-mail插件指定了它在dependencies中对winston的版本依赖为"0.5.x",因为这是该插件经过测试的最新版本。然而,作为应用程序开发者,你可能想要使用最新版本的插件,所以你在package.json中将winston和winston-mail的最新版本写入dependencies中。然而,运行npm install后,你会得到以下意外的依赖关系图:
├── winston.6.2
└─┬ winston-mail.2.3
└── winston.5.11
这种情况下可能会导致多个版本的包共存,从而引发一些问题。通过使用peer dependencies,npm开发者可以确保用户在根文件夹中安装了指定的模块。但你所说的只描述一个特定版本的包可能会导致其他使用不同版本的包发生问题,这一点是正确的。这个问题需要npm开发者来解决,正如文章所述:
“一个建议是:与常规依赖不同,peer dependency的要求应该是宽容的。你不应该将peer dependency锁定为特定的补丁版本。”
因此,开发者应该遵循semver来定义peerDependencies。你应该在GitHub上为grunt-steroids包提交一个issue……
你提到“多个版本的包可能会导致一些问题”,但这不正是包管理器的用意吗?文章中甚至在前面更详细地讨论了这个问题,项目中有两个相同包的版本:一个由开发者提供,一个由第三方库提供。
我想我明白了peer dependency的意义,但在winston的例子中,现在我是否无法使用winston-mail库,因为我的winston版本与peer dependency不匹配?与其完全无法使用该库,我宁愿对winston进行临时降级以保证该库的正常使用。
针对你的第一个评论,据我理解和使用,这与测试有关。例如,如果你有一个经过你测试的包,它依赖于一个特定的第三方包,你无法确定如果你的依赖关系发生变化(修复错误,重大功能更新),你的包是否仍然能够正常工作。因此,你可以指定一个特定的插件版本,并通过测试来确保安全性。
关于你的第二个评论:这就是为什么文档中说开发者在包的依赖关系中应该宽容,并使用semver的原因。例如,可以使用"~0.2.1"代替"0.2.1",它允许"0.2.x"的版本,但不允许"0.3.x"的版本,或者使用">=0.2.1",它允许"0.2.x"到"1.x"的版本,或者使用"x.2."……(但不太推荐,npm包通常使用~)。
为什么要在npm中使用peerDependencies
来进行插件的依赖管理?
问题的出现的原因是:
- NPM的模块系统是分层的,当你安装一个npm包时,该包会自带它自己的依赖,以便它可以直接使用。
- 但是当你的项目和你正在使用的某个模块都依赖于另一个模块时,问题就出现了。
解决方法是使用peerDependencies
,它告诉npm:
- 我需要这个包,但是我需要的是项目中的版本,而不是我的模块私有的版本。
- 当npm看到你的包被安装在一个不具备这个依赖或者具有不兼容版本的项目中时,它会在安装过程中警告用户。
什么时候应该使用peerDependencies
呢?
- 当你正在构建一个要被其他项目使用的库,并且这个库使用了其他库,而且你希望/需要用户也使用这个其他库时,应该使用peerDependencies
。
- 常见的情况是大型框架的插件。比如Gulp、Grunt、Babel、Mocha等。如果你编写一个Gulp插件,你希望这个插件与用户项目中使用的相同的Gulp一起工作,而不是与你自己的私有版本的Gulp一起工作。
当存在版本不兼容时,peerDependencies
并不能解决问题,但它能帮助我们明确地显示版本不匹配的问题,而不是在使用两个版本的情况下默默地使用。应用程序开发人员在选择库时将不得不找到解决方案。
当项目维护者没有响应时,你可以将自己的修改后的分支发布到以你的名字命名的NPM空间下,并使用你的分支。如果维护者没有响应,你可以将你的分支发布到以你的名字命名的NPM空间下,并使用你的分支。你也可以先提交一个bug,说明这个依赖已经过时,你愿意帮助更新。如果你提交了一个好的PR,大多数库的维护者会合并并感谢你的贡献。
如果项目维护者没有响应,并且我将我的分支发布到NPM上,其他人如何与我合作,向我的分支发送问题和PR,而不是原始/无响应的仓库?
你可以在你自己的分支上创建一个Issues选项卡,这样其他人就可以与你合作,向你的分支发送问题和PR。
以上就是关于为什么要在npm中使用peerDependencies
来进行插件的依赖管理的内容。