若是您构建一个相似web服务器的应用程序,那么锁定文件很是有用。可是,若是将库或CLI发布到npm,则永远不要发布锁文件。若是使用锁文件,则意味着您的用户和您可能使用不一样版本的依赖项。html
一个锁文件描述了整个依赖树,由于它在建立时被解析,包括与特定版本的嵌套依赖关系。在npm中,这些被称为package-lock.json
和在yarn中,它们被称为yarn.lock
。在npm和yarn中,它们都放在package.json旁边。node
package-lock.json
看起来像这样:git
{
"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
文件格式不一样,但包含相似的信息:web
# 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"
复制代码
这两份文件都记录了一些重要的信息:npm
- 安装的每一个依赖项的实际版本
- 每一个依赖项的依赖项
- 已解析的包,包括一个校验和,用于验证包的完整性
所以,若是全部依赖项都列在锁文件中,为何还要在package.json中列出它们呢?为何咱们须要两个文件?json
项目“package.json”文件中的dependencies
字段的目的是显示应该安装的依赖项,而不是这些依赖项的依赖项。依赖项能够指定精确的版本或在Semver版本号范围内。对于使用semver版本号规则的,npm或yarn将选择最适合安装的版本。bash
这意味着,若是在发布新版本期间运行两次npm install
,那么实际上可能获得不一样依赖项的版本。例如,若是您使用npm install twilio
安装一个叫twilio
的依赖项。json可能有一个相似的条目:服务器
{
"dependencies": {
"twilio": "^3.30.3"
}
}
复制代码
若是你在npm页面上查看semver的文档,你会发现^
实际上意味着任何大于3.30.3和小于4.0.0的版本都是有效的。所以,若是任何新版本发布,而你没有一个锁文件存在,npm或yarn将安装那个新的版本并不会自动更新package.json
。然而,若是存在锁文件就不会这样子。并发
若是npm或yarn找到各自的锁文件,它们将使用这些文件进行模块安装。这对于在须要确保测试在可预测环境中运行的平台上进行持续集成(CI)之类的状况特别有用。对于这个用例,您可使用特殊的命令或标志与相应的包管理器:app
npm ci # 将确切地安装package-lock.json中的内容
yarn install --frozen-lock-file # 将准确地安装yarn.lock中的内容。不更新锁定
复制代码
这在构建web应用程序或服务器之类的应用程序时很是有用,由于在CI环境中,咱们但愿模拟用户的行为。所以,若是咱们开始在源代码控制中跟踪锁文件(如git),咱们能够确保每一个开发人员、服务器、构建系统和CI系统使用相同版本的依赖。
那么,当咱们编写库或其余打算发布到npm仓库的东西时,为何不但愿作一样的事情呢?为了回答这个问题,咱们首先要谈谈发包是如何运做的。
与一些人通常认知不一样,发布到npm的内容并不老是与GitHub上的内容相同,也不老是与项目中的整体内容相同。模块发布的方式是,npm将经过检查package.json
文件中的files
配置和.npmignore
文件来肯定应该发布的文件。若是没有.npmignore
文件则使用.gitignore
文件。还有一些文件老是包含在其中,而另外一些文件老是被排除在外。您能够在npm页面上找到这些文件的完整列表。例如,.git
文件夹老是会被忽略。
以后,npm将获取文件列表,并使用npm pack
将它们打包成一个tarball
。若是你想查看哪些文件被打包,你能够运行npm pack --dry-run
命令,它将输出与全部文件:
而后,该tarball
将被上传到npm包仓库。运行此命令时,您可能注意到了,package-lock.json
并无被打入包中。这是由于package-lock.json
老是会被忽略,正如npm文档中的列表所指定的那样。
这意味着若是其余开发人员安装了你发布的包,他们将永远不会下载你的package-lock.json
。所以,在安装期间将彻底不受锁文件影响。
这可能会意外地致使“在个人机器明明是好的”的效果,由于您的CI和开发人员环境可能会得到不一样版本的依赖关系。那么咱们应该作些什么呢?
首先,咱们应该确保中止跟踪锁定文件。若是您正在使用git,请将如下内容添加到项目中的.gitignore
文件中:
yarn.lock
package-lock.json
复制代码
yarn官方文档说即便是你写的库,也应该登记一份yarn.lock
文件。可是,若是你想确保拥有与用户相同的体验,我建议将yarn.lock
添加到.gitignore
。
您能够关闭package-lock.json
文件的生成。经过在项目中建立或将如下内容添加到.npmrc文件
package-lock = false
复制代码
对于yarn
,您可使用yarn install --no-lockfile
命令不生成锁定文件。
然而,不是说由于咱们不使用package-lock.json
文件就没有办法锁定依赖项和子依赖项。咱们还可使用另外一个名为npm-shrinkwrap.json
的文件。
它基本上与package-lock.json
相同。由npm shrinkwrap
命令生成,并实际打包并发布到npm仓库。
所以,经过将npm shrinkwrap
做为预打包脚本甚至git提交钩子添加到npm脚本中,您能够确保在开发环境、用户和CI中使用相同版本的依赖关系。
有一点很重要,必定要当心使用。经过使用shrinkwrap
文件安装依赖包,你能够锁定准确的版本,这可能很棒,但它也能够阻止人们得到关键补丁。npm强烈反对对库使用shrinkwrap
,并建议只在CLIs或相似的场景使用shrinkwrap
。
虽然在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 # 将以verbose模式运行包的安装,而无需实际将其安装到文件系统
复制代码
有关该主题的一些有用的文档连接以下:
这在很大程度上取决于npm如何处理打包、发布和安装依赖项,并且随着不断变化的环境,这一点可能会在某一时刻发生变化。我但愿这篇文章能让你对这个复杂的话题有更多的了解。