レンダリングパターンをいらすとやで解説してみた

## この記事について
[株式会社CAM Advent Calendar 2019](https://qiita.com/advent-calendar/2019/cam-inc) の11日目です
昨日は、@koooooo の「[OpenAPI 3のドキュメントの一部翻訳](https://qiita.com/koooooo/items/daa65615d8f840549432)」 でした

この記事では、レンダリングパターンの違いにおけるあれこれや向いてるサービスなどを書いています

はじめまして、まるけんです！
株式会社CAMでフロントエンドエンジニアをしています
入社してからはや８ヶ月、これまでに`フルCSR`, `フルSSR`, `CSR with (Re)hydration`（後述）のサービス開発に携わってきました
私がそれぞれのサービス開発で感じた、レンダリングパターンの良し悪しや、向き不向きをできるだけわかりやすく解説していきたいと思います

私自身、デザイナーから転向してきた身なので具体的にハマった箇所などまでは書きません
また、初めての技術（？）ブログなので間違っている箇所もあると思います
その時はコソッと教えていただけると嬉しいです


いろんなレンダリングパターンがあるんだな〜というのを知ってもらって、これからのサービス開発に役立ててもらえれば幸いです


## レンダリングとは？
`render` - 翻訳する, 表現する, 描画する

かみ砕いて説明すると、
「設計図をもとに見た目を整えたり、生成したりすること」を指します

具体的には、HTMLファイルをブラウザが理解して画面に表示する一連の流れや、PHPのコードをPHPサーバーが理解してHTMLファイルを生成することなどを指します

一口にレンダリングといっても、ブラウザで表示される部分だけではないということですね

ウェブをブラウザで表示するにあたって、レンダリングには様々な方法があります
[Rendering on the Web - Web上のレンダリング](https://developers.google.com/web/updates/2019/02/rendering-on-the-web?hl=ja#rehydration-issues) を参考に図解で理解していきましょう

## ウェブアプリケーションにおけるレンダリングの種類
- 静的レンダリング（Static SSR）
- サーバーサイドレンダリング（SSR）
- クライアントサイドレンダリング（CSR)
- プリレンダリング（CSR with Prerendering）
- ハイドレーションレンダリング（SSR with (Re)Hydration)

それぞれのレンダリングパターンを、「先生が生徒に問題を投げかけて、それを黒板に書き出す」というシチュエーションに置き換えてみていきたいと思います

### Static SSR
ホームページなどでよくやるやり方です
あらかじめ用意しておいたHTMLファイルを返すオーソドックスなものですね
URLの数だけHTMLファイルを用意しておく必要がありますが、リクエストが飛んできてから動的に出し分ける処理がないため、表示が早いのが特徴です
ただ、複数機能を求められるウェブアプリケーションにはやや不向きです
![renderingPattern-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386847/f4e53ee5-f3b9-f90d-603f-1b408b2c5bbf.png)


### SSR
いわゆる`PHP`で作るウェブアプリケーションがこれに当てはまります
リクエストを受けてからサーバー側で処理を行い、生成したHTMLファイルを返すため、初期表示までに時間がかかってしまいます
ただ、クライアント側（ブラウザ）での処理がほとんど発生したいため、初期表示さえされればページ全体の表示はあっという間という特徴があります

サーバーサイドの処理をいかに早くするかが使いやすいウェブアプリケーションへの鍵になります

一方で、初期表示までの時間がかかってしまうため、ページ遷移の多いアプリケーションには不向きです
![renderingPattern_アートボード 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386847/650d4826-f562-ffc5-e4f9-2eac2484539f.png)

### CSR
VueとかReactとか、あらかじめ用意しておいたHTMLファイルを展開し、JavaScriptでゴリゴリと中身を書き換えて行くタイプのレンダリング方法です
ネイティブアプリのように多機能なものや、Twitterのような通信回数の多いサービスに向いています
また、画面の切り替えは基本的にクライアントサイドで全て完結するため、必要最低限の通信に抑えられるのも特徴です
ただ、アプリの機能が増えるに連れてJSファイルが肥大化してきてアプリ自体が大きく重くなってしまうのが難点です
必要に応じて必要なJSを読み込むような仕組みが必要となってきます
![renderingPattern-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386847/25e5b863-9537-be35-bca0-6da38953f608.png)

### CSR with Prerendering
CSRの「初期表示」が遅いという問題を回避したレンダリング方法です
ビルド段階である程度のHTMLファイルを生成しておくことで、クライアントサイドでのレンダリングを省略しています
ただ、SSRではないため初期表示時点ではコンテンツやユーザーの個人情報が入っていません
なので、事前にデータが入るであろうアリアをスタイルしておく方法がよく取られます
多機能で、かつ初期表示も早いため多くのサービスで使われているレンダリング方法です
![renderingPattern-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386847/d470f1de-41f8-fb3e-2d20-85672f3abbd1.png)



### SSR with (Re)hydration
SSRとCSRのいいところを組み合わせたレンダリング方法です
サーバーサイドでリクエストに必要なHTMLファイルを生成し、クライアントサイドへ返します
その後、クライアントサイドでさらにレンダリングをしていくことでウェブアプリケーションが表示されます

プリレンダリングではあらかじめ用意したファイルしか返すことができないため、このレンダリング方法を使えば複雑なリクエストにより柔軟に対応することが可能です

しかし、サーバーサイドでの処理が発生するため初期表示が遅れてしまう問題があります
そこで、サーバーサイドではキャッシュを活用することで、まるでプリレンダリングされたアプリケーションのような初期表示の速さを実現する方法がとられます
![renderingPattern-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386847/79fd1dbd-2835-e7b2-5429-6ab42d84e82a.png)


## 実際に開発をしてみて比較
私はこれまで`CSR`, `SSR`, `SSR with (Re)hydration`のウェブアプリケーション開発に携わってきました。

CSRではパーツを使いまわしたり、通信周りの処理を工夫することで、複雑な機能のアプリケーションも完結に実装することができます。しかし、フロントエンジニアに求められる技術がリッチになりすぎて、開発工数が大きくなってしまうという問題があります。

SSRであればバックエンドエンジニアから受け取ったデータを当てはめて、スタイルするだけなのでよりスピーディーに対応することが可能です

また、SEO対策のしやすさで言ってもSSRが優っているでしょう。
現状（2019/12/11時点）、検索エンジンやSNS系のクローラーはJSを展開したアプリケーションを理解してくれるわけではありません

クローラーに対応するために様々な小細工をしなければならない場合も少なくありません

その観点から見れば、CSRもSSRも一長一短があり、どちらが正義というわけでもないという感じです


## まとめ
多機能で現代風だからという理由でCSRを使ったシングルページアプリケーションが最強！という風潮をよく見かけますが、全くそんなことはありません。PHPを使った開発は古いと言われますが、大切なのはサービスの機能や規模にあった開発であり、ユーザにとって使いやすいかどうかなのです。

これからのサービス開発に役立てていただければ幸いです

明日は @KeitaroArata の記事になります
お楽しみに！

## 参考文献
https://developers.google.com/web/updates/2019/02/rendering-on-the-web?hl=ja#rehydration-issues
https://www.toptal.com/front-end/client-side-vs-server-side-pre-rendering