やっとわかる!Next.js App Routerのcacheにおけるrevalidateと苦戦した話
こんにちは。ココナラテックエージェントの開発をしているエンジニアのみんです。
新技術が常に登場しているフロントエンドの開発で、時代の波に乗り、キャッチアップすることが我々エンジニアの使命です。
ココナラテックエージェントのフロントエンドは Next.js アプリケーションです。2023年の9月から、App Router
への移行を始めています。
つい9月末に、ココナラテックエージェントの案件一覧ページをApp Router
に移行しました!
案件一覧と検索を含め、案件まわりのキャッシュ再検証(revalidate)の実装に全身全霊を注いだ成果をシェアしたくて、この記事を書きました。
App Routerのキャッシュ種類
Next.jsは、レンダリングの効率を上げるために、オプション指定がない場合に全てのリクエスト結果をキャッシュする方針です。
公式ドキュメントによると、App Routerのキャッシュは以下の4種類があります。
- Request Memoization
- Data Cache
- Full Route Cache
- Router Cache
Request Memoization
React自体の機能です。コンポーネントツリーから、url先とオプション設定が同様のリクエストは同一のリクエストとみなして一回だけリクエストします。
これを利用することで、複数リクエストが自動的に整理され、ルートコンポーネントでデータを一気にリクエストしてチャイルドコンポーネントにpropsを渡す構造を回避できます。
この種類のキャッシュはレンダリングだけに適用し、他のリクエストと共有されていないので、再検証の必要はないです。
Data Cache
fetch
API経由で取得したデータはキャッシュされてData Cache
と呼ばれます。
この種類のキャッシュは再リクエストしても、もしくはアプリケーションを再デプロイしても持続するので、リセットしたい場合は再検証をしなければなりません。
Full Route Cache
アプリケーションをビルドした時に、ルートのレンダリング結果がキャッシュされます。
この種類のキャッシュはアプリケーションを再デプロイしたら消えますが、強制再検証したい時はData Cache
を再検証するとリレンダリングされます。
Router Cache
クライアントサイドのキャッシュです。ページ遷移する度に目標ページ内のレイアウトとページコンポーネントをキャッシュし、キャッシュがない部分だけを更新してスムーズに遷移することができます。
この種類のキャッシュは、ページをリロード、もしくは5分ごとに自動的に再検証されますが、必要な時に強制再検証も適用できます。
再検証を実装
再検証は、以下の2種類に分けることができます。
- time-base revalidation
- on-demand revalidation
time-base revalidation
名前通りに時間間隔で再検証します。fetchする時にキャッシュの保存時間を指定します。
// キャッシュの保存時間を3600秒(1時間)に指定
fetch('https://...', { next: { revalidate: 3600 } })
保存時間が経過以後の一番目のリクエストは旧キャッシュで返しますが、新たなデータを更新して、2番目以降のリクエストは新たなキャッシュデータになります!
on-demand revalidation
時間間隔ではなく、再検証が必要な時にキャッシュデータをパージします。
- revalidatePath:
パスごと
で再検証 - revalidateTag:
タグごと
で再検証
適用する場面は2つあります。
- Server Actionで使います。(アプリケーション内の処理を対応、例えばフォームの保存か更新の処理が成功したら、相応のキャッシュデータをパージします)
- Route Handlerで使います。(アプリケーション外の処理を対応、エンドポイントを提供して、実行する時に相応のキャッシュデータをパージします。)
今度はRoute Handler
を採用して、ココナラテックエージェントのAPI側で案件が更新される度に、フロントエンドの案件再検証のエンドポイントを叩いて案件のキャッシュデータをパージします。
revalidatePathの使用例
import { revalidatePath } from 'next/cache'
// 特定のurlを再検証
revalidatePath('/blog/post-1')
// パスを再検証
revalidatePath('/blog/[slug]', 'page')
revalidateTagの使用例
fetch側の実装
Ln.45の実装で、fetchリクエストのオプションにキャッシュタグを指定します。
Route Handler側の実装
キャッシュタグを再検証します。
on-demand revalidationの実装上の注意点
Magic code doesn't always work, but engineers have to.
魔法のようなコードはいつもうまく効くわけではありませんが、エンジニアたちはやらなければなりません。By みん
on-demand revalidationの実装はrevalidatePath
、revalidateTag
コード一行だけで、一見かなりシンプルで魔法のようですが、実際にいくつかの罠にハマりました。
Vercelの使用者認証
ステージング環境で、社内メンバーを確認するため使用者認証をかけています。そのためキャッシュ再認証のリクエストが認可できず、401エラーになりました。
使用者認証を突破するため、再認証Route HandlerのHTTPメソッドをOPTION
にしました。
参考:Vercel Authentication Considerations
Next.jsを特定バージョンに上げないといけない可能性があります
下記の討論により、Next.jsのバージョンを13.5.4に上げないとrevalidateTag
がうまく動作しない可能性があります。
サイト機能をテストした上で、ココナラテックエージェントはNext.jsのバージョンを13.5.4に上げました!
既存キャッシュが残って一回パージしないといけないことがあり得ます
既存キャッシュがどうしてもリセットできない場合は、パージしかないです。
Vercelコンソールから、赤い「Purge Everything」ボタンを大胆に押しましょう。
最後に
日々進化しているココナラテックエージェントのサービス、小さい開発チームですが、新技術に挑戦できる環境です。
今回の話に興味を持っていただけた方は是非ご応募ください!
Discussion