はぜにっき

日記です。(毎日更新ではない)

Next.js v9.4 で追加されたIncremental Static Regenerationの挙動を調べた

ReactにSSRとかファイルシステムルーティングとか色んな機能が付いたフレームワークのNext.jsのv9.4で Incremental Static Regeneration (beta) という機能が追加されました。
betaなのでGAになる頃には挙動が変わっていたり機能が増えていたりしそうですが、一旦現状の動きを調べてみたのでメモっておきます。

Incremental Static Regenerationについて

mizchi.dev

mizchiさんのわかりやすい解説を貼っておきます。

三行でどういうものかを書くと、
初回アクセス時にServer Side Renderingをすると同時に、生成されたHTML, JS等が所定の箇所に保存(キャッシュ)され、
初回アクセスで生成されたタイミングから暫くの間はキャッシュされたデータを使いレスポンスがされて、
キャッシュが破棄されてからアクセスされたら再度SSRしつつキャッシュを行う
という仕組み。

で、Vercelにデプロイする場合はVercelのCDNにキャッシュが保管され、めちゃくちゃ速くレスポンスが返ってくる。
CDNからレスポンスが返ってくるということは、(SPA部分でサーバへリクエストを送るような部分は除いて)サーバへのリクエストが飛びません。

すげーー!弊社のメディアこれでリニューアルしたい!!
ということでちょっと気になったいくつかの挙動を実際に動かして試してみることにしました。

補足: 仕様についてはこちらで議論されています。

英語できないのめちゃくちゃしんどい

github.com

調べたこと

  1. Incremental SSG + SPA 構成の作り方
  2. Incremental SSG で生成されたCDN Cacheはコードをdeployし直したら吹っ飛ぶか
  3. 2.でキャッシュが吹っ飛ぶ場合、Incremental SSG とは関係のない部分のコード変更でも吹っ飛ぶか

1. Incremental SSG + SPA 構成の作り方

普通にIncremental SSGにReact.Componentでできたコンポーネントを設置すればOK

gist.github.com

2021.01.31 追記

正式リリースのタイミングかいつかはわからないけど、 unstable_revalidate オプションは revalidate オプションに名前が変わっていた。
最新のバージョンだと上のコードは動かないので注意。

追記ここまで

components/loading がReact.Componentでできたコンポーネントやっていることは全然ローディングじゃないけど。
コンポーネントJavaScriptも含めてキャッシュされるのでそれがブラウザ上で実行される動き。

生成される静的ファイルは .next/server/static/development/pages に置いてある。
ローカルだとIncremental Static RegenerationはされないのでHTML, CSSファイルは無いので確認はできない。

2. Incremental SSG で生成されたCDN Cacheはコードをdeployし直したら吹っ飛ぶか

A. 吹っ飛ぶ

一応確認した。
デプロイのタイミングで .next/ も全部デプロイされたコードに置き換えられるが、そのタイミングでSmartCDNのキャッシュも全部Purgeされるっぽい。
まあそうじゃなかったら旧バージョンのものが残り続けることになるのでよろしくない。

3. 2. でキャッシュが吹っ飛ぶ場合、Incremental SSG とは関係のない部分のコード変更でも吹っ飛ぶか

A. 吹っ飛ぶ

差分デプロイになってたりしないかな?って思ったけど違った。そうだよね。


調査に使ったコードは以下のリポジトリにあります。

github.com

デプロイ先はこっち
https://isr-and-spa-test-h9i09bkq9.now.sh/mag/1

実用を考えた際の課題

記事の更新をフックにその記事のキャッシュを消す、といった動作が現状できない

https://vercel.com/docs/v2/edge-network/frequently-asked-questionsvercel.com

所謂CloudflareでいうCustom Purgeの機能がなさそう。

How do I use Cloudflare over your CDN (disable it)?) の欄があるし、CDNをVercelじゃなくてCloudflareにすればいいのかも。でもそれだとIncremental SSGの意味が無いような。

デプロイ直後にサーバの負荷が跳ね上がる

デプロイと同時にキャッシュが飛ぶので、その後のリクエストがURLに一回ずつ全部サーバまで飛んでくるようになる。
SSRだとキャッシュされずに全部飛んでくるのでそれと比べたらだいぶ少ないけど。
キャッシュされていることを前提にサーバの台数を減らしていたりすると、デプロイするたびに負荷が上がって大変なことになる。

そういう意味で、デプロイが差分でできたりすると良いなと思った次第。まあこれは難しいよなあ


tech.smartcamp.co.jp

インフラレイヤにあんまり力を入れたくはないけど実現できることは増やしたいので、VercelのFrontend All-inっぽい作りはめちゃくちゃ好き。
なんか貢献できないかな、zeit/next.js のissueとかPRをもうちょっと読んでみようと思いました。

やりたいこと自体はCloudflare + Nuxt.js Universal Mode(をどっかに置く) でできるんだけど、こう、楽したい。