如何将npm嵌套子依赖替换为完全不同的包而非仅更换版本号
我在修复npm audit检出的ReDoS漏洞时遇到了问题。我的应用存在一个有攻击风险的嵌套子依赖ansi-html,但不幸的是该包的维护者已失联(AWOL)。从相关Github issue的评论区可知,社区为解决这个问题已经Fork了名为ansi-html-community的仓库,该版本已修复此漏洞。
因此我希望将所有嵌套引用的ansi-html全部替换为ansi-html-community。
我通常使用npm-force-resolutions的方案似乎无法将嵌套子依赖替换为完全不同的包,仅支持更换同一包的不同版本号。我已经查阅了数小时资料,目前找到的唯一可行方案是使用yarn实现,我现在甚至认真考虑弃用npm转用yarn,但我们的整个CI/CD流水线都是基于npm配置的,该方案并不理想。
请问是否有其他无需切换到yarn即可实现嵌套子依赖包替换/解析的方法?
以下是我找到的相关问题,但遗憾的是它们大多只讨论了覆盖包版本号的方法,并未涉及替换包本身的方案。
讨论如何覆盖版本号的问题:
如何覆盖嵌套的NPM依赖版本?
包含关于npm shrinkwrap的评论讨论(方案不理想):
npm如何覆盖依赖包的依赖项?
方案1:使用npm原生overrides字段(推荐,npm ≥8.3.0)
npm从8.3.0版本开始原生支持overrides配置项,直接支持将指定依赖替换为其他第三方包,无需安装任何额外工具。
只需要在项目的package.json中添加如下配置:
{ "overrides": { "ansi-html": "npm:ansi-html-community@^0.0.8" } }
配置完成后删除项目中的node_modules目录和package-lock.json文件,重新执行npm install即可,所有嵌套依赖中引用的ansi-html都会被替换为ansi-html-community的对应版本。
如果只需要替换特定上层依赖下的ansi-html,可以调整配置的层级:
{ "overrides": { "目标上层包名": { "ansi-html": "npm:ansi-html-community@^0.0.8" } } }
该配置只会替换指定上层包依赖的ansi-html,其他依赖的引用不受影响。
方案2:兼容旧版npm(npm <8.3.0)
如果你的npm版本低于8.3.0无法使用原生overrides,可以通过npm-force-resolutions配合包别名实现:
- 在
package.json中添加resolutions配置:
{ "resolutions": { "ansi-html": "npm:ansi-html-community@^0.0.8" } }
- 在
package.json的scripts中添加preinstall钩子:
{ "scripts": { "preinstall": "npx npm-force-resolutions" } }
- 重新执行安装流程即可生效。
内容的提问来源于stack exchange,提问作者Justin Dehorty

