Next.jsをVercelを使わずにキャッシュしたい

1 min read読了の目安(約1500字

Next.jsでSSRやISRを利用する場合にはVercelを用いて配信すれば最もしっかりチューニングされる。ところが、Vercelが使えない場合にどのようにすればチューニングできるか、とりわけフロントエンドでのキャッシュに関する部分の考察をするためにNext.jsではキャッシュ周辺がどのような挙動をするか調べた。

※記事というよりメモである。
※Next.jsのバージョンは 10.0.5 である。

リクエストされるファイルについて

HTML

最初にリクエストされるHTML。ISRであれば .next/server/pages/ に出力されている。

パスは /_next/data/<ハッシュ>/<ページのパス>.json
next/link ライブラリを利用しているリンクがビューポート内に表示されている場合、その先のページ表示に必要なJSONのデータがリクエストされる。このデータの中身は getStaticProps の戻り値に相当する。

その他静的ファイル

パスが /_next/static/ 以下のファイル。
これらのファイルはURLのどこかににハッシュがついているため、キャッシュしても問題がない。(revving)

ハッシュについて

_buildManifest.js 及び _ssgManifest.js を取得するためのURLや /_next/data/ 以下のファイルのURLに含まれるハッシュは next build するごとに再生成される。 next start を再起動しても変わらない。

Cache-Controlについて

/_next/static/ 以下のファイルのレスポンスでは Cache-Control: public, max-age=31536000, immutable になる。(SSR、ISR共通)

/_next/data/ 以下のファイル及び、HTMLのレスポンスではSSRとISRで結果が異なる。
SSRの場合は Cache-Control: private, no-cache, no-store, max-age=0, must-revalidate になり、ISR(revalidate: 10)の場合は Cache-Control: s-maxage=10, stale-while-revalidate になる。 命名がわかりづらくて少しややこしいのだが、s-maxage の値はrevalidateの値に等しい。

結論

nginx を使うのであれば proxy_cache はバックエンドのレスポンスを見て相応のキャッシュしてくれるので特に問題が無いように思える。特にISRはレスポンスにいい感じのCache-Controlが返るので深く考えずともフロントエンドでキャッシュする構成にできるだろう。(未検証)
また、nginx で実装する場合には下記の記事が参考になる。

https://steveholgado.com/nginx-for-nextjs/

参考リンク

https://developer.mozilla.org/ja/docs/Web/HTTP/Caching
https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Cache-Control
https://www.nginx.com/blog/nginx-caching-guide/

記事に使用したソース

https://github.com/gc-locks/next_sample1