JavaScriptパッケージ管理ツール「pnpm」の紹介
こんにちは、クラウドエース SRE ディビジョン所属の荒木です。
この記事では、JavaScript のパッケージ管理ツール「pnpm」についてご紹介します。
pnpm とは
pnpm は Performant NPM を略したもので、JavaScript のパッケージ管理ツールです。npm や yarn と似ていますが、主にディスク容量の節約とインストール速度の向上、node_modules
の厳格さに焦点を当てています。
これは pnpm の公式サイトのトップをスクリーンショットしたものなのですが、ページリロードのたびに "p"、"n"、"p"、"m" の大文字小文字がランダムで入れ替わるようになっています。
この仕様が原因で、「PnPm が正式名称だ!」「いや、pnpM が正しい!」といった論争が起きたり起きなかったりします。
npm と比較して pnpm が優れている点
ストレージが効率的
npm と pnpm のストレージの使い方には大きな違いがあります。
npm では、同じ依存関係を使う複数のプロジェクトが、それぞれにコピーを保存します。例えば、hoge という 1 MB のパッケージを使用するプロジェクトを 100 個ローカル環境に用意すると、 100 回 hoge がコピーされるため、コンピューターのストレージを 100 MB 使用します。
一方で pnpm では、これらの依存関係を一箇所に集約し、各プロジェクトはその場所へのリンクを作成することでディスク容量を節約します。hoge という 1 MB パッケージを使用するプロジェクトを 100 個ローカル環境に用意した場合、pnpm のストアに保存されている hoge へのリンクが 100 個作成されるだけで hoge 自体は増えないため、コンピュータのストレージは 1 MB のみ使用されます。
(画像引用:https://medium.com/@jesuva/node-package-managers-cab41450c2da )
この図では、LICENSE.md
を project_1 と project_2 で共有しています。このとき、それぞれのプロジェクトの node_modules
に実際に配置されているのは LICENSE.md
へのリンクです。このように、同じパッケージを繰り返し保存せずプロジェクト間で共有することで、ディスク容量を節約しています。
インストールが高速
JavaScript のパッケージ管理ツールでは、次の 3 ステップでインストールが行われます。
- 依存関係の解決(Resolving)
- ディレクトリ構造の計算(Fetching)
- 依存関係をリンク(Linking)
従来のパッケージ管理ツールは、すべてのパッケージでこれらの各プロセスを共有していました。
どういうことかイメージしづらいので hoge
、fuga
、piyo
という 3 つのパッケージをインストールする場合を考えてみます。もし、hoge
と fuga
の Resolving が終わっても、piyo
の Resolving が終わるまでは hoge
と fuga
は次のステージの Fetching に進むことができません。つまり、処理に時間のかかるパッケージがあると、他のパッケージの処理が待ち状態になってしまうということです。
(画像引用:https://pbs.twimg.com/media/Eg_YM2lXcAEZn3B?format=png&name=large )
pnpm では、下の図のようにパッケージごとに個別にステージを実行することで、待ち状態を生み出さないようにし、インストールのプロセスを効率化しています。
(画像引用:https://pbs.twimg.com/media/Eg_YM29XcAIJMIn?format=jpg&name=large )
この説明の参考にした pnpm 公式の X(旧 Twitter)のポストを載せておきます。
node_modules
が厳格
npm を使う場合、プロジェクトの package.json
に記載されていないパッケージにアクセスできることがあります。例えば、express というパッケージをインストールしたとき、node_modules
フォルダには以下のように関連パッケージが配置されます。
$ cd node_modules
$ ls -1
accepts
array-flatten
content-disposition
content-type
cookie
cookie-signature
debug
depd
destroy
ee-first
encodeurl
escape-html
etag
express
finalhandler
forwarded
fresh
http-errors
inherits
ipaddr.js
media-typer
merge-descriptors
methods
mime
mime-db
mime-types
ms
negotiator
on-finished
parseurl
path-to-regexp
proxy-addr
qs
range-parser
send
serve-static
setprototypeof
statuses
type-is
unpipe
utils-merge
vary
一方で pnpm では、express パッケージのシンボリックリンクのみが配置されます。これにより、プロジェクトの package.json
に記載されていないパッケージにはアクセスできなくなり、不要な依存関係による問題やバグの発生を防ぐことができます。
詳しくは公式ドキュメントの Symlinked `node_modules` structure を参照してください。
機能の比較
pnpm は npm や yarn と比較して、機能面で以下のような違いがあります。
機能 | pnpm | Yarn | npm |
---|---|---|---|
ワークスペースのサポート | ✔️ | ✔️ | ✔️ |
分離されたnode_modules
|
✔️ - デフォルト | ✔️ | ✔️ |
ホイストされた node_modules
|
✔️ | ✔️ | ✔️ - デフォルト |
Peerの自動インストール | ✔️ | ❌ | ✔️ |
Plug'n'Play | ✔️ | ✔️ - デフォルト | ❌ |
Zero-Installs | ❌ | ✔️ | ❌ |
依存関係のパッチ | ✔️ | ✔️ | ❌ |
Node.jsバージョンの管理 | ✔️ | ❌ | ❌ |
ロックファイル | ✔️ - pnpm-lock.yaml
|
✔️ - yarn.lock
|
✔️ - package-lock.json
|
オーバーライドのサポート | ✔️ | ✔️ - resolutionsによって | ✔️ |
連想ストレージ | ✔️ | ❌ | ❌ |
パッケージの直接実行 | ✔️ - pnpm dlx によって |
✔️ - yarn dlx によって |
✔️ - npx によって |
副作用キャッシュ | ✔️ | ❌ | ❌ |
ライセンスの一覧表示 | ✔️ - pnpm licenses list によって |
✔️ - プラグインによって | ❌ |
(引用:https://pnpm.io/ja/feature-comparison )
まとめ
pnpm は従来のパッケージ管理ツールと比較して、以下のメリットがありました。
- ストレージが効率的
- パッケージのインストールが高速
- 依存関係によるバグを防ぎやすい
npm に不満を持っている方は、ぜひ pnpm を試してみてください。
ただし、npm や yarn と比較してネット上に情報が少なく、ある程度自分でトラブルに対処しなくてはならないという点に注意が必要かなと思いました。
Discussion