大阪に生息しているプログラマーのブログ
普段、Next.jsを用いて開発を行っています。 Next.jsでは、さまざまなレンダリング方法の仕組みが提供されています。
しかしながら、なぜNext.jsがそんなにいろいろなレンダリング方法が存在しているのか、なんでそんなややこしいことになっているのか全然理解できていませんでした。
そのため、ひとつひとつのメリット・デメリットについて挙げながら、それぞれの関係性や用語について歴史的経緯を調べつつ、自分自身の理解を深めていくための記事です。
また、今回はコードで検証というよりは知識理解を前提としているため、基本的に文章や図オンリーです。ご了承ください。
間違い等ありましたらTwitter等で指摘いただけるとありがたいです。
まず初めにSPAから。
Single Page(1枚のページ)で構成されるアプリケーションのことを指します。
対義語とされているものに、MPA(Multi Page Application)があります。
もともと、SPAの登場以前はそれぞれのURLごとにサーバーサイドにアクセスし、返却されたHTMLを表示する、MVCフレームワーク(SpringやASP.NET MVC, Ruby on Railsなど)での開発が主流でした。
これらのフレームワークで開発されたアプリケーションは、ページ遷移時にサーバーに問い合わせて新たなHTMLを読み込むため、たびたびロード時間が発生してしまいます。
(厳密にはMVCフレームワークを用いてもSPAを開発することは可能です)
この「ページ遷移のたびに発生するロード時間」を短縮し、ユーザー体験を向上する目的でSPAでのアプリケーション開発が広まっていきました。
SPAはその名の通り、「Single PageのApplication」です。ユーザーがアプリケーションに初めてリクエストした際、ページレンダリングに必要な情報を全てレスポンスで返します。その後はページ遷移のためにサーバーサイドへアクセスすることなく、JavaScriptを用いて動的にコンテンツを更新していきます。そのため、SPAのアプリケーションはロード時間が非常に少なくなり、ユーザー体験が非常に向上します。
後述するCSRとSPAはしばし同義に扱われることもありますが、SPAはアプリケーションの種別であり、CSRはレンダリングの技術のため厳密には別物であると僕は考えています。
※ SPA=CSRとする記事もちらほらあるため、自分の認識はそうであるという主張に留めておきます。 主張の参考にさせていただいた記事たち
SPAを実現するためのレンダリング技術で、クライアント(ブラウザ)側でレンダリングを行う仕組みです。
ブラウザからリクエストが送られると、Webサーバはbody部が空のHTMLとCSS, JavaScript, その他諸々… を返します。
その後、クライアント側でJavaScriptを実行することで、HTML/CSSを生成します。
初回にページ全体に必要な要素を返却するため、初めの表示は重くなってしまいます。しかし、その後のページ遷移に関してはサーバー側に問い合わせてHTMLを作成するのではなく、APIから取得したデータをもとに差分のみをJavaScriptでレンダリングします。
これにより、ページ間遷移のロード時間が大幅に短縮されることでUXが向上し、よりインタラクティブ(対話的な)操作が可能になります。
その名の通り、サーバーサイドでレンダリングする技術。
ここで「サーバーサイドでレンダリング」とだけ聞くと、SPA以前のレンダリング方法と同じと思うところですが、SSRと呼ばれる場合ではCSRの弱点を補う形で用いられることが多いです。
初めに記載したMVCフレームワークでのレンダリング手法も、同じようにサーバーサイドに問い合わせ → HTMLを生成 → クライアント側にレスポンスとして返す。
という流れでした。方法としては同じことをしているようにも見えます。
この違いを理解するために調べた結果、以下のような記述を見つけたため引用します。
サーバーサイドレンダリング(SSR)とは、その名の通りサーバー側でアプリケーションの HTML を生成し、レスポンスとして返すことを言います。 一般的に利用されている MPA(Multiple Page Application)では言うまでもなく行われていることなので、SSR というワードは自ずと SPA(Single Page Application)を構築する際のオプション機能を指します。
違いとしては、SSRはSPAでのCSRの弱点を補う形で行われることが挙げられます。CSRを行った際の「初期表示が遅い」や「SEOに弱い」といった点、またはクライアント側に処理の負荷が偏ってしまう点を、事前にサーバーサイドでレンダリングしたHTMLを渡すことで解決しようというアプローチです。
今回記事を書くきっかけとなったNext.jsを用いた場合であれば、不足するデータがあったり、ユーザーの操作によってインタラクティブに変化するUIなどは引き続きCSRで行うこともできるため、SPA開発においては「CSR + SSR」というような選択肢が生まれ、より自由度が高まったのではないかと思います。
※ MPAのサーバーでのレンダリングはSR(Server Rendering)と区別する場合もあるようです。
※ SSRなどで生成したHTML(静的なページ)に対して、JavaScriptを実行することで動的なWebページにすることを「Hydration(ハイドレーション)」と呼びます。ハイドレーションとは水和や水分補給というような意味を持つ言葉で、静的になっているものを動的に戻す = 水を得る という連想でこのワードが使われているようです。
参考:TypeScriptとReact/Next.jsでつくる実践Webアプリケーション開発
日本語では「静的(Static)サイトジェネレーター」と呼びます。
前述のCSRやSSRと違って、こちらはビルド時にデータの取得などを全て行い、最終的に静的なHTMLファイルとして生成してしまう方法のことです。
ユーザーから実際にリクエストが来た場合、SSRであればリクエストに応じてHTMLファイルを生成してからレスポンスを返していました。しかし、SSGであればリクエストの前から事前にHTMLを生成しているため、ページアクセス時にはそれを返却するだけでよく、非常に高速なレスポンスが可能になります。
また、CSRのように動的にHTMLをクライアントで作成している訳ではなく、静的なHTMLのためSEOに対しても強くなります。高速かつ、SEOにも強い。一見最強に見えますがもちろん欠点もあります。
事前にサイトの中身を準備しているため、ビルドを実行しなければデータが更新されません。そのため、もし頻繁にデータの更新があるようなWebアプリケーションなどの場合、使い物にはなりません。
また、ページ数が非常に多くなった場合、「事前に全て生成する」という性質上非常にビルド時間が長くなってしまう、といった問題点もあります。そのため、ブログなどのような、ユーザーがデータの更新削除をする訳ではなく、管理者側でコンテンツの増減を行うサイトなどによく用いられます。
最後に、Next.jsを触り始めてからずっと謎の存在として認識していた、ISRについて記述していこうと思います。
日本語では「インクリメンタル静的再生成」と呼ばれます。言葉だけ聞いても意味があんまりわからないですね。
「インクリメンタル」は「段階的」のように訳されます。
ISRは前述したSSGの応用というべきレンダリング方法です。
具体的には、指定した一定の間隔でバックグラウンドでデータの再取得、再レンダリングを行います。
ISRは「Stale While Revalidation」というコンセプトがベースになっており、Next.js 9.5から導入されました。
Stale While Revalidationは「SWR」というReactライブラリでもお馴染みです。こちらもNext.jsと同じくVercelが中心となって開発しているライブラリです
実際にはどんな動きをするのか、図で見ていきます。
Next.jsでは、getStaticProps関数の中のrevalidateというキーに対して秒数を指定します。
以下の図では10分(600秒)を指定しました。
この時返されるのは、SSGの時と同じく「事前に生成されたHTMLファイル」です。
次の例では、10分後にまたクライアントからリクエストを送信した場合です。
この場合、リクエストに対するレスポンスは、ビルド時に生成された(キャッシュに保存された)HTMLファイルです。そして、バックグラウンドではサーバーが新たにデータのリクエストを行い、HTMLを再生成します。
そして、次回以降リクエストが行われた場合には、先ほど再生成したHTMLファイルがレスポンスで返却されます。SSGの「高速にレスポンスを返すことができる」という利点を生かしたまま、任意の時間で「段階的に」最新データの取得とHTMLの再生成を行うことで、ビルドしなければ最新データが反映されないという欠点を補っています。
ISRは静的生成のデメリットである情報の最新性を保ってくれますが、それでもリアルタイムなデータのやり取りを行わなければいけない場合などは問題点もあります。
こちら参考になりました。2020年時点のツイートのため、現在はもっと状況は変わっているかと思いますが、概要理解までに…。
※ 現在(Next.js 12.1以降)では、秒数指定ではなく任意のタイミングで再生成を行うようにできる 「On-Demand ISR」も提供されてます。こちらはまた別の記事で…。
CSR, SSR, SSG, ISRと3文字の略語がずらっと並ぶことで、初見ではウッとなってしまうレンダリングの方法ですが、それぞれの意義やメリット・デメリットを理解することで「何のためにこのレンダリング方法なのか」が明快になりました。
歴史的な背景とあわせて俯瞰してみると、常に何らかの問題があり、それを解消するために新しいアプローチが生まれ、改善を繰り返している。ということがレンダリングの方法ひとつにフォーカスを当てても感じ取れます。
このブログもNext.jsで作成しているため、どのようにすれば爆速になるのかをいろいろ試行錯誤していこうと思います。
今回はこんなところで!
めっちゃいろいろ見比べてたら多くなりました。
もっと公式Docから深く読み取れるように精進…!
ChatGPTくんにもいろいろ聞きました。Thanks!