npm 5 今天发布,其中一项新功能包括通过创建package-lock.json
文件进行确定性安装。
此文件是否应保存在源代码管理中?
我假设它类似于yarn.lock
和composer.lock
,两者都应该保存在源代码管理中。
是的,package-lock.json
旨在签入源代码管理。如果您使用的是 npm 5+,您可能会在命令行上看到此通知:created a lockfile as package-lock.json. You should commit this file.
根据npm help package-lock.json
:
package-lock.json
是为 npm 中的任何操作自动生成的 修改node_modules
树或package.json
。它描述了 生成的精确树,以便后续安装能够 生成相同的树,而不考虑中间依赖项更新。此文件旨在提交到源存储库中,并用于 各种用途:
描述依赖关系树的单个表示形式,以便保证团队成员、部署和持续集成安装完全相同的依赖关系。
为用户提供一种工具,使其可以"时间旅行"到以前的
node_modules
状态,而无需提交目录本身。通过可读的源代码管理差异提高树更改的可见性。
通过允许 npm 跳过以前安装的包的重复元数据解析来优化安装过程。
关于
package-lock.json
的一个关键细节是它不能发布,而且它 如果在顶级包以外的任何地方找到,将被忽略。它分享 npm-shrinkwrap.json的格式,本质上是相同的文件,但是 允许发布。除非部署 CLI 工具或 否则使用发布过程来生成生产包。如果
package-lock.json
和npm-shrinkwrap.json
都存在于 的根中 一个包,package-lock.json
将被完全忽略。
是的,你应该:
-
提交
package-lock.json
。 - 在 CI 和本地开发计算机上构建应用程序时,请使用
npm ci
而不是npm install
npm ci
工作流需要存在package-lock.json
。
npm install
命令的一大缺点是它的意外行为,它可能会改变package-lock.json
,而npm ci
只使用锁文件中指定的版本并产生错误
- 如果
package-lock.json
和package.json
不同步 - 如果缺少
package-lock.json
。
因此,在本地运行npm install
,特别是在具有多个开发人员的大型团队中,可能会导致package-lock.json
内部发生大量冲突,开发人员决定完全删除package-lock.json
。
然而,有一个强大的用例能够信任项目的依赖项在不同机器上以可靠的方式重复解析。
从package-lock.json
中,您可以得到确切的:已知工作状态。
过去,我有一些没有package-lock.json
/npm-shrinkwrap.json
/yarn.lock
文件的项目,这些项目的构建有一天会失败,因为随机依赖项得到了中断性更新。
这些问题很难解决,因为您有时必须猜测最后一个工作版本是什么。
如果要添加新的依赖项,仍运行npm install {dependency}
。如果要升级,请使用npm update {dependency}
或npm install ${dependendency}@{version}
并提交更改的package-lock.json
。
如果升级失败,您可以恢复到上一个已知的工作package-lock.json
。
引用 npm 文档:
强烈建议您将生成的包锁提交到 源代码控制:这将允许团队中的其他任何人,您的 部署、CI/持续集成以及运行的任何其他人 在包源中安装 npm 以获得完全相同的依赖项 你正在开发的树。此外,与这些的区别 更改是人类可读的,并且会通知您 npm 的任何更改 制作到您的node_modules,因此您可以注意到是否有任何传递 依赖项已更新、提升等。
关于npm ci
与npm install
之间的区别:
- 该项目必须具有现有的 package-lock.json 或 npm-shrinkwrap.json。
- 如果包锁中的依赖项与 package.json 中的依赖项不匹配,
npm ci
将退出并显示错误,而不是更新 包锁。npm ci
一次只能安装整个项目:不能使用此命令添加单个依赖项。- 如果
node_modules
已存在,则npm ci
开始安装之前将自动将其删除。- 它永远不会写入
package.json
或任何包锁:安装基本上被冻结。
注意:我在这里发布了类似的答案
是的,它旨在签入。我想建议它获得自己独特的提交。我们发现它给我们的差异增加了很多噪音。
是的,最佳做法是办理登机手续(是的,办理登机手续)
我同意在看到差异时会引起很多噪音或冲突。但好处是:
-
保证开发和生产环境之间的每个包版本完全相同。在不同时间的不同环境中构建时,这部分是最重要的。您可以在
package.json
中使用^1.2.3
,但是如何确保每次npm install
都会在开发计算机和构建服务器中选取相同的版本,尤其是那些间接依赖项包?好吧,package-lock.json
将确保这一点。(在基于锁定文件安装软件包的npm ci
的帮助下) - 它改进了安装过程。
- 它有助于新的审计功能
npm audit fix
。
我不在我的项目中提交这个文件。有什么意义?
- 它已生成
- 这是gitlab-ci.yml构建的gitlab中SHA1代码完整性错误的原因
虽然我从来没有在我的 package.json 中使用 ^ 作为库,因为我对它有不好的经历。
[编辑]这个答案已经过时(2018年),公平地说,它也缺乏知识。截至 2023 年 4 月,我的答案是 =>当然,您必须提交此文件: 例如,CI 平台上的标准安装命令npm ci
需要该文件正常工作以确保依赖树与提交完全相同;
对于在做 git diff 时抱怨噪音的人:
git diff -- . ':(exclude)*package-lock.json' -- . ':(exclude)*yarn.lock'
我所做的是使用别名:
alias gd="git diff --ignore-all-space --ignore-space-at-eol --ignore-space-change --ignore-blank-lines -- . ':(exclude)*package-lock.json' -- . ':(exclude)*yarn.lock'"
要忽略整个存储库(使用它的每个人)的差异中的 package-lock.json,您可以将其添加到.gitattributes
:
package-lock.json binary
yarn.lock binary
这将导致差异显示"二进制文件 a/package-lock.json 和 b/package-lock.json 在包锁定文件更改时都不同。此外,一些 Git 服务(特别是 GitLab,但不是 GitHub)也会在执行此操作时在线查看时从差异中排除这些文件(不再更改 10k 行!)。
是的,您可以提交此文件。来自 npm 的官方文档:
对于
npm
修改node_modules
树或package.json
的任何操作,都会自动生成package-lock.json
。它描述了生成的确切树,以便后续安装能够生成相同的树,而不考虑中间依赖项更新。此文件旨在提交到源存储库[。
是的,提交package-lock.json
是标准做法。
提交package-lock.json
的主要原因是项目中的每个人都使用相同的包版本。
优点:
- 如果您遵循严格的版本控制并且不允许自动更新到主要版本以使您免于第三方软件包中的向后不兼容更改,则提交包锁定会有很大帮助。
- 如果您更新特定包,它会在 package-lock.json 中更新,并且使用该存储库的每个人在提取您的更改时都会更新到该特定版本。
缺点:
- 它可以使您的拉取请求看起来很丑陋:)
npm install
不会确保项目中的每个人都使用相同的包版本。npm ci
将对此有所帮助。
是
答案是肯定的,绝对始终将您的锁定文件提交到 git。
类比 git 哈希
如果使用 git,则应使用锁定文件,因为它们具有相同的目的:
- Git 哈希保证了 Git存储库中文件内容的稳定性。
- 锁定文件保证了node_modules内容的稳定性。
因为。。。
- Git 存储库中的文件可能会随时间而更改,但Git 哈希是指文件的精确快照。
- npm 注册表中的npm 包可能会随时间而更改,但锁文件是指依赖项的确切快照。
来自包管理器本身
包管理器供应商明确表示您应该提交锁定文件。
新人掌
强烈建议您将生成的包锁提交到源代码管理...
https://docs.npmjs.com/cli/v6/configuring-npm/package-locks
当npm
安装时没有锁文件时,它会清楚地告诉您提交锁文件:
npm notice created a lockfile as package-lock.json. You should commit this file.
纱
应在所有项目上提交锁定文件
https://classic.yarnpkg.com/blog/2016/11/24/lockfiles-for-all/
PNPM
您应该始终提交锁定文件 (
pnpm-lock.yaml
)。
https://pnpm.io/git
原因
一致性
单个提交应永远相同,并且其生成输出不应随时间而更改。
从 npm :
[锁文件] 将允许团队、部署、CI/持续集成中的其他任何人以及在包源中运行 npm install 的任何其他人获取与开发完全相同的依赖项树。
从纱线:
如果您不存储最终安装的版本,则有人可能会安装同一组依赖项,并根据他们的安装时间最终获得不同的版本。这可能会导致"在我的机器上工作"问题,应避免。
变更的可追溯性
当某些内容发生变化时,您希望 git 跟踪该更改。
从 npm :
[使用锁定文件] 与 [安装] 更改的差异是人类可读的,并且会通知您 NPM 对
node_modules
所做的任何更改,因此您可以注意到是否有任何传递依赖项被更新、提升等。
稳定性和安全性
避免引入错误和漏洞。
从纱线:
由于包作者是人,他们可能会犯错误,因此他们可能会在次要版本或修补程序版本中发布意外的重大更改。如果在无意的情况下安装此中断性更改,则可能会产生不良后果,例如在生产环境中中断应用。
如果包作者是恶意的或受到恶意攻击,并且发布了错误的版本,则您不希望该代码在您不知情的情况下最终运行。
常见异议
"没有意义">
这是一个"无知的论证",这是一个逻辑谬误。换句话说,"我不知道原因,所以没有"。
"它已生成">
如果这个文件是自动生成的,他们为什么要提交它?为什么 npm 不能根据我的包.json 再次生成它。
从评论
回应:生成不是缺陷。生成 Git 提交哈希;我们不应该使用 git 吗?事实是,锁文件不是从 package.json 确定地生成的,因为它容易受到时间和 npm 注册表中包的状态的影响。这是一个快照,为了稳定。
"它会导致合并冲突">
解决签入锁定文件中的合并冲突是一种负担。
从 npm :
从
npm@5.7.0
开始,这些冲突可以通过手动修复任何package.json
冲突,然后再次运行npm install [--package-lock-only]
来解决。
从纱线:
当锁定文件中存在合并冲突时,Yarn 将在运行
yarn install
时自动为您处理冲突解决方案。
https://engineering.fb.com/2017/09/07/web/announcing-yarn-1-0/
从 pnpm 开始:
pnpm 可以自动解决
pnpm-lock.yaml
中的合并冲突。如果遇到冲突,只需运行pnpm install
并提交更改。
因此,所有包管理器都会自动解决锁文件合并冲突。在旧版本中可能不是这种情况,但现在是这种情况。
唯一失败的情况是package.json
本身存在冲突,因为您无法从无效package.json
安装。您必须手动解决这些冲突,因为无论如何都必须这样做。
"合并冲突会干扰 PR 和 MR">
使用锁定文件会大大增加合并一个 PR 导致第二个 PR 与基本分支发生冲突的可能性。
https://docs.renovatebot.com/noise-reduction/#lock-file-considerations
这是真的。Git 提供程序(GitHub、GitLab 等)不会自动解决锁定文件冲突,因此这可能会增加合并的负担。但是,在权衡此骗局时,请了解锁定文件通常不会更改;仅当 DEP 更改package.json
或开发人员专门更改文件或已安装的node_modules
DEP 时,它们才会更改。
"它会产生差异噪音">
如果差异工具显示锁定文件差异,则噪音很大。
这是真的,但这是一个工具问题,许多工具可以优雅地处理(例如自动最小化、分页或虚拟滚动)。如果您根本不想看到锁定文件差异,请尝试git diff -- . ':(exclude)yarn.lock'
,或者.gitattributes
中将文件标记为二进制文件(但是,如果这对您很重要,您将看不到其差异)。
"确切的版本已经足够好了">
为什么不通过删除插入符号和波浪号(^ 和 ~)来硬编码依赖项版本?
评论
这个想法是,不使用package.json
依赖项 semver 表达式中的范围与拥有锁定文件相同。
这是错误的。即使指定了确切版本,依赖项也有其自己的依赖项,这些依赖项可能使用其版本范围,而不是确切版本。因此,这最终不会锁定整个依赖树,只会锁定其顶部。
"应用程序的锁定文件,没有库的锁定文件">
此异议的示例:
- Sindre Sorhus: "Lockfiles for apps, but not for packages" sindresorhus/ama!479
- 特鲁斯克特评论
人们的观点是,库需要对前沿部门做出反应,而没有锁定文件支持这一点。
从纱线:
有些人想知道为什么图书馆应该使用锁文件......在开发库时使用 LockFiles 会产生一种虚假的安全感,因为您的用户可能安装的版本与您不同。
这在逻辑上似乎是有道理的,但让我们更深入地研究这个问题。
纱线文章深入探讨了这种反对意见。请阅读它。
此参数中的一个常见错误是认为,如果您不提交锁定文件,它就不存在。实际上,它仍然存在于您的计算机上,锁定您的依赖项。忽略锁定文件不会改善这种情况。
如果库维护者希望持续测试兼容性,那么他们应该在安装和构建他们的库之前删除他们的锁文件(无论锁文件是否已签入!)。与签入锁文件的唯一区别是,您具有node_modules发生时状态的持久记录,因此将来可以重现它。
有像绿色守护者和翻新机器人这样的机器人。Greenkeeper 提倡签入锁定文件(Greenkeeper 和 Lockfiles:天作之合)和翻新机器人不发表意见,但如果存在,确实会提交锁定文件。
"不同系统以不同的方式生成锁定文件">
这是一个提到的声明(例如这里):不同的操作系统生成不同的锁定文件内容。如果是这种情况,这是一个错误。
但是,不同版本的npm
(或任何包管理器)可能会产生不同的锁文件输出。我还没有证实这一点,但假设如果是这样,那么为稳定付出的代价很小。若要解决此问题,贡献者需要使用 nvm 等工具切换其包管理器版本。
"锁定文件可能存在安全风险">
请参阅 Snyk - 为什么 npm 锁定文件可以成为注入恶意模块的安全盲点
这是一个真正的风险。具有锁定文件的公共项目可能会收到包含锁定文件内容的恶意 PR,一旦拉取并安装分支,这些 PR 可能会危及维护者的计算机。
通过 CI 检查(如 lockfile-lint 或简单的npm ci
或yarn --immutable
)来防御这种情况(在 Yarn 1 上yarn --frozen-lockfile
),也许可以在您的npmrc
中本地设置ignore-scripts
。
每当安装包含不受信任代码的包时,都会存在此风险。
结语
始终提交锁定文件。
全局禁用package-lock.json
在终端中键入以下内容:
npm config set package-lock false
这真的像魔术一样对我有用
所有答案都说"是",但这也取决于项目,文档说:
关于 package-lock.json 的一个关键细节是它不能发布,如果在顶级包以外的任何地方找到它将被忽略。
这意味着您不需要在 npm 上发布依赖项的package-lock.json
,但您需要在存储库中使用package-lock.json
来锁定测试依赖项的版本,构建依赖项......
但是,如果使用 lerna 来管理具有多个包的项目,则应仅将package.json
放在存储库的根目录上,而不是在每个子包中都使用npm init
创建。你会得到这样的东西:
.git
lerna.json
package.json
package-lock.json <--- here
packages/a/package.json
packages/a/lib/index.js
packages/b/package.json
packages/b/lib/index.js
将 package-lock.json 提交到源代码版本控制意味着项目将使用特定版本的依赖项,该版本可能与 package.json 中定义的依赖项匹配,也可能不匹配。 如您所见,依赖项具有没有任何插入符号 (^) 和波浪号 (~) 的特定版本,但这意味着依赖项不会更新到最新版本。 npm 安装将选择相同的版本,因为我们需要它当前版本的 Angular。
注意:package-lock.json强烈建议我提交它,如果我将任何插入符号(^)和波浪号(~)添加到要在CI期间更新的依赖项中。
TLTR
承诺以下情况。
- 提交 if,将新的
npm/yarn
包添加到项目中。 - 如果
package.json
中的任何更改正在更新.lock
文件,则提交。 - 如果包,nodejs,yarn中的任何版本更改正在更新
.lock
文件,则提交。
不要在以下情况下承诺。
-
您没有编码并
更新锁定文件it means other dev did not push lock file during above specified commit points
-
您刚刚将拉取并获取更新的锁定文件
it means other dev did not push lock file during above specified commit points
-
刚刚做了 git 克隆并
更新锁定文件it means other dev did not push lock file during above specified commit points
-
您编写了一个功能,但未执行与上述指定提交点相关的任何操作,并且仍然锁定文件正在更新
it means other dev did not push lock file during above specified commit points
结论
锁定文件的主要目标是 安装项目的all developers
all environments
all machines
应该有ULTRA ACCURATED库和版本
所以基本上,只有 3 种提交情况。
我对 npm 的使用是生成缩小/丑陋的 css/js,并生成 django 应用程序提供的页面所需的 JavaScript。在我的应用程序中,Javascript在页面上运行以创建动画,有时执行ajax调用,在VUE框架内工作和/或使用css。如果 package-lock.json 对 package.json 中的内容具有一些覆盖性控制,则可能需要有一个版本的此文件。根据我的经验,它要么不会影响 npm install 安装的内容,要么即使影响,它迄今为止还没有对我所了解的应用程序产生不利影响。我不使用 mongodb 或其他传统上是瘦客户端的应用程序。
我从存储库中删除包锁.json 因为 npm install 会生成此文件,而 npm install 是运行该应用的每台服务器上部署过程的一部分。node和npm的版本控制是在每台服务器上手动完成的,但我小心它们是相同的。
当npm install
在服务器上运行时,它会更改package-lock.json, 如果服务器上的存储库记录的文件发生了更改,则下一次部署将不允许从源中提取新更改。那是 无法部署,因为拉取将覆盖对 package-lock.json 所做的更改。
您甚至不能用存储库上的内容覆盖本地生成的 package-lock.json(重置硬源主节点),因为如果 package-lock.json 由于 npm 安装而没有反映node_modules中的内容,npm 会在您发出命令时抱怨,从而中断部署。现在,如果这表明node_modules中安装了略有不同的版本,那么这又从未给我带来问题。
如果node_modules不在您的存储库中(并且不应该在存储库中),则应忽略 package-lock.json。
如果我遗漏了什么,请在评论中纠正我,但从该文件中获取版本控制的观点毫无意义。文件package.json中有版本号,我假设这个文件是用于在npm安装发生时构建包的文件,因为当我删除它时,npm install抱怨如下:
jason@localhost:introcart_wagtail$ rm package.json
jason@localhost:introcart_wagtail$ npm install
npm WARN saveError ENOENT: no such file or directory, open '/home/jason/webapps/introcart_devtools/introcart_wagtail/package.json'
并且构建失败,但是在安装 node_modules 或应用 npm 来构建 js/CSS 时,如果我删除 package-lock.json 不会有任何抱怨
jason@localhost:introcart_wagtail$ rm package-lock.json
jason@localhost:introcart_wagtail$ npm run dev
> introcart@1.0.0 dev /home/jason/webapps/introcart_devtools/introcart_wagtail
> NODE_ENV=development webpack --progress --colors --watch --mode=development
10% building 0/1 modules 1 active ...