SSR? SG? Next.jsのページ生成方式はどれを選べばいい?
この記事は書籍、出来る100%TypeScript 作って学ぶNext.js + GraphQL + Prismaの第2章内のコラムです。
Next.jsはパフォーマンスに優れたSG(事前の静的生成)を第一選択として推奨していますが、対象となるページの特性によっては必ずしもSGが採用できるわけではありません。しかし複数の方式をページ単位で切り替えられるのもNext.jsの強みの一つです。
SSR(Server side Rendering)
旧来のWordPressのようなCMSやRuby on Rails等で作られた一般的なWebサービスの多くもこれに該当し、Next.jsにおいてはgetServerSidePropsを利用したページがこれに該当します。ブラウザからのリクエストを受けたサーバーがその都度リクエスト内容に応じたHTMLを動的に生成してブラウザへ返すという仕組みです。ただしSSRの場合でもユーザーの操作に応じて部分的にCSR(後述)を行ったり、CDN等を経由した配信ではSGと動作モデルが似るなど、画一的に分類できるわけではありません。
Next.jsの魅力の一つは「SSRはERB(Ruby)だけどCSRはjQuery(JavaScript)」のようにそれぞれ異なる言語で二重管理されていたViewをどちらも同じ言語(JavaScript)の同じViewライブラリ(React)で統一できるという点で、この形態はUniversal/Isomorphic JavaScriptと呼ばれる事があります。なお本書では扱いませんが、逆にサーバーサイド言語へViewを一本化するLivewireやHotWireのようなアプローチもあります。
CSR(Client side Rendering)
コンテンツ更新頻度の極端に高いチャットアプリケーションや複雑でインタラクティブなUIを持ったアプリケーション色の強いサービスなどで採用される事が多い、よりネイティブアプリケーションに近い動作モデルの方式です。サーバーサイドから完成済のHTMLをブラウザが受け取るのではなく、JSON等の形式でデータを受け取ったブラウザがクライアントサイドでページ全体、あるいは一部のパーツについてHTMLを組み立てます。
Next.jsにおいてSSRと組み合わせる場合は、サーバーサイドでReactによって生成されたHTMLをブラウザが受け取った後、ハイドレーションと呼ばれるクライアントサイドでの初期化作業が行われます。これによってReactアプリケーションとしてシームレスにクライアントサイドからも操作が可能になります。
なお純粋にCSRのみで構成されたアプリケーションはSPA(Single Page Application)と呼ばれる事もあります。SPAの場合JavaScriptが動作しないとページとして機能しないためJavaScriptが十分にサポートされていないクライアント、例えばOGPタグを取得しに来たクローラーやBOT等が機能しない事があります。また完成品のHTMLを(場合によってはCDNのような共有キャッシュから)受け取るSSRに対してCore Web VitalsのLCP等で不利になりやすいという側面もあります。そういった要件のない管理画面など、認証を必要とするアプリケーションもまたSPA向きだと言えるでしょう。
SG(Static Generation)
旧来のMovable TypeのようなCMSやJekyll等もこれに該当し、Next.jsにおいてはgetStaticPropsやgetStaticPathsを利用したページがこれに該当します。サーバーサイドでHTMLを組み立てるという点ではSSRと同一ですが、ブラウザからリクエストがあったタイミングではなくビルドと呼ばれる作業で事前にページを静的なファイルとして生成してから配信するため、配信自体には複雑な仕組みを必要とせず高速で安全な配信を実現しやすいという特長があります。SGによって生成される静的ファイルをキャッシュの一種だと見做すなら、SGはCDNやVarnishのようなHTTPアクセラレータの親戚だとも言えるでしょう。
SG単独では更新頻度の高いページや、性質上事前生成が難しいページ(例えばログインしたユーザーにのみ表示されるカスタマイズされたページ、検索条件と並び順の組合せで爆発的にページ数が増える検索結果ページ、ユーザーの入力に対してインタラクティブに結果を返す入力フォームのページなど)に対応できないため、CSR等と組み合わせて利用される事もあります。
ISG(Incremental Static Generation)
10万件の商品を持ったECサイトで素直にSGする場合、10万件の商品ページを一度に生成しようとして莫大なビルド時間がかかってしまいます。この問題を解決するためNext.jsではそのページが必要になったタイミングで徐々にページ生成をする事ができます。具体的にはgetStaticPathsの返り値でfallbackオプションをblockingやtrueにする事で利用できます。
これはSSRとSGの中間形態のような動作イメージで、対象ページの初回リクエスト時にビルドが走りそれ以降のリクエストではビルドされた静的ファイルが利用されます。fallback: 'blocking'
の場合はこの初回ビルドが全て完了してからブラウザにHTMLを返し、fallback: true
の場合はブラウザに一旦仮のページを返してからビルドを進める動作になります。例えば重たい外部APIに依存していて長いビルド時間が必要なページであれば、fallback: true
にして仮のページとしてSkeleton Screenを返すのも良いでしょう。
ISR(Incremental Static Regeneration)
SGやISGによって一度生成された静的ページを徐々に最新の内容へ更新するNext.jsの機能で、具体的にはgetStaticPropsの返り値でrevalidateに秒数を指定する事でSWR(stale-while-revalidate)方式での再生成をする事ができます。SWR方式については第4章のコラムで詳しく触れます。
Discussion