npm package.json文件中的依赖关系,devDependencies和peerDependencies之间有什么区别?


2025

该文档很难回答我的问题。我不明白那些解释。有人可以用简单的话说吗?如果很难选择简单的单词,也许还有例子?

EDIT还添加了peerDependencies,这是密切相关的,可能会引起混乱。


48
注意optionalDependencies现在也有。
艾丹·费尔德曼

117
@AidanFeldman“ optionalDependencies”是我今天的矛盾话题
Nick Bull

1
npm文档说:“依赖关系”:生产中应用程序所需的软件包。“ devDependencies”:仅本地开发和测试所需的软件包。参见链接:docs.npmjs.com/…–
Deke,

Answers:


2359

重要行为差异摘要:

  • dependencies 都安装在两个上:

    • npm install 从包含以下内容的目录中 package.json
    • npm install $package 在任何其他目录上
  • devDependencies 是:

    • 也安装在npm install包含的目录上package.json,除非您通过该--production标志(转到盖亚·查理斯的答案)。
    • npm install "$package"除非您提供该--dev选项,否则不会安装在任何其他目录上。
    • 不能过渡安装。
  • peerDependencies

    • 3.0之前的版本:如果缺少,总是安装;如果不同的依赖项使用多个不兼容的依赖项版本,则会引发错误。
    • 预期从3.0开始(未试用):如果缺少npm install,则发出警告,您必须自己自行解决依赖关系。运行时,如果缺少依赖项,则会出现错误(@nextgentech提到)
  • 可传递性(由Ben Hutchison提及):

    • dependencies 是通过传递安装的:如果A需要B,而B需要C,则必须安装C,否则B无法工作,A也将无法工作。

    • devDependencies没有过渡安装。例如,我们不需要测试B就可以测试A,因此可以省去B的测试依赖项。

这里未讨论的相关选项:

devDependencies

dependenciesdevDependencies仅在开发时才需要运行,例如:单元测试,CoffeeScript到JavaScript的代码转换,缩小,...

如果要开发软件包,请下载软件包(例如通过git clone),转到包含的根目录package.json并运行:

npm install

由于您拥有实际的源代码,因此很显然要开发它,因此默认情况下,dependencies(当然,因为您必须运行以进行开发)和devDependency依赖项都已安装。

但是,如果您只是希望安装软件包以使用它的最终用户,则可以从任何目录进行操作:

npm install "$package"

在这种情况下,你通常不希望发展的依赖,所以你只能使用包所需要的:dependencies

如果您确实希望在这种情况下安装开发包,则可以将dev配置选项设置为true,可能从命令行将其设置为:

npm install "$package" --dev

false默认情况下,此选项是默认情况,因为这种情况不太常见。

peerDependencies

(在3.0之前测试)

资料来源:https : //nodejs.org/en/blog/npm/peer-dependencies/

使用常规依赖项,您可以具有多个版本的依赖项:只需将其安装在node_modules依赖项中即可。

例如,如果dependency1并且dependency2两者都依赖dependency3于不同版本,则项目树将如下所示:

root/node_modules/
                 |
                 +- dependency1/node_modules/
                 |                          |
                 |                          +- dependency3 v1.0/
                 |
                 |
                 +- dependency2/node_modules/
                                            |
                                            +- dependency3 v2.0/

但是,插件是通常不需要其他软件包的软件包,在此上下文中,该软件包称为主机。代替:

  • 主机需要插件
  • 插件提供了主机希望找到的标准接口
  • 用户只能直接调用主机,因此必须有一个单独的版本。

例如,如果dependency1dependency2peer依赖dependency3,项目树将如下所示:

root/node_modules/
                 |
                 +- dependency1/
                 |
                 +- dependency2/
                 |
                 +- dependency3 v1.0/

即使您从未dependency3package.json文件中提及,也会发生这种情况。

我认为这是控制反转设计模式的一个实例。

对等依赖关系的一个典型示例是Grunt,主机及其插件。

例如,在https://github.com/gruntjs/grunt-contrib-uglify之类的Grunt插件上,您将看到:

  • grunt 是一个 peer-dependency
  • 唯一的问题require('grunt')tests/:该程序实际上并未使用它。

然后,当用户使用插件时,他将Gruntfile通过添加grunt.loadNpmTasks('grunt-contrib-uglify')一行来隐式要求插件来自插件,但这grunt是用户将直接调用。

如果每个插件都需要不同的Grunt版本,则无法使用。

手册

我认为文档很好地回答了这个问题,也许您对节点/其他包管理器还不够熟悉。我可能只了解它,因为我对Ruby bundler有所了解。

关键是:

这些东西将在从软件包根目录执行npm link或npm install时安装,并且可以像任何其他npm配置参数一样进行管理。有关该主题的更多信息,请参见npm-config(7)。

然后在npm-config(7)下找到dev

Default: false
Type: Boolean

Install dev-dependencies along with packages.

5
啊。我知道我误会了。您的答案似乎npm install package是一条命令,您将使用该命令来安装所有非开发依赖项的软件包,而不是我现在认为的意思,即“安装名为[package]的软件包”,这就是我认为的工作方式在阅读本文之前。如果您是我,我会编辑说[package-name],它清楚地表明您的意思是“在此处插入名称”。
汤姆W

184
这很棒!我从未意识到,但是这个答案告诉我依赖关系与devDependencies的差异仅在您要发布npm软件包时才适用。如果您只是在一个应用程序或网站上工作,那没什么关系。谢谢!
jedd.ahyoung 2014年

3
该帖子应进行更新,以反映peerDependencies即将到来的npm @ 3 的更改行为。从blog.npmjs.org/post/110924823920/npm-weekly-5中:“我们将不再自动下载对等依赖项。相反,如果尚未安装对等依赖项,我们会警告您。这需要您手动解决peerDependency冲突,但是从长远来看,这应该会减少包的依赖关系导致的麻烦。”
nextgentech

8
而且,devDependencies不会通过相关软件包临时安装。例如:包A依赖于软件包D.包B.包B依赖于包C和B也devDepends如果你运行npm install的程序包A,你会得到B和C,但不是D.
奔记

9
它以这句话很重要devDependencies,当没有安装NODE_ENV设置为production
奥古斯托·弗朗佐娅

489

如果您不想安装devDependencies,则可以使用 npm install --production


1
npm install --save是否依赖软件?
Vamsi Pavan Mahesh 2015年

18
npm install将安装所有依赖项。当您也想将特定模块添加到package.json时,将使用--save标志。例如:-npm install uglify --save将uglify安装在您的项目文件夹中,并将uglify添加到项目的package.json文件中。
Gayan Charith 2015年

6
并且由于我们在谈论devDependency,因此可以使用--save-dev将新模块另存为devDependency。示例:npm install
uglify

9
从npm 5开始,--save不再需要该选项。如果您执行“ npm install my-package”,它将把my-package添加为package.json文件中的依赖项。
马丁·卡雷尔

只是npm安装
苏丹阿斯拉姆

116

例如,mocha通常是devDependency,因为在生产中不需要测试,而express是依赖项。


4
我倾向于将测试作为依赖项,因为您可能要在启动生产服务器之前运行自检

47
相反,我建议使用像Hudson或CircleCI这样的持续集成服务,该服务运行您的测试,如果通过则部署到生产中。
丹·科恩

1
仍然可能需要测试实际的服务器,因为CI服务器可能与产品服务器有所不同,而这种差异可能例如会阻止应用程序启动……
Nicole

2
@Nicole为什么要使登台服务器的配置与产品不同?
卢卡斯

1
再一次,将测试依赖项添加为常规依赖项会引入一大堆额外的库,每个库都可能以某种方式失败。我会倾向于(双关语)倾向于使用尽可能少的代码的轻量级生产服务器。记住,最好的代码就是没有代码!
Stijn de Witt

69

依赖项
项目需要运行的依赖项,例如提供从代码中调用的函数的库。
它们是可传递安装的(如果A依赖于B依赖于C,则在A上进行npm install将安装B和C)。
示例:lodash:您的项目调用了一些lodash函数。

devDependencies
仅在开发或发布期间需要的依赖项,例如将代码带入javascript,测试框架或文档生成器的编译器。
它们不是临时安装的(如果A依赖于B,而开发人员依赖于C,则在A上进行npm install只会安装B)。
示例:grunt:您的项目使用grunt进行构建。

peerDependencies
您的项目在父项目(通常是某些其他库或工具的插件)中挂钩或修改的依赖项。只是为了进行检查,请确保父项目(将取决于您的项目)对您挂接到的项目具有依赖性。因此,如果您制作了一个向库B添加功能的插件C,那么制作项目A的某人如果对C有依赖性,就需要对B有依赖性。
除非安装了它们(除非npm <3),否则它们只是检查。
示例:grunt:您的项目为grunt添加了功能,并且只能在使用grunt的项目上使用。

该文档非常好地解释了对等方的依赖性:https : //nodejs.org/en/blog/npm/peer-dependencies/

另外,随着时间的推移,npm文档也得到了改进,现在对不同类型的依赖项有了更好的解释:https : //github.com/npm/cli/blob/latest/doc/files/package.json.md#devdependencies


63

要将软件包作为dev依赖项保存到package.json

npm install "$package" --save-dev

运行时npm install,它将同时安装devDependenciesdependencies。为了避免安装devDependencies运行:

npm install --production

3
您还可以使用:npm i -S
Maysara Alhindi

36

有些模块和软件包仅对于开发是必需的,而在生产中则不需要。就像它在文档中说的那样:

如果有人计划在其程序中下载和使用您的模块,则他们可能不想或不需要下载并构建您使用的外部测试或文档框架。在这种情况下,最好在devDependencies哈希中列出这些其他项。


如果您在生产中仅运行bundle.js文件怎么办?您真的需要那些依赖吗?
RegarBoy

如果您在服务器上运行bundle.js,则说明您正在执行服务器端webpack或其他操作...请检查是否是这种情况,因为通常情况并非如此,并且要使其正常运行实际上需要大量工作(我知道是因为我做到了)。我怀疑您的bundle.js仅适用于浏览器,并且包含客户端代码。
Stijn de Witt

16

一个使我更清楚的简单解释是:

部署应用程序时,需要安装依赖项中的模块,否则您的应用程序将无法运行。无需在生产服务器上安装devDependencies中的模块,因为您不在该计算机上进行开发。 链接


2
那么,如果我们正在制作网站,并且在prod版本中,所有库都将内联到vendor.js,如果将已编译的代码提交到仓库中,则我们所有的deps应该是dev deps?它应该被提交,因为奇怪的是,您不得不编译模块,而不仅仅是安装它(测试也在此处,因为子模块中的任何更改都可能导致回归)...
Qwertiy

很棒的答案,但是有问题吗?Webpack可能会构建损坏的捆绑软件吗?我的猜测是devDependencies软件包在产品版本中不起作用webpack -p。请回答我的问题。
AmerllicA

如果在生产构建时出现任何问题,则应以某种方式设计部署过程,使其在构建时显示错误,并且不要将损坏的代码推送到生产中(例如,您可以尝试Jenkins)。无论如何,不​​需要在生产服务器上安装依赖关系。
Jyoti Duhan

对等依赖关系又如何呢?
dev27

13

我想对这些依赖关系的解释加我的看法

  • dependencies 用于代码库中的直接使用,通常在生产代码或代码块中结束的事情
  • devDependencies 用于构建过程,可帮助您管理最终代码的最终生成方式的工具,第三方测试模块(例如webpack的东西)

CSS资产呢?
Brian Zelip

8

简而言之

  1. 依赖关系 - npm install <package> --save-prod在生产环境中安装应用程序所需的软件包。

  2. DevDependencies - npm install <package> --save-dev只需要为本地开发和测试安装包

  3. 只需键入即可npm install安装package.json中提到的所有软件包

因此,如果您在本地计算机上工作,只需键入npm install并继续:)


6

peerDependencies直到我从上面提到的有关Ciro 的博客文章中阅读了以下片段,对我来说才有意义:

[ plugins ]需要的是一种表达插件及其主机包之间的“依赖关系”的方式。可以这样说:“我只能在插入主机程序包的1.2.x版本时才能工作,因此,如果您安装了我,请确保它与兼容主机一起使用。” 我们称这种关系为对等依赖。

该插件不期望主机的特定版本...

peerDependencies是针对插件的,是需要“主机”库来执行其功能的库,但可能是在发布最新版本的主机之前编写的。

也就是说,如果我PluginX v1为自己写信HostLibraryX v3并走开,则无法保证PluginX v1HostLibraryX v4(甚至HostLibraryX v3.0.1)发布时也能正常工作。

...但是该插件不依赖于主机...

从插件的角度来看,它仅向主机库添加功能。我并不是真的“需要”主机向插件添加依赖项,并且插件通常实际上并不依赖于其主机。如果您没有主机,则该插件不会执行任何操作。

这意味着dependencies对于插件而言,这并不是正确的概念。

更糟糕的是,如果将我的主机视为依赖项,我们最终会遇到同一篇博客文章提到的情况(稍作编辑以使用此答案的主机和插件组成):

但是现在,[如果我们将当代版本的HostLibraryX视为PluginX的依赖项,则运行npm install结果将导致意外的依赖关系图

├── HostLibraryX@4.0.0
└─┬ PluginX@1.0.0
  └── HostLibraryX@3.0.0

我将使用与主应用程序不同的[HostLibraryX] API来解决由插件引起的细微故障,这是您的想象力。

...而且主机显然不依赖于插件...

...这就是插件的全部重点。现在,如果主机足够好,可以为其所有插件添加依赖项信息,那么就可以解决问题,但这也将带来一个巨大的新文化问题:插件管理!

插件的全部目的是它们可以匿名配对。在一个理想的世界中,让主人来管理它们会很整洁,但是我们不会要求图书馆放牧猫。

如果我们不是层次依赖的,也许我们是内部依赖的同行...

相反,我们有成为同行的概念。主机和插件都不位于另一个的依赖项存储桶中。两者都生活在依赖图的同一级别上。


...但这不是自动的关系。<<<金钱球!!!

如果我PluginX v1期望的对等(也就是,有一个peerDependencyHostLibraryX v3,我会这么说。如果您已自动升级到最新HostLibraryX v4版本(请注意版本4Plugin v1安装,则需要知道,对吗?

npm 我无法应付这种情况-

“嘿,我看你在用PluginX v1!我会自动HostLibraryX从v4 降级到v3,kk?”

... 要么...

“嘿,我看到您正在使用PluginX v1。希望如此HostLibraryX v3,您在上一次更新时就把它留在了尘土中。为了安全起见,我会自动卸载Plugin v1!! 1!

不,npm ?!

所以npm不会。它会提醒您这种情况,并让您确定是否HostLibraryX v4适合Plugin v1


结尾

peerDependency插件中的良好管理将使该概念在实践中更加直观。从博客文章中,又一次...

建议之一:与常规依赖性不同,对等依赖性要求应该宽松。您不应将对等依赖项锁定到特定的补丁程序版本。如果一个Chai插件同等地依赖Chai 1.4.1,而另一个依赖Chai 1.5.0,那真是很烦人,这仅仅是因为作者很懒,并且没有花时间去弄清他们的实际最低Chai版本。兼容。


4

依赖与开发依赖

开发依赖项是仅在开发期间需要的模块,而运行时则需要依赖项。如果要部署应用程序,则必须安装依赖项,否则您的应用程序将无法正常工作。您从使程序能够运行的代码中调用的库可被视为依赖项。

例如反应

开发依赖项模块不需要安装在生产服务器中,因为您不需要在该机器上进行开发。将您的代码隐藏为javascript,测试框架和文档生成器的编译器可以视为开发依赖项,因为它们仅在开发期间才需要。

例如,ESLint,Babel,Webpack

@FYI,

mod-a
  dev-dependents:
    - mod-b
  dependents:
    - mod-c

mod-d
  dev-dependents:
    - mod-e
  dependents:
    - mod-a

----

npm install mod-d

installed modules:
  - mod-d
  - mod-a
  - mod-c

----

checkout the mod-d code repository

npm install

installed modules:
  - mod-a
  - mod-c
  - mod-e

如果要发布到npm,则对正确的模块使用正确的标志很重要。如果您的npm模块需要该功能,则使用“ --save”标志将模块另存为依赖项。如果这是您的模块不需要运行但需要测试的东西,请使用“ --save-dev”标志。

# For dependent modules
npm install dependent-module --save

# For dev-dependent modules
npm install development-module --save-dev

1

尝试分发npm软件包时,应避免使用dependencies。相反,您需要考虑将其添加到中peerDependencies或从中删除dependencies


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.