🎭 CSR vs SSR vs SSG
📖 定義
Webページを生成して表示する方式は大きく3つに分かれます:
- CSR (Client-Side Rendering): ブラウザでJavaScriptでページを生成
- SSR (Server-Side Rendering): サーバーでHTMLを完成させて送る
- SSG (Static Site Generation): ビルド時点で事前にHTML生成
各方式には長所と短所があり、プロジェクトの特性に合わせて選択する必要があります。
🎯 比喩で理解する
レストランの比喩
3つのレンダリング方式をレストランに例えると:
CSR (Client-Side Rendering)
= セルフクッキングレストラン 🍳
お客様(ブラウザ):
1. レストラン入場 (空のHTMLを受け取る)
2. 材料を受け取る (JavaScriptダウンロード)
3. 自分で調理 (レンダリング)
4. 完成した料理を食べる
長所: キッチン(サーバー)の負担が少ない、自由に調理
短所: 調理時間が必要、初心者には難しい
---
SSR (Server-Side Rendering)
= 一般的なレストラン 🍽️
キッチン(サーバー):
1. 注文を受ける (リクエスト)
2. 調理する (HTML生成)
3. 完成した料理を提供 (HTML送信)
お客様(ブラウザ):
すぐに食べられる!
長所: 速い初期ロード、検索エンジン対応
短所: キッチンの負担が大きい、毎回調理が必要
---
SSG (Static Site Generation)
= お弁当チェーン店 🍱
ビルドタイム:
1. 事前にすべてのお弁当を準備
2. 冷蔵庫に保管 (CDN)
お客様(ブラウザ):
1. 注文
2. すぐに包装されたお弁当を受け取る
3. 食べる
長所: 超高速配達、低コスト
短所: メニュー変更が難しい、新鮮さに制限
建築の比喩
CSR = 組み立て式家具 (IKEA) 🪑
- 部品と説明書を配送
- 自宅で組み立て
- 配送料が安い
- 組み立て時間が必要
SSR = オーダーメイド家具 🛋️
- オーダー製作
- 完成品を配送
- すぐに使える
- コストが高い、時間がかかる
SSG = 既製品家具 🪟
- 事前に作っておく
- 倉庫に保管
- すぐに配送
- 安くて速い
- カスタマイズ不可
⚙️ 動作原理
1. CSR (Client-Side Rendering)
// CSRの流れ
// 1段階: サーバーから最小限のHTMLを送信
// index.html
<!DOCTYPE html>
<html>
<head>
<title>CSR App</title>
</head>
<body>
<div id="root"></div> <!-- 空っぽ! -->
<script src="/bundle.js"></script>
</body>
</html>
// 2段階: ブラウザがJavaScriptをダウンロード
// GET /bundle.js (2MB)
// 3段階: JavaScript実行
ReactDOM.render(<App />, document.getElementById('root'));
// 4段階: APIを呼び出してデータを取得
fetch('/api/posts')
.then(res => res.json())
.then(data => setPost(data));
// 5段階: 画面レンダリング完了
// タイムライン:
// 0ms: HTML到着 (空白画面)
// 100ms: JavaScriptダウンロード開始
// 1000ms: JavaScriptパースと実行
// 1500ms: API呼び出し
// 2000ms: データ到着
// 2100ms: 画面表示完了 ✅
// ユーザーが見るもの:
// 0-2100ms: 白い画面またはローディングスピナー
// 2100ms~: 完成したページ
2. SSR (Server-Side Rendering)
// SSRの流れ
// 1段階: クライアントリクエスト
// GET /posts/123
// 2段階: サーバーでデータを取得
// server.js (Node.js + Express)
app.get('/posts/:id', async (req, res) => {
// データベース照会
const post = await db.posts.findById(req.params.id);
// ReactコンポーネントをHTML文字列に変換
const html = ReactDOMServer.renderToString(
<PostPage post={post} />
);
// 完成したHTMLを送信
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>${post.title}</title>
</head>
<body>
<div id="root">${html}</div>
<script>
window.__INITIAL_DATA__ = ${JSON.stringify(post)};
</script>
<script src="/bundle.js"></script>
</body>
</html>
`);
});
// 3段階: ブラウザがHTMLを受け取る
// すぐに画面表示可能! (HTMLが完成している)
// 4段階: Hydration
// JavaScriptがロードされるとイベントリスナーを接続
ReactDOM.hydrate(<PostPage />, document.getElementById('root'));
// タイムライン:
// 0ms: リクエスト
// 50ms: サーバーでデータ照会
// 100ms: HTML生成
// 200ms: HTML到着
// 250ms: 画面表示 ✅ (速い!)
// 1000ms: JavaScriptロード
// 1100ms: Hydration完了 (インタラクティブ)
// ユーザーが見るもの:
// 0-250ms: ローディング
// 250-1100ms: 見えるがクリックできない
// 1100ms~: 完全に動作
3. SSG (Static Site Generation)
// SSGの流れ
// ビルドタイム (デプロイ前)
// next build
// 1段階: すべてのページを事前に生成
// pages/posts/[id].js
export async function getStaticPaths() {
// 生成するページリスト
const posts = await db.posts.findAll();
return {
paths: posts.map(post => ({
params: { id: post.id.toString() }
})),
fallback: false
};
}
export async function getStaticProps({ params }) {
// 各ページのデータ
const post = await db.posts.findById(params.id);
return {
props: { post }
};
}
// 2段階: HTMLファイル生成
// .next/server/pages/posts/1.html
// .next/server/pages/posts/2.html
// .next/server/pages/posts/3.html
// ...
// 3段階: CDNにデプロイ
// Vercel、Netlify、CloudFrontなど
// ランタイム (ユーザーリクエスト時)
// GET /posts/123
// CDNがすぐにHTMLを返す (超高速!)
// タイムライン:
// 0ms: リクエスト
// 10ms: CDNからHTML返却 ✅ (非常に速い!)
// 500ms: JavaScriptロード
// 600ms: Hydration完了
// ユーザーが見るもの:
// 0-10ms: ローディング
// 10-600ms: 見えるがクリックできない
// 600ms~: 完全に動作
💡 実例
CSRの例 (Create React App)
// src/App.js
import React, { useState, useEffect } from 'react';
function App() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
// ブラウザでAPI呼び出し
fetch('https://api.example.com/posts')
.then(res => res.json())
.then(data => {
setPosts(data);
setLoading(false);
})
.catch(error => {
console.error('Error:', error);
setLoading(false);
});
}, []);
if (loading) {
return <div>読み込み中...</div>;
}
return (
<div className="app">
<h1>ブログ投稿</h1>
<ul>
{posts.map(post => (
<li key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</li>
))}
</ul>
</div>
);
}
export default App;
// 長所:
// 1. サーバー負荷なし
// 2. ページ遷移が速い (SPA)
// 3. 豊富なインタラクション
// 短所:
// 1. 初期ロードが遅い
// 2. SEOが難しい (空のHTML)
// 3. JavaScript必須
// 適している場合:
// - 管理者ダッシュボード
// - ログイン後に使用するアプリ
// - SEO不要なサービス
SSRの例 (Next.js)
// pages/posts/[id].js
import { useRouter } from 'next/router';
function Post({ post }) {
const router = useRouter();
// ローディング状態 (fallback)
if (router.isFallback) {
return <div>読み込み中...</div>;
}
return (
<article>
<h1>{post.title}</h1>
<p>{post.author}</p>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
);
}
// サーバーで実行 (リクエストごと)
export async function getServerSideProps({ params }) {
// データベースまたはAPI呼び出し
const res = await fetch(`https://api.example.com/posts/${params.id}`);
const post = await res.json();
// 404処理
if (!post) {
return {
notFound: true
};
}
// propsで渡す
return {
props: {
post
}
};
}
export default Post;
// サーバーで生成されたHTML:
// <!DOCTYPE html>
// <html>
// <head>
// <title>Next.js</title>
// </head>
// <body>
// <div id="__next">
// <article>
// <h1>タイトルです</h1>
// <p>作成者: 山田太郎</p>
// <div>
// <p>本文内容...</p>
// </div>
// </article>
// </div>
// <script src="/_next/static/chunks/main.js"></script>
// </body>
// </html>
// 長所:
// 1. 速い初期ロード
// 2. SEO最適化
// 3. リアルタイムデータ
// 短所:
// 1. サーバーコストが高い
// 2. レスポンス時間の変動
// 3. キャッシュが難しい
// 適している場合:
// - ニュースサイト
// - ソーシャルメディアフィード
// - リアルタイム更新が必要
SSGの例 (Next.js)
// pages/blog/[slug].js
function BlogPost({ post }) {
return (
<article>
<h1>{post.title}</h1>
<time>{post.date}</time>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
);
}
// ビルド時に実行: どのページを生成するか
export async function getStaticPaths() {
// すべての投稿リストを取得
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
// 生成するパスリスト
const paths = posts.map(post => ({
params: { slug: post.slug }
}));
return {
paths,
fallback: 'blocking' // 新しいページはSSRで処理
};
}
// ビルド時に実行: 各ページのデータ
export async function getStaticProps({ params }) {
const res = await fetch(`https://api.example.com/posts/${params.slug}`);
const post = await res.json();
return {
props: {
post
},
revalidate: 60 // ISR: 60秒ごとに再生成
};
}
export default BlogPost;
// ビルド結果:
// .next/server/pages/blog/first-post.html
// .next/server/pages/blog/second-post.html
// .next/server/pages/blog/third-post.html
// 長所:
// 1. 超高速ロード
// 2. サーバー負荷なし
// 3. SEO完璧
// 4. 安価なホスティング
// 短所:
// 1. ビルド時間が長い
// 2. リアルタイムデータ不可
// 3. ページが多いと問題
// 適している場合:
// - ブログ
// - ドキュメントサイト
// - マーケティングページ
// - ポートフォリオ
ISR (Incremental Static Regeneration)
// SSG + SSRの長所を結合!
// pages/products/[id].js
function Product({ product }) {
return (
<div>
<h1>{product.name}</h1>
<p>価格: {product.price}円</p>
<p>在庫: {product.stock}個</p>
</div>
);
}
export async function getStaticPaths() {
// 人気商品100個だけ事前生成
const popularProducts = await getPopularProducts(100);
return {
paths: popularProducts.map(p => ({
params: { id: p.id.toString() }
})),
fallback: 'blocking' // 残りはリクエスト時に生成
};
}
export async function getStaticProps({ params }) {
const product = await getProduct(params.id);
return {
props: { product },
revalidate: 10 // 10秒ごとに再検証
};
}
export default Product;
// 動作方式:
// 1. ビルド時: 人気商品100個のHTML生成
// 2. 最初のリクエスト: 残りの商品はSSRで生成後キャッシュ
// 3. 10秒後: バックグラウンドで再生成
// 4. 常に最新データを維持!
// 長所:
// - 速いビルド時間
// - 速いレスポンス速度
// - 最新データ提供
// - 無限のページ可能
ハイブリッドの例
// Next.jsアプリで複数の方式を混合
// 1. ホームページ - SSG (静的)
// pages/index.js
export async function getStaticProps() {
return {
props: { hero: '...' },
revalidate: 3600 // 1時間ごと
};
}
// 2. ブログリスト - ISR
// pages/blog/index.js
export async function getStaticProps() {
const posts = await getPosts();
return {
props: { posts },
revalidate: 60 // 1分ごと
};
}
// 3. ブログ投稿 - SSG
// pages/blog/[slug].js
export async function getStaticPaths() {
const posts = await getPosts();
return {
paths: posts.map(p => ({ params: { slug: p.slug }})),
fallback: 'blocking'
};
}
export async function getStaticProps({ params }) {
const post = await getPost(params.slug);
return {
props: { post },
revalidate: 3600
};
}
// 4. ユーザーダッシュボード - CSR
// pages/dashboard.js
function Dashboard() {
const [data, setData] = useState(null);
useEffect(() => {
// クライアントでのみ実行
fetch('/api/user/dashboard')
.then(res => res.json())
.then(setData);
}, []);
return <div>{/* ダッシュボードUI */}</div>;
}
// 5. 検索結果 - SSR
// pages/search.js
export async function getServerSideProps({ query }) {
const results = await search(query.q);
return {
props: { results, query: query.q }
};
}
// 各ページに最適なレンダリング方式を適用!
SEO比較
<!-- CSR: 検索エンジンが見るもの (JavaScript実行前) -->
<!DOCTYPE html>
<html>
<head>
<title>React App</title>
</head>
<body>
<div id="root"></div>
<!-- 内容なし! -->
<script src="/static/js/main.js"></script>
</body>
</html>
<!-- 検索エンジンは空のページと認識 ❌ -->
<!-- SSR/SSG: 検索エンジンが見るもの -->
<!DOCTYPE html>
<html>
<head>
<title>最高のReactチュートリアル</title>
<meta name="description" content="Reactを学ぶ最も簡単な方法">
<meta property="og:title" content="最高のReactチュートリアル">
<meta property="og:image" content="https://example.com/og.jpg">
</head>
<body>
<div id="__next">
<article>
<h1>最高のReactチュートリアル</h1>
<p>Reactを学ぶ最も簡単な方法を紹介します...</p>
<section>
<h2>1. Reactとは?</h2>
<p>Reactはユーザーインターフェースを作成するための...</p>
</section>
</article>
</div>
</body>
</html>
<!-- 完全な内容あり! ✅ -->
<!-- Google、Bingがよくインデックス -->
<!-- ソーシャルメディアプレビュー動作 -->
パフォーマンス比較
// Web パフォーマンス指標
// CSR (Create React App)
const csrMetrics = {
FCP: '2.5s', // First Contentful Paint
LCP: '3.5s', // Largest Contentful Paint
TTI: '4.0s', // Time to Interactive
TBT: '500ms', // Total Blocking Time
CLS: '0.1', // Cumulative Layout Shift
// ユーザー体験:
// 0-2.5s: 白い画面
// 2.5-4s: ローディングスピナー
// 4s: 完全に使用可能
};
// SSR (Next.js)
const ssrMetrics = {
FCP: '0.8s', // ⬆️ 速い!
LCP: '1.2s', // ⬆️ 速い!
TTI: '2.5s', // ⬆️ 速い!
TBT: '300ms', // ⬆️ 低い!
CLS: '0.05', // ⬆️ 低い!
// ユーザー体験:
// 0-0.8s: ローディング
// 0.8-2.5s: 見えるがクリックできない
// 2.5s: 完全に使用可能
};
// SSG (Next.js)
const ssgMetrics = {
FCP: '0.3s', // ⬆️⬆️ 非常に速い!
LCP: '0.5s', // ⬆️⬆️ 非常に速い!
TTI: '1.5s', // ⬆️⬆️ 非常に速い!
TBT: '100ms', // ⬆️⬆️ 非常に低い!
CLS: '0.02', // ⬆️⬆️ 非常に低い!
// ユーザー体験:
// 0-0.3s: ローディング
// 0.3-1.5s: 見えるがクリックできない
// 1.5s: 完全に使用可能
};
// 結論:
// SSG > SSR > CSR (初期ロード速度)
// CSR = SSR = SSG (その後のナビゲーション)
🤔 よくある質問
Q1. どのレンダリング方式を選ぶべきですか?
A: プロジェクトの特性に応じて選んでください:
// 選択ガイド
// 1. CSRを選択:
const csrUseCases = {
conditions: [
'SEOが重要ではない',
'ログイン後に使用するアプリ',
'リアルタイムインタラクションが多い',
'サーバーコストを節約'
],
examples: [
'管理者ダッシュボード',
'チャットアプリケーション',
'ゲーム',
'デザインツール (Figmaなど)',
'音楽プレーヤー',
'To-Do管理アプリ'
],
framework: 'Create React App, Vite'
};
// 2. SSRを選択:
const ssrUseCases = {
conditions: [
'SEOが重要',
'リアルタイムデータが必要',
'ユーザーごとのカスタムコンテンツ',
'速い初期ロード'
],
examples: [
'ニュースサイト',
'ソーシャルメディア',
'eコマース商品ページ',
'検索結果ページ',
'リアルタイム株式情報',
'天気アプリ'
],
framework: 'Next.js, Nuxt.js, SvelteKit'
};
// 3. SSGを選択:
const ssgUseCases = {
conditions: [
'SEOが重要',
'コンテンツがあまり変わらない',
'最高のパフォーマンスが必要',
'安価なホスティング'
],
examples: [
'ブログ',
'ドキュメントサイト',
'マーケティングランディングページ',
'ポートフォリオ',
'会社紹介',
'製品カタログ'
],
framework: 'Next.js, Gatsby, Astro'
};
// 4. ハイブリッド (推奨!):
const hybridUseCases = {
strategy: 'ページごとに異なる方式を使用',
example: {
'/': 'SSG', // ホームページ
'/about': 'SSG', // 紹介
'/blog': 'ISR', // ブログリスト
'/blog/[slug]': 'SSG', // ブログ投稿
'/products': 'ISR', // 商品リスト
'/products/[id]': 'ISR', // 商品詳細
'/search': 'SSR', // 検索結果
'/dashboard': 'CSR', // ダッシュボード
'/profile': 'CSR' // プロフィール
},
framework: 'Next.js (最高の選択)'
};
// 意思決定ツリー:
function chooseRenderingMethod(project) {
// SEOが必要?
if (!project.needsSEO) {
return 'CSR';
}
// リアルタイムデータ?
if (project.needsRealtime) {
return 'SSR';
}
// コンテンツが頻繁に変わる?
if (project.contentChangesOften) {
return 'ISR'; // SSG + 再生成
}
// 静的コンテンツ
return 'SSG';
}
Q2. Next.jsはどのレンダリング方式ですか?
A: Next.jsはすべての方式をサポートしています:
// Next.js - ハイブリッドフレームワーク
// 1. SSG (デフォルト)
// pages/about.js
function About() {
return <div>会社紹介</div>;
}
export default About;
// getStaticPropsがなければ自動的にSSG
// 2. SSG with Data
// pages/blog/[slug].js
export async function getStaticPaths() {
return {
paths: [{ params: { slug: 'hello' }}],
fallback: false
};
}
export async function getStaticProps({ params }) {
const post = await getPost(params.slug);
return { props: { post }};
}
// 3. ISR (Incremental Static Regeneration)
export async function getStaticProps() {
return {
props: { data: '...' },
revalidate: 60 // 60秒ごとに再生成
};
}
// 4. SSR
// pages/news.js
export async function getServerSideProps() {
const news = await getLatestNews();
return { props: { news }};
}
// 5. CSR
// pages/dashboard.js
function Dashboard() {
const { data } = useSWR('/api/user', fetcher);
return <div>{data}</div>;
}
// 6. API Routes (サーバーレス関数)
// pages/api/hello.js
export default function handler(req, res) {
res.status(200).json({ message: 'Hello' });
}
// Next.jsの長所:
// - ファイルベースのルーティング
// - 自動コード分割
// - 画像最適化
// - TypeScriptサポート
// - 高速リフレッシュ
// - Vercelデプロイ最適化
Q3. Hydrationとは?
A: SSR/SSGで静的HTMLをインタラクティブにするプロセスです:
// Hydrationプロセス
// 1段階: サーバーでHTML生成
// server.js
const html = ReactDOMServer.renderToString(<App />);
// 生成されたHTML:
<div id="root">
<button>クリック (0)</button>
</div>
// 2段階: ブラウザに送信
// ユーザーがすぐに見られる!
// ただしボタンがクリックできない (イベントリスナーなし)
// 3段階: JavaScriptロードと実行
// client.js
ReactDOM.hydrate(<App />, document.getElementById('root'));
// Hydration中:
// 1. ReactがDOMツリーを分析
// 2. Virtual DOMと比較
// 3. イベントリスナーを接続
// 4. 状態を初期化
// 4段階: Hydration完了
// 今ボタンがクリック可能! インタラクティブ!
// Hydrationの問題:
// 不一致警告
const MismatchComponent = () => {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
return (
<div>
{/* ❌ サーバー: "サーバー", クライアント: "クライアント" */}
{typeof window === 'undefined' ? 'サーバー' : 'クライアント'}
{/* ✅ Hydration後にのみレンダリング */}
{mounted && <ClientOnlyComponent />}
</div>
);
};
// Hydration最適化:
// 1. 初期HTMLサイズを減らす
// 2. JavaScriptバンドルサイズを減らす
// 3. Critical CSSをインライン
// 4. 必要な部分だけHydrate (Progressive Hydration)
Q4. CSRのSEO問題を解決できますか?
A: いくつかの方法がありますが、完璧ではありません:
// CSR SEO改善方法
// 1. Prerendering (ビルド時にHTML生成)
// react-snapを使用
// package.json
{
"scripts": {
"postbuild": "react-snap"
}
}
// クローラーボットが訪問すると事前生成されたHTMLを提供
// 実際のユーザーはCSRで動作
// 2. Server-Side Rendering Service
// Prerender.io、Rendertronのようなサービスを使用
// nginx設定
location / {
if ($http_user_agent ~* "googlebot|bingbot|yandex") {
proxy_pass http://prerender-service;
}
}
// 3. Google Search Console
// - JavaScriptレンダリングテスト
// - robots.txt確認
// - sitemap.xml提出
// 4. メタタグの動的更新
import { Helmet } from 'react-helmet';
function BlogPost({ post }) {
return (
<>
<Helmet>
<title>{post.title}</title>
<meta name="description" content={post.excerpt} />
<meta property="og:title" content={post.title} />
<meta property="og:image" content={post.image} />
</Helmet>
<article>{/* ... */}</article>
</>
);
}
// 5. Structured Data (JSON-LD)
<script type="application/ld+json">
{`
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "${post.title}",
"author": "${post.author}",
"datePublished": "${post.date}"
}
`}
</script>
// 限界:
// - 完璧なSEOは不可能
// - 複雑で保守が難しい
// - SSR/SSGの方が良い
// 結論: SEOが重要ならSSR/SSGを使用!
Q5. レンダリングパフォーマンスを測定する方法は?
A: 複数のツールで測定できます:
// 1. Lighthouse (Chrome DevTools)
// Chrome DevTools > Lighthouse タブ
// - Performance
// - Accessibility
// - Best Practices
// - SEO
// 主要指標:
const webVitals = {
FCP: 'First Contentful Paint', // 最初のコンテンツ表示
LCP: 'Largest Contentful Paint', // 最大コンテンツ表示
FID: 'First Input Delay', // 最初の入力遅延
TTI: 'Time to Interactive', // インタラクティブまで
TBT: 'Total Blocking Time', // 総ブロック時間
CLS: 'Cumulative Layout Shift' // 累積レイアウトシフト
};
// 2. web-vitalsライブラリ
import { getCLS, getFID, getFCP, getLCP, getTTI } from 'web-vitals';
function sendToAnalytics({ name, value, id }) {
console.log(name, value);
// Google Analyticsに送信
gtag('event', name, {
event_category: 'Web Vitals',
value: Math.round(value),
event_label: id,
non_interaction: true
});
}
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTI(sendToAnalytics);
// 3. Next.js Analytics
// pages/_app.js
export function reportWebVitals(metric) {
console.log(metric);
// {
// name: 'FCP',
// value: 1234.5,
// id: 'v2-1234567890'
// }
}
// 4. Chrome DevTools Performance
// 1. DevTools > Performance タブ
// 2. 記録開始
// 3. ページを再読み込み
// 4. 記録停止
// 5. 分析:
// - Loading: HTML、CSS、JSダウンロード
// - Scripting: JavaScript実行
// - Rendering: レイアウト、ペイント
// - Painting: ピクセル描画
// 5. Network タブ
// - リソースロード時間
// - ファイルサイズ
// - ウォーターフォールチャート
// - 並列ダウンロード
// 6. React DevTools Profiler
import { Profiler } from 'react';
function onRenderCallback(
id,
phase,
actualDuration,
baseDuration,
startTime,
commitTime
) {
console.log(`${id} (${phase}) took ${actualDuration}ms`);
}
<Profiler id="App" onRender={onRenderCallback}>
<App />
</Profiler>
// 目標指標:
const goodMetrics = {
FCP: '< 1.8s',
LCP: '< 2.5s',
FID: '< 100ms',
TTI: '< 3.8s',
TBT: '< 200ms',
CLS: '< 0.1'
};
🎓 次のステップ
レンダリング方式を理解したら、次を学習してみましょう:
- Virtual DOMとは? - Reactレンダリングの核心原理
- Webパフォーマンス最適化 (ドキュメント作成予定) - パフォーマンス改善方法
- SEO基礎 (ドキュメント作成予定) - 検索エンジン最適化
🎬 まとめ
レンダリング方式はWebアプリケーションのパフォーマンスとSEOに大きな影響を与えます:
- CSR: 豊富なインタラクション、SEOが難しい
- SSR: 速い初期ロード、サーバーコストが高い
- SSG: 最高のパフォーマンス、静的コンテンツに適している
- ISR: SSG + 自動更新、最高の組み合わせ
プロジェクトの特性に合ったレンダリング方式を選択し、必要ならハイブリッドで組み合わせましょう!