View more

モダンフレームワークと呼ばれているNext.jsですが、現在では標準的に採択されることが多くなってきています。Next.jsでは様々なレンダリング手法があり、それぞれの得意、不得意、どういったコンテンツや運用に適しているかをまとめました。
Next.jsのレンダリング別用途

Next.jsのレンダリング

フロントエンドを取り巻く環境は目まぐるしく変化していますが、昨今はJSで構築する際、Reactはスタンダードな選択肢となっています。

中でも、ReactベースのフレームワークであるNext.jsは世界的に見ても多くの人が利用しており、エンジニアとしても標準で扱えることが求められてきているなと感じています。

そのNext.jsですが、Reactベースの成果物を包括的に開発、構築できるだけでなく、様々なレンダリング手法が用意されています。数あるレンダリング手法がサイト制作においてのメリット、デメリット、どういう内容に適しているか?を調査、まとめてみることにしました。

レンダリング別簡易対応表

  SPA SSG SSR ISR On-demand ISR
手軽さ
表示速度
運用・更新制の高さ
SEO
規模感

対応サーバー
(ホスティングサービス有無)

※上の表は2024年7月現在の所感です。今後技術の発展で変わっていく可能性はあります。

レンダリング別の実現方法(App Router)

Next.jsには様々なレンダリング手法があります。それぞれのレンダリング手法にはメリット、デメリットが様々あり、それぞれがどのようなコンテンツに向いているか、特長があります。

それぞれの特性から何に向いている、向いてないを、実践も交えて見えてきたものをまとめました。

 

Next.jsのApp Routerについて

Next.js 13.0以降からApp Routerが実装されました。従来のPages Routerと比較し大きくディレクトリ構造が変更となり、各ページの配置はpagesからappになりました。

また、これを境にサーバーコンポーネント(サーバー側でHTMLを構築して返す)がデフォルトになり、より強化されています。

fecthの機能も強化され、コンポーネント間のデータの受け渡し(いわゆるバケツリレー)が不要になりました。また、サーバーサイドでfetch→レンダリングまでを担えるようになっています。

他にもそれに伴い、廃止になった、新しく置き換えられた関数や機能等もあるため、比較的大きなアップデートになります。

先述の通りデフォルトでサーバーコンポーネントとしてレンダリングするようになり、従来よりもサーバーサイドを活かした構築が可能になっています。

まず、それぞれのレンダリング方式を解説します。

引用元:Next.js: The Ultimate Cheat Sheet To Page Rendering

CSR(Client Side Rendering)

クライアントサイドレンダリングで、ビルドしたファイルをWebサーバー等に設置し、ブラウザ側のJavascriptで処理をします。

SPA(Single Page Application)

単一のhtmlでビルドし、配信する方法です。

メリット

サーバーサイドで処理を行わずに静的に動作するので環境を選びません。AWS S3など、Webサイトが公開できるようなストレージでも動作します。

デメリット

クライアントサイドで全てレンダリングするため、ファイルの読み込み、レンダリングしてすべて表示するまでに時間がかかります。

レンダリング特性上、SEOで不利とされることが多いです。SPAはDOMの殆どをJavascirptによって構築するため、クローラーが理解できないというものです。特にURLがハッシュなどでわけられている場合は、ひとつのページとして判別することができません。 また、コアウェブバイタルの観点からも、初期の読み込みが遅いことはSEO上不利になると考えられます。

以前SPAのSEO対策として挙げられていたダイナミックレンダリング手法も、現在ではGoogleでは非推奨となっているようです。

※SPAを作る際、多くの場合は、Next.jsは過剰かもしれません。もっとミニマム構成で構築するのがベストと考えます(詳しくは割愛しますが、vite+Reactとかが候補としてあげられます)

SSG(Static Site Generation)

各ページをルーティングなどの設定に応じて静的なページ(html)をビルドし、配信する方法です。

メリット

SPA同様、静的に生成されたファイルを配置する方法になるので、HTMLが配信できるサーバーであれば公開ができます。

また、SPAと違い、あらかじめコンテンツとしてビルドしたHTMLを配置するため、SEO上不利とされていたクローラーのコンテンツ理解については解消されます。

デメリット

静的に生成されているファイルのため、何かを更新する際には都度ビルドする必要があります。

また、サイト全体としてはSPAのような振る舞いになるので、初期の読み込みは多少重くなりがちです。

(クライアントサイドでJSがレンダリングする領域はSPAと比べて少ないので、全ページ用に一括でビルドしたJSファイルのファイル読み込みが多少ネックポイントになります。)

SSG(Static Site Generation)

各ページをルーティングなどの設定に応じて静的なページ(html)をビルドし、配信する方法です。

メリット

SPA同様、静的に生成されたファイルを配置する方法になるので、HTMLが配信できるサーバーであれば公開ができます。

また、SPAと違い、あらかじめコンテンツとしてビルドしたHTMLを配置するため、SEO上不利とされていたクローラーのコンテンツ理解については解消されます。

デメリット

静的に生成されているファイルのため、何かを更新する際には都度ビルドする必要があります。

また、サイト全体としてはSPAのような振る舞いになるので、初期の読み込みは多少重くなりがちです。

(クライアントサイドでJSがレンダリングする領域はSPAと比べて少ないので、全ページ用に一括でビルドしたJSファイルのファイル読み込みが多少ネックポイントになります。)

SSR(Server Side Rendering)

メリット

サーバー側でレンダリングしたものを返します。 リクエストに応じて動的にページを生成するため常に最新の状態を保つことができます。

SEO的にも◯です。

デメリット

配信用サーバーの用意、もしくはNode.js環境の構築が必要です。

Next.jsをSSRで簡単に配信できるサービスはいくつかあるため、そのサービスを用いることで解決することが多いです。(Vercel、Amplifyなど)

SSR配信用に用意する必要があるため、もともと運用している既存サーバーでは動かせない、準備が必要など状況によっては別途ランディングコストがかかるケースがあります。

リクエストに対して、つど最新の状態のものを返すようにするので処理をするサーバーへの負荷がかかります。

ISR(Incremental Static Regeneration)

サーバーサイドでビルド、キャッシュを生成しキャッシュを返すような仕組みです。

キャッシュ値は固定秒数で指定でき、その秒数を過ぎてアクセスされたタイミングでキャッシュを再生成します。SSRとSSGのハイブリットのような仕組みです。

メリット

あらかじめ生成しておいたキャッシュを返すため、サーバーの負荷を低くかつ早いレスポンスで返すことができます。SSRに近い状態になるためSSRのメリットを活かしつつ、更に発展した仕組みであると言えます。

SSGのようにヘッドレス化しているCMSを更新したら再ビルドの必要がなく、運用コストが下がります。

デメリット

キャッシュの更新が技術的に少し癖があります。また、秒数指定となるので、常に最新というわけではないことに注意です。

※設定値を短くすれば高頻度で更新を書けることが可能ですが、その分ISRのメリットが薄まってしまいます。

また、キャッシュパージのタイミングで閲覧したユーザーはサーバーから再生成したものが返されるため、表示が遅くなってしまうおそれがあります。

SSR同様、専用の配信環境が必要なのと、ISRの技術に対応した配信サービスが少ないです。(Vercelは完全対応。Amplify、cloudflareも可)

on-demand ISR

ISRのキャッシュパージを手動でできるようにしたISRの発展形です。

メリット

任意のタイミングでキャッシュをパージすることができます。

ISR間隔は大きくしておき、コンテンツを更新をするタイミングでキャッシュをパージし更新するといったことが可能です。

コンテンツ更新者が更新→キャッシュパージ→キャッシュ再生成までを行えばユーザー側は常に最速で最新のコンテンツが見れる状態にできます。

デメリット

仕組みとしては存在するものの、完全対応している環境が現状vercelのみで、選択肢の範囲が狭いです。

Next.jsでそれぞれのレンダリングに必要な設定

各レンダリングには下記のような設定が必要です。

SSG

// next.config.js

  const nextConfig = {
    output: "export",
  };

SSR

  • fetchで指定する場合
// 各page.tsxなど

fetch('http://localhost:3000/api/blog',{ cache: 'no-store' })
  • pageやcomponentに指定する場合
// 各page.tsxなど

export const dynamic = 'force-dynamic'

ISR

  • fetchで指定する場合
// 各page.tsxなど

fetch('http://localhost:3000/...', { next: { revalidate: 3600 } })

fetch時にrevalidateを秒数で指定します。上記だと3600秒=60分になります。

 

  • pageやcomponentに指定する場合
// 各page.tsxなど

export const revalidate = 3600;

revalidateをexportします。単位はfetch時と同様です。

On-demand ISR

ISRの設定をしつつ、リクエストすればキャッシュパージできるページないしAPIエンドポイントをNext.jsで作成します。
ヘッドレスCMS等カスタムフックでそのURLを叩くと、強制的にキャッシュパージされるような仕組みです。apiを作成するにはAPI Routesを使います。

// app/api/perge/route.ts

import { NextResponse } from 'next/server';
import { revalidateTag, revalidatePath } from 'next/cache';

export async function GET() {
  revalidatePath('/hoge/');  // 特定のページRouteに対してキャッシュをパージ。
  revalidateTag('posts');  // fetch時に特定のタグ付けをしたデータに対してキャッシュをパージ。
  return NextResponse.json({ message: 'revalidate /ond & posts' });
}

ヘッドレスCMS等カスタムフックに登録して、トリガーしたら上記で作成したAPIにリクエストするように設定すれば、CMSから任意のタイミングでキャッシュをパージ(最新化)できる。

余談:プレビュー時の注意点

devモードでは常にSSRのような振る舞いをするため、SSGやISRのレンダリング検証をローカルでしたい場合は、一度ビルドする必要があります。

コンテンツ種別でレンダリング方法を検討してみる

コンテンツ種別でレンダリング方法を検討してみる

どういうコンテンツにそれぞれのレンダリング方法が最適なのか、考えてみます。

CMSでコンテンツ管理していて更新頻度が比較的多い

レンダリングの特性から見るとOn-demand ISR・ISRが最良の選択肢です。

記事を更新したときにビルドする必要がないのと、キャッシュの仕組みを利用しているため、ほぼ最新の状態を保ちつつ、静的に近い配信が可能なためです。

ただ、Nodeサーバー環境の構築が必要だったり、対応するサービスが少ないため、インフラの選択肢が狭いことは懸念として挙げられます。

SSRは常に最新の状態を保ちつつ記事更新にビルドも必要ないですが、常にサーバーサイドでレンダリングして返すため、応答速度やサーバー負荷に弱点があると考えています。

SSGの場合、記事を更新する度にビルドをする必要があるため、運用手順に少し手間がかかるのと、コンテンツが大きくなってきた場合、都度ビルドをするために時間を要してしまうデメリットがあります。ただ、静的なホスティングサーバーにも配信可能なため、配信環境の選択肢はグッと広がるほか、インフラのコストは抑えられる傾向です。

※いずれの場合でも、Next.jsのプロジェクトそのもののソースコードを変更した場合、再度ビルドが必要なのはご留意ください

ログインシステムがあり、CMSのような機能を提供する場合

認証、ログイン必要ページで想定される操作(フォーム入力による送信、その内容を即時に表示する)からSPA、もしくはSSRである必要があります。

それ以外の方法では仕組み的にそもそも実現が難しい場合や、不都合が多いです。

Next.jsで作る場合、認証システムはNextAuth.jsが使え、手軽かつセキュアな認証ページが実装できます。

会員専用サイトのような場合

閲覧に会員のみの制限を設ける目的でのログイン認証であればSSG、ISR等でも実現可能です。

記事や商品などを検索をしたり、常にリアルタイムな情報を求める

CMS、サービス等で管理している情報の更新を即座に反映したい場合もSSRが適しています。また、任意のタイミングでキャッシュをパージできる仕組みであるOn-demand ISRの選択肢もあります。ただ、On-demand ISRの場合は、更新都度キャッシュパージの操作が必要となってしまうため、かなりの頻度で更新が見込まれる場合、SSRのほうが良い選択肢となりそうです。

更新頻度はそれほどでもないが、CMSを使った管理をしたい

更新頻度が多くなければ、更新都度ビルドすることも許容できれば、SSGが最適です。

更新時にwebhookで自動デプロイする仕組みを設けておけば、少ないラグで更新、運用ができます。

情報閲覧が目的、インナーサイト

内部公開で情報閲覧目的、SEOも必要なくある程度表示速度等も譲歩できるのであれば、SPAがローコストで実現できます。

ただ、この場合、Next.jsを使う必要はもしかしたらないかもしれないため、Vite+React.jsを使うなどのもっとミニマムな構成で良いかもしれません。

 

そもそもJSフレームワークでないほうがいい場合もある

CMSを伴わない小規模かつ静的なページ

小さいLPのようなページにNext.jsのようなフレームワークを使うのはオーバーです。SPA構成か、静的に実装してしまったほうが早いでしょう。

長期的にサービス運用を想定している場合

JSフレームワークを使ったデプロイを行う場合、どうしてもサービスやJavascriptランタイム環境がついて回ります。

包括的に考えて、もしかしたらWPやMTのほうが要件、条件的に合致する可能性もあります。

Javascriptランタイム(Node.js)の更新サイクルについて

Node.jsは更新サイクルが早く、だいたい2年前後で、現在利用しているNode.jsのバージョンが利用しているホスティングサービスによってはサポートしなくなる可能性があります。ソースコードを変える度にビルドしなくてはいけない関係上、Node.jsのバージョンがサポートしなくなったタイミングでビルドができなくなる、といった場面に遭遇し、バージョンアップメンテナンスを余儀なくされます。また、利用しているフレームワーク等のバージョンが古いと、Node.jsのバージョンアップに耐えられず、フレームワークのバージョン移行作業などが必要になる場合があります。

後に想定していなかった思わぬ工数が発生しうる可能性があるため、長期で運用する場合は、バージョンメンテナンスも視野に入れた選定が重要です。

対してPHPは、下位バージョンでもセキュリティメンテナンスをやっているケースや、レンタルサーバーでは独自に脆弱性のフォローなどしており、比較的長めに使い続けることができます。

後のメンテナンスを考慮しない(作りきって終わり)場合は、WPなどで作ってしまったほうが良いかもしれません。

サーバー環境や構成にもよる

vercelやcloudflare、amplifyなどのホスティングサービスはNode.jsのリリースサイクルに乗っていくので、サイクルが早い傾向です。

スクラッチでホスティング環境も作ってしまえば任意のタイミングで行うことはできるので、サービスのリリースタイミングに合わせて慌てて変えるなどのケースに悩まされることはなくなりますが、だからといってバージョンアップを怠ってしまうと、アプリケーションを脆弱性にさらすことになります。

特にSSR、ISRなどの場合は、常にサーバーサイドで処理されるため注意が必要です。

SSGのように、ビルドしたHTMLを配信するだけの場合は、ビルド環境だけをスクラッチで用意して外部からはアクセスできないような状態にしておけばバージョンメンテナンスしなくても良くなるため、この場合であれば最良の選択肢となるかもしれません。

まとめ

Next.jsで実現できる各レンダリング手法についてまとめました。アプリケーションとしてBESTを目指せれば最高ですが、開発の手間、予算、開発後の運用などすべてを包括してどういう選択肢が最もベターなのか、が非常に重要と考えています。

今回はNext.jsで実現できる各レンダリング手法がそれぞれどういうアプリケーション、コンテンツに適しているかを例にしましたが、要件次第ではシンプルでレガシーなシステムを組んだほうが要件に合致している、お客様に喜ばれるケースもあると思います。

エンジニアの欲求的にはなるべく開発体験が良く、モダンで、イケていて、素晴らしいアプリケーションを作りたい、と常々思いますが、利用する側からすればそれがベストかどうかはしっかりと考えていかなくてはならない部分です。

これらの情報が、最適な技術選定をするための一助となれば幸いです。