Next.js + microCMSでトップページの記事一覧が更新されない原因はISRだった

現在、ambientworks のトップページには最新のブログ記事を3件表示しています。
ところがmicroCMS に新しい記事を公開しても、本番環境のトップページだけ更新されないという現象に遭遇しました。
ブログ一覧ページでは最新の記事が表示されているのに、トップページだけ古いままです。
localhost環境では再現せず、本番環境だけで発生していたため、最初はキャッシュ周りを疑いました。
症状
トップページでは以下のようにブログ記事を取得しています。
export default async function Blog() {
const { contents: blogs } = await getBlogs();
return <BlogList blogs={blogs} limit={3} />;
}
ブログ一覧ページは次のように実装していました。
export const revalidate = 60;
この状態では、ブログ一覧ページは最新取得後60秒経過後には、また最新の記事を取得する流れになります。
しかしトップページには何も設定していなかったため、ビルド時に生成された内容が表示され続けていたようです。
最初に勘違いしたこと
原因を調べる中で、ブログ一覧を表示しているコンポーネントに次のコードを書いてみました。
export const revalidate = 60;
しかし状況は変わりません。
後から知ったのですが、revalidate は React コンポーネントではなく、Route Segment に対して指定するものです。
つまり、
src/components/sections/home/WeblogPreview.tsx
ではなく、
src/app/page.tsx
に書かなければ意味がありません。
解決方法
トップページの page.tsx に以下を追加しました。
export const revalidate = 60;
これだけです。
export const revalidate = 60;
export default async function Home() {
...
}
デプロイ後、microCMS に記事を追加して確認すると、トップページも正常に更新されるようになりました。
revalidate = 60 の意味
最初は「60秒ごとに自動更新される」と思っていました。
実際は少し違います。
初回アクセス
↓
ページ生成
↓
60秒キャッシュ
60秒以内
↓
キャッシュを返す
60秒経過後の次のアクセス
↓
再生成
という仕組みです。
そのため、ページを開きっぱなしにしていても自動で更新されるわけではありません。
更新内容を確認するにはリロードが必要です。
dynamic = 'force-dynamic' との違い
force-dynamic を使うと、アクセスのたびにサーバーで処理が実行されます。
export const dynamic = 'force-dynamic';
一方で ISR を使う場合は、
export const revalidate = 60;
とします。
毎回必要になるほどのタイムリーさは求めていないので、個人サイトであれば ISR の方がバランスが良く時限付き更新頻度のコントロールが良きと判断しました。
学んだこと
今回の件で理解できたのは次の3点です。
revalidateは Route Segment に設定する- React コンポーネントに書いても効果はない
- ISR は「一定時間後の次回アクセスで再生成」する仕組み
Next.js App Router を触り始めた頃は、どこに設定を書くべきか分かりにくく感じました。
ですが仕組みを理解すると、静的生成と動的生成を細かく使い分けられるのは非常に便利です。
※ 静的生成と動的生成の境界線・サーバーサイドとフロントサイドの境界線が分かりづらいのは習熟度がまだ低いからなのかしらと思う今日この頃です。