yarn3 が出たことだし pnp 使ってみる
◆ デフォルトで pnp が有効だった
◆ .yarn\cache フォルダにパッケージごとの zip が配置される
◆ 実行時は yarn node index.js 形式で yarn を通す
◆ ES Modules は対応してないみたい
◆ .yarn\cache フォルダにパッケージごとの zip が配置される
◆ 実行時は yarn node index.js 形式で yarn を通す
◆ ES Modules は対応してないみたい
気づけば yarn に 3 が出ていました
2 でけっこう大きな違いがあったので 1 を使い続けて そのまま 2 を使わず 3 になってしまいました
この機会なので 3 で pnp を使ってみます
ついでに yarn を入れるのに corepack も使おうと思ったのですが corepack は Node.js 15 からデフォルトみたいなことを Readme に書いているのに 16 でも同梱されてないようでした
なので普通に yarn を入れます
yarn 2, 3 はプロジェクトフォルダの中にインストールするタイプで グローバルなコマンドは yarn 1 を使います
yarn 1 でコマンドを実行したときに yarn 2, 3 がインストールされているプロジェクトフォルダ内だと yarn 2, 3 を使ってくれます
適当にフォルダを作って移動してから yarn 3 をインストールします
インストール後にバージョンを表示すると 3 になっています
フォルダを見ると以下のファイルが追加されていました
yarn-berry.cjs の方が yarn 3 の本体のようで 1 ファイルにまとめた JavaScript ファイルです
.yarnrc.yml は yarn-berry.cjs のパスが記述されてました
node_modules を使うなら .yarnrc.yml の nodeLinker に node_modules を指定しないといけないみたいです
指定しなければデフォルトで pnp として扱われるようです
pnp としてインストールが行われると .yarn フォルダが作られたのと同じフォルダに .pnp.cjs というファイルが作られます
これが require を置き換えて pnp 形式のプロジェクトのパッケージをロードするためのモジュールのようです
node_modules フォルダはつくられず .yarn\cache 以下にパッケージごとの zip ファイルが作られます
fastify をインストールした例です
それぞれが zip なので 1 つ 1 つの小さいテキストファイルをすべて展開するのに比べて高速になりそうです
ただ node_modules に比べるとライブラリ内のコードを確認したいときに手間が増えそうです
それにデバッグ実行で node_modules 内も含めたステップ実行とかできるのでしょうか……
試してませんが この辺を考えると開発時は node_modules の方がいいのかなという気もします
pnp を有効にして実行するには yarn コマンドを通します
これは結構いろいろなところで面倒になりそうな気がします
直接 node コマンドが呼び出される前提なところが多いでしょうし
yarn コマンドが実行されるプロジェクトで振る舞いを変えるのでプロジェクト外からの実行ができません
C:\ や / にいるときに
は yarn がプロジェクト内のバージョンにならず pnp も有効になりません
カレントディレクトリがルートになるツールを通して実行していると カレントディレクトリを移動させる必要もあります
試しに単純に ES Modules に書き換えてみたところ やっぱりエラーでした
issue を探すと議論はあるものの まだ実装されてなさそうな感じです
webpack とかで cjs 化すれば動くらしいですが なんかそれは違う気がします
webpack するとプロダクション環境はビルドファイルのみで node_modules も pnp も不要ですし
プロダクション環境で yarn install したくない都合で node_modules フォルダごと git に含めたこともありますが ファイル数がすごく多くて不便も多いのでこれはありかもしれません
複数のプロジェクトで毎回同じパッケージをインストールする場合にはかなり効率的になるはずです
そういうことができないのか調べてみるとグローバルキャッシュという仕組みがありました
.yarnrc.yml の enableGlobalCache を true にすれば良いみたいです
プロジェクトごとにキャッシュを持たないので ゼロインストールにはできませんが ローカルで自分しか使わないならこっちのほうが良いかもしれません
yarn 1
yarn 3
yarn 1 はシンプルでしたが yarn 3 では yarn の設定ファイルや pnp のスクリプトも入るので プロジェクトのルートフォルダが少しごちゃごちゃしてくる欠点があります
yarn.lock のフォーマットも変わってるようでした
最初の部分を比べるとこういう感じです
yarn 1
yarn 3
最初に __metadata というブロックができていたり パッケージごとの情報も増えています
pnp を無効にして yarn 3 を使うこともできるようなので yarn 3 だけ使うことはできますが 1 で困ってないので pnp 使わないなら yarn も 1 のままで良い気がしてます
2 でけっこう大きな違いがあったので 1 を使い続けて そのまま 2 を使わず 3 になってしまいました
この機会なので 3 で pnp を使ってみます
ついでに yarn を入れるのに corepack も使おうと思ったのですが corepack は Node.js 15 からデフォルトみたいなことを Readme に書いているのに 16 でも同梱されてないようでした
なので普通に yarn を入れます
yarn3
yarn は 1 と 2 で大きな違いがありますが 3 は 2 系のままで 1 と 2 ほどの違いはないようですyarn 2, 3 はプロジェクトフォルダの中にインストールするタイプで グローバルなコマンドは yarn 1 を使います
yarn 1 でコマンドを実行したときに yarn 2, 3 がインストールされているプロジェクトフォルダ内だと yarn 2, 3 を使ってくれます
npm -g install yarn
適当にフォルダを作って移動してから yarn 3 をインストールします
yarn set version berry
インストール後にバージョンを表示すると 3 になっています
>yarn --version
3.0.0
フォルダを見ると以下のファイルが追加されていました
- .yarn\releases\yarn-berry.cjs
- .yarnrc.yml
yarn-berry.cjs の方が yarn 3 の本体のようで 1 ファイルにまとめた JavaScript ファイルです
.yarnrc.yml は yarn-berry.cjs のパスが記述されてました
yarnPath: ".yarn/releases/yarn-berry.cjs"
pnp
pnp はオプトインと見た気がするのですが yarn add でインストールするとデフォルトで pnp としてインストールされましたnode_modules を使うなら .yarnrc.yml の nodeLinker に node_modules を指定しないといけないみたいです
指定しなければデフォルトで pnp として扱われるようです
pnp としてインストールが行われると .yarn フォルダが作られたのと同じフォルダに .pnp.cjs というファイルが作られます
これが require を置き換えて pnp 形式のプロジェクトのパッケージをロードするためのモジュールのようです
node_modules フォルダはつくられず .yarn\cache 以下にパッケージごとの zip ファイルが作られます
fastify をインストールした例です
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 8/8/2021 1:55 PM 20 .gitignore
-a---- 8/8/2021 1:55 PM 7864 @fastify-ajv-compiler-npm-1.1.0-8f156239a8-b8a2522ead.zip
-a---- 8/8/2021 1:55 PM 2059 abstract-logging-npm-2.0.1-b805b8edfa-6967d15e5a.zip
-a---- 8/8/2021 1:55 PM 245015 ajv-npm-6.12.6-4b5105e2b2-874972efe5.zip
-a---- 8/8/2021 1:55 PM 5493 archy-npm-1.0.0-7db8bfdc3b-504ae7af65.zip
-a---- 8/8/2021 1:55 PM 4031 atomic-sleep-npm-1.0.0-17d8a762a3-b95275afb2.zip
-a---- 8/8/2021 1:55 PM 37812 avvio-npm-7.2.2-59206ab649-ece793dd14.zip
-a---- 8/8/2021 1:55 PM 7627 cookie-npm-0.4.1-cc5e2ebb42-bd7c47f5d9.zip
-a---- 8/8/2021 1:55 PM 15326 debug-npm-4.3.2-f0148b6afe-820ea160e2.zip
-a---- 8/8/2021 1:55 PM 11921 deepmerge-npm-4.2.2-112165ced2-a8c43a1ed8.zip
-a---- 8/8/2021 1:55 PM 5312 fast-decode-uri-component-npm-1.0.1-578ba9fecf-427a48fe09.zip
-a---- 8/8/2021 1:55 PM 7393 fast-deep-equal-npm-3.1.3-790edcfcf5-e21a9d8d84.zip
-a---- 8/8/2021 1:55 PM 11434 fast-json-stable-stringify-npm-2.1.0-02e8905fda-b191531e36.zip
-a---- 8/8/2021 1:55 PM 68432 fast-json-stringify-npm-2.7.8-d29e90f9f0-78699673bf.zip
-a---- 8/8/2021 1:55 PM 20891 fast-redact-npm-3.0.1-bd84a09cb8-89de97ea5c.zip
-a---- 8/8/2021 1:55 PM 10877 fast-safe-stringify-npm-2.0.8-33b49729ad-be8a07f342.zip
-a---- 8/8/2021 1:55 PM 5676 fastify-error-npm-0.3.1-9c1ef70a86-fd6a0f6f87.zip
-a---- 8/8/2021 1:55 PM 362172 fastify-npm-3.20.1-2d1c005b89-e6742daf0f.zip
-a---- 8/8/2021 1:55 PM 6139 fastify-warning-npm-0.2.0-f9c53563fc-c19ebccf54.zip
-a---- 8/8/2021 1:55 PM 11752 fastq-npm-1.11.1-ed420613b5-3877a63bee.zip
-a---- 8/8/2021 1:55 PM 60680 find-my-way-npm-4.3.3-71a92171a0-c5f212d2d2.zip
...
(略)
それぞれが zip なので 1 つ 1 つの小さいテキストファイルをすべて展開するのに比べて高速になりそうです
ただ node_modules に比べるとライブラリ内のコードを確認したいときに手間が増えそうです
それにデバッグ実行で node_modules 内も含めたステップ実行とかできるのでしょうか……
試してませんが この辺を考えると開発時は node_modules の方がいいのかなという気もします
実行
普通に実行すると require がデフォルトのままなので node_modules を探してエラーになりますpnp を有効にして実行するには yarn コマンドを通します
yarn node index.js
これは結構いろいろなところで面倒になりそうな気がします
直接 node コマンドが呼び出される前提なところが多いでしょうし
yarn コマンドが実行されるプロジェクトで振る舞いを変えるのでプロジェクト外からの実行ができません
C:\ や / にいるときに
yarn node path/to/project/index.js
は yarn がプロジェクト内のバージョンにならず pnp も有効になりません
カレントディレクトリがルートになるツールを通して実行していると カレントディレクトリを移動させる必要もあります
ES Modules
require を置き換えるので cjs なら問題なさそうですが ES Modules でのインポートで問題が出そうです試しに単純に ES Modules に書き換えてみたところ やっぱりエラーでした
issue を探すと議論はあるものの まだ実装されてなさそうな感じです
webpack とかで cjs 化すれば動くらしいですが なんかそれは違う気がします
webpack するとプロダクション環境はビルドファイルのみで node_modules も pnp も不要ですし
ゼロインストール
cache フォルダ内の zip をリポジトリに含めることでゼロインストールにもできるようですプロダクション環境で yarn install したくない都合で node_modules フォルダごと git に含めたこともありますが ファイル数がすごく多くて不便も多いのでこれはありかもしれません
グローバルキャッシュ
この仕組みを見てると プロジェクトごとじゃなくグローバルにパッケージの zip を保持して すべてのプロジェクトがそれを見に行けば無駄なコピーやストレージ使用量が減りそうに思います複数のプロジェクトで毎回同じパッケージをインストールする場合にはかなり効率的になるはずです
そういうことができないのか調べてみるとグローバルキャッシュという仕組みがありました
.yarnrc.yml の enableGlobalCache を true にすれば良いみたいです
プロジェクトごとにキャッシュを持たないので ゼロインストールにはできませんが ローカルで自分しか使わないならこっちのほうが良いかもしれません
固有ファイル比較
yarn1 と yarn3 でプロジェクトフォルダに作られるファイル・フォルダの比較ですyarn 1
node_modules\
yarn.lock
yarn 3
.pnp.cjs
.yarn\
.yarnrc.yml
yarn.lock
yarn 1 はシンプルでしたが yarn 3 では yarn の設定ファイルや pnp のスクリプトも入るので プロジェクトのルートフォルダが少しごちゃごちゃしてくる欠点があります
yarn.lock のフォーマットも変わってるようでした
最初の部分を比べるとこういう感じです
yarn 1
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@fastify/ajv-compiler@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@fastify/ajv-compiler/-/ajv-compiler-1.1.0.tgz#5ce80b1fc8bebffc8c5ba428d5e392d0f9ed10a1"
integrity sha512-gvCOUNpXsWrIQ3A4aXCLIdblL0tDq42BG/2Xw7oxbil9h11uow10ztS2GuFazNBfjbrsZ5nl+nPl5jDSjj5TSg==
dependencies:
ajv "^6.12.6"
yarn 3
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!
__metadata:
version: 4
cacheKey: 8
"@fastify/ajv-compiler@npm:^1.0.0":
version: 1.1.0
resolution: "@fastify/ajv-compiler@npm:1.1.0"
dependencies:
ajv: ^6.12.6
checksum: b8a2522ead00a01ab7ff2921f00aa8e4aeb943949191ce2a617c88e4679db1358a70e4099791828a397a50e5d6f6bd75184ad0ac75a12dffeb9df4c089986a32
languageName: node
linkType: hard
最初に __metadata というブロックができていたり パッケージごとの情報も増えています
まだいいかな
思ってた以上にデメリットもありましたし もっと一般的に使われるようになって ESModules 対応もされたころにまた考えるでいいかなと思いましたpnp を無効にして yarn 3 を使うこともできるようなので yarn 3 だけ使うことはできますが 1 で困ってないので pnp 使わないなら yarn も 1 のままで良い気がしてます