client-side-rendering について
クライアントサイドレンダリング(CSR)を解説する学習スキルです。ブラウザー上の JavaScript による描画、データ取得、ルーティングを説明し、適した用途や読み込み性能の改善方法も扱います。
主な機能
- 01ブラウザーの JavaScript でページを描画
- 02シングルページナビゲーションに対応
- 03SEO と読み込み時間のトレードオフを説明
- 04コード分割と遅延読み込みを解説
- 05Service Worker によるシェルのキャッシュ
活用シーン
- 01操作性の高い社内ダッシュボードの構築
- 02ページ遷移で再読み込みしない SPA の作成
- 03遅延読み込みによる初期 JavaScript の削減
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ patternsdev/ skills --skill client-side-renderingインストール後、Claude Code で/client-side-renderingを入力して読み込まれたか確認します。
詳細
クライアントサイドレンダリング
クライアントサイドレンダリング(CSR)では、サーバーがレンダリングするのはページの最小限の HTML コンテナのみです。ページにコンテンツを表示するために必要なロジック、データ取得、テンプレート処理、ルーティングは、ブラウザー/クライアントで実行される JavaScript コードが処理します。CSR は、シングルページアプリケーションを構築する方法として普及しました。ウェブサイトとインストール型アプリケーションの違いを曖昧にするのに役立ちました。
使用する場合
- SEO が優先事項ではない内部ツール、ダッシュボード、SPA に使用します
- 完全にインタラクティブなシングルページアプリケーションの操作性が必要な場合に役立ちます
使用しない場合
- 検索エンジンがコンテンツをインデックスするために、サーバーでレンダリングされた HTML を必要とする、SEO が重要なページ
- JavaScript の読み込みと実行が完了するまで、ユーザーに空白のページが表示される、コンテンツ量の多いサイト
- 初回コンテンツ描画までの時間が重要な指標である場合 — CSR ではすべてのレンダリングがクライアント側に委ねられます
手順
- 初回コンテンツ描画を高速化するため、初期 JavaScript バンドルは小さく保ちます(圧縮後 100~170 KB 未満)
- コード分割と遅延読み込みを使用して、重要でない JavaScript の読み込みを遅らせます
- SEO と初期読み込みパフォーマンスが重要な一般公開ページでは、SSR/SSG を検討します
- オフライン時や再訪時のパフォーマンス向上のため、サービスワーカーとアプリケーションシェルのキャッシュを使用します
詳細
基本構造
React を使ってページの現在時刻を表示し、更新する簡単な例を考えてみましょう。
import { createRoot } from 'react-dom/client'
import { useEffect, useState } from 'react'
function Clock() {
const [time, setTime] = useState(new Date())
useEffect(() => {
const id = setInterval(() => setTime(new Date()), 1000)
return () => clearInterval(id)
}, [])
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {time.toLocaleTimeString()}.</h2>
</div>
)
}
createRoot(document.getElementById('root')!).render(<Clock />)
<div id="root"></div>
HTML は単一のルート <div> タグだけで構成されています。一方、コンテンツの表示と更新はすべて JavaScript が処理します。サーバーへの往復はなく、レンダリングされた HTML はその場で更新されます。ここでの時刻は、API から取得した為替レートや株価など、ほかのリアルタイム情報に置き換えることができます。その情報は、ページを再読み込みしたりサーバーを往復したりすることなく表示できます。
JavaScript バンドルとパフォーマンス
ページが複雑になり、画像の表示、データストアからのデータ表示、イベント処理が必要になるにつれて、ページのレンダリングに必要な JavaScript コードの複雑さとサイズも増加します。CSR では JavaScript バンドルが大きくなり、ページの FCP と TTI が遅くなりました。
bundle.js のサイズが大きくなるほど、FCP と TTI は遅くなります。つまり、FP から FCP までの間、ユーザーには空白の画面が表示されます。
メリットとデメリット
React では、アプリケーションのロジックの大部分がクライアントで実行され、データの取得や保存には API 呼び出しを通じてサーバーと通信します。そのため、UI のほぼすべてがクライアントで生成されます。最初のリクエストで、Web アプリケーション全体が読み込まれます。ユーザーがリンクをクリックして移動しても、ページをレンダリングするための新しいリクエストはサーバーに送信されません。クライアントでコードを実行して、表示やデータを変更します。
CSR を使うと、ページを更新せずに移動でき、優れたユーザー体験を提供するシングルページアプリケーションを実現できます。表示の変更に伴って処理するデータが限られているため、ページ間の移動は一般的に高速で、CSR アプリケーションの応答性が高く感じられます。また、CSR によって、開発者はクライアントコードとサーバーコードを明確に分離できます。
優れたインタラクティブなユーザー体験を提供する一方で、CSR にはいくつかの注意点があります。
-
SEO に関する考慮事項: 多くのWeb クローラーは、サーバーでレンダリングされたWeb サイトを問題なく解釈できます。一方、クライアントサイドレンダリングでは状況がやや複雑になります。大きなペイロードや、ネットワークリクエストの連鎖(API のレスポンスなど)が原因で、クローラーがインデックスに登録する前に、意味のあるコンテンツが十分に速くレンダリングされない場合があります。クローラーは JavaScript を理解できる場合もありますが、制約があります。そのため、クライアントでレンダリングされるWeb サイトを SEO に適したものにするには、いくつかの回避策が必要です。
-
パフォーマンス: クライアントサイドレンダリングでは、サーバーとの往復がないため、操作時の応答時間が大幅に短縮されます。しかし、ブラウザーが初回にクライアントサイドでコンテンツをレンダリングするには、まず JavaScript の読み込みと処理の開始を待つ必要があります。そのため、初期ページの読み込みまでに遅延が発生します。JS バンドルのサイズが大きくなる場合や、クライアントの処理能力が不十分な場合は、ユーザー体験に影響する可能性があります。
-
コードの保守性: コードの一部が、クライアント側とサーバー側(API)で異なる言語を使って重複する場合があります。また、ビジネスロジックを明確に分離できないこともあります。たとえば、通貨フィールドや日付フィールドの検証および書式設定のロジックがこれに該当します。
-
データの取得: クライアントサイドレンダリングでは、通常、イベントに応じてデータを取得します。ページは、最初はデータなしで読み込まれることがあります。その後、ページの読み込みやボタンのクリックなどのイベントが発生した際に、API 呼び出しでデータを取得できます。データのサイズによっては、アプリケーションの読み込み時間や操作への応答時間が長くなる可能性があります。
これらの考慮事項の重要度は、アプリケーションによって異なります。開発者は、操作時の応答時間を損なわずにページをより速く提供できる、SEO に適したソリューションを求めることがよくあります。
CSR パフォーマンスの向上
CSR のパフォーマンスは JavaScript バンドルのサイズに反比例するため、最善の方法は、最適なパフォーマンスが得られるように JavaScript コードを構成することです。役立つヒントを以下に示します。
-
JavaScript の予算設定:初回ページ読み込み時の JavaScript の予算を、妥当な範囲に抑えてください。初期バンドルのサイズは、圧縮後かつ gzip 圧縮後で 100~170KB 未満を目安にするとよいでしょう。その後、機能が必要になった時点でコードをオンデマンドで読み込めます。
-
プリロード:この手法では、ページのライフサイクルの早い段階で、ページに必要となる重要なリソースをプリロードできます。重要なリソースには JavaScript が含まれることがあります。HTML の
<head>セクションに次のディレクティブを記述すると、プリロードできます。
<link rel="preload" as="script" href="critical.js" />
これにより、ページのレンダリング処理が始まる前に、ブラウザーは critical.js ファイルの読み込みを開始します。そのため、スクリプトをより早い段階で利用でき、ページのレンダリング処理を妨げることなく、パフォーマンスを向上させられます。
-
遅延読み込み:遅延読み込みを使うと、重要ではないリソースを特定し、必要になったときだけ読み込めます。最初に読み込むリソースのサイズを小さくできるため、この方法で初回ページの読み込み時間を改善できます。たとえば、チャットウィジェットのコンポーネントは通常、ページの読み込み直後には必要ないため、遅延読み込みできます。
-
コード分割:JavaScript コードのバンドルが大きくなりすぎないよう、バンドルを分割できます。Webpack などのバンドラーはコード分割をサポートしており、実行時に動的に読み込める複数のバンドルを作成できます。また、コード分割により JavaScript リソースの遅延読み込みも可能になります。
-
サービスワーカーによるアプリケーションシェルのキャッシュ:この手法では、ユーザーインターフェースを動作させるための最小限の HTML、CSS、JavaScript であるアプリケーションシェルをキャッシュします。サービスワーカーを使って、アプリケーションシェルをオフラインでキャッシュできます。残りのコンテンツを必要に応じて段階的に読み込むことで、ネイティブアプリのようなシングルページアプリの操作感を実現するのに役立ちます。
これらの手法を使うと、CSR により、適切な FCP と TTI を備えた、より高速なシングルページアプリの操作体験を提供できます。