Open14

Yarn 3.0/3.1のhardlinks-local/hardlinks-globalを試す

ピン留めされたアイテム
suinsuin

ハードリンクを試してみての感想

  • 容量削減効果○
  • グローバルの.yarnrc.ymlにnmMode: hardlinks-globalを設定しておくといいと思った。
  • go getの容量の使い方と同じような感じになるので、この方式に違和感はあまり感じられない。(Go言語のgo getは中央にストアがある。ハードリンクはしないが)
  • pnpmのシンボリックリンクで解決するのと比べて、ハードリンクのほうがインストールされるNPMパッケージたちにとってはただのファイル・普通のnode_modules構成として見えるので、パッケージの実装によってはシンボリックリンクが解決できないとか、標準のnode_modules構成と異なるとかで、プラグインがロードできないといったトラブルに巻き込まれずに済みそう。
  • パーティションをまたぐとhardlinks-globalはhardlinks-localにダウングレードされるので注意。
    • パーティションごとに.yarnrc.ymlを作り、そこでglobalFolderを設定するとダウングレードは発生しない。
  • pnpmより良さそう
suinsuin

Yarn 3.0

https://dev.to/arcanis/yarn-3-0-performances-esbuild-better-patches-e07

breaking changes

  • Node 10がサポートされない
    • 最新のLTSはNode 16なので問題なさそう

パフォーマンス改善

  • インストールは場合によってはpnpmより速い。
    • これはすごい
  • プロジェクトサイズに比例して遅くなる問題が解決した。
  • 試験的なnmMode設定の追加
  • これにhardlinks-localhardlinks-globalが指定できる。
  • hardlinks-local: 同パッケージ同バージョンがプロジェクト内で複数見つかった場合、ハードリンクになる。
  • hardlinks-global: バージョンが違ってもファイル単位で内容が同じなら、グローバルのcontent-addressable directoryに向けてハードリンクが張られる。もし、ファイルが編集されたりしてキャッシュと合わなくなった場合、yarnはそれをインストール時に修正する。pnpmっぽい仕組み。

所感

従来のnpm installやyarn addはひとつのマシンにパッケージのコピーがいくつもできるのは、容量逼迫につながっていたのでこれは良さそうな機能。

シェルの改善

  • "scripts" (npm script)の実行に、自前のインタプリターを使うようになった
  • そのおかげで、WindowsとPOSIXで同じシンタックスが使えるようになった
build-js & build-css &    # Background jobs
ls 2>/dev/null            # File descriptor redirections

esbuildのサポート

新しいプラグインAPI

suinsuin

Yarn 3.1

https://dev.to/arcanis/yarn-31-corepack-esm-pnpm-optional-packages--3hak

Corepackへの統合

  • Corepackを有効にしておくとyarn init -2がちゃんと実行されるようになった
    • -2って何?
package.json
{
  "packageManager": "yarn@3.1.0"
}

ESMサポート

  • PnPでESMがサポートされた
  • ただし安定版ではない

新しいインストールモード: pnpm

  • シンボリックリンクを使ったpnpmスタイルのnode_modulesディレクトリ構成になる
.yarnrc.yml
nodeLinker: pnpm

Conditional Package

  • optionalDependenciesoscpuが定義されている場合、yarnはそれにマッチする環境でないとインストールしなくなった。
  • 環境が何をサポートするかはsupportedArchitecturesで手動で宣言する必要あり
supportedArchitectures:
  os: [linux, darwin]
  cpu: [x64, arm64]

Smart Changeset Filters

  • yarn workspaces foreachyarn workspaces list--sinceオプションが追加された
  • このオプションがつくと、mainブランチから変更があったパッケージに対象が絞られる
yarn workspaces foreach --since run eslint .
yarn workspaces list --since

新しいワークスペース構文: workspace:^

  • ワークスペース構文にworkspace:^workspace:~が使えるようになった。
suinsuin

所感

pnpmがベンチマークに入ってるかんじがした。ハードリンクやpnpmスタイルのnode_modules、workspace:^などはpnpmの特徴を輸入している感がある。

suinsuin

復習ハードリンク

ハードリンクとシンボリックリンクの違い


souce: What is the difference between a symbolic link and a hard link? | by Miladi AhmedOmar | Medium

  • ハードリンク
    • ひとつのファイル実態(inode)に複数のファイル名を付けられる
    • シンボリックリンクと違い、まるでファイル実態のように見える
    • ディレクトリのハードリンクは作れない
    • 異なるパーティションを超えてハードリンクは作れない
  • シンボリックリンク
    • ファイル名に対する別ファイル名が付けられる
    • シンボリックリンクファイルにはリンク先のファイル名とパスが格納されるため、ファイル実態のようには見えない
    • ディレクトリにもシンボリックリンクは作れる

どちらもファイル容量節約には効果的な手法

ハードリンクの作り方

ln リンク先ファイル名 ハードリンクファイル名
echo test > file
ln file file_copy
cat file_copy
#=> test
echo test2 > file_copy
cat file
#=> test2

ハードリンクか調べる方法

$ ls -li
total 16
28282039 -rw-r--r--  2 suin  wheel  6 Feb  6 04:12 file
28282039 -rw-r--r--  2 suin  wheel  6 Feb  6 04:12 file_copy
# ^inode id          ^2以上ならハードリンクがある

ハードリンクの探し方

$ find . -type f -links +1
./file
./file_copy

ハードリンク元の探し方

$ find . -samefile file
./file
./file_copy

ハードリンクだとディスク容量は増えない

同じ内容のファイルを複数作った場合

echo 12345678 > packageA
echo 12345678 > packageA_different_place
du -s .
#=> 16

ディスク容量が16消費される。

同じ内容のファイルにハードリンクを使った場合。

echo 12345678 > packageA
ln packageA packageA_different_place
du -s .
#=> 8

ディスク容量が8しか消費されない。

suinsuin

Yarn 3.1をインストールする

せっかくなのでCorePackを使う。

fnm install 16.13.2
fnm use 16.13.2
corepack enable
which yarn
#=> /private/var/tmp/fnm_multishells/74410_1643938574626/bin/yarn
ls -l /private/var/tmp/fnm_multishells/74410_1643938574626/bin/yarn
#=> lrwxr-xr-x  1 suin  staff  41 Feb  6 04:26 /private/var/tmp/fnm_multishells/74410_1643938574626/bin/yarn -> ../lib/node_modules/corepack/dist/yarn.js

yarnがCorePackを指すようになった。

このままだとyarn 1系。

yarn --version
#=> 1.22.15

package.jsonを作って3.1を指定する。

echo '{"packageManager": "yarn@3.1.0"}' > package.json
yarn --version
#=> 3.1.0

3.1.0になった。

suinsuin

nodeLinker node-modules

yarn2以降はデフォルトでnode_modulesを作らないPnP方式になるので、旧来のでnode_modules方式にするには、nodeLinkerを設定する必要がある。

.yarnrc.yml
nodeLinker: node-modules
yarn add @suin/is-object @suin/event-data
yarn info
├─ @suin/event-data@npm:1.0.0
│  ├─ Version: 1.0.0
│  │
│  └─ Dependencies
│     └─ @suin/is-object@npm:^1.1.3 → npm:1.1.3
│
├─ @suin/is-object@npm:1.1.3
│  └─ Version: 1.1.3
│
└─ root-workspace-0b6124@workspace:.
   ├─ Version: 0.0.0
   │
   └─ Dependencies
      ├─ @suin/event-data@npm:^1.0.0 → npm:1.0.0
      └─ @suin/is-object@npm:^1.1.3 → npm:1.1.3
tree -NC -a
.
├── .yarn
│   ├── cache
│   │   ├── .gitignore
│   │   ├── @suin-event-data-npm-1.0.0-6f2a1de360-3489bc96f7.zip
│   │   └── @suin-is-object-npm-1.1.3-e5a269333e-3fad929ce5.zip
│   └── install-state.gz
├── .yarnrc.yml
├── node_modules
│   ├── .yarn-state.yml
│   └── @suin
│       ├── event-data
│       │   ├── CHANGELOG.md
│       │   ├── LICENSE
│       │   ├── README.md
│       │   ├── index.d.ts
│       │   ├── index.d.ts.map
│       │   ├── index.js
│       │   ├── index.ts
│       │   └── package.json
│       └── is-object
│           ├── CHANGELOG.md
│           ├── LICENSE
│           ├── index.d.ts
│           ├── index.d.ts.map
│           ├── index.js
│           ├── index.ts
│           └── package.json
├── package.json
└── yarn.lock

6 directories, 23 files
suinsuin

nmHoistingLimit: dependecies

.yarnrc.yml
nodeLinker: node-modules
nmHoistingLimits: dependencies
tree -NC -a
.
├── .yarn
│   ├── cache
│   │   ├── .gitignore
│   │   ├── @suin-event-data-npm-1.0.0-6f2a1de360-3489bc96f7.zip
│   │   └── @suin-is-object-npm-1.1.3-e5a269333e-3fad929ce5.zip
│   └── install-state.gz
├── .yarnrc.yml
├── node_modules
│   ├── .yarn-state.yml
│   └── @suin
│       ├── event-data
│       │   ├── CHANGELOG.md
│       │   ├── LICENSE
│       │   ├── README.md
│       │   ├── index.d.ts
│       │   ├── index.d.ts.map
│       │   ├── index.js
│       │   ├── index.ts
│       │   ├── node_modules
│       │   │   └── @suin
│       │   │       └── is-object
│       │   │           ├── CHANGELOG.md
│       │   │           ├── LICENSE
│       │   │           ├── index.d.ts
│       │   │           ├── index.d.ts.map
│       │   │           ├── index.js
│       │   │           ├── index.ts
│       │   │           └── package.json
│       │   └── package.json
│       └── is-object
│           ├── CHANGELOG.md
│           ├── LICENSE
│           ├── index.d.ts
│           ├── index.d.ts.map
│           ├── index.js
│           ├── index.ts
│           └── package.json
├── package.json
└── yarn.lock

9 directories, 30 files

@suin/is-objectが@suin/event-dataにぶら下がる形のツリー構造になった。

du -sh .
128K	.
suinsuin
yarnrc.yml
nodeLinker: node-modules
nmHoistingLimits: dependencies
nmMode: hardlinks-local
tree -NC -a
.
├── .yarn
│   ├── cache
│   │   ├── .gitignore
│   │   ├── @suin-event-data-npm-1.0.0-6f2a1de360-3489bc96f7.zip
│   │   └── @suin-is-object-npm-1.1.3-e5a269333e-3fad929ce5.zip
│   └── install-state.gz
├── .yarnrc.yml
├── node_modules
│   ├── .yarn-state.yml
│   └── @suin
│       ├── event-data
│       │   ├── CHANGELOG.md
│       │   ├── LICENSE
│       │   ├── README.md
│       │   ├── index.d.ts
│       │   ├── index.d.ts.map
│       │   ├── index.js
│       │   ├── index.ts
│       │   ├── node_modules
│       │   │   └── @suin
│       │   │       └── is-object
│       │   │           ├── CHANGELOG.md
│       │   │           ├── LICENSE
│       │   │           ├── index.d.ts
│       │   │           ├── index.d.ts.map
│       │   │           ├── index.js
│       │   │           ├── index.ts
│       │   │           └── package.json
│       │   └── package.json
│       └── is-object
│           ├── CHANGELOG.md
│           ├── LICENSE
│           ├── index.d.ts
│           ├── index.d.ts.map
│           ├── index.js
│           ├── index.ts
│           └── package.json
├── package.json
└── yarn.lock

ツリー構造は上と同じ。

du -sh .
100K	.

ディスク容量は128K→100Kに減った。

ハードリンクされたファイル:

find . -type f -links +1
./node_modules/@suin/event-data/node_modules/@suin/is-object/LICENSE
./node_modules/@suin/event-data/node_modules/@suin/is-object/CHANGELOG.md
./node_modules/@suin/event-data/node_modules/@suin/is-object/index.js
./node_modules/@suin/event-data/node_modules/@suin/is-object/package.json
./node_modules/@suin/event-data/node_modules/@suin/is-object/index.ts
./node_modules/@suin/event-data/node_modules/@suin/is-object/index.d.ts
./node_modules/@suin/event-data/node_modules/@suin/is-object/index.d.ts.map
./node_modules/@suin/is-object/LICENSE
./node_modules/@suin/is-object/CHANGELOG.md
./node_modules/@suin/is-object/index.js
./node_modules/@suin/is-object/package.json
./node_modules/@suin/is-object/index.ts
./node_modules/@suin/is-object/index.d.ts
./node_modules/@suin/is-object/index.d.ts.map
suinsuin

2つのプロジェクトがあり、

.
├── project1
│   ├── .yarnrc.yml
│   └── package.json
└── project2
    ├── .yarnrc.yml
    └── package.json

どちらの.yarnrc.ymlの内容も

.yarnrc.yml
nodeLinker: node-modules
nmMode: hardlinks-local

のとき、ツリー構造はつぎのようになる:

tree -NCa
.
├── project1
│   ├── .yarn
│   │   ├── cache
│   │   │   ├── .gitignore
│   │   │   └── @suin-is-object-npm-1.1.3-e5a269333e-3fad929ce5.zip
│   │   └── install-state.gz
│   ├── .yarnrc.yml
│   ├── node_modules
│   │   ├── .yarn-state.yml
│   │   └── @suin
│   │       └── is-object
│   │           ├── CHANGELOG.md
│   │           ├── LICENSE
│   │           ├── index.d.ts
│   │           ├── index.d.ts.map
│   │           ├── index.js
│   │           ├── index.ts
│   │           └── package.json
│   ├── package.json
│   └── yarn.lock
└── project2
    ├── .yarn
    │   ├── cache
    │   │   ├── .gitignore
    │   │   └── @suin-is-object-npm-1.1.3-e5a269333e-3fad929ce5.zip
    │   └── install-state.gz
    ├── .yarnrc.yml
    ├── node_modules
    │   ├── .yarn-state.yml
    │   └── @suin
    │       └── is-object
    │           ├── CHANGELOG.md
    │           ├── LICENSE
    │           ├── index.d.ts
    │           ├── index.d.ts.map
    │           ├── index.js
    │           ├── index.ts
    │           └── package.json
    ├── package.json
    └── yarn.lock

12 directories, 28 files

この2つのプロジェクトをまたいでのハードリンクは作られない。

この2つのプロジェクトの容量合計は120K。

suinsuin

2つのプロジェクトがあり、

.
├── project1
│   ├── .yarnrc.yml
│   └── package.json
└── project2
    ├── .yarnrc.yml
    └── package.json

どちらの.yarnrc.ymlの内容も

.yarnrc.yml
nodeLinker: node-modules
nmMode: hardlinks-global

のとき、ツリー構造はつぎのようになり、hardlinks-localと変わらない:

tree -NCa
.
├── project1
│   ├── .yarn
│   │   ├── cache
│   │   │   ├── .gitignore
│   │   │   └── @suin-is-object-npm-1.1.3-e5a269333e-3fad929ce5.zip
│   │   └── install-state.gz
│   ├── .yarnrc.yml
│   ├── node_modules
│   │   ├── .yarn-state.yml
│   │   └── @suin
│   │       └── is-object
│   │           ├── CHANGELOG.md
│   │           ├── LICENSE
│   │           ├── index.d.ts
│   │           ├── index.d.ts.map
│   │           ├── index.js
│   │           ├── index.ts
│   │           └── package.json
│   ├── package.json
│   └── yarn.lock
└── project2
    ├── .yarn
    │   ├── cache
    │   │   ├── .gitignore
    │   │   └── @suin-is-object-npm-1.1.3-e5a269333e-3fad929ce5.zip
    │   └── install-state.gz
    ├── .yarnrc.yml
    ├── node_modules
    │   ├── .yarn-state.yml
    │   └── @suin
    │       └── is-object
    │           ├── CHANGELOG.md
    │           ├── LICENSE
    │           ├── index.d.ts
    │           ├── index.d.ts.map
    │           ├── index.js
    │           ├── index.ts
    │           └── package.json
    ├── package.json
    └── yarn.lock

12 directories, 28 files

この2つのプロジェクトをまたいでのハードリンクが作られる:

find . -type f -links +1
./project1/node_modules/@suin/is-object/LICENSE
./project1/node_modules/@suin/is-object/CHANGELOG.md
./project1/node_modules/@suin/is-object/index.js
./project1/node_modules/@suin/is-object/package.json
./project1/node_modules/@suin/is-object/index.ts
./project1/node_modules/@suin/is-object/index.d.ts
./project1/node_modules/@suin/is-object/index.d.ts.map
./project2/node_modules/@suin/is-object/LICENSE
./project2/node_modules/@suin/is-object/CHANGELOG.md
./project2/node_modules/@suin/is-object/index.js
./project2/node_modules/@suin/is-object/package.json
./project2/node_modules/@suin/is-object/index.ts
./project2/node_modules/@suin/is-object/index.d.ts
./project2/node_modules/@suin/is-object/index.d.ts.map

この2つのプロジェクトの容量合計は92K。hardlinks-localと比べて28K減。

suinsuin

$globalFolder/storeにある。

$ yarn config get globalFolder
/Users/suin/.local/share/yarn/berry
$ find $(yarn config get globalFolder) -samefile ./project1/node_modules/@suin/is-object/index.js
/Users/suin/.local/share/yarn/berry/store/v1/7a/a09f014c9e9622038c776b11ca97f01ba7d386.dat
find . -type f -links +1 \
        -exec echo {} \; \
        -exec echo -n '  -> ' \; \
        -exec find $(yarn config get globalFolder) -type f -samefile {} \;
./project1/node_modules/@suin/is-object/LICENSE
  -> /Users/suin/.local/share/yarn/berry/store/v1/38/6f02339841252a8dcbc06bd5c071e078871832.dat
./project1/node_modules/@suin/is-object/CHANGELOG.md
  -> /Users/suin/.local/share/yarn/berry/store/v1/39/0ac6fca18d2f50387998b9c210e9b881cc33c5.dat
./project1/node_modules/@suin/is-object/index.js
  -> /Users/suin/.local/share/yarn/berry/store/v1/7a/a09f014c9e9622038c776b11ca97f01ba7d386.dat
./project1/node_modules/@suin/is-object/package.json
  -> /Users/suin/.local/share/yarn/berry/store/v1/80/2f583fe66d3cb063caf472179fcf30314bb566.dat
./project1/node_modules/@suin/is-object/index.ts
  -> /Users/suin/.local/share/yarn/berry/store/v1/08/e8e2c175a6d7e7688cacea2555cec2896c80d6.dat
./project1/node_modules/@suin/is-object/index.d.ts
  -> /Users/suin/.local/share/yarn/berry/store/v1/56/fac7b580bc6a08c72e80f2468a2ed994b9c206.dat
./project1/node_modules/@suin/is-object/index.d.ts.map
  -> /Users/suin/.local/share/yarn/berry/store/v1/7c/c83ccb615bbf4b99bff7110cad1a9cc5b9aa89.dat
./project2/node_modules/@suin/is-object/LICENSE
  -> /Users/suin/.local/share/yarn/berry/store/v1/38/6f02339841252a8dcbc06bd5c071e078871832.dat
./project2/node_modules/@suin/is-object/CHANGELOG.md
  -> /Users/suin/.local/share/yarn/berry/store/v1/39/0ac6fca18d2f50387998b9c210e9b881cc33c5.dat
./project2/node_modules/@suin/is-object/index.js
  -> /Users/suin/.local/share/yarn/berry/store/v1/7a/a09f014c9e9622038c776b11ca97f01ba7d386.dat
./project2/node_modules/@suin/is-object/package.json
  -> /Users/suin/.local/share/yarn/berry/store/v1/80/2f583fe66d3cb063caf472179fcf30314bb566.dat
./project2/node_modules/@suin/is-object/index.ts
  -> /Users/suin/.local/share/yarn/berry/store/v1/08/e8e2c175a6d7e7688cacea2555cec2896c80d6.dat
./project2/node_modules/@suin/is-object/index.d.ts
  -> /Users/suin/.local/share/yarn/berry/store/v1/56/fac7b580bc6a08c72e80f2468a2ed994b9c206.dat
./project2/node_modules/@suin/is-object/index.d.ts.map
  -> /Users/suin/.local/share/yarn/berry/store/v1/7c/c83ccb615bbf4b99bff7110cad1a9cc5b9aa89.dat
suinsuin

基本的にやってはいけないことだけど、パッケージを直接変更したらどうなるのか試す。

まず、インストールされたパッケージに手を加える。

project1/node_modules/@suin/is-object/index.js
+// へんこう
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });

これをやるとproject2のほうも変更された状態になる。(ハードリンクなので)

次に、yarn installしてみる。

yarn install
➤ YN0000: ┌ Resolution step
➤ YN0000: └ Completed
➤ YN0000: ┌ Fetch step
➤ YN0000: └ Completed
➤ YN0000: ┌ Link step
➤ YN0000: └ Completed
➤ YN0000: Done in 0s 43ms

特にindex.jsに変化は見られない。

project1のnode_modulesを削除してから

rm -rf node_modules/

yarn installすると、index.jsに手を加えた部分がもとに戻った。

project1/node_modules/@suin/is-object/index.js
-// へんこう
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
 exports.isObject = void 0;
suinsuin

ハードリンクはパーティションを超えて使えないはずなので、異なるAPFSボリュームでどうなるか試す。

yarnのstoreがあるのがAPFS Volume Macintosh HD - Dataで、yarn installするボリュームがAPFS Volume vのとき。

diskutil list

/dev/disk1 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   1:                APFS Volume Macintosh HD            11.2 GB    disk1s1
   2:                APFS Volume Macintosh HD - Data     938.1 GB   disk1s2
   6:                APFS Volume v                       22.9 GB    disk1s6
df
Filesystem    512-blocks       Used Available Capacity     iused      ifree %iused  Mounted on
/dev/disk1s1  1953595632   21918168  44754432    33%      488287 9767489873    0%   /
devfs                474        474         0   100%         820          0  100%   /dev
/dev/disk1s2  1953595632 1832279984  44754432    98%     2247447 9765730713    0%   /System/Volumes/Data
/dev/disk1s6  1953595632   44652056  44754432    50%     1161997 9766816163    0%   /Volumes/v

2つプロジェクトがあり、まだnode_modulesが無い状態。

/Volumes/v/suinplayground/yarn-hardlink/
├── proj1
│   ├── .yarnrc.yml
│   └── package.json
└── proj2
    ├── .yarnrc.yml
    └── package.json

2 directories, 4 files

どちらの.yarnrc.ymlも:

nodeLinker: node-modules
nmMode: hardlinks-global

proj1でyarn addしてみる。

cd proj1
yarn add @suin/is-object
➤ YN0000: ┌ Resolution step
➤ YN0000: └ Completed
➤ YN0000: ┌ Fetch step
➤ YN0013: │ @suin/is-object@npm:1.1.3 can't be found in the cache and will be fetched from the remote registr
➤ YN0000: └ Completed
➤ YN0000: ┌ Link step
➤ YN0074: │ 'nmMode' has been downgraded to 'hardlinks-local' due to global cache and install folder being on different devices
➤ YN0000: └ Completed
➤ YN0000: Done with warnings in 0s 75ms

警告が出た。

'nmMode' has been downgraded to 'hardlinks-local' due to global cache and install folder being on different devices

グローバルキャッシュとインストールフォルダが異なるデバイス上にあるため、「nmMode」は「hardlinks-local」にダウングレードされました

ということらしい。賢い。

続いてproj2でもyarn addしたが、同じ警告が出た。

パーティションごとにグローバルフォルダを設定するとどうなるか

/Volumes/v/.yarnrc.ymlを作る。

/Volumes/v/.yarnrc.yml
globalFolder: ./yarn-global

続いて、/Volumes/v/suinplayground/yarn-hardlink/proj1でもう一度yarn install

cd /Volumes/v/suinplayground/yarn-hardlink/proj1
rm -rf node_modules/
yarn install
➤ YN0000: ┌ Resolution step
➤ YN0000: └ Completed
➤ YN0000: ┌ Fetch step
➤ YN0000: └ Completed
➤ YN0000: ┌ Link step
➤ YN0000: └ Completed
➤ YN0000: Done in 0s 106ms

今度はhardlinks-localへのダウングレードは発生しなかった。

ハードリンクはパーティションのストアに向けて張られていた。

./node_modules/@suin/is-object/index.js
  -> /Volumes/v/yarn-global/store/v1/7a/a09f014c9e9622038c776b11ca97f01ba7d386.dat
./node_modules/@suin/is-object/LICENSE
  -> /Volumes/v/yarn-global/store/v1/38/6f02339841252a8dcbc06bd5c071e078871832.dat
./node_modules/@suin/is-object/package.json
  -> /Volumes/v/yarn-global/store/v1/80/2f583fe66d3cb063caf472179fcf30314bb566.dat
./node_modules/@suin/is-object/index.ts
  -> /Volumes/v/yarn-global/store/v1/08/e8e2c175a6d7e7688cacea2555cec2896c80d6.dat
./node_modules/@suin/is-object/index.d.ts
  -> /Volumes/v/yarn-global/store/v1/56/fac7b580bc6a08c72e80f2468a2ed994b9c206.dat
./node_modules/@suin/is-object/CHANGELOG.md
  -> /Volumes/v/yarn-global/store/v1/39/0ac6fca18d2f50387998b9c210e9b881cc33c5.dat
./node_modules/@suin/is-object/index.d.ts.map
  -> /Volumes/v/yarn-global/store/v1/7c/c83ccb615bbf4b99bff7110cad1a9cc5b9aa89.dat