GitHub ActionsのCIでpnpm installを実行するたびに、全パッケージのダウンロードを待つのが少し非効率に感じる方もいるかと思います。
今回はよく使う方法ではありますが、CIの実行時間を短縮するために、actions/cacheを使ってpnpmの依存パッケージをキャッシュした際の設定メモを書いておきます。
基本のキャッシュ設定
まずはactions/cacheを使い、pnpmがパッケージを保存しておく「ストア」と呼ばれる場所を丸ごとキャッシュするように。
実際のコードはこんな感じです。まずpnpm store pathでキャッシュすべき場所を取得し、それをactions/cacheに渡しています。
- name: pnpmのstoreパスを取得
  id: pnpm-cache
  run: |
    echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: pnpmのキャッシュを設定
  uses: actions/cache@v4
  with:
    path: ${{ env.STORE_PATH }}
    key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
    restore-keys: |
      ${{ runner.os }}-pnpm-store-キャッシュを識別するためのkeyがここで重要になります。pnpm-lock.yamlのハッシュ値をキーに含めることで、「ロックファイルに変更がなければ同じキャッシュを使い、変更があれば新しいキャッシュを作る」という賢い動きをしてくれます。
応用メモ
キャッシュには、他にもいくつか便利な使い方があるようです。
いろんなキャッシュを一度に
pnpmのキャッシュだけでなく、ビルドツール(Turborepoなど)やFirebaseエミュレーターのキャッシュなども一緒に保存しておくと、さらにCIが速くなるかもしれません。pathには複数のパスを指定できます。
- uses: actions/cache@v4
  with:
    path: |
      ${{ env.STORE_PATH }}
      ~/.cache/firebase
      ./functions/.turbo
    key: ${{ runner.os }}-build-${{ hashFiles('**/pnpm-lock.yaml') }}
    # ...あえてキャッシュを無効にする時
まれにキャッシュが原因で問題が起きたり、クリーンな状態で動作確認したい時もあります。そんな時は、キャッシュキーを毎回ユニークなものにすれば、キャッシュがヒットしなくなります。
ワークフローの実行番号(github.run_number)をキーに加えるのが簡単な方法です。
key: cache-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.run_number }}これなら実行ごとに必ずキーが変わるので、毎回新しいキャッシュが作られる(=キャッシュが使われない)状態になります。
まとめ
pnpmのキャッシュ設定は、CIの実行時間を短縮するのにかなり効果がありました。ビルドが速くなると開発体験も良くなるので、試してみて損はないと思います。
また、キャッシュキーの仕組みや応用的な使い方を知っておくと、いざという時のトラブルシューティングにも役立ちそうだと感じました。
どなたかの参考になれば嬉しいです。
