Yarn 3.0/3.1のhardlinks-local/hardlinks-globalを試す
ハードリンクを試してみての感想
- 容量削減効果○
- グローバルの.yarnrc.ymlにnmMode: hardlinks-globalを設定しておくといいと思った。
- go getの容量の使い方と同じような感じになるので、この方式に違和感はあまり感じられない。(Go言語のgo getは中央にストアがある。ハードリンクはしないが)
- pnpmのシンボリックリンクで解決するのと比べて、ハードリンクのほうがインストールされるNPMパッケージたちにとってはただのファイル・普通のnode_modules構成として見えるので、パッケージの実装によってはシンボリックリンクが解決できないとか、標準のnode_modules構成と異なるとかで、プラグインがロードできないといったトラブルに巻き込まれずに済みそう。
- パーティションをまたぐとhardlinks-globalはhardlinks-localにダウングレードされるので注意。
- パーティションごとに.yarnrc.ymlを作り、そこでglobalFolderを設定するとダウングレードは発生しない。
- pnpmより良さそう
Yarn 3.0
breaking changes
- Node 10がサポートされない
- 最新のLTSはNode 16なので問題なさそう
パフォーマンス改善
- インストールは場合によってはpnpmより速い。
- これはすごい
- プロジェクトサイズに比例して遅くなる問題が解決した。
hardlinks-local
とhardlinks-global
新しいnode_modulesリンカー- 試験的な
nmMode
設定の追加 - これに
hardlinks-local
とhardlinks-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
Yarn 3.1
Corepackへの統合
- Corepackを有効にしておくと
yarn init -2
がちゃんと実行されるようになった-
-2
って何?
-
{
"packageManager": "yarn@3.1.0"
}
ESMサポート
- PnPでESMがサポートされた
- ただし安定版ではない
pnpm
新しいインストールモード: - シンボリックリンクを使ったpnpmスタイルのnode_modulesディレクトリ構成になる
nodeLinker: pnpm
Conditional Package
-
optionalDependencies
にos
やcpu
が定義されている場合、yarnはそれにマッチする環境でないとインストールしなくなった。 - 環境が何をサポートするかは
supportedArchitectures
で手動で宣言する必要あり
supportedArchitectures:
os: [linux, darwin]
cpu: [x64, arm64]
Smart Changeset Filters
-
yarn workspaces foreach
とyarn workspaces list
に--since
オプションが追加された - このオプションがつくと、mainブランチから変更があったパッケージに対象が絞られる
yarn workspaces foreach --since run eslint .
yarn workspaces list --since
workspace:^
新しいワークスペース構文: - ワークスペース構文に
workspace:^
とworkspace:~
が使えるようになった。
所感
pnpmがベンチマークに入ってるかんじがした。ハードリンクやpnpmスタイルのnode_modules、workspace:^
などはpnpmの特徴を輸入している感がある。
復習ハードリンク
ハードリンクとシンボリックリンクの違い
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しか消費されない。
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になった。
nodeLinker node-modules
yarn2以降はデフォルトでnode_modulesを作らないPnP方式になるので、旧来のでnode_modules方式にするには、nodeLinkerを設定する必要がある。
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
nmHoistingLimit: dependecies
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 .
nmMode: hardlinks-local
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
nmMode: hardlinks-localと2つのプロジェクト
2つのプロジェクトがあり、
.
├── project1
│ ├── .yarnrc.yml
│ └── package.json
└── project2
├── .yarnrc.yml
└── package.json
どちらの.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。
nmMode: hardlinks-globalと2つのプロジェクト
2つのプロジェクトがあり、
.
├── project1
│ ├── .yarnrc.yml
│ └── package.json
└── project2
├── .yarnrc.yml
└── package.json
どちらの.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減。
hardlinks-globalのグローバルのcontent-addressable directoryはどこにあるか?
$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
hardlinks-globalでパッケージを変更した場合
基本的にやってはいけないことだけど、パッケージを直接変更したらどうなるのか試す。
まず、インストールされたパッケージに手を加える。
+// へんこう
"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に手を加えた部分がもとに戻った。
-// へんこう
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isObject = void 0;
hardlinks-globalでapfsボリュームをまたいだらどうなるか?
ハードリンクはパーティションを超えて使えないはずなので、異なる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を作る。
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