paint-brush
PNPM と YARN が必要ない理由by@bormando

PNPM と YARN が必要ない理由

Dmitrii Bormotov9m2024/07/23
Read on Terminal Reader

npm は、**Node.js** エコシステムのデフォルトのパッケージ マネージャーです。インストール パッケージに付属しているため、基本的には、**Node.js** をマシンにインストールするとすぐに使用できます (または、**Node.js** をセットアップした **CI** プロバイダーにインストールすると使用できます)。安定しており、速度は他のパッケージ マネージャーに匹敵します。
featured image - PNPM と YARN が必要ない理由
Dmitrii Bormotov HackerNoon profile picture
0-item

こんにちは、みんな!


さまざまなパッケージ マネージャーを使用しているNode.js プロジェクトを見たことがあると思います。たとえば、



私自身もそれを見てきましたし、上記のすべてに取り組んできましたが、常に疑問がありました。人々やチームがnpmではなくyarnpnpmを使用する理由は何でしょうか? メリットは何でしょうか? デメリットはあるのでしょうか?


さて…調べてみましょう!

パフォーマンス比較ルール

npmyarn、 pnpmを「速度」の観点から比較してみることにしました...


以下に 3 つの対策が表示されます。


  1. キャッシュなしでロック ファイルを生成します。


  2. キャッシュなしで既存のロック ファイルから依存関係をインストールします。


  3. グローバル キャッシュを使用して既存のロック ファイルから依存関係をインストールします。


キャッシュには 2 つの種類があります。


  1. グローバル。

    通常、ユーザーのホームディレクトリ (fe、 ~/.yarn/berry/cache ) に保存されます。


  2. 地元。

    プロジェクト ディレクトリ (fe、 <project-dir>/.yarn ) に保存されます。


私の経験では、 #2#3が最も一般的な使用例ですが、念のため#1も採用しました (ただし、非常にまれなケースです)。


ベンチマークの例として、create-react-appのサンプル プロジェクトを使用しました。

ネプ

これは、 Node.jsエコシステムのデフォルトのパッケージ マネージャーです。他に何を言うべきでしょうか。インストール パッケージに付属しているため、基本的には、マシンにNode.js をインストールするとすぐに使用できます (または、 CIプロバイダーでNode.jsをセットアップした場合は、そのプロバイダーにインストールします)。


これは私にとって大きな「利点」です。別途インストールする必要はありません。


特に目立つ点はありません。ただ…動作します。また、長年大きなバグは見ていません。かなり安定しており、問題なく動作します。


これまで使用したnpmの機能:


  1. 依存関係の管理(インストール、削除、更新)
  2. パッケージを公開する(プライベート、パブリック)
  3. リンクローカルパッケージ
  4. ワークスペースを管理します。

依存関係の管理

npm は依存関係をプロジェクト ルートのnode_modulesフォルダーに保存します。非常に簡単です。


ℹ️ package-lock.jsonリストされているパッケージのレジストリに関する情報を保存します。単一のスコープ、つまり@example-companyからのパッケージを異なるレジストリ (例: npmGitHub パッケージ) に持っている場合に非常に便利です。


package-lock.json エントリ


さて、インストール速度の面でのパフォーマンスを見てみましょう...

キャッシュなしでpackage-lock.jsonを生成する

package-lock.json を生成し、キャッシュなしで依存関係をインストールする


かかった1分npm がpackage-lock.jsonを生成し、キャッシュなしで依存関係をインストールします。


使用されたコマンド:

 npm i

キャッシュなしでpackage-lock.jsonから依存関係をインストールする

キャッシュなしでpackage-lock.jsonから依存関係をインストールする


かかった18秒npm がキャッシュなしでpackage-lock.jsonから依存関係をインストールできるようにします。


使用されたコマンド:

 npm ci

グローバルキャッシュを使用して package-lock.json から依存関係をインストールする

グローバルキャッシュを使用して package-lock.json から依存関係をインストールする


かかった8秒npm がグローバル キャッシュを使用してpackage-lock.jsonから依存関係をインストールします。


使用されたコマンド:

 npm ci

ワークスペースの管理

ワークスペースを作成し、ワークスペース全体の依存関係を一度に管理したり、特定のプロジェクトの依存関係を個別に管理したりできるようになりました。


言い換えれば、バグや問題なく作業が完了し、公式ドキュメントも非常にわかりやすいということです。


これまで使用したワークスペース機能:


  1. ワークスペース内のすべてのプロジェクトの依存関係をインストールします。
  2. 特定の単一のプロジェクトの依存関係をインストールします。
  3. すべてのプロジェクトに対して単一のスクリプトを一度に再帰的に実行します。

正直に言うと、私はyarn の機能のいくつかをあまり試していません。つまり、いくつかのプロジェクトで作業中に「依存関係のインストール」という点でそれをたくさん使用しましたが、それだけです。


yarnにはNode.jsインストーラーが付属していないため、別途インストールする必要があります。つまり、 CIパイプラインに追加の手順が必要になります。つまり、プロジェクトの依存関係をインストールする前にyarnを設定する必要があります。

依存関係の管理

yarnには依存関係をインストールする 2 つの方法があります。


  1. ゼロインストール」(デフォルト) - .yarnフォルダーを作成し、 yarn.lockおよび.pnp.cjsファイルにパッケージをリストします。


  2. 通常のものはnpmに似ており、依存関係をnode_modulesに保存し、 yarn.lockファイルにリストします。


ℹ️ yarn lock ファイルには、古い (通常の) インストール方法を使用する場合にのみリストされているすべてのパッケージのレジストリに関する情報が保存されます。


⚠️ 「 Zero Installs 」はパッケージをローカル キャッシュに保存し、ロック ファイルへのリンクを提供しているようです。


パッケージリンク

依存関係を 1 つのクリーンな環境にインストールし、それを別の環境に移動するDockerfileまたはCIパイプラインがある場合、これは重要になる可能性があります ( .yarnフォルダーとローカル キャッシュの両方をコピーする必要があります)。


現在、yarn のデフォルトのアプローチは「ゼロ インストール」であり、古いアプローチよりもパフォーマンスが優れているため、このアプローチのみでベンチマークを記録します。

キャッシュなしでロックファイルを生成する

yarnでロックファイルを生成し、依存関係をインストールする


かかった16.5秒yarn がyarn.lockファイルを生成し、キャッシュなしで依存関係をインストールします。


使用されたコマンド:

 yarn install

キャッシュなしで既存のロックファイルから依存関係をインストールする

「ゼロインストール」アプローチでキャッシュなしで依存関係をインストールする


かかった11秒yarn が「ゼロ インストール」アプローチでキャッシュなしで依存関係をインストールします。


使用されたコマンド:

 yarn install --frozen-lockfile

グローバルキャッシュを使用して既存のロックファイルから依存関係をインストールする


「ゼロインストール」アプローチとグローバルキャッシュを使用して依存関係をインストールする


かかった8秒yarn が「ゼロ インストール」アプローチとグローバル キャッシュを使用して依存関係をインストールします。


使用されたコマンド:

 yarn install --frozen-lockfile

ワークスペースの管理

ワークスペースを作成し、すべてのプロジェクトの依存関係を一度に管理したり、特定のプロジェクトの依存関係を個別に管理したりできるようになりました。


これまで使用したワークスペース機能:


  1. ワークスペース内のすべてのプロジェクトの依存関係をインストールします。
  2. 特定の単一のプロジェクトの依存関係をインストールします。
  3. すべてのプロジェクトに対して単一のスクリプトを一度に再帰的に実行します。


ドキュメントは問題ありませんが、コマンド名とフラグがややわかりにくいです。


たとえば、ルート( . ) およびネストされたb2bプロジェクトでtestスクリプトを実行するには、これを実行する必要があります。


 yarn workspaces foreach -A --include '{.,b2b}' run test


npmとの比較:


 npm run test --workspace=b2b --include-workspace-root

ピンポン

pnpmは現在話題になっており、多くの企業やオープンソース プロジェクトで使用されています


yarnと同様に、 pnpmにはNode.jsインストーラーが付属していないため、別途インストールする必要があります。つまり、 CIパイプラインに追加の手順が必要になります。つまり、プロジェクトの依存関係をインストールする前にpnpmをセットアップする必要があります。

依存関係の管理

pnpm は高速でディスク容量効率の良いパッケージ マネージャーと考えられています...


確かに、依存関係をローカルで管理するという点では、 「ディスク スペース効率が良い」という意見に同意します。


デフォルトでは、 pnpm は共有依存関係の重複を排除します。pnpm、複数の依存関係で使用されるパッケージのシンボリックリンクを作成します。つまり、パッケージabがパッケージcを依存関係として使用する場合、 pnpm はパッケージc単一のコピーとして保存し、パッケージabのシンボリックリンクを作成します。こうすることで、パッケージ マネージャーはハード コピーを作成せず、SSD/HDD のメモリを節約します。


ℹ️ pnpm-lock.yamlリストされているパッケージのレジストリに関する情報は保存されません。


⚠️ pnpm は依存関係をプロジェクトとして保持するのではなく、グローバル キャッシュに保存することがあることに留意してください。

キャッシュなしでpnpm-lock.yamlを生成する

pnpm-lock.yaml を生成する


かかった31秒pnpm がpnpm-lock.yamlを生成し、キャッシュなしで依存関係をインストールします。


使用されたコマンド:

 pnpm install

グローバルキャッシュなしで pnpm-lock.yaml から依存関係をインストールする

グローバルキャッシュなしでpnpm-lock.yamlから依存関係をインストールする


かかった16秒pnpm がキャッシュなしでpnpm-lock.yamlから依存関係をインストールします。


使用されたコマンド:

 pnpm i --frozen-lockfile


グローバル キャッシュを使用して既存のロック ファイルから依存関係をインストールする

キャッシュ付きpnpm-lock-yamlから依存関係をインストールする


かかった5秒pnpmがグローバル キャッシュを使用してpnpm-lock.yamlから依存関係をインストールします。


使用されたコマンド:

 pnpm i --frozen-lockfile

ワークスペースの管理

さて、ここからが本当に面白くなってくるのですが…


pnpmには多くの設定オプションがありますが、一部のコア機能は動作しません。


私が直面したバグをいくつか見てみましょう:

pnpm インストール --filter

特定のプロジェクトのみの依存関係をインストールできることは重要です。これは、ワークスペース内の特定のプロジェクトに関連するパイプラインを作成するときに、モノレポに非常に役立ちます。


つまり、ワークスペースに次のようなものがあると想像してください。


  • ウェブアプリ、
  • バックエンドサーバー、
  • テスト プロジェクト (エンドツーエンド テスト)。


これらはすべて別々のnpmプロジェクトですが、同じリポジトリの一部です ☝️


ここで、パイプラインでエンドツーエンドのテストのみを実行する必要があります。つまり、エンドツーエンドのテスト依存関係のみが必要なわけですね。


まあ、それはできません - pnpm はワークスペース全体の依存関係をインストールするように強制します。


pnpm install --filter <project-name> 、選択したプロジェクトの依存関係のみをインストールするはずでしたが、機能しません。


1 年前のバグがあり、最近、機能しない修正で閉じられました。

再帰インストール=false

pnpmはデフォルトでpnpm install実行するとワークスペース全体(すべてのプロジェクト)の依存関係をインストールします。


ワークスペース ルートの.npmrcrecursive-install=false設定すると、この動作を切り替えることができます。


しかし、それはすでにほぼ 2 年前の別のバグを導入します

共有ワークスペースロックファイル=false

pnpm はデフォルトで依存関係リストを単一のロック ファイルに保存します ( npmおよびyarnと同じ)。


ワークスペース ルートの.npmrcshared-workspace-lockfile=falseを設定すると、この動作を変更することもできます。


これにより、ワークスペース機能を維持し、 --ignore-workspaceフラグを使用して特定のプロジェクトの依存関係をインストールできるようになります。


いずれにせよ、この設定により、さらにいくつかの問題が発生します。


  1. eslinttsc --noEmit GitHub Actionsパイプラインで「JavaScript ヒープ メモリ不足」エラーをスローします。


  2. 依存関係の一部はグローバル キャッシュに保存され、 node_modules/.pnpmにシンボリック リンクされます。

パフォーマンス比較結果

#

ネプ

ピンポン

ロックファイルを生成する

60秒

16.5秒

31秒

キャッシュなしで依存関係をインストールする

18秒

11秒

8秒

グローバルキャッシュを使用して依存関係をインストールする

8秒

8秒

5秒


上記のベンチマークによると、 npm は最も遅いパッケージ マネージャーです ☝️


とにかく、これらの結果を解釈してみましょう...

ロックファイルを生成する

これはまれなケースです。通常、ロック ファイルはプロジェクトの初期化時に作成され、パッケージをインストール/更新するときに拡張されます。


それを念頭に置くと、パッケージ マネージャーを選択するときに頼るべきことはそれほど重要ではないようです。

依存関係をインストールする

ほとんどの場合、プロジェクトは特定の依存関係のリストを保持しており、何かを追加/削除することはほとんどありません。


おそらく、パッケージのバージョンは時々変更されるでしょう。これらの変更は小さく、残りのパッケージはキャッシュから再利用されます。


つまり、一般的な使用例は、パッケージ レジストリから新しいパッケージを取得し、残りをキャッシュから取得することです。


pnpm (5〜8 秒) はnpm (8〜18 秒) のほぼ 2 倍の速度で、 yarn (8〜11 秒) が中間です。

結論

事実

  • pnpm は確かに「高速でディスク効率の良い」パッケージ マネージャーです。これは現在のレビューでも明らかです。


  • pnpmワークスペース機能にはバグがあり、そのバグのいくつかは何年も解決されていません。


  • pnpmyarn はどちらも CI パイプラインで追加の設定が必要ですが、 npm では必要ありません。


  • pnpmyarn はどちらもロック ファイルにパッケージ レジストリ情報を保存しませんが、 npm は保存します。

著者の考え

パッケージ マネージャーに対する要件が「依存関係のみをインストールする」という単純なものである場合は、 pnpmが最適だと思います。


pnpmにはすぐに使えるNode.jsインストーラーが付属していませんが、 corepackまたは既存の actionを使用して CI パイプラインで簡単にセットアップできます。


私はnpmを好みます。その理由は次のとおりです:


  • 安定している(特にワークスペース)


  • Node.jsに付属しており、CIパイプラインで追加の設定は必要ありません。


  • パッケージ レジストリをpackage-lock.jsonに保存するので、異なるレジストリから単一のスコープで依存関係をインストールできます。


これらの利点は、 yarnpnpmで節約できる数秒の速度とディスク容量を上回ります。


パッケージ マネージャーを選択する際の基準は何ですか? 遠慮せずに、下のコメント セクションであなたの考えを教えてください! 👇😊