我应该在“package.json”的“dependencies”字段中复制“peerDependencies”吗?

为了实验,我下载了@typescript-eslint/eslint-plugin的源代码。这个包有两个对等依赖项:

{
  "peerDependencies": {
    "@typescript-eslint/parser": "^4.0.0",
    "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
  },
  "dependencies": {
    "@typescript-eslint/experimental-utils": "4.11.1",
    "@typescript-eslint/scope-manager": "4.11.1",
    "debug": "^4.1.1",
    "functional-red-black-tree": "^1.0.1",
    "regexpp": "^3.0.0",
    "semver": "^7.3.2",
    "tsutils": "^3.17.1"
  },
}
{
  "peerDependencies": {
    "@typescript-eslint/parser": "^4.0.0",
    "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
  },
  "dependencies": {
    "@typescript-eslint/experimental-utils": "4.11.1",
    "@typescript-eslint/scope-manager": "4.11.1",
    "debug": "^4.1.1",
    "functional-red-black-tree": "^1.0.1",
    "regexpp": "^3.0.0",
    "semver": "^7.3.2",
    "tsutils": "^3.17.1"
  },
}

如果我npm list在安装所有依赖项后运行,我会得到:

npm ERR! peer dep missing: eslint@^5.0.0 || ^6.0.0 || ^7.0.0, required by @typescript-eslint/eslint-plugin@4.11.1
npm ERR! peer dep missing: eslint@*, required by @typescript-eslint/experimental-utils@4.11.1
npm ERR! peer dep missing: eslint@^5.0.0 || ^6.0.0 || ^7.0.0, required by @typescript-eslint/eslint-plugin@4.11.1
npm ERR! peer dep missing: eslint@*, required by @typescript-eslint/experimental-utils@4.11.1

这是否意味着npm想要:

回答

@Daniel_Knights 主要回答了这个问题。但我也想加上我的两分钱。所以这里是:

NPM 中的依赖类型:

为了理解这一点,了解 NPM 包中不同类型的依赖项很重要。一般来说,NPM 中有 4 种依赖类型:

  1. 直接依赖(或简单的依赖):这些依赖是 NPM 包运行所绝对必需的。如果您正在使用 express.js 构建 Web 应用程序,那么您绝对希望express安装 以便您的应用程序启动。因此,这将是您的应用程序的直接依赖项。这些应列在"dependencies": {}部分下package.json

  2. 开发依赖:这些依赖在开发应用程序时很有帮助,但不一定被应用程序包用来运行。这种依赖的一个例子是typescript. NodeJS 不理解 Typescript。因此,即使您可以在 Typescript 中编写应用程序,在通过 typescript 编译器运行它之后,您也只能使用 Javascript。因此,即使您需要typescript在开发过程中添加包,您的应用程序在编译后也不需要它来运行。

因此,如果您添加typescript到您的"devDependencies": {}部分package.json并执行npm install,NPM 将安装依赖项和 devDependencies。在此阶段,您可以调用 Typescript 编译器来构建应用程序。但是在那之后,您可以运行npm prune --production,NPM 将从node_modules/. 这减少了最终应用程序包的大小并使其不受任何开发依赖项的影响。

你不应该在你的源代码中引用任何开发依赖,除非你的代码安全和优雅地回退到替代品,因为包将在修剪时被删除。

  1. 可选的依赖:这些都是你可以在里面指定依赖"optionalDependencies": {}的部分package.json。当您将依赖项指定为可选时,您会让 NPM 知道“如果该依赖项可用您的程序将使用该依赖项。如果不可用,那也很酷。它将使用其他东西。”

这可以帮助的一个常见场景是使用数据库驱动程序。用 JS 编写的数据库驱动程序不是特别有效或高性能。因此,通常使用具有本机绑定的驱动程序(使用本机 (C/C++) 包运行其任务的 JS 库)。但问题是对于本地绑定,本地包必须安装在运行应用程序的机器上。这可能并不总是可用。所以我们可以指定一个本地库作为可选库。您可以在 JS 代码中引用它,例如:

var pg = require('pg-native'); // Native binding library
if (!pg) {                     // If it's not available...
  pg = require('pg');          // ...use non native library.
}

因此,在使用 安装软件包时npm install,NPM 也会尝试安装一个可选的依赖项。但是如果它无法安装(可能是因为本机绑定不可用),它就不会出错。它只会发布警告并继续前进。

现在是有问题的依赖类型......

  1. 同行的依赖:正如你已经知道,这是你的内部指定依赖"peerDependencies": {}的部分package.json。与上述其他三个依赖项不同,NPM在执行npm install. 这是因为 NPM 期望这些依赖项由其他依赖项提供。

我们将看到为什么这是有道理的,但我们必须绕道而行,以了解 NPM 如何在node_modules/文件夹中构建依赖关系。

NPM 如何存储依赖

让我们用一个例子来做这个:

我们将初始化一个 npm 包并express作为依赖项安装:

$ npm install express --save

如果我们现在查看node_modules/目录,我们可以看到它qs安装了软件包express

$ ls -l node_modules/
total 196
// ...more stuff...
drwxr-xr-x 3 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 express <---------- here is our express
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 finalhandler
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 forwarded
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 fresh
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 http-errors
drwxr-xr-x 4 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 iconv-lite
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 inherits
drwxr-xr-x 3 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 ipaddr.js
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 media-typer
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 merge-descriptors
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 methods
drwxr-xr-x 3 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 mime
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 mime-db
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 mime-types
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 ms
drwxr-xr-x 3 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 negotiator
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 on-finished
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 parseurl
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 path-to-regexp
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 proxy-addr
drwxr-xr-x 5 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 qs <---------- focus here for a bit
drwxr-xr-x 2 rajshrimohanks rajshrimohanks 4096 Dec 31 16:00 range-parser
// ...even more stuff ...

现在,node_modules/文件express/夹中没有文件夹,即使它有一个package.json

$ ls -l node_modules/express/
total 132
-rw-r--r-- 1 rajshrimohanks rajshrimohanks 109589 Oct 26  1985 History.md
-rw-r--r-- 1 rajshrimohanks rajshrimohanks   1249 Oct 26  1985 LICENSE
-rw-r--r-- 1 rajshrimohanks rajshrimohanks   4607 Oct 26  1985 Readme.md
-rw-r--r-- 1 rajshrimohanks rajshrimohanks    224 Oct 26  1985 index.js
drwxr-xr-x 4 rajshrimohanks rajshrimohanks   4096 Dec 31 16:00 lib
-rw-r--r-- 1 rajshrimohanks rajshrimohanks   3979 Dec 31 16:00 package.json

如果你看package.json的的express包,你会看到,它需要qs包版本6.7.0

$ cat node_modules/express/package.json
{
  // other stuff ...

  "dependencies": {
    "accepts": "~1.3.7",
    "array-flatten": "1.1.1",
    "body-parser": "1.19.0",
    "content-disposition": "0.5.3",
    "content-type": "~1.0.4",
    "cookie": "0.4.0",
    "cookie-signature": "1.0.6",
    "debug": "2.6.9",
    "depd": "~1.1.2",
    "encodeurl": "~1.0.2",
    "escape-html": "~1.0.3",
    "etag": "~1.8.1",
    "finalhandler": "~1.1.2",
    "fresh": "0.5.2",
    "merge-descriptors": "1.0.1",
    "methods": "~1.1.2",
    "on-finished": "~2.3.0",
    "parseurl": "~1.3.3",
    "path-to-regexp": "0.1.7",
    "proxy-addr": "~2.0.5",
    "qs": "6.7.0", <-------------- this is what we are looking at
    "range-parser": "~1.2.1",
    "safe-buffer": "5.1.2",
    "send": "0.17.1",
    "serve-static": "1.14.1",
    "setprototypeof": "1.1.1",
    "statuses": "~1.5.0",
    "type-is": "~1.6.18",
    "utils-merge": "1.0.1",
    "vary": "~1.1.2"
  },

  // ... more stuff ...
}

所以express需要qs版本,6.7.0所以 NPM 把它放在一起express使用。

$ cat node_modules/qs/package.json
{
  // ... stuff ...

  "name": "qs",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/ljharb/qs.git"
  },
  "scripts": {
    "coverage": "covert test",
    "dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js",
    "lint": "eslint lib/*.js test/*.js",
    "postlint": "editorconfig-tools check * lib/* test/*",
    "prepublish": "safe-publish-latest && npm run dist",
    "pretest": "npm run --silent readme && npm run --silent lint",
    "readme": "evalmd README.md",
    "test": "npm run --silent coverage",
    "tests-only": "node test"
  },
  "version": "6.7.0" <---- this version
}

现在让我们看看如果我们想qs在我们的应用程序中使用BUT 版本会发生什么6.8.0

$ npm install qs@6.8.0 --save
npm WARN dep-test@1.0.0 No description
npm WARN dep-test@1.0.0 No repository field.

+ qs@6.8.0
added 2 packages from 1 contributor, updated 1 package and audited 52 packages in 0.796s
found 0 vulnerabilities

$ cat node_modules/qs/package.json
{
  //... other stuff ...

  "name": "qs",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/ljharb/qs.git"
  },
  "scripts": {
    "coverage": "covert test",
    "dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js",
    "lint": "eslint lib/*.js test/*.js",
    "postlint": "eclint check * lib/* test/*",
    "prepublish": "safe-publish-latest && npm run dist",
    "pretest": "npm run --silent readme && npm run --silent lint",
    "readme": "evalmd README.md",
    "test": "npm run --silent coverage",
    "tests-only": "node test"
  },
  "version": "6.8.0" <-------- the version changed!
}

NPM 替换了6.8.0我们想要的版本。但是对于需要at的express包的需求呢?不用担心,NPM 通过提供自己的at本地副本来处理它。qs6.7.0expressqs6.7.0

$ cat node_modules/express/node_modules/qs/package.json
{
  // ... other stuff ...

  "name": "qs",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/ljharb/qs.git"
  },
  "scripts": {
    "coverage": "covert test",
    "dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js",
    "lint": "eslint lib/*.js test/*.js",
    "postlint": "editorconfig-tools check * lib/* test/*",
    "prepublish": "safe-publish-latest && npm run dist",
    "pretest": "npm run --silent readme && npm run --silent lint",
    "readme": "evalmd README.md",
    "test": "npm run --silent coverage",
    "tests-only": "node test"
  },
  "version": "6.7.0" <----- just what express wants!
}

所以,你可以看到,NPM增加了当地node_modulesexpress孤独,给了它自己的版本。这就是 NPM 确保我们的应用程序以及express满足他们自己的要求的方式。但这里有一个关键要点:

“如果多个包需要另一个相同但版本不同的包,NPM 将安装多个副本,为每个包安装多个副本以满足它们。”

在某些情况下,这可能并不总是理想的。假设我们的包想要使用,qs但我们不关心它是什么版本,只要它高于版本,6.0.0并且我们确信其他一些包,例如express也将一起使用(它有自己的qsat 6.7.0)。在这种情况下,我们可能不希望 NPM 安装另一个增加批量的副本。相反,我们可以指定qs为...对等依赖

现在 NPM 不会自动安装对等依赖项。但是会期望它由其他一些包提供。

所以最后,来到你的案子......

在以下情况下@typescript-eslint/eslint-plugin

@typescript-eslint/eslint-plugin旨在与@typescript-eslint/parsereslint包一起使用。如果@typescript-eslint/eslint-plugin不使用它们,您就无法使用,因为所有这些都是一个更大的包的一部分eslint,可以帮助您整理 Typescript 和 JS 代码。所以你eslint无论如何都会安装,这将是使用@typescript-eslint/eslint-plugin.

因此,作者认为添加它们是合适的,@typescript-eslint/eslint-plugin只要您eslint5.x.x6.x.x7.x.x系列中有任何次要版本,就不必在意。@typescript-eslint/eslint-parser与版本类似4.x.x


哇!那是一段相当长的旅程,但希望这能回答您的问题!:)


根据评论编辑:

现在假设我分叉了@typescript-eslint/eslint-plugin 并且想要所有的 ERR!有问题的消息消失。如果我将 eslint 和解析器添加到分叉包的依赖项中, peerDependencies 变得毫无意义。我应该将它们添加到 devDependencies 中吗?

你可以,但这会使devDependencies意义变得毫无意义。您必须了解的是,该package.json文件只是一个清单,用于指示 NPM 在其他人“安装”该包时要执行的操作 - 无论是在另一个包中作为依赖项,还是单独作为全局包。无论如何,这package.json就像 NPM 的说明手册。

它不会以任何方式影响您作为开发人员。因此,如果您只想添加eslint@typescript-eslint/eslint-parser用于开发目的,您可以简单地执行以下操作:

$ npm install --no-save eslint @typescript-eslint/eslint-parser

--no-save标志告诉 NPM 不要将这些添加到 ,package.json而是node_modules/无论如何获取包并将其放入目录中。当你运行你的应用程序时,它会做的就是查看node_modules/包的存在而不是package.json。的目的package.json是在安装步骤之后完成。

如果这能澄清您的问题,请告诉我。如果需要,我会添加更多。

新年快乐!:)


以上是我应该在“package.json”的“dependencies”字段中复制“peerDependencies”吗?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>