github actions の npm のキャッシュについて
やりたい
- PRが上がったら自動でeslintを走らせたい
- node
- 将来的にtestとかを並列で走らせたい
- npm packageはキャッシュしておきたい
方針
- setupのjobsでnpmをinstallしてキャッシュしておく
並列実行したいjobでsetupでinstallしたpackageをつかいた(かった)- キャッシュしてるので npm ciにした
actions/setup-node@v3
で cache: npm
するとキャッシュされるって書いてあるけど、
されないぞ、って言ってる人も結構いる、どっちやねん。
あと、各job間でinstallしたnpm packageは共有できない
会社のプロジェクトだと各job間でnpm packageが共有できててなんでやねんってなったけど、setup job で、npm install
したあとにnode_modules
フォルダをキャッシュして、ほかのjobでそのフォルダを展開していたからっぽい?
actions/setup-node@v3
の cache: npm
の例だと npm ci
している
この設定だと ~/.npm
をキャッシュする?
で、npm ci
は node_modules
があった場合は削除して、~/.npm
をまず確認してあればそこからinstallして、なければ落としてくる挙動っぽい?
ので、各jobごとに最初に npm ci
すればちゃんとキャッシュをつかってpackageがinstallされる・・・
ということっぽい?
actions/setup-node@v3
の cache: npm
だと各job間で必ずnpm ci
をやらないといけないのでその分時間がかかる、そしてgithub actionsは時間課金なので、ちょっとした時間が積み重なってかなりの額になる。
actions/cache@v3
で node_modules
をキャッシュしておけば、npm install
のコマンド自体を飛ばせるし、そのあとのjobはそのキャッシュを展開するだけで、npm install
が不要なので、実行時間自体はだいぶ短くなってるっぽい。
ただし、npm install
は package-lock.json
に必ずしも沿うわけではないので、local環境とciの環境でバージョンが異なってなにか問題が起きる可能性があるかもしれない。
でも正直会社で1年以上、この設定で業務をしているが、問題が起こったことがない。
とりあえずcache: npm
でnpm ci
。
お金の問題があるならnode_modules
をキャッシュする方向が良さそうかなぁ?
ある程度効率がよくてシンプルなサンプルないかなぁ?
まぁやっぱり node_modulesをキャッシュするのは推奨してないよね
actions/cache@v3
で node_modules
をキャッシュした際の利点は npm ci
でキャッシュから再インストールするのとくらべて早いこと。
hashFiles('**/package-lock.json')
完全一致で node_modules
のキャッシュを作っておいて、ヒットすればそれを展開するだけ、ヒットしなければ npm ci
で package-lock.json
にそってインストールしてキャッシュするようにすれば早そう
# node_modules がキャッシュされていれば展開する
- name: Cache node modules
id: cache-npm
uses: actions/cache@v3
env:
cache-name: cache-node-modules
with:
path: node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
# node_modules がキャッシュされてなければ npm ci
- if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
name: node
uses: actions/setup-node@v3
with:
node-version: '16'
- if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
name: npm install
run: npm ci
- name: なんかやりたい処理
run: npm run hoge
実際やってみたら一番はやくなった。
node_modules
をキャッシュしたらだめなのは、npm ci
だとnode_modules
が一回削除される、npm i
だと依存パッケージがおかしくなる可能性があるから(ほかにも理由あるのかな?)
このコードだとキャッシュがない = package-lock.json
が変わっている(or 初回)ことになるのでnpm ci
で新しく作られていいし、キャッシュがあるなら npm ci
も npm i
も走らないので依存関係は正しい状態の node_modules
が展開されるので問題は起こらない気がした。
問題があるとしたら、jobが多いと、同じ処理が何回も出てきて微妙ってところなのかな?