0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「Vue完全攻略への道」Day12-レンダリングの種類(CSRなど)

Posted at

〇背景

CSR(Client-Side Rendering)という単語を知らずに詰められたので、Vue/Nuxt の文脈で “レンダリング方式の全体像” を整理する。

〇今回のコード例

今回のメモは概念中心。最後に Nuxt 3 を使った最小コード例をいくつか添付(SSR/SSG/ISR/Island)。

〇調べる前の自分の認識

  • Vue は基本 CSR(SPA)で動く。
  • Nuxt を使うと SSR/SSG ができる(はず…)。
  • SEO は SSR/SSG が有利らしい。

→ 実際には CSR/SSR/SSG/ISR/Streaming/Islands/Edge など複数の方式があり、配信・UX・SEO・コスト・複雑性がトレードオフになる。

〇調べた結果(要点サマリ)

1) CSR(Client-Side Rendering)

  • 初回は空の HTML + JS を返し、ブラウザで JS が実行されてから描画
  • 長所:CDN 配信が容易、ホスティングが安い、フロント主導で操作感が軽快。
  • 短所:初回表示が遅くなりがち(FCP/TTI)、SEO が弱い(クローラは改善しているが完全でない)。

2) SSR(Server-Side Rendering)

  • サーバで HTML を生成して返す → 初期描画が速い、SEO に強い。
  • 返した HTML を クライアントでハイドレーション(hydration) してインタラクティブ化。
  • コスト:サーバ実行基盤が必要(Node/Edge)。

3) SSG(Static Site Generation)

  • ビルド時に 静的 HTML を生成して CDN から配信。
  • 超高速・安価・スケール容易。更新頻度が低いページに最適。
  • 動的データはクライアント取得 or エッジ関数と組み合わせる。

4) ISR(Incremental Static Regeneration / Incremental Static Revalidation)

  • 静的生成 + 有効期限。期限切れ時にバックグラウンドで再生成して差し替え。
  • 頻繁に変わるが “リアルタイムほどではない” ページに向く。

5) Streaming SSR(ストリーミング)

  • サーバが HTML を分割送信。LCP を早めつつ、重い部分は後続で。
  • 体感速度改善、長いページに有効。Nuxt3 は標準で対応。

6) Islands Architecture(部分ハイドレーション)

  • ページはサーバ側で HTML 化し、必要なウィジェットだけをクライアントでハイドレート
  • JS 量を劇的に削減可能。Nuxt の / 遅延ハイドレーション系の仕組み・分割コンポーネントで実現。

7) Edge Rendering

  • CDN のエッジ(近い場所)で SSR/ISR を実行(Nitro on Vercel/Netlify/Cloudflare)
  • 低レイテンシ、グローバル配信に強い。

実運用では

Nuxt3(Nitro)

〇動作解説(図解)

CSR の流れ

[Browser] --GET--> [CDN/Static Host] --index.html(+bundle.js)--> [Browser]
[Browser] --runs JS--> fetch APIs --> render DOM
  • 初回は白画面→JS 読込→API→描画。

SSR の流れ

[Browser] --GET--> [SSR Server/Edge]
                   └> fetch data -> render HTML (server)
<- HTML (fully rendered) --
[Browser] hydrate -> interactive
  • 初回から内容が見える(SEO/シェアカードに強い)。

SSG の流れ

[Build time] fetch data -> generate HTML files
[Browser] --GET--> [CDN] <- prebuilt HTML/CSS/JS
  • ページは事前生成。更新は再ビルド or ISR。

Islands(部分ハイドレーション)

<Page HTML (server-rendered)>
   [static text]
   <div id="island-1">widget A</div>
   <div id="island-2">widget B</div>
// ブラウザでは island A/B の JS だけ読み込み・起動
  • 大半は静的、必要箇所だけ JS。

〇実務での注意点(チェックリスト)

  • ハイドレーション不一致:v-if と onMounted の条件差、Date.now()/Math.random() の使用で DOM が一致しない → SSR では 同一出力を保証。ランダムは mounted 後に。
  • データ取得の二重実行:SSR + CSR で同じ API を二度叩く設計を避け、サーバで取得→状態注入(state serialization) を活用。
  • 認証/セッション:SSR では サーバ側でクッキー/ヘッダを読む。機微情報はクライアントに埋め込まない。
  • キャッシュ戦略:SSG/CDN キャッシュに Cache-Control, stale-while-revalidate。
  • エッジ/リージョン:API と SSR 実行場所を近づける。遠いと TTFB が悪化。
  • SEO:メタタグ/OGP は SSR/SSG で確実に出力。クライアント後書き換えはボツ。国際化は hreflang/meta。
  • アナリティクス:SPA 遷移時に pageview 発火を忘れがち(router.afterEach)。
  • エラーハンドリング:SSR 中の例外は 500 になりがち。Error Boundary / Nuxt の error ページを用意。
  • パフォーマンス
    • 画像最適化( / Nuxt Image)
    • クリティカル CSS, code-splitting, prefetch/prerender
    • Island/遅延ハイドレーションで送る JS を減らす

〇Nuxt 3 での最小コード例

A. SSR(デフォルト)

pages/index.vue

<script setup lang="ts">
const { data } = await useFetch('/api/hello')
</script>
<template>
  <h1>SSR Page</h1>
  <p>{{ data?.message }}</p>
</template>

server/api/hello.get.ts

export default defineEventHandler(() => ({ message: 'Hello from server' }))

B. SSG(プリレンダー)

nuxt.config.ts

export default defineNuxtConfig({
  nitro: { prerender: { routes: ['/', '/about'] } }
})

→ npx nuxi build で静的出力。CDN へ配信。

C. ISR 的リバリデーション

server/routes/posts.ts(例)でヘッダ付与 or キャッシュキー制御。

export default defineEventHandler(async (event) => {
  // データ取得...
  setHeader(event, 'Cache-Control', 'public, max-age=60, stale-while-revalidate=600')
  return await getPosts()
})

⇒ 60 秒以内は即返、期限切れ後にバックグラウンド更新(CDN と合わせて運用)。

D. Islands(部分ハイドレーション)

pages/index.vue

<template>
  <section>
    <StaticHero />
    <ClientOnly>
      <InteractiveChart />
    </ClientOnly>
  </section>
</template>

→ StaticHero は SSR のみ、InteractiveChart だけクライアントでハイドレート。

〇方式選定の指針(早見表)

目的 推奨 理由
ブログ/ドキュメント SSG (+ ISR) 高速/安価、変更は定期リビルド or 再検証で十分
EC 商品一覧 SSR + キャッシュ SEO・初期描画◎、在庫/価格をサーバ側で統一
ダッシュボードSPA CSR/Islands 認証必須・インタラクション重視、JS を必要箇所に限定
グローバル配信 Edge SSR/ISR レイテンシ低、地域別 A/B も実装容易

〇まとめ・所感

  • 単一の正解はない。 ページの性質(更新頻度・SEO 重要度・双方向性)と 運用コスト を秤にかける。
  • Vue 単体なら CSR/Islands を軸に、Nuxt3 を使えば SSR/SSG/Streaming/Edge/ISR まで柔軟に選べる。
  • 次回以降は ハイドレーション不一致を再現→解決Nuxt Image での最適化 など手を動かして検証する。

レンダリング方式も技術選定の際には必要そうだな。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?