← 解説「SSRとは — 最初のHTMLをサーバで作る」に戻る
サンプルコードで身につける: SSRとは — 最初のHTMLをサーバで作る
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1CSRとSSRのタイムライン比較
ユーザーがURLを開いてから中身が見えるまでの流れを並べると、SSRの狙いが分かります。CSRは「JSが全部揃ってから表示」、SSRは「まずHTMLで表示、動きは後から」です。
// ── CSR: 中身が見えるのはJS実行後 ──
// 1. HTMLが届く(ほぼ空) → 白い画面
// 2. JSをダウンロード → まだ白い画面
// 3. JSを実行、APIから取得 → まだ白い画面
// 4. 画面を描画 → やっと中身が見える
//
// ── SSR: 中身は最初のHTMLに入っている ──
// 1. サーバがアプリを実行してHTMLを作る
// 2. HTMLが届く → もう中身が見える!
// 3. JSをダウンロード・実行 → (見えたまま)
// 4. ハイドレーション → 操作もできるようになる
2クローラーから見た2つのHTML
SNSでURLを共有したときのカード表示や検索結果は、多くの場合サーバが返したHTMLだけを見て作られます。CSRでは商品名がHTMLに存在しないため、正しく拾ってもらえないことがあります。
<!-- CSR: クローラーが見るのはこれだけ -->
<head><title>MyShop</title></head>
<body><app-root></app-root></body>
<!-- どの商品ページも同じに見える -->
<!-- SSR: ページごとの中身がHTMLに存在する -->
<head>
<title>りんご 100円 | MyShop</title>
<meta property="og:title" content="りんご 100円" />
</head>
<body>
<app-root><h1>りんご</h1><p>産地直送...</p></app-root>
</body>
3サーバでは動かないコードの例
SSRではコンポーネントのコードがNode.js上でも実行されます。windowやlocalStorageはブラウザにしか無いため、サーバ実行時にエラーで落ちます。これがSSR導入時の典型的なつまずきです。
@Component({ selector: 'app-theme', template: '...' })
export class ThemeComponent {
constructor() {
// ブラウザでは動くが、サーバで実行されると
// ReferenceError: localStorage is not defined で落ちる
const saved = localStorage.getItem('theme');
// window も同様にサーバには存在しない
const width = window.innerWidth;
}
}
// 対処は次のレッスンで学ぶ afterNextRender() など、
// 「ブラウザでだけ実行する」場所へ移すこと
4CSR・SSR・プリレンダリングの使い分け
描画方式は3択です。判断軸は「中身はユーザーごとに違うか」と「共有・検索されるページか」の2つ。1つのアプリの中でページごとに混ぜられるのがAngularの強みです。
// ── 3つの描画方式の使い分け ──
//
// CSR(ブラウザで描画)
// 向き: ログイン後の管理画面・ダッシュボード
// 理由: 検索されないし、中身がユーザーごとに違う
//
// SSR(リクエストごとにサーバで描画)
// 向き: 商品詳細・記事ページなど動的で共有されるページ
// 理由: 内容が変わるが、クローラーにも見せたい
//
// プリレンダリング/SSG(ビルド時に作り置き)
// 向き: トップページ・会社概要・利用規約
// 理由: 誰が見ても同じなら、毎回描画する必要がない
5SSRの代償も知っておく
SSRは無料ではありません。導入判断の場では利点だけでなくコストも並べて比べます。「全ページSSRにする」ではなく「必要なページだけSSRにする」のが現実的な落とし所です。
// ── SSRで得るもの ──
// ・初期表示が体感で速い(白い画面の時間が短い)
// ・クローラー/SNSカードに中身が見える
//
// ── SSRで払うもの ──
// ・Node.jsサーバの運用が必要(静的配信では済まない)
// ・リクエストごとにサーバでアプリを実行するCPUコスト
// ・window等に触れない制約とコードの書き分け
// ・ビルド/デプロイ構成が少し複雑になる
//
// → 迷ったら: 公開ページだけSSR/Prerender、
// ログイン後はCSR、が定番の構成