Parse Yarn Lock File

JavaScript

在使用 Yarn 管理项目的依赖时,会在项目根目录生成一个 yarn.lock 文件。这个文件的内容格式,大体如下:

# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


ansi-styles@^3.2.0, 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"

一些简单的解释:

  1. 最开始的两行,是一些注释内容。这里 Yarn 使用的还是 v1 版本,v2 版本的 Yarn 依然在规划中,目前的进度可以查看这里。根据规划,v2 版本的 yarn.lock 将会成为 YAML 的一个子集,在格式上也会和 v1 有些许不同(比如 #5892 提到的去除 registry 的改动);
  2. ansi-styles@^3.2.0 是在项目某个依赖的 package.json 中使用到的依赖。需要注意的是,这里 ^3.2.0 是一个依赖的允许范围,而不是某个固定的版本号(具体允许的范围参考 semver 的定义)。只规定一个版本范围而不是某个固定的版本号,这在 Node.js 中是非常常见的,但也容易因此造成问题(如,各个环境具体安装的版本号不一致,导致运行结果有差异);
  3. Yarn 为了解决上面一条提到的问题,通过 yarn.lock 文件锁死了版本号。上面例子中,version "3.2.1" 表示的就是,最终 Yarn 使用 3.2.1 这个版本。如果有多个依赖最终使用相同的一个版本,Yarn 会将这些内容合并成一条显示,并用 , 进行分割;
  4. resolved 这个字段,表示当前的依赖应该从哪个位置进行下载。在 v1 中,这个地址是一个包含 registry 的完整地址;在 v2 版本中,前面的 registry 会被隐去,方便开发者进行 registry 的切换(参考 #5892 的讨论);
  5. integrity 这个字段,表示当前下载的包对应的 Hash 值。这个值会被用于检查开发者下载的包是否符合预期,如果下载的结果 Hash 值不同,Yarn 会报错并停止安装的步骤;
  6. dependencies 这个字段,表示当前的包还有哪些需要的依赖,这部分的字段和该包内 package.json 中写的 dependencies 字段内容是一一对应的。

如果开发某些工具,需要解析 yarn.lock 文件的内容,可以使用 Yarn 官方提供的 @yarnpkg/lockfile 工具(npm 地址见这里,GitHub 地址在这里)。

@yarnpkg/lockfile 提供了两个 API,分别是 parse(负责读)和 stringify(负责写)。用起来也很简单,参考官方给出的例子:

const fs = require('fs');
const lockfile = require('@yarnpkg/lockfile');
// or (es6)
import fs from 'fs';
import * as lockfile from '@yarnpkg/lockfile';
 
let file = fs.readFileSync('yarn.lock', 'utf8');
let json = lockfile.parse(file);
 
console.log(json);
 
let fileAgain = lockfile.stringify(json);
 
console.log(fileAgain);

经过 @yarnpkg/lockfile 解析后的 Yarn.lock,返回的对象结构如下:

{
  "type": "success",
  "object": {

  }
}

这里,type 字段有三种可能的结果,分别是(代码见这里):

  • success:表示正常的 yarn.lock 文件;
  • merge:表示存在 Git Merge Conflict 且自动 merge 的 yarn.lock 文件;
  • conflict:表示存在 Git Merge Conflict 且无法自动 merge 的 yarn.lock 文件。

object 对象中存储的内容是 yarn.lock 文件真正的解析结果(其中 conflict 情况下输出空对象,见这里)。

还是以最开始的 yarn.lock 内容为例,经过 @yarnpkg/lockfile 解析之后,object 中的对象,结构如下:

{
  "ansi-styles@^3.2.0": {
    "version": "3.2.1",
    "resolved": "xxx",
    "integrity": "sha512-xxx",
    "dependencies": {
      "color-convert": "^1.9.0"
    }
  },
  "ansi-styles@^3.2.1": {
    "version": "3.2.1",
    "resolved": "xxx",
    "integrity": "sha512-xxx",
    "dependencies": {
      "color-convert": "^1.9.0"
    }
  }
}

可以看到基本上和之前 yarn.lock 文件给出的数据是一一对应的。如果将这个对象传递给 stringify 函数,会得到一个 yarn.lock 文件的字符串,可以用于更新 yarn.lock 文件的内容。其中,这里无论给的对象是 {type:"success",object:{}} 还是仅 object 字段内的对象,都是可以正确生成 yarn.lock 文件的。