フロントエンドの HTMLレンダリング手法と周辺技術について理解する

# 1. はじめに
CSR や SSR、SSG などの HTMLレンダリング手法について、詳しく理解しきれていなかったのでそれぞれの特徴や周辺知識についてまとめてみました。

対象読者としては、

- 最近のレンダリング手法のキャッチアップがしたい
- フロントエンドのフレームワークについて詳しくない
- フロントエンド技術の選択肢を知りたい

といったようなフロントエンド初学者向けとなっています。
間違い等ありましたらコメントでご指摘いただけると嬉しいです。

# 2. レンダリングとは
フロントエンドでレンダリングといえば、「HTMLを生成する」といったような意味で紹介されることが多いですが、厳密に考えると2つの意味があります。
- クライアント側（ブラウザ）で HTMLファイル等を読み込んで描画までする
  - ブラウザレンダリングといいます
- サーバー側で HTMLコードを生成する

どちらも似たような意味ではありますが、クライアントとサーバーのどちらでレンダリングという言葉を使うかによって微妙に意味が異なります。

この記事ではどちらも、または両方を含めて「レンダリング」と表記する場合があるので、文脈に応じて読み分けをお願いします。

# 3. CSR
CSR（Client Side Rendering）は、クライアント側でレンダリングすることを意味します。
というと、全てのWebサイトは CSR していることになってしまいますが、API からデータ取得して UI を動的に作るなど JavaScript を駆使してページを作る場合に特に CSR と呼ばれます。

CSR をしている場合にページが表示されるまでの流れは以下の通りです。

1. ページにアクセス（ブラウザが HTTPリクエストする）
1. サーバーから HTML, CSS, JSファイルなどがブラウザに返される
1. ブラウザレンダリングする（≒ CSR）

CSR には MPA と SPA の２つのアーキテクチャが存在しますが、それらを紹介する前にブラウザレンダリングとは何かについて簡単に説明します。

## 3.1. ブラウザレンダリング
ブラウザがWebページを描画するまでのプロセスのことを指します。省略している部分もありますが、大まかに以下のプロセスで行われています。

1. **Loading**
   HTMLファイル等のリソースのダウンロードや、HTMLパース（構文解析）を行い、DOMツリーと CSSOMツリーを構築します。
2. **Scripting**  
   JSコードを解析し、実行まで行います。（DOM や CSSOM を変更）
3. **Rendering**  
   DOMツリーと CSSOMツリーからレンダリングツリーを構築します。その後、各要素のサイズや配置を計算します。  
4. **Painting**  
   Rendering の結果を描画します。

このプロセスは並列処理で行われるので、準備ができた箇所から描画されていきます。

## 3.2. MPA
MPA（Multi Page Application）は複数の HTMLファイル（ページ）で構成され、ページ遷移の度にページ全体を再レンダリングするアプリケーション、またはそのようなアーキテクチャです。
つまり、ブラウザレンダリングをページ遷移の度に繰り返します。

MPA は昔からあるアーキテクチャで、テンプレートエンジン等を利用して構築されていました。ここ数年ではAngular, React, Vue.js といったフレームワークが登場し、これらを利用しても構築することができます。
フレームワークを利用して後述のSPAが構築できるようになってから、SPA の対比として MPA という言葉が誕生しました。
（React や Vue.js はライブラリですが、この記事では便宜上フレームワークに含めます）

SPA と比較した MPA のメリットとしては、主に開発コストを抑えられることが挙げられると思います。
SPA はこれまでブラウザが担当していた機能を利用しない代わりにシームレスな挙動などを実現させているため、MPA で開発を進めるよりもコストがかかりがちです。

## 3.3. SPA
SPA（Single Page Application）は、ページ全体を再レンダリングする**ページ遷移**をなくし、JavaScriptで動的にコンテンツを描画してページ遷移したような挙動をする**画面遷移**を利用して構築したアプリケーション、またはそのようなアーキテクチャを指します。
SPA で構築されたサービスでは、ページ遷移していないのに URL が変わる挙動を見ることがありますが、これは History API というセッション履歴へのアクセス機能を利用して変えています。

初回リクエストではサーバーから返却される HTMLファイルは１つのみで、バンドルされた JSファイルが他のページを描画し、アプリケーションを構築します。
初回リクエスト以降でデータが必要な場合は Ajax でその都度リクエストします。

:::note
Ajax とは、クライアント側から JavaScriptを実行し、HTTPリクエストで非同期にデータを取得する技術です。
json等の形式でレスポンスが返ってきます。
:::

SPA を採用しているサービスは [Gmail](https://mail.google.com/mail/), [Twitter](https://twitter.com/), [Zenn](https://zenn.dev/) などです。イメージが湧かない方は実際に触ってみると理解しやすいかもしれません。

### 3.3.1. メリット
- UX（ユーザー体験）向上につながる
  - ページ全体を再レンダリングするページ遷移をしないため、シームレスに操作できます。これが SPA の大きなメリットといえるでしょう。
  - MPA のページ遷移ではアニメーションが設定できませんが、SPA は画面遷移なので遷移アニメーションを設定することができます。
- フロントエンドとバックエンドを疎結合にできる
  - 例として以下のようなメリットがあります。
    - マルチデバイスに対応しやすくなる。
    - フロントエンドとバックエンドを並行して開発ができる。
    - 他のシステムへの影響を少なくし、障害対応がしやすくなる。

### 3.3.2. デメリット
- 初回のレンダリングに時間がかかる
  - 初回に返却される HTMLファイルは１つのみですが、複数ページを描画するために膨大な量の JSコードが含まれているため、MPA よりも初回レンダリングに時間がかかってしまいます。この問題の対策としては後述の SSR や SSG などがあります。
- SEO で不利になる場合がある
- ユーザーのデバイススペックに依存する
  - ユーザーが古い PC など処理能力の低いデバイスを使っている場合に、初回レンダリングを含む様々な処理が遅くなる可能性があります。
- セキュリティリスクが高まる
  - MPAと同じような感覚で実装してしまうと、個人情報が流出するなどといった事態になる場合があるので、特にセキュリティに関しては最新の注意を払う必要があります。
- 実装コストがかかる
  - ブラウザに任せていた機能を実装する必要があり、その他にも考慮しながら実装する要素があります。
- 動的OGPが設定できない
  - Twitter などのクローラーは JavaScript を実行することができません。そのため、HTMLファイル１つからページを生成していく SPA で各ページに個別の OGP画像を設定するには、SSR等の対応が必要になってきます。
:::note
OGP とは、Twitter などの SNS で URL をシェアした際にそのページの内容（サムネイル画像等）を伝える仕組みのことです。
:::

### 3.3.3. 初回レンダリングについて
初回レンダリングが完了するまでをいくつかの段階に分けることができます。各レンダリング手法の比較で用語が登場するのでここで説明したいと思います。

:::note <dl>
  <dt>TTFB（Time To First Byte）</dt>
  <dd>ページにアクセスしてから最初の1バイトを受信するまでの時間</dd>
  <dt>FP（First Paint）</dt>
  <dd>ブラウザが読み込んだ最初のピクセルが描画される</dd>
  <dt>FCP（First Contentful Paint）</dt>
  <dd>何らかのコンテンツ（テキストや画像など）が描画される</dd>
  <dt>LCP（Largest Contentful Paint）</dt>
  <dd>メインコンテンツ（ページ内で最大サイズの画像やテキストブロックなど）が描画される</dd>
  <dt>TTI（Time To Interactive）</dt>
  <dd>目に見えるコンテンツが描画されて（FCP）からユーザー入力の受付など操作可能になるまでの時間</dd>
</dl>
:::

SSR 等の対応をしない SPA の場合はバンドルされたJSファイルのサイズが大きくなるため、ダウンロードに時間がかかり、FCP や TTI が遅くなります。
つまり、FP から FCP までの間は空白の画面が表示されることになってしまいます。

これが UX 低下につながることを問題視して行う対応が SSR や SSG といったレンダリング手法になります。

### 3.3.4. Googlebotについて
SSR 等の対応をしていない SPA は、初回リクエストで返却される HTMLファイルはほとんど空で、そこから JSコードが DOMを生成していきます。

Webクローラーである Googlebot は、SPA 登場当初は JavaScript を実行できず、SPA で構築されたサービスのインデックスができませんでした。
現在では JavaScript を実行できるようになったので SPA の SEO 問題は基本的には解決しましたが、まだ懸念点があります。

:::note
インデックスとは、Webクローラーがクロールしたページを検索エンジンのデータベースに登録することです。
ここで登録された情報が検索エンジンの結果に反映されます。
:::

まず、Googlebot のインデックスが完了するまでに2回の工程があります。
最初のクロールでは静的な HTMLページをクロールします。ここで JavaScript の実行が必要だと Googlebot が判断した場合はレンダリング待機のリストに追加され、順番が来たら JavaScript によるレンダリングが行なわれてクロールが完了します。
そのため、SPA はインデックスが完了するまで時間がかかってしまう場合があります。更新頻度の高いサービスの場合は問題になるかもしれません。

また、JavaScript が問題なく実行されるかも保証されていません。JavaScript が想定通りに実行されずコンテンツが表示されない場合や、Googlebot がタイムアウトする前に画像やデータなどのリソースを取得してレンダリングが完了できなかった場合は検索結果に悪影響が出るようです。


### 3.3.5. ダイナミックレンダリング
[ダイナミックレンダリング](https://developers.google.com/search/docs/advanced/javascript/dynamic-rendering?hl=ja)は、ユーザーエージェントによって CSRするか SSRするか を切り替えてコンテンツをレンダリングする手法です。
つまり、クローラーに対しては SSR、クライアントに対しては CSR（SPA）することで SEO や OGPについて対策ができます。

既にある程度開発された SPA に SSR を導入するよりも開発コストを抑えて導入することができるので、場合によっては選択肢としてありだと思います。

より詳しく知りたい方はこちらの記事が参考になります。
https://www.seojapan.com/blog/dynamic-rendering-seo



### 3.3.6. 適したサービス
ページ遷移時の再レンダリングを無くし、シームレスな操作といった UX を提供することに SPA を採用する意義があると思います。
そのため、ユーザーの滞在時間が長いサービスや、１つの目的達成までに MPAではページ遷移が多くなりそうなサービスとは相性が良さそうです。

まとめると、
- UX の重要度が高い
- ユーザーの滞在時間が長い
- ユーザーの１つの目的達成までに MPAではページ遷移が多くなる
- （後述の SSR, SSG をしない場合は）小〜中くらいの規模

といったサービスに適していると思います。


# 4. SSR
SSR（Server Side Rendering）は、ユーザーのリクエストごとにサーバー側で HTMLをレンダリングする手法です。

サーバー側での HTML生成方法は主に2つあり、フレームワークを利用する方法とテンプレートエンジンを利用する方法があります。

:::note
テンプレートエンジンは、テンプレートにデータを当てはめて最終的に HTMLを出力するライブラリです。
最近では話題に挙がりませんが昔からある技術で、今でも採用しているサービスは多いと思います。
:::

## 4.1. フレームワークによるSSR
CSR では React や Vue.js などを使いますが、それぞれをベースにしたSSR対応フレームワーク（Next.js, Nuxt.js）を使うことでサーバー上でも React や Vue.js を実行可能にし、SSR を可能にします。

レンダリングの流れは以下の通りです。

1. ページにアクセス（ブラウザが HTTPリクエストする）
1. サーバーがレンダリングに必要なデータを取得する
1. サーバーが HTMLをレンダリングする
1. レンダリングされた HTMLファイル等がブラウザに返される
1. ブラウザレンダリングする過程でハイドレーションを行う

:::note
ハイドレーションは、SSR された HTMLに対して最小限の JavaScript を紐付けておき、それをクライアント側で実行してページをクライアントでのデータ変更に対応できるよう（インタラクティブ）にするプロセスです。
:::

ここでサーバー側の「HTMLをレンダリングする」というのは、React などを使って CSR で DOMを生成していた工程をサーバー側で行うイメージです。
これによって、クライアント側でダウンロードする JSファイルのサイズが減り、FCP（First Contentful Paint）までの時間が短くなります。

### 4.1.1. メリット
- 初回レンダリングが早い
  - SPA は特に JSコードの量が多くなりがちなため、TTI（Time To Interactive）までの時間が長くなってしまいます。SSR で HTMLがレンダリング済 & JSコードが最小限になることで、FCP や TTI までの時間が短くなります。
- SPA でも動的OGPが設定できる
- クローラビリティが高い（SEO改善）
  - Webクローラーは JavaScript を実行する必要がなくなるので、コンテンツを遅延なくインデックスさせられます。
- ユーザーのデバイススペックに依存しない
  - スペックの低いデバイスでも表示速度を安定させることができます。

### 4.1.2. デメリット
- サーバー負荷が高い
  - ブラウザで行っていたレンダリングをサーバー側で行うので負荷がかかります。
  - これについてはキャッシュを活用することで負荷を減らすことができます。
- TTFB（Time To First Byte）が少し遅くなる
  - サーバー側のレンダリング処理が終わらないとリソースのダウンロードが始まらないため、TTFB までの時間が遅くなる場合があります。
- フレームワークで SSR をするためには Node.js が動くサーバーが必要になる
- 開発が複雑になり、開発コストがかかりやすい

### 4.1.3. Streaming SSR
SSR にはまだいくつかの問題があります。

- SSR は全てのデータ取得が完了しないとレンダリングが完了せず、クライアントを待たせてしまう
- クライアントの全てのコンポーネントの JavaScript がロードされないとハイドレーションされない
- 全てのコンポーネントのハイドレーションが完了しないとインタラクティブにならない

これらの問題を解決するのが Next.js 12 で追加された Streaming SSR です。
Streaming SSR は、React 18 で追加された機能を Next.js 12 がサポートすることによって実現されました。
具体的な実装方法はここでは割愛しますが、この Streaming SSR を利用することによって、
- データ取得が不要なコンポーネントを先に配信し、必要なコンポーネントはデータ取得が完了した後に逐次配信する
  - 配信されるまではローディングアニメーションなどを代わりに表示できます。
- コード分割・遅延ロードすることで部分的に先にハイドレーション、インタラクティブにする

といったことができるようになります。

:::note warn
Streaming SSR は Next.js 12.1 のアルファ版の機能です。
:::

### 4.1.4. 適したサービス
リクエストごとにレンダリングするため、SNS のようにリアルタイム性が必要なサービスに適していると思います。また、開発コストを考えると規模が大きめなサービスに向いていると思います。


## 4.2. テンプレートエンジンによる SSR
SSR は、フレームワークをサーバー側でも動かしてレンダリングする方法といった意味で使われることが一般的だと思いますが、テンプレートエンジンによるサーバー側でのレンダリングも広義では SSR に分類できると思います。

テンプレートエンジンを採用している場合は、開発当初は テンプレートエンジン + jQuery などでスタートして、複雑な UI の実装が必要になった段階でフレームワークを CSR で部分的に採用した、という流れで運用されているサービスが一定数ありそうです。

このパターンではテンプレートエンジンによって HTMLがサーバー側で生成されており、一度それが画面に描画されてからフレームワークによる CSR をするため、初回表示が CSR のみの場合より早くなります。
フレームワークによる CSR は、テンプレートエンジンで生成された HTMLを部分的に置き換える形で実装できるので、見た目を変えずにインタラクティブにさせることができます。

テンプレートエンジンとフレームワークの SSR はいろいろ違いがあると思いますが、大きな違いとしては Universal JavaScript で書かれているか、というのが挙げられます。


## 4.3. Universal JavaScript
Universal JavaScript は、クライアントとサーバーの両方で実行できる JavaScript、またはそのアプリケーションのことです。Isomorphic JavaScript ともいいます。
フレームワークによる SSR を行うということは Universal JavaScript でサービスが構築されることになります。

テンプレートエンジンと比較した Universal JavaScript のメリットは、主に以下が挙げられると思います。（テンプレートエンジンによっては当てはまらない話かもしれません）

- ロジックや UI を共通化できる
- 型の恩恵を受けられる

<dl>

<dt>ロジックや UI を共通化できる</dt>
<dd>テンプレートエンジン + 部分的にフレームワークを採用している場合では、テンプレートとフレームワークでロジックや UI が重複する場合があります。<br>
<br>
また、初回表示でテンプレートの UI を表示した後に CSR でフレームワークの UI に置換して表示する場合、実装ミス等で UI に差異ができてしまい、UX を損ねてしまうことが考えられます。<br>
多少の差異なら UX を損ねるまでにはならないかもしれませんが、このような違和感や操作性の小さな不満が増えていくとサービスの全体的な印象や満足度が下がることに繋がる可能性があるので、小さなことでも対処するほうがいいと思います。<br>
<br>
Universal JavaScript ではロジックや UI を共通化できるため、上で挙げたコードの重複や分散による工数増加と保守性の低下、UI の差異による UX 低下などを防ぐことができます。</dd>
<br>

<dt>型の恩恵を受けられる（TypeScript）</dt>
<dd>型が適用されないことでエラーを含むコードに気づかず、そのままリリースしてしまう可能性が考えられます。<br>
React など JSX（TSX） を採用できるフレームワークであれば型システムを利用してマークアップを書けるようになるので、開発工率や安全性が上がります。</dd>

</dl>

と、Universal JavaScript の良い点を紹介しましたが、エンジニアの技術スタックやサービス要件などによってはテンプレートエンジンのほうが適している場合があるので、テンプレートエンジンは選択肢としては駄目というわけではありません。

# 5. SSG
SSG（Static Site Generation）は、アプリケーションのビルド時にAPI等からデータ取得し、クライアントがリクエストする前に HTMLをレンダリング（Pre-Rendering）しておく手法のこと。
HTML が既にレンダリング済のため CDN にキャッシュさせることができ、サイト表示が非常に高速になります。

:::note
SSG は Static Site Generator の略としても使われる場合があり、その場合の SSG は Gatsby などのフレームワークを指します。
:::

レンダリングの流れは以下の通りです。SSR とはレンダリングのタイミングが違います。
1. ソースコードをデプロイしてビルドする
1. ビルドのタイミングでデータ取得・レンダリングを行う
1. ページにアクセス（ブラウザが HTTPリクエストする）
1. レンダリング済の HTMLファイル等がブラウザに返される
1. ブラウザレンダリングする過程でハイドレーションを行う


## 5.1. メリット
- TTFB（Time To First Byte）が早い
  - リクエスト時にはHTMLがレンダリング済なのでレスポンスが早く、SSR よりも高速に表示できます。
- サーバー負荷が少ない
  - レンダリング済のHTMLを返すので SSR でデメリットだったサーバーへの負荷が解消されます。
- クローラビリティが高い
  - SSR と同様にコンテンツを遅延なくインデックスさせられるため、SEO改善に繋がります。
- 動的OGPの設定が可能

## 5.2. デメリット
- 変更を反映させるために再ビルドが必要になる
  - 少しの変更でも全てのページをビルドする必要があるのでコンテンツ量によっては毎回のビルドに時間がかかってしまいます。
  - 変更のあるページのみをビルドする機能（差分ビルド）など、フレームワークによってはこの問題を解決する手段が用意されています。
- ファイルサーバーの使用容量が大きくなる
  - サービスの規模によりますが、SSG は事前にパスごとの HTMLファイルを生成するので、ECサイトやユーザー作成コンテンツが大きいサービスの場合は注意が必要かもしれません。

## 5.3. 適したサービス
ブログやメディア、コーポレートサイトなどといったデータ更新頻度が少ないサイトに適していると思います。
特にメディアサイトはトラフィックが高く、高いパフォーマンスも求められるため SSG は最適です。

また当然ですが、ビルド時にレンダリングされるためリアルタイム性の強いサービスには向いていません。
SSG が採用できる要件であれば SSR よりサーバー負荷が少なく、表示も高速な SSG を選択するといいと思います。

## 5.4. Jamstack
ここで SSG と一緒によく解説される Jamstack について少しだけ紹介します。
[Jamstack](https://jamstack.org/)は、Webをより速く・安全に・簡単に拡張できるように設計されたWebアーキテクチャのことです。Jamの部分は JavaScript・API・Markup の頭文字から取られています。
具体的には、SSG で Pre-Rendering されたファイルを CDN から配信し、動的なデータはクライアントで必要に応じて Ajax で取得するような構成のサイトです。

Jamstack なサイトを構築するメリットは以下の通りです。

- パフォーマンスが高い
  - 事前に生成されたファイルを CDN で配信するので高速です。
- セキュリティが高い
  - サーバー側の攻撃箇所が API に集約されるため、対策箇所を絞ることができます。
- スケーリングが簡単
  - ファイルが事前に生成されているため、ホスティングサービスの選択肢が広く、ほとんどの場合でスケーリングプランが用意されています。
- 保守性が高い
  - CDN から配信するので保守が必要なサーバーが不要になり、保守コストが軽減されます。

# 6. ISG
SSG は Pre-Rendering するため、ページの新規作成など後から作成したコンテンツなどは生成しておくことができません。
また、メディアサイトや ECサイトなど膨大なコンテンツがあるサイトの全てを一括でビルドしようとするとかなりの時間がかかってしまいます。

この問題を解決する SSG のオプションが ISG（Incremental Static Generation）です。
ISG は、動的ルーティングで定義していないページ（Pre-Rendering で生成していないページ）をリクエストされた際に HTMLを CSR または SSR で生成する手法です。

:::note
動的ルーティングは、`/articles/001/`のような静的なルートではなく、`/articles/[id]/`のような複数のパスに対応したルートを定義してリクエストをハンドリングできる機能のことです。
:::

これにより一括ビルド時の負担を減らしつつ、API 側にデータを追加するだけでサイトに変更を反映させることができます。


# 7. ISR
SSG や ISG で一度生成されてキャッシュされた HTMLファイルは、データが更新された場合でも再レンダリングしてファイルを再キャッシュさせない限り、古いデータのままファイルを返却してしまいます。

ISR（Incremental Static Regeneration）は、この問題を解決するオプション的手法で、次にキャッシュを再検証（revalidate）するまでの時間を設定することができます。

設定した時間以降にクライアントからリクエストが発生したタイミングで、バックグラウンドでデータの再取得と再レンダリングを行い、その時リクエストしたユーザーにはキャッシュしていた古い HTMLファイルを返します。
これにより動的に作成されたデータにも対応できるようになり、SSR 程のリアルタイム性はないものの、定期的にキャッシュを更新し、最新のレンダリング結果を保つことができます。

この ISR は SWR というキャッシュ戦略をフレームワーク上で可能にした機能になります。

:::note
SWR は、Stale-While-Revalidate というキャッシュ戦略の略称で、指定した期間内のリクエストには古いキャッシュを使用しつつ、バックグラウンドで非同期にデータを取得して、取得でき次第キャッシュを更新する仕組みのことです。

この仕組みにより、キャッシュを活用したいがなるべく新しいリソースを提供したい、といった要求に対応することができます。
:::

ISR を利用するメリットはフレームワーク内で実装が完結することなので、既にバックエンド側で同等の機能を実装している場合は特に ISR を導入する必要はないかもしれません。

## 7.1. On-Demand Revalidation
ISR で再検証時間を設定した場合、設定した時間が来るまでキャッシュは更新できず、更新するには再検証時間を過ぎた後に誰かがそのページにアクセスする必要があります。

これを解決する手段として、 On-Demand Revalidation という機能があります。この機能を利用することで設定した再検証時間を待たずに、特定のページのキャッシュを任意のタイミングで削除 & 再レンダリングすることができます。

:::note warn
On-Demand Revalidation は Next.js 12.1 のベータ版の機能です。
:::


## 7.2. 適したサービス
SSR や CSR+Ajax のようなリアルタイム性が必要ではないが、一定の更新があるサービス（ページ）に ISR は適しているでしょう。


# 8. 主要なフレームワーク
最後に各レンダリング手法を実現する技術について軽く紹介していこうと思います。

## 8.1. React
[React](https://ja.reactjs.org/) は UIライブラリで、仮想DOMを導入しているので高速にレンダリングすることができます。MPA, SPA のどちらも構築できます。
また、JavaScript でマークアップを記述できるようにした JSX を採用しています。

JSX は JavaScript の拡張構文で、テンプレートエンジンや Vue.js などのようにHTMLを主体として JavaScript で制御を加えるのではなく、JavaScript を主体としてマークアップをしていきます。TypeScriptの場合はTSXとなります。
JSX（TSX） については以下のような利点があります。
- JavaScript でシンプルにマークアップを書ける
- テンプレートエンジン特有の制御構文や v-model といったディレクティブを記述する必要がなく、覚える必要もない
- 型や Linter などの恩恵を受けられる
  
JavaScript を主体として書いていくため、エンジニアは直感的に書ける一方で、デザイナーはマークアップに参加しづらいというデメリットがあります。

### 8.1.1. Next.js
[Next.js](https://nextjs.org/) は React のフレームワークで、特別な設定不要（ゼロコンフィグ）で SSR や SSG、ISG・ISR を可能にします。
Next.js 登場時は SSR をするためのフレームワークでしたが、ここ数年では SSG を推奨しているようです。

Next.js は新しい機能を次々とリリースしていますが、レンダリングに関しての特徴としては、ページ単位で SSRするか SSGするかを選択できる点が挙げられます。
これは現時点では Next.js のみで可能で、リアルタイム性が重要なページでは SSR、重要でないページでは SSG、というようにそのページに最適なレンダリング手法を適用することができます。

ISR を利用したい場合の主なホスティング先は Vercel と AWS Amplify です。少し前までは Vercel しか有力な選択肢がありませんでしたが、Amplify も ISR に対応したことで選択肢に入るようになりました。
ただ、ホスティング先の選択肢が狭く、ロックインされてしまうのはデメリットになってしまいます。

### 8.1.2. Gatsby
[Gatsby](https://www.gatsbyjs.com/) は React ベースの SSG用フレームワークで、SSR はサポートしていません。
Gatsby の特徴としては、差分ビルド（Incremental Build）が可能という点です。
これまでの SSG は少しの変更でもプロジェクト全体を再ビルドする必要がありましたが、差分ビルドでは変更のあるページのみをビルドすることができるのでビルド時間の大幅な短縮が可能となっています。

ブログ等を作りたい場合は汎用性の高い開発ができる Next.js を採用するよりも、Gatsby の用意したレールに従って開発したほうがいいかもしれません。
[Gatsby と Next.js の比較](https://www.gatsbyjs.com/features/jamstack/gatsby-vs-nextjs)

## 8.2. Vue.js
[Vue.js](https://v3.ja.vuejs.org/) も React と同様に仮想DOMを導入している UIライブラリで、MPA, SPAを構築できます。また、Vue.js は React の後を追うように機能が追加されていて、追加頻度は緩やかな印象です。

特徴としては、従来の HTML, CSS, JS を１つのファイルに記述するので、これまでのマークアップに慣れている場合は、敷居が低く始めやすさがあります。（一応 JSX で書くこともできます）
そのため、デザイナーもマークアップの修正に参加しやすいです。

Vue.js と React はよく比較されますが、こちらの記事では具体的かつわかりやすく比較されているので目を通しておくといいと思います。
[Reactを使うのかVueを使うのかについて個人的なモチベーションを整理したかった](https://zenn.dev/marokanatani/articles/compare_vue_and_react)

### 8.2.1 Nuxt.js
[Nuxt.js](https://nuxtjs.org/ja/) は Vue.js のフレームワークで、SSR や SSG を可能にします。プロジェクトごとでしか SSR・SSG を指定できないので、この点は Next.js と違います。

Nuxt.js は2022年6月に [Nuxt3](https://v3.nuxtjs.org/) の安定版をリリース予定で、ISG や ISR が利用可能になったり、TypeScript のサポートが強化されたり、JSX の導入が容易になったりなど多くの新機能が登場するようです。

Next.js と Nuxt.js を比較した記事があったので載せておきます。
[Nuxt.jsとNext.jsを比較して、表とグラフにまとめてみた!](https://qiita.com/dtakkiy/items/7d79c153860fbda102a7)

## 8.3. Angular
[Angular](https://angular.jp/) はフルスタックフレームワークです。Angular の導入だけでWebアプリケーション構築に必要な機能を揃えることができますが、柔軟性に欠けてしまうので他の技術を採用しづらくなるというデメリットもあります。
Angular も React, Vue.js と同様に MPA, SPA のどちらも構築でき、Angular Universal という SSR を行う機能があります。

Angular はバージョン8から Incremental DOM という仕組みが登場しました。
DOM を更新する際、仮想DOMの場合は変更前と後の2つの仮想DOMを作成し、変更差分を実際のDOMに反映します。
一方で、Incremental DOM は実際のDOMから変更箇所を探すため、仮想DOMよりもメモリ使用量を抑えることができます。
ただし、レンダリング速度は仮想DOMを使用するよりも遅いようです。

フロントエンドフレームワークのトレンド的には、Angular は React や Vue.js と比較してここ数年は下降傾向にあるため、採用する際はそのリスクを考慮する必要がありそうです。

## 8.4. Svelte
React や Vue.js などは、ブラウザで仮想DOMを用いた変更差分検出などの工程を行なっていました。
[Svelte](https://svelte.jp/) はビルドの時のコンパイルでそれらの工程を行うコンパイラであり、コンポーネント指向な UIライブラリです。MPA, SPA を構築できます。
コンパイル後は、ランタイムのコード量が少ないほぼ純粋なJSコードを生成されます。
特徴としては以下が挙げられます。

- 仮想DOMの差分検出のオーバーヘッドがないため、軽量で高速に動作する
- シンプルでコードの記述量が少ない
- 双方向バインディング
- 純粋な HTML, CSS, JS を書くような感覚のため、とっつきやすい
- ランタイムのサイズは非常に小さいがコンポーネントのサイズが他 UIライブラリより大きい

まだ国内での採用事例や知見が少なく、エコシステムも成熟していないため、現状は中規模以上のサービスには向いていないかもしれません。

### 8.4.1. SvelteKit
[SvelteKit](https://kit.svelte.dev/) は Svelte のフレームワークで SSR と SSG を可能にします。ページごとに SSR や SSG を設定できるようです。

他に Sapper という Svelte の SSRフレームワークがあったようですが、SvelteKit に統合されました。

# 9. 参考文献
1. [patterns.dev - Rendering Patterns](https://www.patterns.dev/posts/rendering-patterns/)
1. [New Suspense SSR Architecture in React 18 #37](https://github.com/reactwg/react-18/discussions/37)
1. [Next.jsにおけるSSG（静的サイト生成）とISRについて（自分の）限界まで丁寧に説明する](https://qiita.com/thesugar/items/47ec3d243d00ddd0b4ed)
1. [ISRから考察するこれからのJamstack](https://blog.microcms.io/think-about-jamstack-2021/)
1. [Stale-While-Revalidate ヘッダによるブラウザキャッシュの非同期更新](https://blog.jxck.io/entries/2016-04-16/stale-while-revalidate.html)
1. [Next.jsのISRで動的コンテンツをキャッシュするときの戦略](https://zenn.dev/catnose99/articles/8bed46fb271e44)
1. [JSXが実はベターな解だったのではないか？](https://note.com/erukiti/n/n6f673021469e)
1. [Incremental vs Virtual DOM](https://blog.bitsrc.io/incremental-vs-virtual-dom-eb7157e43dca)
1. [Svelteとは](https://zenn.dev/toshitoma/articles/what-is-svelte)
1. [各 JavaScript フレームワークの TodoMVC サイズ比較（翻訳）](https://zenn.dev/jay_es/articles/2021-10-22-javascript-framework-size-comparison)
1. [Nuxt 3 を今すぐオススメしたい 15 のポイント](https://zenn.dev/ytr0903/articles/d0a91f6180d34e)