ChatGPT解决这个技术问题 Extra ChatGPT

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

我想使用 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 明确需要 grunt-lib-phantomjs 的“~0.2.0”版本,它明确需要 phantomjs 的“~1.8.1”版本。

首先将 phantomjs 添加到我的包的依赖项中没有效果;两个版本都已安装,并且 grunt-contrib-jasmine 仍然使用旧版本(请参阅:使用 NPM 安装包时,你能告诉它使用其依赖项之一的不同版本吗?)。

只需 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

H
Heath Borders

您可以使用 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 目录,以便完整的收缩包装依赖转储正是我想要的,而不仅仅是覆盖。但仍然是一种痛苦的解决方案。
@Domi 这个文件是通过运行 npm shrinkwrap 创建的,条目不是手动添加的
不幸的是,正如那个 bug 中提到的,对于 npm4,简约的方法不再有效。 (删除 node_modules 时,尽管忽略 dependencies,但使用最小的收缩包装运行安装似乎会使 devDependencies 完好无损,但运行另一个安装会删除非显式项,因此现在运行 npm shrinkwrap 以获取完整文件,修改相关部分,然后再次运行 npm install
npm 6.4 只会覆盖收缩包装文件并使用过时的依赖项
i
izogfif

从 npm cli v8.3.0 (2021-12-09) 开始,可以使用 package.json 的 overrides field 解决此问题StriplingWarrior's answer 中所述

例如,该项目具有 typescript 版本 4.6.2 作为 direct 开发依赖项,而 awesome-typescript-loader 使用旧版本 2.7typescript。以下是告诉 npmtypescript4.6.2 版本用于 awesome-typescript-loader 的方法:

{
  "name": "myproject",
  "version": "0.0.0",
  "scripts": ...
  "dependencies": ...
  "devDependencies": {
    "typescript": "~4.6.2",
    "awesome-typescript-loader": "^5.2.1",
    ...
  },
  "overrides": {
    "awesome-typescript-loader": {
      "typescript": "$typescript"
    }
  }
}

如果您不使用 typescript 作为 direct 开发依赖项,那么您必须在 overrides 部分编写 4.6.2 而不是 $typescript

{
  "name": "myproject",
  "version": "0.0.0",
  "scripts": ...
  "dependencies": ...
  "devDependencies": {
    "awesome-typescript-loader": "^5.2.1",
    ...
  },
  "overrides": {
    "awesome-typescript-loader": {
      "typescript": "~4.6.2"
    }
  }
}

dependenciesdevDependencies 可以使用相同的 overrides

如果您使用的是 npm 版本 >5 但 <8.3.0:编辑您的 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
t
targumon

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

如果您需要对依赖项的依赖项进行特定更改,例如用已知的安全问题替换依赖项的版本,用分叉替换现有的依赖项,或者确保在任何地方都使用相同版本的包,那么你可以添加一个覆盖。覆盖提供了一种将依赖关系树中的包替换为另一个版本或完全替换为另一个包的方法。这些更改的范围可以根据需要具体或模糊。确保软件包 foo 始终安装为版本 1.0.0,无论您的依赖项依赖什么版本:{“overrides”:{“foo”:“1.0.0”}}

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


@georgebrock 请考虑将此标记为正确答案——自从你提出这个问题后,生态系统已经发生了变化,这是一个高排名的谷歌结果
考虑将 "engines": { "npm": ">=8.3.0" } 添加到您的 package.json 以指示需要新的 npm 版本
这让我大吃一惊:如果你使用带有工作空间的 monorepo,你需要在根包中定义覆盖,而不是在具有实际依赖项的嵌套项目中。
我将此添加到 package.json 但不适用于 yarn install。我用纱线。但我补充说,也许其他任何人都可以使用 npm。我希望这也适用于 npm。
来自@leumasme 的好建议!我们在 .npmrc 中使用 engine-strict=true 对其进行了扩展,不仅会收到警告,因为需要覆盖的依赖项对我们来说有很大的破坏性。
M
MiniGod

唯一对我有用的解决方案(节点 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 方依赖项升级相应的依赖项,这将不起作用
2021 年最新版本的 NPM 中是否有任何内置解决方案?我不想依赖第三方库来处理这种事情——操纵依赖树。
@DaniP。 npm 是穷人的依赖管理器,所以我对此表示怀疑
对我来说,Circle CI 中的 preinstall 命令中断了,所以我改用了这个:"preinstall": "npm install --package-lock-only --ignore-scripts && npx npm-force-resolutions" 请参阅 stackoverflow.com/a/67446313/6627882
G
Gus

对于那些使用纱线的人。

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

为此,Yarn 有 https://yarnpkg.com/lang/en/docs/selective-version-resolutions/。整洁的。

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


J
Justin Dehorty

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

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

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

直接指定tarball

对于使用其他人提到的 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 install 时使 npm-force-resolutions 工作,您需要在 package.jsonscripts 部分下有一个 preinstall 条目:

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

谢谢,这真的很有用。我认为可以通过使用引用(例如,上一个示例 here 中记录的 "bar": "$foo")覆盖来替换包,但我无法让它工作。但是你的解决方案成功了,我会为细节多加一点。
E
Ethan Yang

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

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


使用 npm 6 这不起作用。 npm i 覆盖对包锁定文件的任何更改
E
Emilio Venegas

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

npm-force-resolutions: command not found

我必须将 preinstall 脚本更新为:

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

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

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


我按照这里的建议使用了 "preinstall": "npx force-resolutions" github.com/rogeriochaves/npm-force-resolutions/issues/…
还有一条更快的路线,通过一点点 bashery: stackoverflow.com/a/68095189/132735
C
CTS_AE

我正要走 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.jsonplyr 依赖项。

package.json

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

S
Suraj Rao

先运行这个

npm i -D @types/eslint@8.4.3

它将解决问题