npm-shrinkwrap.json和package-lock.json有什么区别?

206

随着npm@5发布,除非已经存在npm-shrinkwrap.json,否则它将会写入一个package-lock.json

我通过以下方式全局安装了npm@5:

npm install npm@5 -g

现在,在以下情况下,如果找到 npm-shrinkwrap.json

npm install

会打印出一个警告:

npm WARN read-shrinkwrap This version of npm
is compatible with lockfileVersion@1,
but npm-shrinkwrap.json was generated for lockfileVersion@0.
I'll try to do my best with it!

我的结论是,我应该将shrinkwrap替换为package-lock.json

但是,为什么会有一个新的格式呢?package-lock.json相对于npm-shrinkwrap.json有哪些优势呢?

4个回答

230

这些文件的内容完全相同,但 npm 在处理它们时有一些差异,其中大部分都在文档页面:package-lock.jsonnpm-shrinkwrap.json 中有说明:

  • package-lock.json 从不发布到 npm 上,而 npm-shrinkwrap 则默认会发布
  • 不在顶级包中的 package-lock.json 文件将被忽略,但属于依赖项的 shrinkwrap 文件将受到尊重
  • npm-shrinkwrap.json 向后兼容 npm 版本 2、3 和 4,而只有 npm 5+ 才能识别 package-lock.json

您可以通过运行 npm shrinkwrap 来将现有的 package-lock.json 转换为 npm-shrinkwrap.json

因此:

  • 如果您不打算将您的包发布到 npm 上,则在这两个文件之间进行选择并没有多大影响。您可能希望使用 package-lock.json,因为它是默认值,对于初学者来说其名称更清晰;或者,如果您很难确保开发团队中的每个人都在 npm 5+ 上,您可能希望使用 npm-shrinkwrap.json 来实现与 npm 2-4 向后兼容。 (请注意,npm 5 于 2017 年 5 月 25 日发布;向后兼容性将越来越不重要,因为大多数人最终都会升级。)

  • 如果您要发布您的包到 npm 上,则可以选择:

    1. 使用 package-lock.json 记录您安装的依赖项的确切版本,但允许安装您的包的人使用与由您的 package.json 指定的版本范围兼容的任何版本的依赖项,或者
    2. 使用npm-shrinkwrap.json来确保所有安装你的包的人都获得完全相同版本的所有依赖项


    官方文档中描述,选项1应该用于库(可能是为了减少在许多包的依赖项都依赖于略有不同版本的相同次要依赖项时造成的包重复量),但对于将被全局安装的可执行文件,选项2可能是合理的。


3
可以请问您能否澄清一下第二个要点?那种行为与拥有npm-shrinkwrap有什么区别呢?请注意,翻译后的内容不能改变原意,并尽量使用通俗易懂的语言。 - Rhys
4
在实际情况下,除非你在做一些奇怪的事情,否则第二个要点并不重要。基本上,它只是说,如果一个库(这是不可能的)以某种方式发布了 package-lock.json,然后如果你将该库安装为其他包的依赖项,NPM 将忽略该库的 package-lock.json。但是,如果一个库发布了 npm-shrinkwrap.json,并且你将该库安装为一个依赖项,那么你还将作为次要依赖项安装库中 npm-shrinkwrap.json 中指定的所有依赖项的确切版本 - Mark Amery
请问您能否加上npm ci来确保package-lock.json只读安装。(npm install会改变package-lock.json,可能会引起混乱和潜在的错误,并且不能充分利用package-lock.json本身。) - k0pernikus
1
@k0pernikus 我认为 npm ci 如何处理 npm-shrinkwrap.jsonpackage-lock.json 没有任何区别 - 这与这个问题关于这两个文件的区别有什么关系呢?此外,阅读了一些资料后:我认为自从 npm 5.4 版本以来,"npm install ... 不会利用 package-lock.json" 的说法是错误的 - 我相信 npm install 现在会尊重你的 package-lock,除非它与你的 package.json 明显不兼容,在这种情况下,以后者为准。(但我已经离开 JavaScript 领域有一段时间了 - 我错过了什么吗?) - Mark Amery
1
@Ini 选项2的优点(适用于任何类型的软件包)是,当您安装软件包的X版本时,您绝对可以确保获得与子依赖版本相同的所有内容(这减少了由于使用与软件包作者测试时不同版本的子依赖项而导致的错误或行为差异的风险)。这仅适用于全局安装的可执行软件包,因为在任何其他情况下,选项2存在一个很大的缺点(它往往会增加依赖于您的软件包的构建大小),但对于全局可执行文件则没有这个问题。 - undefined
显示剩余6条评论

30

NPM 开发者的解释

这个想法肯定是让 package-lock.json 成为最新和最伟大的缩小包技术,而 npm-shrinkwrap.json 则保留给那些非常关心他们的库是否有精确 node_modules 的宝贵少数人以及想要使用 npm@>=2 进行 CI 安装特定树木而不必提高其 npm 版本的人。

新的锁定文件("package-lock.json")基本上与 npm-shrinkwrap 具有完全相同的代码、完全相同的格式(可以在它们之间重命名!)。这也是社区似乎理解的东西:"它有一个锁定文件"似乎更容易被人们接受。最后,有一个新文件意味着我们可以相对低风险地向后兼容缩小包,而不必像父帖子中提到的那样做一些奇怪的事情,比如允许发布。


23
我还是不太清楚它们之间的区别。如果npm-shrinkwrap用于精确锁定node_modules......那么我认为package-lock.json锁定的就不是非常精确?如果是这样,那么npm-shrinkwrap锁定了什么而package-lock.json没有锁定的呢? - dman
1
你错了@dman。package-lock是npm-shrinkwrap的新版本。package-lock是默认启用的(因此您必须删除该功能,因为它是默认启用的),npm-shrinkwrap是默认未包含的(因此您必须启用它,因为它不是默认包含的)。他们引入package-lock的原因是:1.用户现在有更安全的方法来处理依赖关系,因为它默认启用;2.名称说明了它与“shrinkwrap”的相反之处。npm-shrinkwrap具有一些特殊的依赖项行为设置,而package-lock现在没有。npm-shrinkwrap现在已经过时了。 - SeriousM
10
这是不正确的。通过说package-lock是npm-shrinkwrap的新版本,你在暗示它是一个替代品。然而,npm-shrinkwrap并没有被弃用,并且与package-lock.json有所不同。此外,package-lock.json存在一个bug,而npm-shrinkwrap则没有...因此更加强调它们不是相同的代码。 - dman
经过多次阅读后,我必须将一个项目的完全相同依赖项传递到另一个项目中,因此我尝试了使用npm ci。不幸的是,我最终得到了一个空的node_modules,而不是一个新的。当然,在运行npm i时,如果package.json中没有依赖,那么它会使用~或^,因此不会查找更新(但我可能对此有所错误),生成一个新的修改后的package-lock.json。 - Carmine Tambascia
当然,这不是我想要的,因为我有一些遗留依赖项,为了开发的缘故,我想保留它们。我找到的唯一解决方案就是再次删除node_module,并手动复制其他项目的package-lock.json文件,然后运行npm install。请问是否可以通过命令行实现这个目标,需要采取哪些步骤? - Carmine Tambascia
显示剩余2条评论

14
我认为这个想法是默认执行--save和shrinkwrap,但避免在不需要的情况下发生shrinkwrap。因此,他们只是给它一个新的文件名以避免任何冲突。 npm的某位成员在这里更详细地解释了这一点:https://www.reddit.com/r/javascript/comments/6dgnnq/npm_v500_released_save_by_default_lockfile_better/di3mjuk/ 相关语录:
npm 默认发布源目录中的大多数文件,而人们已经发布了数年的shrinkwrap。我们不想破坏兼容性。使用默认的--save和shrinkwrap,有很大的风险意外地进行操作并通过注册表传播,从而使我们更新依赖项和去重的能力变得无效。所以我们选择了一个新名称。我们突然选择了一个新名称。 新的锁定文件与旧版共享基本相同的代码和完全相同的格式。

7

-1;我刚刚检查了一下,至少对于npm 10.2.0来说,这是不正确的。快速测试:在一个新的文件夹中运行npm init --yes && npm install lodash && npm shrinkwrap。现在,在package.json中修改"lodash": "^4.17.21"(或者如果你是在未来进行此操作,则修改为你看到的更高版本),将其改为"lodash": "3.0.0"。现在运行npm install;观察输出中的"changed 1 package"消息。检查你的npm-shrinkwrap.json,你会发现它已经被更新为指定Lodash的版本3.0.0,而不是之前安装的任何版本。 - undefined
如果npm-shrinkwrap文件按照这个答案描述的方式工作,我真的不确定你该如何处理它。如果npm install不会写入shrinkwrap文件,那么更新依赖版本的工作流程会是什么样子呢?随着依赖关系的变化,更新锁定文件是开发过程中必不可少的一部分。如果你的回答是准确的,那么使用Shrinkwrap文件时,这种必要的行为将不会得到支持。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接