5 分から 1 分に! yarn install の時間を劇的に短縮した話

2023/03/23に公開

yarn install (フロントエンドの依存ライブラリインストール) の時間が長くなってしまった原因の調査と、解決した記録です。

(今回はyarn v1を使用していますが、npmでは yarn why の代わりに npm ls を用いることで同様に調査可能です)

背景

とあるプロダクトで、いつの間にかyarn install (フロントエンドの依存ライブラリインストール) の時間に5分ほどかかるようになってしまいました。

一見はローカル環境での初回インストール時しか影響がなく感じるので気にしなくていいやと思いがちですが、よく考えると結構大きな問題です。

  • ローカル環境の構築に時間がかかることにより、オンボーディングの手間が増加
  • dependencies更新時に各ローカル環境でyarn installが必要なため、開発効率の低下
  • CIの結果がすぐに分からないことにより、レビューの速度が低下
  • CDの時間がかかることにより、マージからリリースまでの速度が低下
  • CI / CDのコストが増大

そこで、時間をかけて調査と修正をすることにしました。

インストールに時間がかかるライブラリの特定

すべてのライブラリを再インストールするため、 node_modulesをまるごと削除します。

rm -rf node_modules

そして、再度インストールします。

yarn install --immutable

インストール中はターミナルを目視で眺めます。

そして、 Building fresh packages... というステータスになったら注視します。今回のプロダクトでは次の画面の状態で2分かかっていました。

yarn でインストール中の画面。後述のコードブロックの内容が表示されている。

[4/4] Building fresh packages...
[-/11] waiting...
[2/11] fsevents
[-/11] waiting...
[-/11] waiting...
[8/11] node-sass

その後、次の画面になり、さらに2分ほどかかっていました。

[4/4] Building fresh packages...
[-/11] waiting...
[-/11] waiting...
[-/11] waiting...
[-/11] waiting...
[10/11] grpc

以上の結果から、 node-sassgrpc のビルドに4分かかっていることがわかります。

verboseモードにしてログを保存して分析することも最初は考えていたのですが、インストールに時間のかかるライブラリは目視で十分確認できました。

node-sass については node-sass@4.13.1 がdependenciesに指定されていました。

しかし、 grpc は指定していません。そのため、どのライブラリの依存関係になっているのか調べました。

yarn why grpc

yarn why v1.22.19
[1/4] Why do we have the module "grpc"...?
[2/4] Initialising dependency graph...
[3/4] Finding dependency...
[4/4] Calculating file sizes...
=> Found "grpc@1.24.2"
info Reasons this module exists
   - "firebase#@firebase#firestore" depends on it
   - Hoisted from "firebase#@firebase#firestore#grpc"
Done in 0.44s.

firebase が依存していることがわかりますね。たしかに firebase@7.8.1 はインストールしています。

該当ライブラリの README の確認

原因は node-sass@4.13.1firebase@7.8.1 であることがわかったところで、ライブラリ該当のバージョンのREADMEを見に行ってみましょう。何かヒントがあるかもしれません。

node-sass

まずはnode-sassを調べてみます。

当時の README を参照すると、次のように記載があります。

Supported Node.js versions vary by release, please consult the releases page.

リリースページを要確認とのことで、リリースページを見てみると原因がわかりました。つい最近Nodeを14系にアップデートしたばかりだったのです。

Supported Environments
Node 0.10, 0.12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13

Install runs only two Mocha tests to see if your machine can use the pre-built LibSass which will save some time during install. If any tests fail it will build from source.

通常はビルド済みのものをコピーするだけですが、今回サポート外のNodeバージョンだったため、毎回ソースコードからビルドしていたことがわかりました。

今回、影響を最小限度にするべく、Node 14をサポートしている最も近いバージョン4.14.1へアップデートすることにしました。プロダクトに影響のある差分がなかったので、もっと早く動いていれば良かったと反省しました。

https://github.com/sass/node-sass/compare/v4.13.1...v4.14.1

firebase

次にgrpcに依存しているfirebaseのリリースノートを調べてみます。

7.14.0に次のようなリリースノートがありました。

Replaced grpc with @grpc/grpc-js in the Node.js builds. As a result, the minimum supported NodeJS version is now 8.13.0.

7.14.0未満は grpc のソースコードを毎回ビルドしていましたが、7.14.0以降はビルド済みの @grpc/grpc-js へ依存するようになったようです。

こちらも、7.14.0へアップデートすることにしました。

まとめ

yarn installの時間が5分から1分に短縮できました 🎉!

特にCIの速度が速くなったことによる恩恵が大きかったです。開発効率を大きく向上させることができました。

node-sassからdart-sassの移行など、他にも改善が必要なため着々と進めていく所存です。

Discussion