【初学者向け】Next.jsのSSR/SG(SSG)/CSRに関する基礎知識

JavaScript

『SSR(Server-side Rendering)はサーバサイドでHTMLを生成する仕組み』『SG(Static Generation)は事前に生成した静的なHTMLを配信する仕組み』『CSR(Client-side Rendering)はクライアントサイドでUIを構築する仕組み』と定義し、Next.jsにおけるSSR/SG/CSRに関する基礎知識について紹介します。

いわゆる『SSG』はNext.jsでは『SG』と略される

『静的なHTMLファイルを事前に生成する仕組み』はStatic Site Generation(SSG)という呼び名で広く知られています。

しかし、Next.jsにおける静的ファイルの事前生成の役割は静的なサイトを用意するためではなく、あくまで静的なファイルを返すためです。ですので、Next.jsの公式ドキュメントではStatic Generation(SG)と呼んでいます。1

Next.jsの記事でSGの略語を見たら「いわゆるSSGのことをいってるんだな」と思っておくとよいです。

Next.jsのページレンダリングのデフォルトはSSRもしくはSG

Next.jsのページのレンダリングはデフォルトでPre-rendering、つまりSSR(Server-side Rendering)もしくはSG(Static Generation)です。2

Next.jsはページ単位でSSR/SGを決められる

SSRとSGのどちらを採用するかはページ単位で選択可能です。3 1
ですので、Next.jsではSGのページとSSRのページが組み合わさったアプリケーションの構築ができます。

開発モードの場合、SGはSSRになる

Next.jsは開発モード(npm run devあるいはyarn dev)で起動する場合、SGの画面もSSR(Server-side Rendering)となります。1

Next.jsのルータ機能による画面遷移ではCSRで画面が作成される

Next.jsのルータ機能にはnext/linknext/routerがあります。

例えばnext/linkでSSRのページに遷移した場合、サーバサイドからはHTMLではなくレンダリングに必要なPropsがJSON形式で返されます。その後クライアントサイドでレンダリングを行います。

next/linkを利用した画面遷移の流れを図で表現すると以下のようになります。

next/linkの流れの詳細は【Next.js】next/linkの画面遷移(CSR)から画面反映までの流れの図解解説で解説しています。

SSR/SGのページでブラウザの機能を利用する場合は副作用を活用する

副作用とは「JSXあるいはTSXからUIを構築する処理」以外に関する処理のことをいいます。

副作用の実行は、関数コンポーネントであれば副作用フックと呼ばれるuseEffectuseSWR、クラスコンポーネントであればcomponentDidMountcomponentDidUpdatecomponentWillUnmountで行います。

サーバサイドではブラウザの機能は利用できないので、SSR/SGのページでCookieやWindow関数などを利用したい場合は副作用で実行する必要があります。詳細解説は【Next.js】SSR/SGでブラウザ機能(Cookieなど)を活用する際の注意点で紹介しています。

Next.jsのSSR/SGのページではCSRも実行される

Next.jsではPre-renderingによって生成されたHTMLにはページに必要なJavaScriptが関連付けられています。
ページがブラウザに読み込まれるとCSRによってJavaScriptが実行され、ページがインタラクティブ(操作可能)になります。4
HTMLに付随したJavaScriptを利用してインタラクティブなページを生成するCSRの過程をHydrationと呼びます。

Next.jsのSSRの過程を図で表現すると以下のようになります。

Next.jsのSSRの詳細解説は【図解】Next.jsのSSRが画面反映されるまでの具体的な流れで紹介しています。

CSRではイベントリスナの登録に加え、サーバサイドとクライアントサイドそれぞれで生成されたレンダリング結果を比較します。
結果が一致する場合はCSRによる再レンダリングをスキップ、不一致の場合は再レンダリングをします。

レンダリング結果の不一致はパフォーマンス低下やデザイン崩れの原因となります。
レンダリング結果が一致しない場合はReactアプリケーションが警告をしてくれるので修正するようにしましょう。

さいごに

Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!