アジャイル開発でのレンダリング戦略について
こんにちは、Tanzu LabsのソフトウェアエンジニアのAtsuhiroです。
アジャイル開発では、常に変化へ迅速に対応しながらアプリケーションを素早く開発することが求められます。このような環境では、適切な技術選択が非常に重要です。
今回は、Reactのレンダリング戦略に焦点を当て、初期開発からスケールフェーズに至るまでの最適な選択肢について考察します。
レンダリング戦略はユーザー体験、パフォーマンス、開発速度に大きな影響を与えます。技術選択はプロジェクトのフェーズや規模、チームのスキルセットによって異なりますが、重要なのは変化に柔軟に対応できる戦略を採用することだと考えます。
また、今回ご紹介する内容はあくまで私の体験に基づいた考察ですので、必ずしも正しいとは限りません。あくまで参考程度に捉えていただければ幸いです。
それでは、具体的な技術選択とその理由について、順を追って見ていきましょう。
レンダリング戦略について
この記事では、HTMLを生成するタイミングに関する方針を「レンダリング戦略」と呼ぶことにします。
今回は、以下のレンダリング戦略を取り上げ、それぞれのメリット・デメリットについて比較・考察します。
- CSR(Client Side Rendering)
- SSR(Server Side Rendering)
- SSG(Static Site Generator)
- ISR(Incremental Static Regeneration)
- DSG(Deferred Static Generation)
- React Server Components
1. CSR(Client Side Rendering)
最初に紹介するのは、Client Side Rendering (CSR) です。CSRとは、サーバーから受け取ったJavaScriptを用いて、HTMLをクライアントサイドで生成する手法です。
主にSingle Page Application (SPA) で用いられ、一度サーバーから取得した単一のHTMLを基盤として、JavaScriptを使用してサーバーからのデータを元にコンテンツを動的に更新します。
Reactでは、JavaScriptで仮想DOMを使用して動的にDOMを作成することができるため、Reactを使用している時点でCSRが自然と使用されています。
メリット
- 高速なユーザー体験: ページ遷移が高速で、スムーズなインタラクションが可能
- 開発の迅速化: フロントエンドとバックエンドの分離が明確で、開発の分担が容易
- オフライン対応が容易: PWA(プログレッシブウェブアプリ)としての実装が容易
デメリット
- SEOの課題: クライアント側でレンダリングされるため、検索エンジンによるインデックスが難しい場合がある
- 初回読み込みの遅さ: 初回の読み込みで多くのリソースをダウンロードする必要があるため、初回表示が遅くなることがある
2. SSR(Server Side Rendering)
次に紹介するのは、Server Side Rendering (SSR) です。SSRは、サーバー側でページをレンダリングし、完全なHTMLをクライアントに送信する手法です。これにより、クライアントがサーバーから受け取ったHTMLをすぐに表示できるため、初回ロード時のパフォーマンスが向上し、SEOにも有利です。
Reactでは、Next.jsなどのフレームワークを使用することで、SSRを簡単に実装することができます。これにより、サーバーサイドで初期レンダリングを行い、その後クライアントサイドでハイドレーションを行いインタラクティブな操作を可能にするハイブリッドなアプローチを取ることができます。
メリット
- SEOの向上: サーバー側でレンダリングされたコンテンツは検索エンジンにインデックスされやすい
- 初回表示の速さ: 初回表示が速く、ユーザーがコンテンツをすぐに見ることができる
- パフォーマンスの向上: サーバー側でレンダリングするため、クライアントのリソース負担が軽減される
- データレイヤとの親和性 : バックエンドでHTMLがレンダリングされるため、dbなどフロントからはアクセスできないコンテンツへ容易に接続することができる
デメリット
- 複雑なインフラ: SSRの実装には、サーバー側のリソース管理が必要で、インフラが複雑になる
- 開発の複雑さ: フロントエンドとバックエンドの統合が必要で、開発が複雑になる
- サーバー側の負荷 : サーバーでHTMLの生成を行うため、サーバー側へ負荷が発生する
3. SSG (Static Site Generation)
他のレンダリング戦略ではリクエスト時にHTMLが生成されますが、Static Site Generation (SSG) ではビルド時にHTMLを生成するという特徴があります。
SSGでは、あらかじめビルドプロセス中にすべてのページのHTMLを生成し、静的ファイルとして保存します。これにより、ユーザーがページにアクセスする際には、サーバーから既に生成された静的HTMLを返すだけで済むため、非常に高速なパフォーマンスを実現できます。
メリット
- SEOの向上: SSRと同様サーバーからは完全なHTMLを返すため検索エンジンにインデックスされやすい
- 初回表示の速さ: 初回表示が速く、ユーザーがコンテンツをすぐに見ることができ、事前にHTMLを生成しているためSSRよりも早い場合が多い
- パフォーマンスの向上: 事前にHTMLを作成しているため、サーバー・ブラウザへの負荷が低い
デメリット
- ページの制約: 静的なHTMLを生成するため、事前に動的な処理が必要なページには向かない
- ビルド時間の増加: ビルド時にHTMLを生成するため、ページ数が増えるとその分時間を必要とする
4. ISR(Incremental Static Regeneration)
Incremental Static Regeneration (ISR) とは、リクエスト時に静的なファイルを作成し、そのファイルを次回以降に再利用する手法です。この手法により、頻繁に更新が必要なコンテンツでも静的生成の利点を享受しながら、動的な更新が可能となります。
ISRは、Static Site Generation (SSG) の課題であるビルド時間の長さを解決します。SSGでは、すべてのページをビルド時に生成するため、大規模なサイトではビルド時間が膨大になる可能性があります。一方、ISRでは、初回アクセス時に静的ファイルを生成し、その後キャッシュとして保存され、次回以降のリクエストではそのキャッシュを再利用します。
Reactでは、Next.jsがISRをサポートしており、ページごとに再生成のタイミングを設定することができます。これにより、最新のコンテンツを提供しつつ、ビルド時間を効率的に管理できます。
メリット
- SEOの向上: SSRと同様サーバーからは完全なHTMLを返すため検索エンジンにインデックスされやすい
- 初回表示の速さ: 初回表示が速く、ユーザーがコンテンツをすぐに見ることができる。事前にHTMLを生成しているためSSRよりも早い場合が多い
- パフォーマンスの向上: 事前にHTMLを作成しているため、サーバー・ブラウザへの負荷が低い
- 再ビルドが不要: HTMLが生成されていない場合、リクエスト時にHTMLを作成するためブログなどのコンテンツを更新しても再ビルドが不要
デメリット
- ページの制約: SSGと同様にリクエストごとにコンテンツを変えるなど動的な対応を求めるページには向かない
- インフラ構築の難易度増加: リクエスト時にHTMLをキャッシュするためそれら環境を構築するコストが発生する
5. DSG(Deferred Static Generation)
Deferred Static GenerationはISRと類似しており、SSGで任意のページをビルド時に生成せず、リクエストが来たタイミングでHTMLを作成します。
ISRとの違いとしては、ISRではパス単位(`/posts/:slug`)で指定するのに対し、DSGではページ単位で指定することができる点と、生成されるHTMLのコンテンツはISRではリクエスト時に取得し、DSGではビルド時に取得したものが使用されるという点です。
またDSGは後述するGatsbyというフレームワーク独自のレンダリング戦略であるため、もし使用したい場合はGatsbyを選択する必要があります。
メリット
- SEOの向上: SSRと同様サーバーからは完全なHTMLを返すため検索エンジンにインデックスされやすい
- 初回表示の速さ: 初回表示が速く、ユーザーがコンテンツをすぐに見ることができる。事前にHTMLを生成しているためSSRよりも早い場合が多い
- パフォーマンスの向上: 事前にHTMLを作成しているため、サーバー・ブラウザへの負荷が低い
デメリット
- ページの制約: SSGと同様にリクエストごとにコンテンツを変えるなど動的な対応を求めるページには向かない
- インフラ構築の難易度増加: リクエスト時にHTMLをキャッシュするためそれら環境を構築するコストが発生する
- コンテンツ更新時の対応 : ブログなどのコンテンツを更新した場合に再度ビルドを実行する必要がある
6. React Server Components
React Server Components とは、コンポーネント単位でサーバーサイドとクライアントサイドでのレンダリングを調整できる新しいアプローチです。これにより、各コンポーネントがどこでレンダリングされるべきかを柔軟に制御することができます。
React Server Componentsを使用すると、サーバー上で重たい計算を行うコンポーネントや、クライアントサイドでインタラクティブな操作が必要なコンポーネントをそれぞれ最適な場所でレンダリングすることが可能です。これにより、パフォーマンスの最適化や、クライアント側のリソースの効率的な利用が実現します。
またSSRとは異なりReact Server Componentsのレスポンスではサーバーコンポーネントが直接HTMLとなるわけではなく、独自のデータ表現としてクライアントに返されます。
メリット
- データレイヤとの親和性 : バックエンドでHTMLがレンダリングされるため、dbなどフロントからはアクセスできないコンテンツへ容易に接続することができる
- JSのバンドルサイズ削減: Server ComponentsではJSを持つ必要がないためサイズの削減が期待できる、ただし生成されるHTMLがJSよりも小さい場合に限る
- 非同期処理の簡素化: Server Componentsではコンポーネントにasyncをつけられ、useEffectなど今まで行ってきた非同期処理より簡潔にコードを書くことができる
デメリット
- 管理の複雑さ: コンポーネント毎にclient, serverどちらでレンダリングされるかを意識しコードを書く必要があるため管理コストが増加する
- 扱いが難しい : 正しい使用ができれば従来よりもパフォーマンスがよくなるが誤るとこの恩恵が皆無(むしろマイナス)になる可能性がある
フレームワーク・ビルドツールの選定
上記で説明したレンダリング戦略には、クラウド環境やその処理に関するいくつかのデメリットがあります。しかし、最適なフレームワーク・ビルドツールやクラウド環境を選択することで、これらのデメリットを克服することが可能です。
アジャイル開発では、無駄なコストを抑えつつ、プロダクトを高速に開発することが求められます。そのため、適切なフレームワーク・ビルドツールの選定は非常に重要です。Reactを使用した開発において、フレームワーク・ビルドツールを使用しないことは稀であり、ほとんどの場合これらを活用することが一般的です。
この章では、主要なフレームワークとビルドツールを紹介し、それぞれのレンダリング戦略の観点から最適な選択肢を検討します。また、CSRについては、Reactを使用していれば実現できるため、この章ではCSRの代わりにSingle Page Applicationに対応しているかどうかを見ることとします。
フレームワーク
Next.js
Next.jsは、Reactで非常に人気の高いフレームワークで、Vercelがメンテナンスを行っています。次に紹介するフレームワークと比較しても、多くのレンダリング戦略に対応しており、機能の実装が最も容易にできると考えられます。
Next.jsは、様々なレンダリング戦略をサポートしているため、プロジェクトの要件に応じて最適な方法を選択できます。しかし、その容易さの反面、内部構造が隠蔽されているため、特殊な使い方をする際には予想以上の労力が必要となる場合があります。
また、Next.jsの開発元がVercelというPaaSを開発している会社であるため、Vercelとの相性が非常に良く、高度なクラウド環境が必要なレンダリング戦略でも、Vercelと組み合わせることで容易に実現することができます。Next.jsはサーバーサイドも包括しており、フロントエンドとバックエンドのコードを密接に統合して開発することが可能です。
Next.jsが対応しているレンダリング戦略は以下の通りです。
- SPA (Single Page Application)
- SSR (Server Side Rendering)
- ISR (Incremental Static Regeneration)
- SSG (Static Site Generation)
- RSC (React Server Components)
Astro
Astroはブログなど、コンテンツ重視のウェブサイトを構築するためのフレームワークです。
Astroは、他のフレームワークと比べてJavaScriptの負荷と複雑さを軽減するアイランドという新しいフロントエンドアーキテクチャを先駆けて導入しました。公式にも書かれているように読み込み速度が他フレームワークど比べて早く、もし読み込みが速くSEOに優れたウェブサイトが必要であれば、Astroが良い選択肢になるでしょう。またAstroは他フレームワークと異なりReactのみ対応しているわけではなくVueやSvelteなどを組み合わせることも可能です。
ただしAstroはSNSなど会員機能を持たせたり、Single Page Applicationなど複雑な機能を必要とするプロダクトには適していません。また独自のAstroテンプレート構文が存在するため、別途書き方を覚える必要があります。
Astroが対応しているレンダリング戦略は以下の通りです。
- SSR(Server Side Rendering)
- SSG (Static Site Generation)
- SPA (Single Page Application) ※可能であるが推奨されていない
Gatsby
元々SSGとして有名なフレームワークでしたが現在は独自のレンダリング戦略であるDSGやSSRをサポートしています。またGatsbyはGraph APIとの親和性が高くAPIやPluginなどが提供されています。
Next.jsと同様にGatsby CloudというPaasを提供していたのですが、2023年にnetlifyというPaaSを開発する会社に買収され、元々存在していたGatsby CloudというPaaSもnetlifyへと統合される予定です。
Gatsbyが対応しているレンダリング戦略は以下の通りです。
- SSR(Server Side Rendering)
- SSG (Static Site Generation)
- DSG(Deferred Site Generation)
Remix
Remixは内部で後ほど説明をするViteを使用しており、Next.jsほど構成が堅固ではありませんが、独自の強みを持つフレームワークです。ビルド時にはサーバー用のJavaScriptが生成され、サーバーサイドの処理も包括しています。さらに、RemixはReact Routerの上に構築されており、Link
コンポーネントを使用することでクライアントサイドのレンダリング(CSR)も可能です。
Remixは、ルートベースのデータフェッチングや、サーバーサイドとクライアントサイドのデータ同期を効率的に行うための機能を提供しています。これにより、データの取得とUIのレンダリングをシームレスに統合し、ユーザーエクスペリエンスを向上させます。
またRemixではSPAモードというSPAに特化した機能も存在し、SPAに適したコード分割・モジュールの読み込みを行なってくれます。
Remixが対応しているレンダリング戦略は以下の通りです。
- SPA (Single Page Application)
- SSR (Server Side Rendering)
ビルドツール
Vite
Viteは、より高速で無駄のない開発体験を提供することを目的としたビルドツールです。他のフレームワークと比較すると提供される機能は少ないですが、その分軽量で効率的です。
Viteはシンプルなサーバー機能も提供しており、単なるビルドツール以上の存在となっています。また、ホットモジュールリプレースメント(HMR)による高速な開発サイクルを実現し、開発者の生産性を大幅に向上させます。
ただし、現時点では公式にReact Server Componentsをサポートしていないようです。そのため、特定のレンダリング戦略を使用する場合は他のツールやフレームワークと組み合わせる必要があります。
またVitestというViteと親和性の高いTesting Frameworkもあり、Viteを使用する際はVitestと組み合わせることでより素早くテスト環境の構築も可能です。
Viteが対応しているレンダリング戦略は以下の通りです。
- SPA(Single Page Application)
- SSR (Server Side Rendering)
- SSG(Static Site Generation)
Farm
FarmはRust製のビルドツールで速さをうりとしています。プロジェクトが大きくなるとビルドやHMRにかかる時間がボトルネックとなります。
Viteではこれらの速度を解決するために開発モードではソースコードをバンドルせずにnative ESMを使用することでdev-serverを立ち上げ高速なHMRを実現してきました。しかし、バンドル化しない場合、リクエスト数が増えるなどの問題や、本番環境ではrollupを使用しバンドル化するため開発環境と本番環境でソースが異なるといった問題をViteは抱えていました。
Farmはこれらの問題を解決するため生まれたビルドツールとなります。またViteとの互換性もありViteで使用していたpluginを使用することも可能です。
Farmが対応しているレンダリング戦略は以下の通りです。
- SPA(Single Page Application)
- SSR (Server Side Rendering)
- SSG(Static Site Generation)
レンダリング戦略の選定
どのレンダリング戦略を選択するかは、プロダクトの特性に大きく依存します。特にアジャイル開発においては、迅速な開発と柔軟な対応が求められるため、プロダクトの特性に合った戦略を選ぶことが重要です。
例えば、プロダクトがカスタマー向けで、ユーザーをオーガニック検索で獲得することが必須であれば、SEOに強いレンダリング戦略を選択すべきです。このように、プロダクトの特性を軸に、どのレンダリング戦略を採用するかを考察します。
事前に特性の一覧を洗い出し、それに基づいて適切なレンダリング戦略を選定します。
特性一覧
- SEO重視: 検索エンジンのランキング向上を目指し、ユーザーをオーガニック検索から獲得したい場合。
- コンテンツが静的か: 更新頻度が低く、固定されたコンテンツが中心の場合。
- サーバーや言語のこだわり: 特定のサーバー環境やインフラストラクチャに依存する場合、または特定のプログラミング言語にこだわりがある場合。
- オフライン対応: ユーザーがインターネットに接続していない場合でも利用できるようにする必要がある場合。
これらの特性に基づいて、適切なレンダリング戦略を選定していきます。また、すべての戦略選定の前提として、アジャイル開発の観点から「素早く開発ができるのか」という点を重視します。これは特に初期フェーズで迅速に市場に出すための重要な要素です。
この章では、プロダクトの特性に応じたレンダリング戦略の選定方法を具体的に紹介します。アジャイル開発におけるスピードと柔軟性を最大限に活かすための指針を提供します。
特性ごとのレンダリング戦略パターン
次に、特性ごとに適したレンダリング戦略のパターン表を紹介します。このパターン表では、各特性に基づいた最適なレンダリング戦略を一目で把握できるようにします。パターン表を参考にすることで、プロダクトの特性に最も合った戦略を選定する手助けとなります。
パターン1の場合
SEOを重視し、コンテンツが静的なプロダクトを開発する場合、最適なレンダリング戦略はSSG (Static Site Generation) です。このような特性を持つプロダクトとしては、ブログやランディングページ(LP)などが考えられます。
フレームワークの選定には、SSGとISRに対応しているNext.jsをおすすめします。SSGはSEOに強く、静的コンテンツの生成を効率的に行うことができます。また、今後ページ数が増えビルド時間が長くなり、開発者体験やコンテンツの反映に影響が出始めた時には、SSGからISR (Incremental Static Regeneration) への切り替えを検討することも良いでしょう。DSRも候補として考えましたが、コンテンツ更新時に再ビルドが必要なためISRと比べると利便性が劣ると考え今回は候補から外しました。
クラウド環境に特別なこだわりがない場合は、Vercelの使用を推奨します。Vercelの開発元とNext.jsの開発元は同じであり、最適なホスティング環境を提供してくれるため、別途環境構築の負荷を軽減し、ISRを容易に実現することができます。これにより、開発の効率化とパフォーマンスの向上を図ることができます。
パターン2の場合
SEOを重視しつつ、コンテンツが動的なプロダクトを開発する場合、最適なレンダリング戦略はSSR (Server Side Rendering) です。このような特性を持つプロダクトには、ECサイトなどが考えられます。
フレームワークとしては、多くのフレームワークがSSRに対応しているため、好みや使用するクラウド環境との相性を考慮して選定しても良いでしょう。また、後々パフォーマンス改善などでコンポーネント単位でのレンダリング調整を行いたい場合には、React Server Componentsの組み合わせを検討すると良いかもしれません。
この場合、紹介したフレームワーク・ビルドツールの中でReact Server Componentsに対応しているのは現時点でNext.jsのみです。また次のバージョンである React19 ではReact Server Componentsが安定版としてリリースされますが、フレームワークを使用しないで開発することは大きなコストが発生すると考えられるため、 将来的にこれらの対応を行う可能性が高いのであれば、最初にNext.jsを選択しておくと良いでしょう。
Next.jsは、柔軟なレンダリング戦略をサポートしており、長期的なプロジェクトにも対応できる優れた選択肢です。
パターン3の場合
SEOを特に重視しないプロダクトでは、バックエンドにこだわりがあるのか、オフライン対応が必須なのかによって選ぶべきレンダリング戦略が変わると思います。
パターン3–1:
バックエンドにこだわりがある場合は、SPA (Single Page Application) のCSR (Client Side Rendering) を採用するのが良いかもしれません。SPAでは、あらかじめビルドしておいた静的ファイルをサーバー側で配布するだけで済むため、バックエンドでは好みの言語・フレームワークを選択することができます。
ただし別にフロントエンド用のサーバーを構築する場合は他レンダリング戦略を採用し好みのバックエンドを使用できると思いますが、別途サーバーを構築するなどのコストが発生するためトレードオフを意識する必要があります。
フレームワーク・ビルドツールとしてはRemixのSPAモードか、ViteまたはFarmを使用することをお勧めします。
パターン3–2:
オフライン対応が必須となるプロダクトの場合、SPA (Single Page Application) を選択することが適切であると考えられます。オフライン時にサービスを起動するためには、HTML、CSS、JSなどのリソースをキャッシュし、それらのキャッシュを利用してページ遷移を実現する必要があります。この要件を満たすために、SPAは理想的な選択肢です。
さらにユーザー体験を向上させるために、途中でManifestなどを追加してPWA (Progressive Web Application) にすることも可能です。PWAにすることで、ホーム画面にアイコンを追加したり、通知を送信するなど、ネイティブアプリのような体験を提供でき、ユーザーにより高い価値を届けることができます。
パターン3–3:
バックエンドに特別なこだわりがなく、オフライン対応も不要なプロダクトの場合、技術選択の自由度が非常に高くなります。
特にお好みのフレームワークがある場合は、それを選択して開発を進めるのが良いでしょう。
個人的には、Next.js と Vercel の組み合わせを推奨します。これにより、高速にプロダクトをリリースできるだけでなく、Next.jsは多くのレンダリング戦略に対応しているため、開発途中で別のレンダリング戦略に切り替えたり、複数のレンダリング戦略を併用することが可能です。この柔軟性により、変化に強い開発が実現できます。
まとめ
アジャイル開発では、変化に素早く対応できるようにするため、いかに早くユーザーへプロダクトを届けられるかが重要です。しかし、スピードだけを追求してプロダクトの特性を犠牲にすることは避けなければなりません。
そこで、本記事ではプロダクトの特性を考慮し、最適なレンダリング戦略について考察しました。
一つのレンダリング戦略を選定することに焦点を当てましたが、実際にはレンダリング戦略を組み合わせることも可能です。それぞれのトレードオフを比較し、部分的に複数のレンダリング戦略を取り入れることで、より柔軟かつ効果的なアプローチが取れる場合もあります。例えば、静的なページはSSGを使用し、動的な部分はSSRやCSRを利用するなど、状況に応じて最適な戦略を選ぶことができます。
アジャイル開発においては、プロダクトの特性に応じた最適なレンダリング戦略を選定し、柔軟に対応することで、ユーザー体験を向上させつつ、迅速な開発とデプロイを実現することが重要です。今後も、変化するニーズに応じて、最適な戦略を選び続けることが成功の鍵となるでしょう。