CI/CDでnpm ciする際は ~/.npm をキャッシュしよう

2021.07.02

現在自分が担当しているプロジェクトでは、GitHub Acitionsを利用してデプロイを行っています。
npm ci を使ってパッケージのインストールが行われていましたが、 その際に node_modules をキャッシュしていて意味がない状態となっていました。

- name: Cache Node modules
  uses: actions/cache@v2
  with:
    path: hoge/node_modules
    key: ${{ runner.os }}-node_modules-${{ hashFiles('**/package-lock.json') }}

- name: Build hoge
  run: |
    npm ci
    npm run build
  working-directory: hoge

これは修正せねば!ということで、調べると npm ci する際は ~/.npm をキャッシュするのが良さそうだったので、備忘も兼ねてまとめておきます。

そもそも何が問題なのか?

npm installnpm ci は、どちらもパッケージをインストールするためのコマンドです。

npm installpackage.json を参照して依存関係をインストールするため、パッケージのバージョン指定に「メジャーバージョンのみ固定」などの幅がある場合、インストールのタイミングによってバージョンの違いが発生することがあります。
実際にインストールされたバージョンが package-lock.json に記されます。

npm ci は、package-lock.json を参照して依存関係をインストールするため、package-lock.json が作成された時点のバージョンのパッケージをインストールすることが可能です。

CI/CDなどで毎回パッケージがインストールされる場合は、npm ci コマンドを使い package-lock.json からパッケージのインストールを行うことで、開発時とデプロイ時のバージョンの差異を無くすことができます。

npm ci でパッケージのインストールをした場合は node_modules ディレクトリは毎回新しく構築されるため、キャッシュしていても意味がありませんでした。

If a node_modules is already present, it will be automatically removed before npm ci begins its install.

npm ciのドキュメントより

~/.npm をキャッシュする

npm ciのドキュメントでは、 Travis CIを使う際に ~/.npm をキャッシュする例が記されていました。

# .travis.yml
install:
- npm ci
# keep the npm cache around to speed up installs
cache:
  directories:
  - "$HOME/.npm"

npmは、パッケージをインストールする際に ~/.npm にキャッシュを保存し、同じパッケージが必要になった場合に、ネットワークへのアクセスなくインストールが可能です。
そのため、 npm ci を行う場合でも ~/.npm をキャッシュすれば、インストールの高速化を図ることができます。

よって、こんな雰囲気に修正しました。

- name: Cache npm dir
  uses: actions/cache@v2
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

- name: Build hoge
  run: |
    npm ci
    npm run build
  working-directory: hoge

めでたしめでたし