はじめに
Webアプリケーションのレンダリング手法としてCSR (Client Side Rendering), SSR (Server Side Rendering), SSG (Static Site Generator), ISR (Incremental Static Generator)等色々あるが、大まかに分けるとクライアント側にHTMLを生成させるCSRとサーバー側でHTMLを構築したものをクライアントに送るSSRの2つに分けられると思う。本記事ではCSRとSSRの2つの使い分けについて考えていく。
用語集
レンダリング関連
SSR (Server Side Rendering):サーバー側でレンダリングしたHTMLをクライアントサイドで表示する
CSR (Client Side Rendering):ブラウザ側でアプリをレンダリングし、一般的にDOMを使用する
Rehydration:サーバーでレンダリングされたHTMLのDOMツリーとデータを再利用するように、クライアントでJavaScriptを読み込む
Prerendering:ビルド時にクライアントサイドアプリを実行して、初期状態を静的なHTMLとしてキャプチャすること
パフォーマンス関連
TTFB (Time to First Byte):リンクをクリックして最初のコンテンツが表示されるまでの時間
FP (First Paint):ユーザーに表示される最初のピクセルが表示される時間
FCP (First Contentful Paint):要求されたコンテンツ(記事の本文など)が表示される時間
TTI (Time To Interactive):イベントが有効になるなどしてページがインタラクティブになる時間
LCP (Largest Content Paint): ブラウザの表示範囲内で一番大きなコンテンツ(画像や動画等)が表示されるまでの時間
TBT (Total Blocking Time): メインスレッドをブロックして入力の応答性が妨げられる時間。FCP→TTIまでの時間
レンダリングの流れのおさらい
簡単な比較
とても良い記事があったので、画像を引っ張ってきた
こっちがCSR
こっちがSSR
CSR (Client Side Rendering)の概要
CSRは、ブラウザ側でJavaScriptを用いて都度画面描画する手法である。非同期処理がJavaScriptで簡単にプログラムできるようになり、ブラウザのスクリプト実行エンジンの進化により、JavaScriptの実行が非常に高速化されている。このため、CSRでは、サーバーで処理した結果を毎回HTMLで受け取って再描画するのではなく、JSONなどでデータだけを受け取り、クライアント側のJavaScriptで差分描画させることで、ユーザーが体感するレスポンスが向上することができる。
代表的なCSR:SPA (Single Page Application)
CSRの代表的なユースケースであるSPAは、デスクトップアプリのような快適な操作性を提供できるという売り文句がある。SPAでは、最初にページの枠を表示し、非同期通信でデータだけを受け取り、JavaScriptで画面の差分だけを更新する手法を採用している。画面全体のHTMLの解析・表示処理をせず、初期表示のステップを一気にTTIまでスキップすることで、高速化を図る。最近のwebアプリケーションは基本的にSPAである事が多い。
CSRのメリットとデメリット
メリット
サーバー負荷が低い:サーバーはAPIデータや静的ファイルのみを提供するため、負荷が軽減される。
リアルタイムな更新が容易:クライアント側でレンダリングが行われるため、動的な更新がしやすい。
シングルページアプリケーション (SPA) の実装が容易。
デメリット
初期表示が遅い:クライアント側でHTMLを生成するため、初回ロード時に時間がかかることがある。
SEO対策が難しい:クライアント側で生成されるHTMLは検索エンジンによってクロールされにくいことがある。
「クローラー」とは、ウェブサイトを巡回するロボットを指します。
ただし、ただ巡回しているわけではありません。「検索順位を決める要素を収集する」という重要な役目を担っています。
当然、「検索順位を決める要素」という点で、SEOにおいても無視できない存在です。
https://gmotech.jp/semlabo/seo/blog/crawler_measures/
CSRのユースケース
- リアルタイムな更新が重要なウェブアプリケーション(チャットアプリ、ダッシュボードなど)
- ユーザーインタラクションが多いウェブアプリケーション(ゲーム、ドラッグアンドドロップUIなど)
- シングルページアプリケーション (SPA) の実装が必要なウェブアプリケーション
CSRを採用する際の検討事項
CSRを採用する際には、以下の点を検討する必要がある。
パフォーマンスの最適化
初期表示が遅いというデメリットを解消するために、パフォーマンスの最適化が重要。コードの最小化や遅延読み込み、キャッシュの活用などを行い、ページの表示速度を向上させることが求められる。jQueryが肥大化することでパフォーマンスが落ちると言われているのはここら辺。
SEO対策の強化
クライアント側で生成されるHTMLは、検索エンジンによってクロールされにくいことがある。これを解決するために、SSRとの併用や、プリレンダリングなどの技術を利用してSEO対策を強化することが求められる。つまるところググっても出てきづらい。とはいえ、状況も変わってきていて最近は検索エンジンが動的に生成されたコンテンツも評価できるようになったので別にSEO対策のためだけにSSRに舵を切る必要はなくなりつつあるのかもしれない。
SEO対策について良い記事があったので、貼っておく。
セキュリティ対策
CSRでは、JavaScriptを多用するため、クロスサイトスクリプティング (XSS) などの脆弱性に対する対策が必要。セキュアなコーディングを心掛けるとともに、セキュリティに関する最新情報を常にキャッチアップしておくことが求められる。SSRでも同じ事が求められるが、開発の過程でクライアント側にわたるjsパッケージが増えるので、その分気を付けないといけない。
SSR (Server Side Rendering)の概要
SSRは、サーバー側でHTMLを生成し、クライアント(ブラウザ)に送信することでページをレンダリングする手法。CSRとは対照的に、ページの生成やデータの取得がサーバー側で行われ、クライアント側では受け取ったHTMLを表示するだけの処理を行う。
SSRのメリットとデメリット
メリット
初期表示が速い:サーバー側でHTMLを生成するため、クライアント側では受け取ったHTMLを表示するだけでよく、初回ロード時の表示速度が向上する。
SEO対策が容易:サーバー側で生成されたHTMLは検索エンジンによってクロールされやすく、SEO対策がしやすい。
デメリット
サーバー負荷が高い:サーバー側でHTMLの生成やデータの取得が行われるため、負荷が増加する。
リアルタイムな更新が難しい:クライアント側でレンダリングが行われないため、動的な更新がしにくい。
SSRのユースケース
- SEO対策が重要なウェブサイト(ブログ、ニュースサイト、eコマースサイトなど)
- 初期表示速度が重要なウェブサイト
- ユーザーインタラクションが少ないウェブサイト
SSRを採用する際の検討事項
SSRを採用する際には、以下の点を検討する必要がある。
サーバー負荷の軽減
サーバー負荷が高いというデメリットを解消するために、キャッシュの活用やロードバランサーの導入、サーバーのスケーリングなどを行い、サーバーの負荷を軽減することが重要。
リアルタイムな更新の実現
SSRではリアルタイムな更新が難しいというデメリットがあるが、AjaxやWebSocketなどの技術を用いてクライアントとサーバー間の通信を行うことで、動的な更新を実現することが可能。
クライアントとの連携
CSRとSSRを併用することで、初期表示速度の向上やSEO対策の強化に加えて、リアルタイムな更新やユーザーインタラクションの改善も実現できる。このようなハイブリッドアプローチを採用する場合、適切なアーキテクチャ設計やフレームワークの選択が重要。例えば、Next.jsやNuxt.jsなどのフレームワークは、CSRとSSRを組み合わせた開発が容易に行えるよう設計されている。どう併用できるのかについては次に語る
CSRとSSRの併用
webアプリを開発するうえで、別にCSRとSSRのどっちかしか使えないということは別にない。ここでは簡単にランディングのみをSSR、別ページをCSRでレンダリングするNuxt.jsのサンプルコードを書く
導入
npm install -g create-nuxt-app
create-nuxt-app nuxt-ssr-csr-demo
# 質問はEnter連打でok
✨ Generating Nuxt.js project in nuxt-ssr-csr-demo
? Project name: nuxt-ssr-csr-demo
? Programming language: JavaScript
? Package manager: Npm
? UI framework: None
? Template engine: HTML
? Nuxt.js modules: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Linting tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Testing framework: None
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Server (Node.js hosting)
? Development tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? What is your GitHub username? sandy sunday
? Version control system: Git
# プロジェクトファイルに移動
cd nuxt-ssr-csr-demo
必要なファイルを作成していく。今回はランディングページとaboutページの2つを作成する。
# /nuxt-ssr-csr-demo/layouts/default.vue
# 全ページに共通するテンプレートを作成
<template>
<div>
<header>
<nav>
<nuxt-link to="/">Home</nuxt-link>
<nuxt-link to="/about">About</nuxt-link>
</nav>
</header>
<Nuxt />
<footer>
<!-- Your footer content goes here -->
</footer>
</div>
</template>
# /nuxt-ssr-csr-demo/pages/index.vue
# ランディングページの作成
<template>
<div>
<h1>Welcome to the SSR Landing Page</h1>
<p>This page is server-side rendered.</p>
</div>
</template>
<script>
export default {
asyncData(context) {
if (process.server) {
console.log('This code is executed on server-side (SSR)');
} else if (process.client) {
console.log('This code is executed on client-side (CSR)');
}
},
};
</script>
後でちゃんとCSRとSSRを使い分けられているかを確認するためにprocess.client
とprocess.server
を仕込んだ。例えば、サーバー側でコードが動いている時はprocess.server
はtrue
を返すようになっている。クライアント側とサーバー側で二重にコードが走行するのを防ぐのにも使われる記法でもあるらしい。
# /nuxt-ssr-csr-demo/pages/about.vue
# aboutページの作成
<template>
<div>
<h1>About Page</h1>
<client-only>
<CsrComponent />
</client-only>
</div>
</template>
<script>
import CsrComponent from '~/components/CsrComponent.vue';
export default {
components: {
CsrComponent,
},
asyncData(context) {
if (process.server) {
console.log('This code is executed on server-side (SSR)');
} else if (process.client) {
console.log('This code is executed on client-side (CSR)');
}
},
};
</script>
肝心なのはNuxt.jsにおいて、client-only
コンポーネントとno-ssr
コンポーネント以外はSSRがデフォルトになっているということ。
<CsrComponent />
に入る要素はCsrComponent.vue
で作成する。
The ssr property
Change default nuxt ssr valueType: boolean
Default: true
Possible values:
true: Server-side rendering enabled
false: No server-side rendering (only client-side rendering)
https://nuxtjs.org/docs/configuration-glossary/configuration-ssr/
# /nuxt-ssr-csr-demo/components/CsrComponent.vue
# about.vue で呼び出すコンポーネントの作成
<template>
<div>
<p>This content is client-side rendered.</p>
</div>
</template>
一通りできたら、ローカルサーバーを起動する
npm run dev
CSRとSSRを使い分けられているかを確認する
コンソールのログにThis code is executed on server-side (SSR)
とある
コンソールのログにThis code is executed on client-side (CSR)
とある。正しく動作したようだ。
最後に
仕事でNuxt.jsを使うと言われたからNuxt.jsの強みって考えてたら「SSRかなぁ..?」ってなって今回の記事を書いた。けど、仕事で作るの業務改善用のアプリだから別に技術選定として妥当なのかぶっちゃけよく分からんかった()
参考リンク