Node.js项目中最好不要使用锁定文件

该材料的作者(我们今天将其翻译发表)说,程序员必须解决的问题之一是他们的代码对他们有用,并且给其他人带来了错误。 这个问题可能是最常见的问题,这是由于在程序的创建者和用户的系统中安装了该程序使用的不同依赖项这一事实。 为了解决这种现象, yarnnpm软件包管理器中存在所谓的锁定文件。 它们包含有关依赖项的确切版本的信息。 该机制很有用,但是如果有人正在开发计划在npm中发布的软件包,则最好不要使用锁定文件。 该材料专门讲述了为何如此的故事。



简而言之,最重要的事情


在开发Web服务器等Node.js应用程序时,锁定文件非常有用。 但是,如果您要创建以npm发布为目标的库或命令行工具,则需要知道npm中的锁定文件没有发布。 这意味着,如果在开发过程中使用了这些文件,则npm软件包的创建者以及使用该软件包的人员将使用不同版本的依赖关系。

什么是锁定文件?


锁定文件以在项目工作期间获取的形式描述了完整的依赖关系树。 此描述还包括嵌套的依赖项。 该文件包含有关所使用软件包的特定版本的信息。 在npm软件包管理器中,此类文件在package-lock.json中称为package-lock.json yarn.lock 。 在两个管理器中,这些文件都与package.json位于同一文件夹中。

这是package-lock.json样子。

 { "name": "lockfile-demo", "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": {  "ansi-styles": {    "version": "3.2.1",    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",    "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",    "requires": {      "color-convert": "^1.9.0"    }  },  "chalk": {    "version": "2.4.2",    "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",    "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",    "requires": {      "ansi-styles": "^3.2.1",      "escape-string-regexp": "^1.0.5",      "supports-color": "^5.3.0"    }  } } } 

这是一个示例yarn.lock文件。 它不是像package-lock.json那样设计的,但是包含相似的数据。

 # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies:       color-convert "^1.9.0" chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies:       ansi-styles "^3.2.1"       escape-string-regexp "^1.0.5"       supports-color "^5.3.0" 

这两个文件都包含一些关键的依赖项信息:

  • 每个已安装依赖项的确切版本。
  • 每个依赖项的依赖项信息。
  • 有关下载的软件包的信息,包括用于验证软件包完整性的校验和。

如果所有依赖项都在锁定文件中列出,那么为什么还要将有关它们的信息也添加到package.json ? 为什么需要两个文件?

package.json和锁文件的比较


package.json文件的dependencies字段的目的是显示必须安装的项目依赖项,它才能正常工作。 但这不包括有关这些依赖关系的信息。 依赖性信息可以包括确切的软件包版本或根据语义版本控制规则指定的特定版本范围。 使用npm或纱线范围时,将选择最合适的卷装版本。

假设运行了npm install命令以安装某个项目的依赖项。 在安装过程中,npm选择了合适的软件包。 如果一段时间后再次运行此命令,并且在此期间发布了新版本的依赖关系,则很可能第二次加载项目中使用的其他版本的软件包。 例如,如果使用npm install twilio之类的dependencies项,则以下条目可能会出现在package.json文件的“ dependencies部分中:

 { "dependencies": {    "twilio": "^3.30.3" } } 

如果查看npm语义版本控制文档 ,则可以看到^符号表示该软件包的任何版本均适用,该版本的数量应大于或等于3.30.3且小于4.0.0。 结果,如果项目中没有锁定文件,并且发布了新版本的软件包,则npm installyarn install将自动安装该新版本的软件包。 package.json的信息将不会更新。 使用锁定文件时,一切看起来都不同。

如果npm或yarn找到相应的锁定文件,则他们将基于此文件而不是package.json安装软件包。 例如,这在平台上使用持续集成(CI)系统时特别有用,您需要在平台上确保在事先知道其特征的环境中对代码和测试进行统一操作。 在这种情况下,可以在调用适当的程序包管理器时使用特殊的命令或标志:

 npm ci #   ,    package-lock.json yarn install --frozen-lock-file #  ,    yarn.lock,     

如果您正在开发Web应用程序或服务器之类的项目,这将非常有用,因为在CI环境中,您需要模拟用户行为。 结果,如果我们在项目存储库中包含一个锁定文件(例如,使用git工具创建的文件),则可以确保每个开发人员,每个服务器,每个代码构建系统和每个CI环境都使用相同的版本依赖性。

在npm注册表中发布库或其他软件工具时,为什么不做同样的事情? 在回答这个问题之前,我们需要讨论发布程序包的过程如何工作。

包发布过程


一些开发人员认为,npm中发布的内容恰好是git存储库中存储的内容,或者项目在完成工作后变成的内容。 实际上并非如此。 发布软件包时,npm通过访问package.json文件和.npmignore文件中的files键来找出要发布的文件。 如果无法检测到任何一个,则使用.gitignore文件。 此外,某些文件始终发布,而某些文件从未发布。 您可以在此处找到这些文件。 例如,npm始终忽略.git文件夹。

之后,npm将获取所有适当的文件,并使用npm pack命令它们打包tarball文件。 如果要查看打包到该文件中的内容,可以在项目文件夹中运行npm pack --dry-run命令,并在控制台中查看材料列表。


Npm pack --dry-run命令输出

然后将生成的tarball文件上载到npm注册表。 当您运行npm pack --dry-run您应该注意以下事实:如果项目中有package-lock.json文件,则它不包含在tarball文件中。 这是由于以下事实:始终根据npm 规则忽略此文件。

结果是,如果有人安装了其他人的软件包,则不会涉及package-lock.json文件。 当其他人安装软件包时,将不考虑软件包开发人员在此文件中包含的内容。

不幸的是,这可能导致我们一开始就谈到的问题。 在开发人员的系统中,代码可以正常工作,而在其他系统中,则会产生错误。 但是事实是,项目开发人员和使用项目的人员使用不同版本的软件包。 如何解决?

拒绝锁定文件和使用技术包装


首先,您需要防止将锁定文件包含在项目存储库中。 使用git时,需要在项目.gitignore文件中包括以下内容:

 yarn.lock package-lock.json 

yarn文档指出,即使涉及到开发计划发布的库,也需要将yarn.lock添加到存储库中。 但是,如果您希望您和库用户使用相同的代码,则建议在.gitignore文件中包含yarn.lock

您可以通过.npmrc具有以下内容.npmrc文件.npmrc到项目文件夹来禁用package-lock.json文件的自动创建:

 package-lock=false 

使用yarn时,可以使用yarn install --no-lockfile ,该yarn install --no-lockfile可禁用对yarn.lock文件的读取。

但是,我们摆脱了package-lock.json文件这一事实并不意味着我们无法捕获有关依赖项和嵌套依赖项的信息。 还有一个名为npm-shrinkwrap.json 文件

通常,这是与 package-lock.json 相同的文件 ,它是由package-lock.json npm shrinkwrap创建的。 程序包发布时,此文件进入npm注册表。

为了自动执行此操作,可以将npm shrinkwrap作为预打包脚本添加到package.json文件的脚本描述部分。 您可以使用git commit钩子达到相同的效果。 结果,您可以确保在开发环境,CI系统和项目用户中使用相同的依赖项。

值得注意的是,建议以负责任的方式使用此技术。 通过创建拆封文件,您可以提交依赖关系的特定版本。 一方面,这对于确保项目的稳定运行很有用,另一方面,它可以防止用户安装关键补丁,否则,补丁将自动完成。 实际上,npm强烈建议在开发库时不要使用收缩包装文件,将其使用范围限制为CI系统。

查找包和依赖项信息


不幸的是,由于npm 文档中包含了大量有关依赖项管理的信息,因此有时很难导航这些信息。 如果您想知道在依赖性安装过程中究竟安装了什么,或者在将软件包发送到npm之前已经打包了什么,可以使用--dry-run标志,使用不同的命令。 使用此标志导致团队不影响系统的事实。 例如, npm install --dry-run命令实际上不会安装依赖项,而npm publish --dry-run命令不会启动软件包发布过程。

以下是一些类似的命令:

 npm ci --dry-run #  ,   package-lock.json   npm-shrinkwrap.json npm pack --dry-run #     ,       npm install <dep> --verbose --dry-run #            

总结


我们在这里谈论的很多事情都依赖于使用npm执行各种操作的细节。 我们正在谈论打包,发布,安装软件包以及使用依赖项。 鉴于npm不断发展的事实,我们可以说所有这些都可以在将来改变。 另外,此处给出的建议的实际应用可能性取决于包开发人员如何感知在不同环境中使用依赖关系的不同版本的问题。

希望本文能帮助您更好地了解npm依赖生态系统的工作方式。 如果您想更深入地研究这个问题- 在这里您可以阅读有关npm cinpm install命令之间的区别。 在这里,您可以找到package-lock.jsonnpm-shrinkwrap.json package-lock.json npm-shrinkwrap.json到底包含了什么。 是npm文档页面,您可以在其中查找哪些项目文件包含在软件包中,而没有包含在软件包中。

亲爱的读者们! 您是否在项目中使用npm-shrinkwrap.json文件?

Source: https://habr.com/ru/post/zh-CN453582/


All Articles