【Next.js】デプロイから考えるCSR,SSG,SSR

## はじめに

業務でNext.js×Laravelを使ったアプリケーションを開発しており、その中でNext.jsでCSR,SSG,SSRを使用している。
ここもと、これらがデプロイ方法を左右する奥深いものだと改めて考えさせるきっかけがあったので、勉強した以下のことをこの記事にまとめておく。

①CSR,SSG,SSRについて
②Next.jsの2つのデプロイ方法について
（デプロイの手順、各デプロイ方法でCSR,SSG,SSRの何が使えるのか、どんな環境が必要なのか）

※自分なりに調査したことをまとめているが、これから業務で実運用されているノウハウに触れる予定なので、今後また実運用を通して学んだことを追記していきたいと思う。

# ①CSR・SSG・SSRについて

## CSR(Client Side Rendering)

### 概要

ブラウザからリクエストがあった際、サーバーから

・ほぼ中身のない`HTML`
・`CSS`
・ビルドされた`JavaScript`

をレスポンスとして返却する。

その後**ブラウザ側**で、受け取った`HTML`,`CSS`,`JavaScript`を使って、ユーザーに見せるHTMLをレンダリングする。

### メリット（通常の静的ページとではなく、SSG,SSRと比べて）

- SEO が関係なく、データが頻繁に更新され、また事前に静的にページをレンダリング（プリレンダリング）しておく必要がないページの場合は有用。

- デプロイが容易。（静的ホスティングさえできれば良い）

### デメリット

- クライアントに対してJavaScriptを送信するので、アプリケーションが大規模になるとJavaScriptの量が膨大になり、レンダリングにかかる時間、つまりページが表示されるまでの時間も長くなる。

- このときの表示時間は、ユーザーが使用しているデバイスの処理能力や通信環境に依存することになる。

### 備考

- Next.jsのドキュメントでは、データを事前にレンダリングする必要がない場合は、**クライアント側でデータをフェッチすることが推奨**されている。

> `getServerSideProps`リクエスト時にデータをフェッチする必要があるページを事前にレンダリングする必要がある場合にのみ使用してください。サーバーがすべてのリクエストで結果を計算する必要があるため、[最初のバイトまでの時間（TTFB）](https://web.dev/ttfb/)は長くなり、結果はヘッダーを使用するCDNによってのみキャッシュできます（追加の構成が必要になる場合があります）。
> 

> データを事前にレンダリングする必要がない場合は、[クライアント側](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props#fetching-data-on-the-client-side)でデータをフェッチすることを検討する必要があります。
[Data Fetching: getServerSideProps | Next.js](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props)

- また、クライアント側でのデータフェッチには `SWR` というライブラリの使用が推奨されている。

> Next.jsの背後にあるチームは、**[SWR](https://swr.vercel.app/)**と呼ばれるデータフェッチ用のReactフックライブラリを作成しました。クライアント側でデータをフェッチする場合は、これを**強くお勧めします。**
[Data Fetching: Client side | Next.js](https://nextjs.org/docs/basic-features/data-fetching/client-side)

## SSR(****Server Side Rendering)****

### 概要

ブラウザからリクエストがあった際、サーバー側で動的にHTMLを生成し、レンダリング済みのHTMLをレスポンスとして返す。

つまりページのロジックとレンダリングを、CSRではクライアント側（ブラウザ）で行っていたのに対し、SSRでは `Node.js` のサーバー上で実行する。

これにより先述のCSRのデメリットを補うことが出来る。

### メリット

- **CSRと比べて**

JavaScript を大量にクライアントに送信するという問題を回避できる。（ユーザーの環境に依存しない）

ブラウザでは**レンダリング済みのHTMLを受け取る**のでSEOにも強い。

- **SSGと比べて**

データの頻繁な更新に対応できる。

### デメリット

- デプロイには**SSRを実行できる環境（Node.js）**が必要。

- ユーザーからのリクエストごとにサーバー側で演算を行うので、サーバーサイドが重くなる可能性もある。

## SSG(Static Site Generator)

### 概要

デプロイ時に（ビルドするタイミングで）予めレンダリングを行い、必要なデータを埋め込んだ状態のHTMLを生成しておく。

ユーザーからのリクエストがあった際は、サーバーから既に生成済みのHTMLをレスポンスとして返却する。

### メリット

- CSR,SSRと違って、ユーザーからのリクエストに応じてその場でレンダリングを行うことをしないので、パフォーマンスが良い。

- デプロイが容易。（**静的ホスティングさえできれば良い**）

### デメリット

- データの更新をWebページに反映させるためには**ビルドし直す必要がある**ので、頻繁に更新されるサイトには向かない。

### 備考

予め生成したHTMLをユーザーからのリクエストの都度アプリケーションサーバーから返却するのではなく、CDNにHTMLファイルのキャッシュを配置しておき各ユーザーに近いCDNからそのキャッシュを返すことで、よりSSGを有効活用できる。

※ `Vercel`は `Vercel Edge Network` という CDNをデフォルトで備えている。

# ②Next.jsの2つのデプロイ方法

Next.jsで作成したアプリケーションのデプロイ方法には、以下の2つの方法がある。

**(1) SSRできる環境（Node.js）へデプロイ**
**(2) 静的ファイルを出力し、静的ホスティングする**

## **(1)** SSRできる環境（Node.js）へデプロイ

Next.jsのドキュメントでは、

・Vercel（公式で推奨）
・Node.jsサーバー
・Dockerイメージ

の3つの方法が紹介されている。

### デプロイ手順

Next.jsの公式ドキュメントに書かれている3通りの方法をざっくりまとめる。

**【Vercelの場合】**

1. ソースコードをVercelにデプロイする。
2. Vercelが自動的にNext.jsを検出して `next build` を実行し、デプロイまで行ってくれる。

**【Node.jsサーバーの場合】**

1. サーバーへソースコードをデプロイし、 `next build`を実行する。
（これによりHTML, CSS, JSが最適化された形で、`.next`フォルダに出力される。）

2.　`next start`を実行してNode.jsサーバーを起動する。

**【Dockerイメージの場合】**

1. Dockerfileを用意する。

2. Docker imageをビルドする。（この時に `next build` が実行されるように `Dockerfile` で指示する）

3. コンテナをデプロイできる環境へデプロイし、コンテナを起動する。

### **デプロイする必要があるファイルについて**

公式ドキュメントで紹介されている上記の手順では、Next.jsのソースコードを全てデプロイしているように思える。

だが  `next build` を実行してデプロイの為に最適化した `.next` ディレクトリが作られているのだから、実際にデプロイに必要なのは以下のファイルのみであり、ソースコードの全てをデプロイする必要は無いと考えられる。

・ `.next`
・ `node_modules`
・ `package.json`
（・ `.env`）　※ブラウザ側で環境変数を使用しない場合は不要。
（・ `public`）　※デプロイに必要な画像等が無ければ不要。

（実際にNode.js環境にデプロイ済みのアプリケーションで上記のファイルやフォルダのみをデプロイして動作確認してみたところ、問題なく動いた。）

極力リスク低減する為、サーバーには必要なファイルのみをデプロイする方が良いと考えているが、実運用されているノウハウに触れたことが無いので、色んな会社でどのように運用されているのか知りたい…。

### できること

**CSR**,**SSG**,**SSR**のどれでも行うことができる。

※「Next.jsの機能をフル活用できる」と言いたいところだが、この記事では取り上げていない**ISR([Incremental Static Regeneration](https://www.slideshare.net/ssuser8c48a6/netlify-nextjs-isr-incremental-static-regeneration))**に**完全対応**しているのは2022年3月29日時点では`Vercel`と`Netlify`のみらしい。
（他のホスティングサービスでもデプロイ可能ではあるが、サポートされていない？ここはまだまだ勉強不足です。）

### デプロイ環境について

要するに `Node.js` の実行環境が必要ということだが、少し具体的にいうと、

- `Vercel`
- `Node.js` サーバー
- コンテナをデプロイできる環境（ `Node.js` のコンテナをデプロイする）

の3通りということになる。

Vercelについてはそのままなので省略。

- **Node.jsサーバー**

Next.jsのドキュメントでは以下のように書かれている。
> Next.jsは、Node.jsをサポートする任意のホスティングプロバイダーにデプロイできます。たとえば、 [AWSEC2](https://aws.amazon.com/ec2/)または[DigitalOceanDroplet](https://www.digitalocean.com/products/droplets/)です。
[Deployment | Next.js](https://nextjs.org/docs/deployment#:~:text=Next.js%E3%81%AF%E3%80%81Node.js%E3%82%92%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B%E4%BB%BB%E6%84%8F%E3%81%AE%E3%83%9B%E3%82%B9%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%83%97%E3%83%AD%E3%83%90%E3%82%A4%E3%83%80%E3%83%BC%E3%81%AB%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82%E3%81%9F%E3%81%A8%E3%81%88%E3%81%B0%E3%80%81%20AWSEC2%E3%81%BE%E3%81%9F%E3%81%AFDigitalOceanDroplet%E3%81%A7%E3%81%99%E3%80%82)

- **コンテナをデプロイできる環境**

こちらもNext.jsのドキュメントから引用する。
> [Next.jsは、 Docker](https://www.docker.com/)コンテナをサポートする任意のホスティングプロバイダーにデプロイできます。このアプローチは、[Kubernetes](https://kubernetes.io/)や[HashiCorp Nomad](https://www.nomadproject.io/)などのコンテナーオーケストレーターにデプロイする場合、または任意のクラウドプロバイダーの単一ノード内で実行する場合に使用できます。
[Deployment | Next.js](https://nextjs.org/docs/deployment#:~:text=Next.js%E3%81%AF%E3%80%81%20Docker%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%82%92%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B%E4%BB%BB%E6%84%8F%E3%81%AE%E3%83%9B%E3%82%B9%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%83%97%E3%83%AD%E3%83%90%E3%82%A4%E3%83%80%E3%83%BC%E3%81%AB%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82%E3%81%93%E3%81%AE%E3%82%A2%E3%83%97%E3%83%AD%E3%83%BC%E3%83%81%E3%81%AF%E3%80%81Kubernetes%E3%82%84HashiCorp%20Nomad%E3%81%AA%E3%81%A9%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%83%BC%E3%82%AA%E3%83%BC%E3%82%B1%E3%82%B9%E3%83%88%E3%83%AC%E3%83%BC%E3%82%BF%E3%83%BC%E3%81%AB%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E3%81%BE%E3%81%9F%E3%81%AF%E4%BB%BB%E6%84%8F%E3%81%AE%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%83%97%E3%83%AD%E3%83%90%E3%82%A4%E3%83%80%E3%83%BC%E3%81%AE%E5%8D%98%E4%B8%80%E3%83%8E%E3%83%BC%E3%83%89%E5%86%85%E3%81%A7%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AB%E4%BD%BF%E7%94%A8%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82)

## (2) 静的ホスティング

Next.jsのドキュメントに以下のように書かれている。
> `next export`Next.jsアプリケーションを静的HTMLにエクスポートできます。これは、Node.jsサーバーを必要とせずにスタンドアロンで実行できます。
[I’m Advanced Features: Static HTML Export | Next.js](https://nextjs.org/docs/advanced-features/static-html-export)

### デプロイ手順

手順として必要なことは以下の通り。

1. `next build`の後に`next export` を実行することで 、`.out` ディレクトリを生成する

2. `.out` ディレクトリを静的ホスティングのできるサーバーにデプロイする

※以下の記事の方法で、手軽にローカル環境で静的HTMLの動作確認を行うことができる

[Next.jsの静的サイト生成(SSG)について確認 - わくわくBank](https://www.wakuwakubank.com/posts/771-react-nextjs-ssg/)

[Next.jsで静的HTMLエクスポートしたアプリをローカルで確認する方法 - Qiita](https://qiita.com/Nossa/items/bdc6a9705e89ea8fc250)

### できること

CSR,SSG,SSRのうち、**CSR**と**SSG**は静的ホスティングでも使用できる。

**SSRは不可**。

### デプロイ環境

静的ホスティングさえできれば良い。

色んなデプロイ記事を読むと、具体的には以下のようなプラットフォームが使われていた。

・Netlify
・AWS Amplify Console
・firebase hosting
・GitHub Pages
・Amazon S3

## さいごに

改めてNext.jsのドキュメントを読むと、

・データを事前にレンダリングする必要がない場合はSSRではなくCSRを行うようにする

・クライアント側でのデータフェッチにはSWRというライブラリを使用する

ことが推奨されているなど、知らなかったことがあった。

また

・SSRさえ使わなければ静的ホスティングの機能のみのWebサーバーでデプロイすることが出来る

・Next.jsも必要最低限以外はSSRではなくCSRを推奨している

ということを考えると、SSRを使う選択をするケースはかなり少なくなるのかなと思った。

CSR/SSG/SSRの違いは、単純にクライアントサイド/サーバーサイドのどちらでレンダリングするかだったり、パフォーマンス面だけではなく、デプロイ方法やその先にある運用コストも左右するということが分かったので、引き続き勉強していきたい。

## 参考記事

https://zenn.dev/yohei_watanabe/articles/0d30bcf579f939

https://qiita.com/Nossa/items/bdc6a9705e89ea8fc250

https://www.wakuwakubank.com/posts/771-react-nextjs-ssg/

https://qiita.com/thesugar/items/47ec3d243d00ddd0b4ed

https://hackmd.io/@euxn23/r1zO5zzpw