如何覆盖嵌套的 NPM 依赖版本?

Posted

技术标签:

【中文标题】如何覆盖嵌套的 NPM 依赖版本?【英文标题】:How do I override nested NPM dependency versions? 【发布时间】:2013-03-26 05:29:43 【问题描述】:

我想使用grunt-contrib-jasmine NPM 包。它有各种依赖关系。部分依赖图如下所示:

─┬ grunt-contrib-jasmine@0.4.1
 │ ├─┬ grunt-lib-phantomjs@0.2.0
 │ │ ├─┬ phantomjs@1.8.2-2

很遗憾,此版本phantomjs 中存在一个错误,导致它无法在 Mac OS X 上正确安装。此问题已在最新版本中得到修复。

如何让grunt-lib-phantomjs 使用更新版本的phantomjs

一些额外的上下文:

grunt-contrib-jasmine 明确需要 "~0.2.0"grunt-lib-phantomjs 版本,这明确需要 phantomjs 的版本 "~1.8.1"。 首先将phantomjs 添加到我的包的依赖项中没有效果;两个版本都已安装,grunt-contrib-jasmine 仍使用旧版本(请参阅:When installing a package with NPM, can you tell it to use a different version of one of its dependencies?)。

【问题讨论】:

只需 git clone 或 fork 所需的模块。您也可以手动移除嵌套的phantomjs grunt-contrib-jasmine 在 0.5.1 上,它使用 grunt-lib-phantomjs@0.3.1,它使用 phantomjs@1.9.1-0 :) npm 计划在未来发布overrides overrides 现在是一个内置功能。请参阅下面的my answer。 【参考方案1】:

您可以使用npm shrinkwrap 功能,以覆盖任何依赖或子依赖。

我刚刚在我们的 grunt 项目中完成了这项工作。我们需要更新版本的连接,因为2.7.3。给我们带来了麻烦。于是我创建了一个名为npm-shrinkwrap.json的文件:


  "dependencies": 
    "grunt-contrib-connect": 
      "version": "0.3.0",
      "from": "grunt-contrib-connect@0.3.0",
      "dependencies": 
        "connect": 
          "version": "2.8.1",
          "from": "connect@~2.7.3"
        
      
    
  

npm 应该在为项目进行安装时自动选择它。

(参见:https://nodejs.org/en/blog/npm/managing-node-js-dependencies-with-shrinkwrap/)

【讨论】:

当我这样做时,只安装了 grunt-contrib-connect 依赖项及其子项。我在 package.json 中的所有其他依赖项都没有安装。 我遇到了与@iDVB 相同的问题。我最终编辑了node_modules 目录,以便完整的shrinkwrap 依赖转储正是我想要的,而不仅仅是覆盖。但仍然是一种痛苦的解决方案。 @Domi 这个文件是通过运行 npm shrinkwrap 创建的,条目不是手动添加的 不幸的是,正如那个错误中提到的那样,对于 npm4,简约的方法不再有效。 (删除node_modules 时,使用最小收缩包装运行安装似乎使devDependencies 完好无损,尽管忽略dependencies,但运行另一个安装会删除非显式项目,所以现在运行npm shrinkwrap 很重要获取完整文件,修改有问题的部分,然后再次运行npm install npm 6.4 只会覆盖收缩包装文件并使用过时的依赖项【参考方案2】:

对于 2018 年及以后的用户,使用 npm 版本 5 或更高版本:编辑您的 package-lock.json:从 "requires" 部分删除库并将其添加到“依赖项”下。

例如,您希望 deglob 包使用 glob 包版本 3.2.11 而不是其当前版本。你打开package-lock.json看看:

"deglob": 
  "version": "2.1.0",
  "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.0.tgz",
  "integrity": "sha1-TUSr4W7zLHebSXK9FBqAMlApoUo=",
  "requires": 
    "find-root": "1.1.0",
    "glob": "7.1.2",
    "ignore": "3.3.5",
    "pkg-config": "1.1.1",
    "run-parallel": "1.1.6",
    "uniq": "1.0.1"
  
,

"requires" 中删除"glob": "7.1.2",,添加具有正确版本的"dependencies"

"deglob": 
  "version": "2.1.0",
  "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.0.tgz",
  "integrity": "sha1-TUSr4W7zLHebSXK9FBqAMlApoUo=",
  "requires": 
    "find-root": "1.1.0",
    "ignore": "3.3.5",
    "pkg-config": "1.1.1",
    "run-parallel": "1.1.6",
    "uniq": "1.0.1"
  ,
  "dependencies": 
    "glob": 
      "version": "3.2.11"
    
  
,

现在删除您的node_modules 文件夹,运行npm ci(或npm install 用于旧版本的node/npm),它会将缺少的部分添加到"dependencies" 部分。

【讨论】:

这很好,只要npm install 运行一次。在我的情况下,编辑是必要的,因为嵌套的 dep 导致失败。 这将在您运行 npm i 时被删除,而不是编辑您的 package-lock.json 并将子依赖项添加到“依赖项”,将子依赖项添加到您的 package.json “依赖项”部分 我已经创建了一个库,可以自动为您完成这些工作:github.com/rogeriochaves/npm-force-resolutions 它可以工作,但是如果我再次运行npm install,那么对package-lock.json 的所有更改都会恢复,并且我会得到错误版本的dep。 我运行npm ci,这不会触及package-lock.json【参考方案3】:

对于那些使用纱线的人。

我尝试使用 npm shrinkwrap,直到我发现 yarn cli 忽略了我的 npm-shrinkwrap.json 文件。

Yarn 为此提供了https://yarnpkg.com/lang/en/docs/selective-version-resolutions/。整洁。

也请查看此答案:https://***.com/a/41082766/3051080

【讨论】:

【参考方案4】:

我遇到了一个问题,其中一个嵌套依赖项存在 npm 审计漏洞,但我仍想维护父依赖项版本。 npm shrinkwrap 解决方案对我不起作用,所以我做了什么来覆盖嵌套的依赖版本:

    删除 package-lock.json 中“requires”部分下的嵌套依赖项 在 package.json 中的 DevDependencies 下添加更新的依赖项,以便需要它的模块仍然能够访问它。 npm 我

【讨论】:

使用 npm 6 这不起作用。 npm i 覆盖对包锁定文件的任何更改【参考方案5】:

对我有用的唯一解决方案(节点 12.x,npm 6.x)是使用由 @Rogerio Chaves 开发的 npm-force-resolutions。

首先,通过以下方式安装它:

npm install npm-force-resolutions --save-dev

如果某些损坏的传递依赖脚本阻止您安装任何东西,您可以添加 --ignore-scripts

然后在package.json 中定义应该覆盖哪些依赖项(您必须设置确切的版本号):

"resolutions": 
  "your-dependency-name": "1.23.4"

并在"scripts" 部分添加新的预安装条目:

"preinstall": "npm-force-resolutions",

现在,npm install 将应用更改并强制 your-dependency-name 为所有依赖项的版本 1.23.4

【讨论】:

提示:为npm install使用--save-dev标志 如果只想为一个特定的第 3 方依赖项升级相应的依赖项,这将不起作用 注意:这仅在您启用 package-lock.json 时有效,某些开发人员可能由于其固有问题而没有启用。 2021 年最新版本的 NPM 中是否有任何内置解决方案?我不想依赖第三方库来处理这种事情 - 操作依赖树。 @DaniP。 npm 是穷人的 man 依赖管理器,所以我怀疑它【参考方案6】:

@user11153 的答案在本地对我有用,但是在尝试进行全新安装(又名删除 node_modules)时,我会得到:

npm-force-resolutions: command not found

我必须将preinstall 脚本更新为:

"preinstall": "npm i npm-force-resolutions && npm-force-resolutions"

这可确保在尝试运行之前安装 npm-force-resolutions 包。

话虽如此,如果您能够改用 yarn,我会这样做,然后使用 @Gus 的答案。

【讨论】:

我使用了"preinstall": "npx force-resolutions",这里建议github.com/rogeriochaves/npm-force-resolutions/issues/… 还有一条更快的路线,通过bashery:***.com/a/68095189/132735【参考方案7】:

我正要走 npm-force-resolutions 路线,但似乎只需将依赖项包含在我自己的 package.json 中即可解决我的问题。

我相信这对我来说是可行的,因为原始依赖项允许我想要更新的相关依赖项的补丁版本。因此,通过手动包含一个较新的版本,它仍然满足原始依赖项的依赖项,并将使用我手动添加的那个。

示例

问题

我需要将 plyr3.6.8 更新到版本 3.6.9

我的

package.json


  "dependencies": 
    "react-plyr": "^3.2.0"
  

反应 Plyr

package.json


  "dependencies": 
    "plyr": "^3.6.8"
  

注意plyr 依赖项以^ 开头,这意味着它可以接受任何小补丁。您可以在此处了解更多信息:

https://docs.npmjs.com/about-semantic-versioning#using-semantic-versioning-to-specify-update-types-your-package-can-accept

更新我的

这会更新我的package.json 中的plyr 依赖项。

package.json


  "dependencies": 
    "plyr": "^3.6.9",
    "react-plyr": "^3.2.0"
  

【讨论】:

【参考方案8】:

用完全不同的包进行嵌套替换

如果您只是对覆盖包的版本号感兴趣,那么此处其他答案中概述的大多数策略都可以很好地工作,但在我们的例子中,我们需要找到一种方法来覆盖嵌套的 npm 子依赖项 完全不同的包。有关您为什么要这样做的详细信息,请参阅以下问题:

How to override a nested npm sub-dependency with a different package altogether (not just different package version number)?

直接指定压缩包

要使用其他人提到的npm-force-resolutions 策略将一个包嵌套替换为完全不同的包,您只需提供一个指向通常指定覆盖版本号的 tarball 的链接。

例如,对于将易受攻击的软件包 ansi-html 替换为此软件包的固定分支 ansi-html-community 的情况,package.json 的解决方案部分应如下所示:

"resolutions": 
    "ansi-html": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz"

要找到 tarball 的链接,请使用以下命令,并根据需要修改您的注册表:

npm view ansi-html-community dist.tarball --registry=https://registry.npmjs.org/

另外,请注意,要让 npm-force-resolutions 在运行 npm install 时正常工作,您需要在 package.jsonscripts 部分下添加一个 preinstall 条目:

  "scripts": 
    "preinstall": "npx npm-force-resolutions"
  

【讨论】:

谢谢,这真的很有用。我认为可以通过使用引用覆盖来替换包,例如"bar": "$foo" 如上一个示例 here 中所述,但我无法让它工作。但你的解决方案成功了,我会为细节加分。【参考方案9】:

截至 NPM v8.3,处理此问题的正确方法是通过 package.json 文件的 overrides 部分。

如果您需要对您的依赖项进行特定更改 依赖项,例如将依赖项的版本替换为 已知的安全问题,用 fork 替换现有依赖项,或 确保在任何地方都使用相同版本的包, 那么你可以添加一个覆盖。

覆盖提供了一种替换依赖树中的包的方法 使用另一个版本,或完全使用另一个包。这些变化可以 范围可以根据需要具体或模糊。

确保软件包 foo 始终安装为版本 1.0.0 否 不管你的依赖依赖什么版本:


  "overrides": 
    "foo": "1.0.0"
  

还有许多其他更细微的配置,允许您仅在某个包是特定包层次结构的依赖项时才覆盖该包。更多详情,请查看https://docs.npmjs.com/cli/v8/configuring-npm/package-json#overrides

【讨论】:

@georgebrock 请考虑将此标记为正确答案 - 自从您提出问题后,生态系统发生了变化,这是 Google 的高排名结果

以上是关于如何覆盖嵌套的 NPM 依赖版本?的主要内容,如果未能解决你的问题,请参考以下文章

如何强制排除 NPM 的嵌套依赖项?

如何强制 npm 3 安装嵌套依赖项?

如何使用 `yarn` 覆盖嵌套依赖项?

覆盖 npm 包依赖

如何确定旧 npm 包版本的依赖关系

如何解决 npm 中不同版本的传递依赖?