该材料的作者(我们今天将其翻译发表)说,程序员必须解决的问题之一是他们的代码对他们有用,并且给其他人带来了错误。 这个问题可能是最常见的问题,这是由于在程序的创建者和用户的系统中安装了该程序使用的不同依赖项这一事实。 为了解决这种现象,
yarn和
npm软件包管理器中存在所谓的锁定文件。 它们包含有关依赖项的确切版本的信息。 该机制很有用,但是如果有人正在开发计划在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 install
或
yarn 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 ci
和
npm install
命令之间的区别。
在这里,您可以找到
package-lock.json
和
npm-shrinkwrap.json
package-lock.json
npm-shrinkwrap.json
到底包含了什么。
这是npm文档页面,您可以在其中查找哪些项目文件包含在软件包中,而没有包含在软件包中。
亲爱的读者们! 您是否在项目中使用npm-shrinkwrap.json文件?
