1567 文字
8 分
npm, yarn, pnpmパッケージマネージャをベンチマークしてみた
3行まとめ
- pnpm が速いとのことなのでベンチマークをしてみましたが、Yarn v4 が最速です。
- Yarn v1 はキャッシュありのときにとても遅いでが、最新の v4 は全項目において最速です。
- Node.js の Docker image でデフォルトになっているのは Yarn v1 なのでご注意ください。
概要
- pnpm がどのくらい速いかを計測しています。
- Next.js や React を使ったときのベンチマークは掲載されていますが、実際自分のプロジェクトではどの程度かわるのかをベンチマークしてみたいと思います。
- pnpm とは何かを知りたい場合は pnpm概要を参照するのが良いです。
実験環境
個人サービスである 銀行コード検索APIのpackage.jsonを使います。
package.json の中身は以下のようになっています。
{ "private": true, "dependencies": { "@hotwired/turbo-rails": "^7.3.0", "@popperjs/core": "^2", "@rails/activestorage": "^7.0", "@rails/ujs": "^7.0", "bootstrap": "^5.3", "bootstrap-icons": "^1.10.5", "bootswatch": "^5.3", "esbuild": "^0.18.17", "jquery": "^3.7" }, "devDependencies": { "eslint": "^8.46.0", "eslint-plugin-react": "^7.33.1", "npm-check-updates": "^16.10.17" }}測定環境
root@1bf5d376c3a0:/app# node -vv18.17.0root@1bf5d376c3a0:/app# npm -v9.8.1npmのbenchmark
まずは基本となる npm を計測します。28秒。
root@1bf5d376c3a0:/app# rm -rf node_modules/ package-lock.jsonroot@1bf5d376c3a0:/app# time npm install
added 383 packages, and audited 384 packages in 28s
80 packages are looking for funding run `npm fund` for details
found 0 vulnerabilities
real 0m28.308suser 0m9.264ssys 0m5.575syarn v1のbenchmark
Node.jsに標準で組み込まれたyarnは、13秒。
root@1bf5d376c3a0:/app# rm -rf node_modules/ package-lock.jsonroot@1bf5d376c3a0:/app# time yarn installyarn install v1.22.19[1/4] Resolving packages...[2/4] Fetching packages...[3/4] Linking dependencies...[4/4] Building fresh packages...success Saved lockfile.Done in 13.16s.
real 0m13.362suser 0m5.338ssys 0m6.641s/yarn v4のbenchmark
最新のyarnで計測します。なんと5.8秒! 計測ミスかと思って再度docker runして試しましたが同じ結果です。
root@1bf5d376c3a0:/# mkdir /approot@1bf5d376c3a0:/# cat > package.jsonroot@1bf5d376c3a0:/app# yarn set version berryroot@1bf5d376c3a0:/app# yarn -v4.0.2root@1bf5d376c3a0:/app# time yarn install➤ YN0000: · Yarn 4.0.2➤ YN0000: ┌ Resolution step➤ YN0085: │ + @hotwired/turbo-rails@npm:7.3.0, @popperjs/core@npm:2.11.8, and 474 more.➤ YN0000: └ Completed in 3s 435ms➤ YN0000: ┌ Fetch step➤ YN0013: │ 455 packages were added to the project (+ 84.83 MiB).➤ YN0000: └ Completed in 1s 442ms➤ YN0000: ┌ Link step➤ YN0000: │ ESM support for PnP uses the experimental loader API and is therefore experimental➤ YN0007: │ esbuild@npm:0.18.20 must be built because it never has been before or the last one failed➤ YN0000: └ Completed in 0s 501ms➤ YN0000: · Done with warnings in 5s 438ms
real 0m5.816suser 0m7.101ssys 0m1.844spnpmのbenchmark
今回注目のpnpmは18秒。
root@1bf5d376c3a0:/app# time pnpm iPackages: +347++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++Progress: resolved 368, reused 0, downloaded 347, added 347, donenode_modules/.pnpm/[email protected]/node_modules/esbuild: Running postinstall script, done in 93ms
dependencies:+ @popperjs/core 2.11.8+ @rails/activestorage 7.0.7-2+ @rails/ujs 7.0.7-2+ bootstrap-icons 1.10.5+ bootswatch 5.3.1+ esbuild 0.19.2+ jquery 3.7.1
devDependencies:+ eslint 8.48.0+ npm-check-updates 16.13.2
Done in 17.9s
real 0m18.139suser 0m7.202ssys 0m5.991sx余談: pnpmのエラー
余談ですが、2回目以降はエラーが出力されて計測できませんでした。
root@1bf5d376c3a0:/app# rm -rf node_modules/ .pnpm-store/root@1bf5d376c3a0:/app# time pnpm installPackages: +438+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ERR_PNPM_LINKING_FAILED Error: ENOENT: no such file or directory, copyfile '/app/.pnpm-store/v3/files/cf/83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e' -> '/app/node_modules/.pnpm/[email protected]/node_modules/resolve_tmp_124/test/resolver/same_names/foo.js'Progress: resolved 459, reused 0, downloaded 438, added 197
real 0m20.723suser 0m9.377ssys 0m6.953s追記: package-lock.json を削除したら成功しました。また、コンテナを立ち上げ直したら成功したりしたのでpnpmが内部で使っているハードリンク関連とDocker for macOSの相性が悪そうです。
キャッシュ無しベンチマーク結果
| Package manager | Result (s) |
|---|---|
| npm | 28.308 |
| yarn v1 | 13.362 |
| yarn v4 | 5.816 |
| pnpm | 18.139 |

考察
- yarn v4がとても速いです。nodeのdocker imageのデフォルトではv1が使われてしまうので明示的にv4を設定する必要があります。
- 今回は初回実行を計測しました。
- pnpmの初回は遅いですが、パッケージがシステム上で共有されること、依存関係の解決が高速なことを考えると2回目の実行はそこそこ速いです。
- 実際の開発では、CIや開発環境でパッケージの差分を追加していくと行った差分での利用が多いと思います。その際には高速に動作するので実運用では利点がありそうです。
次にパッケージマネージャを通して削除、追加する際のベンチマークを計測します。
パッケージの削除、追加の計測
実際の運用時に多いユースケースであるパッケージの追加、削除のときのベンチマークを計測してみます。
bootstrap パッケージを削除して、追加するケースを想定してベンチマークを取ってみます。
npm
トータル1.5秒。速いです。
root@7d57aaa10c85:/app/a# time npm uninstall bootstrap
removed 1 package, and audited 383 packages in 686ms
80 packages are looking for funding run `npm fund` for details
found 0 vulnerabilities
real 0m0.863suser 0m0.772ssys 0m0.160sroot@7d57aaa10c85:/app/a# time npm install bootstrap
added 1 package, and audited 384 packages in 767ms
81 packages are looking for funding run `npm fund` for details
found 0 vulnerabilities
real 0m0.943suser 0m0.858ssys 0m0.231syarn v1
トータル38秒。めちゃ遅いです。
root@7d57aaa10c85:/app/a# time yarn remove bootstrapyarn remove v1.22.19[1/2] Removing module bootstrap...[2/2] Regenerating lockfile and installing missing dependencies...success Uninstalled packages.Done in 17.74s.
real 0m18.013suser 0m5.547ssys 0m8.845sroot@7d57aaa10c85:/app/a# time yarn add bootstrapyarn add v1.22.19warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.[1/4] Resolving packages...[2/4] Fetching packages...[3/4] Linking dependencies...[4/4] Building fresh packages...success Saved lockfile.success Saved 1 new dependency.info Direct dependenciesinfo All dependenciesDone in 20.55s.
real 0m20.919suser 0m5.861ssys 0m9.193syarn v4
addとremoveがそれぞれ1秒以内に終わります。速い!
root@0c8caa909f49:/app# time yarn remove bootstrap➤ YN0000: · Yarn 4.0.2➤ YN0000: ┌ Resolution step➤ YN0085: │ - bootstrap@npm:5.3.2➤ YN0000: └ Completed➤ YN0000: ┌ Fetch step➤ YN0000: └ Completed➤ YN0000: ┌ Link step➤ YN0000: │ ESM support for PnP uses the experimental loader API and is therefore experimental➤ YN0000: └ Completed➤ YN0000: · Done with warnings in 0s 362ms
real 0m0.848suser 0m0.778ssys 0m0.375sroot@0c8caa909f49:/app# time yarn add bootstrap➤ YN0000: · Yarn 4.0.2➤ YN0000: ┌ Resolution step➤ YN0085: │ + bootstrap@npm:5.3.2➤ YN0000: └ Completed➤ YN0000: ┌ Fetch step➤ YN0000: └ Completed➤ YN0000: ┌ Link step➤ YN0000: │ ESM support for PnP uses the experimental loader API and is therefore experimental➤ YN0000: └ Completed➤ YN0000: · Done with warnings in 0s 330ms
real 0m0.791suser 0m0.820ssys 0m0.171spnpm
トータル4.7秒。速いです。
root@7d57aaa10c85:/app# time pnpm remove bootstrapPackages: -1-Progress: resolved 367, reused 346, downloaded 0, added 0, done
dependencies:- bootstrap 5.3.1
Done in 2.2s
real 0m2.311suser 0m2.041ssys 0m0.906sroot@7d57aaa10c85:/app# time pnpm add bootstrapPackages: +1+Progress: resolved 368, reused 347, downloaded 0, added 0, done
dependencies:+ bootstrap 5.3.1
Done in 2.1s
real 0m2.239suser 0m2.205ssys 0m0.879sremove/addのベンチマーク結果
| Package manager | Remove Result (s) | Add Result (s) |
|---|---|---|
| npm | 0.863 | 0.943 |
| yarn v1 | 18.013 | 20.919 |
| yarn v4 | 0.8480 | 0.791 |
| pnpm | 2.311 | 2.239 |

考察
pnpmが公表しているベンチマーク結果とは違いましたやはり手元でやってみるのは意味があります。

jsbundling-rails は Yarn に依存しているので要注意です。
参考資料
npm, yarn, pnpmパッケージマネージャをベンチマークしてみた
https://blog.teraren.com/posts/2023-08-30-pnpm/ 関連記事
この記事が役に立ったら
GitHub Sponsorsで応援できます