【Next.js】CSR,SSG,SSR,ISRがあやふやな人へざっくり解説する

3 min read読了の目安(約3100字 1

前書き

仕事でNext.jsを書いているのですがSSG SSR ISRらへんの知識があやふやだったので噛み砕いて解説してみました。間違っているところなどあれば、ご指摘していただけるとありがたいです🙇‍♂️

以下、本題です。

それぞれの基本的な解説

CSR(クライアントサイドレンダリング)

クライアントサイド レンダリング(CSR)は JavaScriptを使用し、直接ブラウザでページをレンダリングすることを意味します。すべてのロジック、データフェッチ、テンプレーティングやルーティングは、サーバーではなくクライアント上で扱われます。

引用元

つまりサーバーではなく、(JavaScriptによって)ブラウザ側でレンダリングする方法です。しかしCSR(クライアントサイドレンダリング)は大きいアプリケーションの場合、クライアントで処理するJavascriptの量も増えますよね。これに伴い、ユーザーにページを表示させるのが遅くなってしまいます。(ユーザーのデバイススペックに依存してしまう)

上記の問題を解決するために、SSR(サーバーサイドレンダリング)が出てきます。

SSR(サーバーサイドレンダリング)

CSR(クライアントサイドレンダリング)のようにロジックやデータフェッチをブラウザで行うのではなく、サーバー側で処理(データフェッチ等を)し、HTMLを構築してクライアント側に返す方式です。 この方法ではCSR(クライアントサイドレンダリング)のようにクライアント(ユーザーデバイス)のスペックに依存せず、ハイスペックなサーバーでHTMLを構築することができます。

とはいえリクエストごとにサーバーで処理し、HTMLが構築されるため、ユーザーを待たせる時間が長くなってしまいます。そこで、SSGが出てきます。

SSG(静的サイトジェネレーション)

SSRの問題(CSRもですが)として、ユーザーのリクエストを受けてからHTMLを構築するので、時間がかかってしまう、という課題がありました。これを解決してくれるのがSSG(静的サイトジェネレーション)です。

SSG(静的サイトジェネレーション)はビルド時にHTMLを構築しておきます。この時、外部APIからのデータフェッチも行います。そしてユーザーからリクエストされた時に事前に構築してあるHTMLを表示します。また、アプリケーションサーバーからHTMLを返すのではなく、CDNにキャッシュしておくことでユーザーに対して高速にページを表示することができます。こうすることにより、SSRよりもユーザーに対して高速にページを表示させることができます。

しかし、またもや問題が出てきます。しかも今回は二つ。

一つ目は、ビルド時に大量のデータを取ってくることは現実的ではありません。例えば、アマゾンのように巨大なECサイトの場合、ビルド時に全てのデータを取ってきて、HTMLを構築することは難しいでしょう。

この問題はフォールバックが解決してくれます。

二つ目は、リソースの更新が頻繁な場合は、どうなるでしょうか?例えば、ツイッターみたいに複数人がコンテンツを更新するような場合(更新が激しい場合)は、このままのSSGでは情報を表示させることができません。だってビルド時しかデータフェッチしていないのだから。

この問題を解決するために ISRが使われます。

それぞれ解説していきます。

フォールバック

export async function getStaticPaths() {
  return {
    paths: [
      // 省略
    ],
    //ここ!!
    fallback: true
  }
}

getStaticPaths()関数内のfallbackが確認できるかと思います。この値がfalseの場合、存在しないページにアクセスした時に404ページに飛ばされます。trueにした場合、データフェッチしていない状態のHTMLが返され、その後ブラウザ側でデータフェッチが行われて、HTMLが再構築されます。

同時にサーバー側でも同様にデータフェッチが行われ、HTMLの構築が行われます。次回以降のリクエストでは、サーバー側から完全なHTML(データも含まれた)が返されます。

とはいえ、非完全な状態のHTML(データが含まれていない)でクライアントに送られてしまうので、この部分が欠点ですね。この点も解決できます。

blocking

export async function getStaticPaths() {
  return {
    paths: [
      // 省略
    ],
    //ここ!!
    fallback: 'blocking'
  }
}

fallbackの値にblockingを入れることで、データが取得されていないページにアクセスした時、サーバーから不完全な状態でHTMLが送られるなんてことはなく、データフェッチが行われてからHTMLが構築され、クライアント側にHTMLが送られます。

ISR(Incremental Static Regeneration)

export async function getStaticProps(hoge) {
  return {
    props: { hoge },
    revalidate: 10, // ここを追加
  }
}

getStaticProps()関数のreturn内にrevalidateの値として任意の数字を入れてください。**その秒数以降にリクエストがきた時に、サーバー側でデータフェッチを再度行い、HTMLを再構築します。**ここでポイントになってくるのが、リクエストしたユーザーにはキャッシュしていたHTMLを返すということです。

一定期間ごとにサーバーサイドレンダリングを行うことで、高速なページ描画を実現しています。こうすることにより、表示されるデータの更新頻度が高くても新しいデータが表示されるようになりました。

とはいえ、ISRは常に最新のものがユーザーに届けられるわけではありません。(最初のリクエスト時にはキャッシュされたHTMLが返されるので。)使い分けとしては下記のようなイメージで良いと思います。

  • リクエスト時に最新の情報でなくても良い:ISR
  • リクエスト時に最新の情報が出てほしい:SSRかCSR(SWRを使った)

以上です🙇‍♂️

参考記事