翻译:疯狂的技术宅 原文:www.twilio.com/blog/lockfi…html
未经容许严禁转载前端
“但是在个人机器上能工做啊!”这种场景多是调试 bug 时最多见的问题。这一般是因为出错的机器和你本身的机器上系统的底层依赖性不一样的结果。因此 yarn 和 npm 在引入了所谓的“lock file”,来跟踪你依赖项确切的版本。可是当你在开发要发布到 npm 的包时,应避免使用这类 lock file 。在本文中,咱们将讨论为何要这样。node
若是你开发像 Web 服务器之类的程序,那么 lock file 是很是有用的。可是若是将库或 CLI 发布到 npm,则永远不要发布 lock file。由于若是你使用它,则意味着你和你的用户可能在使用不一样版本的依赖项。git
lock file 描述了整个依赖关系树,它在建立时被解析,包括具备特定版本的嵌套依赖关系。在 npm
名为 package-lock.json
,在 yarn
中名为 yarn.lock
。在这两个npm
和yarn
它们被放置旁边你的package.json
。npm
package-lock.json
的内容应该是这样: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
的格式不一样,但也包含相似的信息:前端工程化
# 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"
复制代码
二者都包含一些重要的信息:bash
既然 lock file 中已经列出了全部的依赖项,拿为何还要将它们写在 package.json
中呢?为何咱们须要两个文件?服务器
package.json
中 dependencies
字段显示你的项目应该安装的依赖项,但不显示这些依赖项的依赖项。依赖项能够指定精确版本或 semver 范围。对于 semver 范围,npm
或 yarn
将h会选择最适合的版本。并发
这意味着,若是在发布新版本时屡次运行 npm install
,有可能会获得相同版本的依赖项。例如用 npm install twilio
安装 twilio
这样的依赖项,那么 package.json
中的依赖项可能会存在相似于这样的条目:
{
"dependencies": {
"twilio": "^3.30.3"
}
}
复制代码
若是你查阅 npm 网站上的 semver 文档,就会看到 ^
意味着任何大于 3.30.3
的版本和小于 4.0.0
都是有效版本。所以,若是在发布新版本时你没有锁定文件,npm install
或 yarn install
会自动安装一个,你的 package.json
将不会被更新。可是 lock file 的内容会有所不一样。
若是 npm
或 yarn
找到它们各自的 lock file,将使用它们代替模块安装。这对于持续集成(CI)等状况尤为有用。对于此这种场景,你能够针对相应的包管理器使用特殊命令或标志:
npm ci # will install exactly what's in the package-lock.json
yarn install --frozen-lock-file # will install exactly what's in yarn.lock without updating it
复制代码
当你在构建 Web 程序或服务器之类的应用时,这很是有用,由于咱们但愿在 CI 环境中模拟用户的行为。所以,若是在源代码控制(如 git)中跟踪咱们的 lock file,就能够确保每一个开发人员以及服务器或构建系统还有 CI 系统都可以使用相同版本的依赖项。
那么当咱们编写要发布到 npm 的库时,为何不能作一样的事呢?要回答这个问题,首先要讨论发布的工做原理。
与某些人想的相反,你发布到 npm 的内容并不老是与 GitHub 上或项目中的内容彻底相同。发布模块的方式是 npm
将经过检查 package.json
和 .npmignore
文件中的 files
键或者若是没有``来肯定应该发布的文件。 gitignore文件。还有一些文件老是包含在内,有些文件将永远被排除在外。你能够在 [npm page](https://docs.npmjs.com/files/package.json#files) 上找到这些文件的完整列表。例如,
.git` 目录始终会被忽略。
以后 npm
将会获取文件列表,并用 npm pack
将它们一块儿打包成 tarball
。若是要查看打包的文件,能够在项目中运行 npm pack --dry-run
,能看到包含全部文件的输出:
那个 tarball 将被上传到 npm注册表。运行此命令时你可能会注意到加入你已经有了一个 package-lock.json
,它实际上没有被捆绑。这是由于 package-lock.json
将始终被忽略。
这意味着若是另外一个开发人员安装了你发布的软件包,他们永远不会下载你的 package-lock.json
,所以在安装过程当中将会彻底忽略它。
这可能会致使“在个人机器上可以工做”的意外,由于你的 CI 和开发环境可能会选择不一样的依赖项版本。那么咱们能够作些什么呢?
首先,应该中止跟踪咱们的 lock file。若是你用的是git,请将如下内容添加到项目中的 .gitignore
文件中:
yarn.lock
package-lock.json
复制代码
Yarn 的文档说即便你建立了库,也应该签入 yarn.lock
,可是若是你想确保本身可以保证与用户相同的体验,我建议将其添加到 .gitignore
。
你能够经过在项目里的 .npmrc
文件中添加如下内容来关闭 package-lock.json
文件的生成:
package-lock=false
复制代码
对于 yarn
,你能够经过添加 yarn install --no-lockfile
标志保证不生成 lock file。
摆脱了 package-lock.json
并不意味着没法固定咱们所拥有的依赖关系和子依赖关系。咱们能够用另外一个名为 npm-shrinkwrap.json
的文件。
它与 package-lock.json
基本相同,并由 npm shrinkwrap
生成并实际的打包并发布到 npm
注册表中。
所以,经过将 npm shrinkwrap
添加到 npm
脚本做为 prepack
脚本甚至是 git commit hook,能够确保在你的开发环境中,与你的用户和 CI 中使用相同版本的依赖项。
**一个重要的提示:**经过使用 shrinkwrap 文件,你能够肯定精确的版本,但它也会阻止人们得到自动安装的关键补丁程序。 npm
强烈反对库的 shrinkwrap
的用例。
不幸的是,虽然 npm docs 中有不少相关内容,但有时很难找到你想要的东西。若是你想更好地了解安装或打包的内容,那么你一个常见标志就是 --dry-run
。运行该命令而不会影响你的系统。例如 npm install --dry-run
并不会将依赖项安装到你的文件系统,或者 npm publish --dry-run
实际上也不会发布该包。
如下是你可能想要查看的一些命令:
npm ci --dry-run # mock-installs based on package-lock.json or npm-shrinkwrap.json
npm pack --dry-run # lists all files that would be packaged up as well as meta info
npm install <dep> --verbose --dry-run # will run the installation of a package in verbose mode without actually installing it to your file system
复制代码
一些有用连接:
npm ci
and npm install
package-lock.json
or npm-shrinkwrap.json