brand logo

ドキュメント

レンダリングモード

Nuxtで利用可能なさまざまなレンダリングモードについて学びましょう。

Nuxtは、ユニバーサルレンダリングクライアントサイドレンダリングをサポートしていますが、ハイブリッドレンダリングCDNエッジサーバーでのアプリケーションのレンダリングも可能です。

ブラウザとサーバーの両方がJavaScriptコードを解釈してVue.jsコンポーネントをHTML要素に変換できます。このステップはレンダリングと呼ばれます。Nuxtはユニバーサルクライアントサイドの両方のレンダリングをサポートしています。これらのアプローチには利点と欠点があり、それについて説明します。

デフォルトでは、Nuxtはユニバーサルレンダリングを使用して、より良いユーザーエクスペリエンス、パフォーマンス、検索エンジンのインデックス最適化を提供しますが、1行の設定でレンダリングモードを切り替えることができます。

ユニバーサルレンダリング

このステップは、PHPやRubyアプリケーションによって実行される従来のサーバーサイドレンダリングに似ています。ブラウザがユニバーサルレンダリングが有効なURLを要求すると、Nuxtはサーバー環境でJavaScript(Vue.js)コードを実行し、完全にレンダリングされたHTMLページをブラウザに返します。Nuxtは、ページが事前に生成されている場合、キャッシュから完全にレンダリングされたHTMLページを返すこともあります。クライアントサイドレンダリングとは異なり、ユーザーはアプリケーションの初期コンテンツ全体を即座に取得します。

HTMLドキュメントがダウンロードされると、ブラウザはこれを解釈し、Vue.jsがドキュメントを制御します。サーバーで一度実行された同じJavaScriptコードが、クライアント(ブラウザ)で再びバックグラウンドで実行され、リスナーをHTMLにバインドすることでインタラクティビティを可能にします(これがユニバーサルレンダリングです)。これをハイドレーションと呼びます。ハイドレーションが完了すると、ページは動的なインターフェースやページ遷移などの利点を享受できます。

ユニバーサルレンダリングにより、Nuxtアプリケーションはクライアントサイドレンダリングの利点を維持しながら、迅速なページロード時間を提供できます。さらに、コンテンツがすでにHTMLドキュメントに存在するため、クローラーはオーバーヘッドなしでインデックスを作成できます。

HTMLドキュメントが読み込まれると、ユーザーは静的コンテンツにアクセスできます。ハイドレーションによりページのインタラクティビティが可能になります

サーバーでレンダリングされるものとクライアントでレンダリングされるものは何ですか?

ユニバーサルレンダリングモードで、Vueファイルのどの部分がサーバーおよび/またはクライアントで実行されるのかを尋ねるのは普通のことです。

app.vue
<script setup lang="ts">
const counter = ref(0); // サーバーとクライアント環境で実行されます

const handleClick = () => {
  counter.value++; // クライアント環境でのみ実行されます
};
</script>

<template>
  <div>
    <p>Count: {{ counter }}</p>
    <button @click="handleClick">Increment</button>
  </div>
</template>

初回リクエスト時、counterのrefはサーバーで初期化されます。これは<p>タグ内でレンダリングされるためです。handleClickの内容はここでは実行されません。ブラウザでのハイドレーション中に、counterのrefは再初期化されます。handleClickは最終的にボタンにバインドされます。したがって、handleClickの本体は常にブラウザ環境で実行されると推測するのが合理的です。

ミドルウェアページは、ハイドレーション中にサーバーとクライアントで実行されます。プラグインはサーバーまたはクライアント、またはその両方でレンダリングできます。コンポーネントはクライアントのみで実行するように強制することもできます。コンポーザブルユーティリティは、その使用コンテキストに基づいてレンダリングされます。

サーバーサイドレンダリングの利点:

  • パフォーマンス: ユーザーはページのコンテンツに即座にアクセスできます。ブラウザはJavaScript生成コンテンツよりも静的コンテンツをはるかに速く表示できます。同時に、Nuxtはハイドレーションプロセス中にWebアプリケーションのインタラクティビティを維持します。
  • 検索エンジン最適化: ユニバーサルレンダリングは、ページのHTMLコンテンツ全体をクラシックなサーバーアプリケーションとしてブラウザに提供します。Webクローラーはページのコンテンツを直接インデックス化できるため、ユニバーサルレンダリングは迅速にインデックス化したいコンテンツに最適です。

サーバーサイドレンダリングの欠点:

  • 開発の制約: サーバーとブラウザの環境は同じAPIを提供しないため、両方の側でシームレスに実行できるコードを書くのは難しいことがあります。幸いなことに、Nuxtはコードがどこで実行されるかを判断するためのガイドラインと特定の変数を提供しています。
  • コスト: ページを動的にレンダリングするためにはサーバーが稼働している必要があります。これは従来のサーバーと同様に月額コストがかかります。ただし、ユニバーサルレンダリングにより、クライアントサイドのナビゲーションでブラウザが引き継ぐため、サーバーコールは大幅に削減されます。エッジサイドレンダリングを活用することでコスト削減が可能です。

ユニバーサルレンダリングは非常に柔軟で、ほぼすべてのユースケースに適合し、特にコンテンツ指向のウェブサイトに適しています:ブログ、マーケティングウェブサイト、ポートフォリオ、eコマースサイト、マーケットプレイス

ハイドレーションの不一致なしにVueコードを書くためのさらなる例については、Vueのドキュメントを参照してください。

ブラウザAPIに依存し副作用のあるライブラリをインポートする場合、それをインポートするコンポーネントがクライアントサイドでのみ呼び出されるようにしてください。バンドラーは副作用を含むモジュールのインポートをツリーシェイクしません。

クライアントサイドレンダリング

標準のVue.jsアプリケーションは、ブラウザ(またはクライアント)でレンダリングされます。その後、Vue.jsは、現在のインターフェースを作成するための指示を含むすべてのJavaScriptコードをブラウザがダウンロードして解析した後にHTML要素を生成します。

ユーザーは、ブラウザがJavaScriptをダウンロード、解析、実行するのを待ってからページのコンテンツを見る必要があります

クライアントサイドレンダリングの利点:

  • 開発速度: 完全にクライアントサイドで作業する場合、コードのサーバー互換性を心配する必要がありません。たとえば、windowオブジェクトのようなブラウザ専用のAPIを使用する場合です。
  • 安価: サーバーを稼働させると、JavaScriptをサポートするプラットフォームで実行する必要があるため、インフラストラクチャのコストがかかります。クライアント専用のアプリケーションは、HTML、CSS、JavaScriptファイルを持つ任意の静的サーバーでホストできます。
  • オフライン: コードが完全にブラウザで実行されるため、インターネットが利用できない場合でも正常に動作し続けることができます。

クライアントサイドレンダリングの欠点:

  • パフォーマンス: ユーザーは、ブラウザがJavaScriptファイルをダウンロード、解析、実行するのを待たなければなりません。ダウンロード部分はネットワークに依存し、解析と実行はユーザーのデバイスに依存するため、時間がかかり、ユーザーエクスペリエンスに影響を与える可能性があります。
  • 検索エンジン最適化: クライアントサイドレンダリングで提供されるコンテンツのインデックス作成と更新には、サーバーレンダリングされたHTMLドキュメントよりも時間がかかります。これは、パフォーマンスの欠点に関連しており、検索エンジンクローラーは、インターフェースが完全にレンダリングされるのを待たずにページをインデックス化しようとします。純粋なクライアントサイドレンダリングでは、コンテンツが検索結果ページに表示され、更新されるまでに時間がかかります。

クライアントサイドレンダリングは、インデックス作成が不要またはユーザーが頻繁に訪れるインタラクティブなWebアプリケーションに適した選択です。ブラウザキャッシュを活用して、次回の訪問時にダウンロードフェーズをスキップできます。たとえば、SaaS、バックオフィスアプリケーション、オンラインゲームなどです。

Nuxtでクライアントサイドのみのレンダリングを有効にするには、nuxt.config.tsで次のように設定します:

nuxt.config.ts
export default defineNuxtConfig({
  ssr: false
})

ssr: falseを使用する場合、アプリがハイドレートされるまでレンダリングされるローディング画面を表示するために、~/app/spa-loading-template.htmlにHTMLファイルを配置する必要があります。

こちらも参照 SPA Loading Template

静的クライアントレンダリングアプリのデプロイ

nuxt generateまたはnuxt build --prerenderコマンドを使用して静的ホスティングにアプリをデプロイする場合、デフォルトでNuxtは各ページを個別の静的HTMLファイルとしてレンダリングします。

nuxt generateまたはnuxt build --prerenderコマンドでアプリをプリレンダリングする場合、出力フォルダにサーバーが含まれないため、サーバーエンドポイントを使用することはできません。サーバー機能が必要な場合は、nuxt buildを使用してください。

純粋にクライアントサイドレンダリングを使用している場合、これは不要かもしれません。単一のindex.htmlファイルと、200.htmlおよび404.htmlのフォールバックだけが必要かもしれません。これらを静的Webホストにすべてのリクエストに対して提供するように指示できます。

これを実現するために、ルートのプリレンダリング方法を変更できます。nuxt.config.tsフックに次のように追加します:

nuxt.config.ts
export default defineNuxtConfig({
  hooks: {
    'prerender:routes' ({ routes }) {
      routes.clear() // ルートを生成しない(デフォルトを除く)
    }
  },
})

これにより、次の3つのファイルが生成されます:

  • index.html
  • 200.html
  • 404.html

200.html404.htmlは、使用しているホスティングプロバイダーに役立つかもしれません。

クライアントフォールバック生成のスキップ

クライアントレンダリングアプリをプリレンダリングする際、Nuxtはデフォルトでindex.html200.html404.htmlファイルを生成します。ただし、ビルドでこれらのファイルの生成を防ぐ必要がある場合、Nitro'prerender:generate'フックを使用できます。

nuxt.config.ts
export default defineNuxtConfig({
  ssr: false,
  nitro: {
    hooks: {
      'prerender:generate'(route) {
        const routesToSkip = ['/index.html', '/200.html', '/404.html']
        if (routesToSkip.includes(route.route)) {
          route.skip = true
        }
      }
    }
  }
})

ハイブリッドレンダリング

ハイブリッドレンダリングは、ルートルールを使用してルートごとに異なるキャッシュルールを設定し、特定のURLへの新しいリクエストに対してサーバーがどのように応答するかを決定します。

以前は、Nuxtアプリケーションとサーバーのすべてのルート/ページが同じレンダリングモード(ユニバーサルまたはクライアントサイド)を使用する必要がありました。さまざまなケースで、一部のページはビルド時に生成されるべきであり、他のページはクライアントサイドでレンダリングされるべきです。たとえば、管理セクションを持つコンテンツウェブサイトを考えてみてください。すべてのコンテンツページは主に静的で一度生成されるべきですが、管理セクションは登録が必要で、より動的なアプリケーションのように振る舞います。

Nuxtにはルートルールとハイブリッドレンダリングのサポートが含まれています。ルートルールを使用して、Nuxtルートのグループに対してルールを定義し、レンダリングモードを変更したり、ルートに基づいてキャッシュ戦略を割り当てたりできます!

Nuxtサーバーは自動的に対応するミドルウェアを登録し、Nitroキャッシングレイヤーを使用してキャッシュハンドラーでルートをラップします。

nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    // ホームページはビルド時にプリレンダリングされます
    '/': { prerender: true },
    // 製品ページはオンデマンドで生成され、バックグラウンドで再検証され、APIレスポンスが変更されるまでキャッシュされます
    '/products': { swr: true },
    // 製品ページはオンデマンドで生成され、バックグラウンドで再検証され、1時間(3600秒)キャッシュされます
    '/products/**': { swr: 3600 },
    // ブログ投稿ページはオンデマンドで生成され、バックグラウンドで再検証され、CDNで1時間(3600秒)キャッシュされます
    '/blog': { isr: 3600 },
    // ブログ投稿ページは次のデプロイまで一度オンデマンドで生成され、CDNでキャッシュされます
    '/blog/**': { isr: true },
    // 管理ダッシュボードはクライアントサイドでのみレンダリングされます
    '/admin/**': { ssr: false },
    // APIルートにCORSヘッダーを追加します
    '/api/**': { cors: true },
    // レガシーURLをリダイレクトします
    '/old-page': { redirect: '/new-page' }
  }
})

ルートルール

使用できるさまざまなプロパティは次のとおりです:

  • redirect: string{lang=ts} - サーバーサイドリダイレクトを定義します。
  • ssr: boolean{lang=ts} - アプリのセクションのサーバーサイドレンダリングを無効にし、ssr: falseでブラウザでのみレンダリングします。
  • cors: boolean{lang=ts} - cors: trueで自動的にCORSヘッダーを追加します - headersで出力をカスタマイズできます。
  • headers: object{lang=ts} - サイトの特定のセクションに特定のヘッダーを追加します - たとえば、アセットに。
  • swr: number | boolean{lang=ts} - サーバーレスポンスにキャッシュヘッダーを追加し、サーバーまたはリバースプロキシで設定可能なTTL(有効期限)でキャッシュします。Nitroのnode-serverプリセットは、完全なレスポンスをキャッシュできます。TTLが切れると、キャッシュされたレスポンスが送信され、ページはバックグラウンドで再生成されます。trueが使用される場合、stale-while-revalidateヘッダーがMaxAgeなしで追加されます。
  • isr: number | boolean{lang=ts} - 振る舞いはswrと同じですが、これにより、対応するプラットフォーム(現在はNetlifyまたはVercel)でCDNキャッシュにレスポンスを追加できます。trueが使用される場合、コンテンツは次のデプロイまでCDN内に保持されます。
  • prerender: boolean{lang=ts} - ビルド時にルートをプリレンダリングし、静的アセットとしてビルドに含めます。
  • noScripts: boolean{lang=ts} - サイトのセクションに対するNuxtスクリプトとJSリソースヒントのレンダリングを無効にします。
  • appMiddleware: string | string[] | Record<string,>{lang=ts} - アプリケーションのVueアプリ部分内のページパスに対して実行する、またはしないミドルウェアを定義できます(Nitroルートではありません)。

可能な限り、ルートルールはデプロイメントプラットフォームのネイティブルールに自動的に適用され、最適なパフォーマンスを実現します(現在、NetlifyとVercelがサポートされています)。

ハイブリッドレンダリングはnuxt generateを使用する場合には利用できないことに注意してください。

例:

エッジサイドレンダリング

エッジサイドレンダリング(ESR)は、Nuxtに導入された強力な機能で、コンテンツデリバリーネットワーク(CDN)のエッジサーバーを介してNuxtアプリケーションをユーザーに近づけてレンダリングすることができます。ESRを活用することで、パフォーマンスが向上し、レイテンシが低減され、ユーザーエクスペリエンスが向上します。

ESRでは、レンダリングプロセスがネットワークの「エッジ」、つまりCDNのエッジサーバーにプッシュされます。ESRは実際のレンダリングモードというよりもデプロイメントターゲットです。

ページのリクエストが行われると、元のサーバーまで行く代わりに、最も近いエッジサーバーによってインターセプトされます。このサーバーはページのHTMLを生成し、ユーザーに返します。このプロセスにより、データが移動する物理的な距離が最小化され、レイテンシが低減され、ページがより速く読み込まれます

エッジサイドレンダリングは、Nuxtを支えるサーバーエンジンであるNitroのおかげで可能です。Node.js、Deno、Cloudflare Workersなどのクロスプラットフォームサポートを提供します。

現在、ESRを活用できるプラットフォームは次のとおりです:

  • Cloudflare Pagesは、git統合とnuxt buildコマンドを使用してゼロコンフィギュレーションで利用可能
  • Vercel Edge Functionsは、nuxt buildコマンドとNITRO_PRESET=vercel-edge環境変数を使用
  • Netlify Edge Functionsは、nuxt buildコマンドとNITRO_PRESET=netlify-edge環境変数を使用

ハイブリッドレンダリングは、ルートルールを使用したエッジサイドレンダリングと組み合わせて使用することができます。

上記のプラットフォームのいくつかにデプロイされたオープンソースの例を探索できます:

tips

このセクションは公式ドキュメントの翻訳ではなく、本サイト独自の補足記事です。

Nuxtのレンダリングモード補足解説

Nuxtは多彩なレンダリングモードをサポートしており、ユニバーサルレンダリング(SSR)やクライアントサイドレンダリング(CSR)をはじめ、ハイブリッドレンダリングやエッジサイドレンダリングなども利用可能です。これにより、パフォーマンスやSEO、開発効率などの課題を柔軟に解決できます。

本記事では、Nuxtのレンダリングモードの基本的な仕組みを踏まえつつ、実務での具体的な使いどころや注意点を丁寧に解説します。特に初〜中級者の方が現場で遭遇しやすいユースケースや落とし穴に焦点を当てています。


まず結論:Nuxtレンダリングモードのポイント

  • **ユニバーサルレンダリング(SSR)**は初期表示が高速でSEOに強いが、サーバー負荷や開発時の環境差異に注意が必要
  • **クライアントサイドレンダリング(CSR)**はサーバー負荷が軽減されるが、初回表示が遅くSEO対策が難しい
  • ハイブリッドレンダリングはページごとにSSRとCSRを使い分けられ、柔軟なパフォーマンス最適化が可能
  • エッジサイドレンダリングはCDNのエッジでレンダリングを行い、グローバルに高速配信が可能
  • SSRではサーバーとクライアントで同じコードが動くため、環境差異によるバグやハイドレーション不一致に注意が必要

いつ使うべきか?使わない方がよいケース

ユニバーサルレンダリング(SSR)を使うべきケース

  • SEOが重要なコンテンツ中心のサイト(ブログ、マーケティングサイト、ECサイトなど)
  • 初回表示速度を重視し、ユーザー体験を向上させたい場合
  • 動的に生成されるページをサーバーで事前にレンダリングしたい場合

SSRを避けたほうがよいケース

  • 完全にユーザー操作中心のSPA的なアプリケーション(管理画面やダッシュボードなど)
  • サーバーリソースが限られていて、サーバー負荷を極力減らしたい場合
  • SEOが不要で、クライアント側で完結するUIがメインの場合

クライアントサイドレンダリング(CSR)を使うべきケース

  • ユーザー認証やリアルタイム更新が多いインタラクティブなアプリ
  • SEOが不要な管理画面や内部ツール
  • サーバーコストを抑えたい場合

実務でよくあるユースケースとサンプルコード

1. SEO重視のブログサイトでのSSR活用

ブログ記事は検索エンジンにインデックスされることが重要です。SSRにより、サーバーで完全にレンダリングされたHTMLを返すため、クローラーがコンテンツを正しく認識できます。

<script setup>
const post = useAsyncData('post', () => $fetch(`/api/posts/${useRoute().params.id}`))
</script>

<template>
  <article v-if="post.data">
    <h1>{{ post.data.title }}</h1>
    <div v-html="post.data.content"></div>
  </article>
</template>

この例では、サーバーで記事データを取得し、初期HTMLに含めることで高速表示とSEO効果を両立しています。

2. 管理画面でのCSR利用

管理画面はSEO不要で、ユーザーの操作に応じて動的にUIが変わるため、CSRが適しています。

<script setup>
const users = ref([])

onMounted(async () => {
  users.value = await fetch('/api/users').then(res => res.json())
})
</script>

<template>
  <div>
    <h2>ユーザー一覧</h2>
    <ul>
      <li v-for="user in users" :key="user.id">{{ user.name }}</li>
    </ul>
  </div>
</template>

このように、クライアント側でAPIを呼び出してデータを取得し、動的に表示します。

3. ハイブリッドレンダリングでページごとに切り替え

Nuxtではページ単位でSSRとCSRを切り替えられます。例えば、トップページはSSRで高速表示、ユーザープロファイルはCSRで動的に。

// nuxt.config.ts
export default defineNuxtConfig({
  ssr: true,
  routeRules: {
    '/profile/**': { ssr: false } // プロファイルページはCSRに切り替え
  }
})

よくある落とし穴・注意点

1. SSRとCSR間のハイドレーション不一致

サーバーでレンダリングしたHTMLとクライアントで再実行されるVueの状態が異なると、ハイドレーションエラーが発生します。例えば、Date.now()Math.random()をサーバーとクライアントで同じ値にしないと不整合が起きます。

対策

  • 状態をサーバーで固定し、クライアントで再現可能にする
  • クライアント専用の処理はマウント後に実行する(onMountedなど)

2. ブラウザAPIの利用制限

SSR中はブラウザのwindowdocumentが存在しません。これらを直接使うとサーバーエラーになります。

対策

  • ブラウザAPIはprocess.clientonMounted内でのみ利用する
  • クライアント専用コンポーネントを分ける(例: ClientOnlyコンポーネントを使う)

3. サーバー負荷とコスト

SSRはサーバーで毎回レンダリングを行うため、アクセスが増えるとサーバー負荷が高まります。特に動的なページが多い場合は注意が必要です。

対策

  • 静的サイト生成(SSG)やキャッシュを活用する
  • エッジサイドレンダリングを利用してCDNで負荷分散する

まとめ

Nuxtのレンダリングモードは、SEOやパフォーマンス、開発効率を最適化するための強力な機能です。ユニバーサルレンダリングはSEOと初期表示速度に優れますが、環境差異やサーバー負荷に注意が必要です。クライアントサイドレンダリングは動的なUIに適し、サーバーコストを抑えられます。ハイブリッドレンダリングやエッジサイドレンダリングを活用することで、さらに柔軟な運用が可能です。

実務では、用途や要件に応じてこれらを使い分け、ハイドレーションの不一致やブラウザAPIの制限などの落とし穴に注意しながら開発を進めることが重要です。Nuxtのレンダリングモードを正しく理解し活用することで、ユーザー体験と開発効率の両立が実現できます。

ハイドレーションの不一致を防ぐためには、サーバーとクライアントで状態を同期させることが重要です。Vue公式ドキュメントのSSRガイドも参考にしてください。

ブラウザAPIを使うライブラリをインポートする場合は、クライアント専用コンポーネント内でのみ呼び出すようにしましょう。そうしないとサーバー側でエラーが発生します。


title: 'Nuxtにおけるクライアントサイドレンダリング(CSR)の実践的理解と活用法' description: 'Nuxtでのクライアントサイドレンダリング(CSR)の基本から実務での活用例、注意点までを丁寧に解説。パフォーマンスやSEOへの影響を踏まえた適切な使い分けを紹介します。'

Nuxtにおけるクライアントサイドレンダリング(CSR)の実践的理解と活用法

Nuxtはサーバーサイドレンダリング(SSR)を強力にサポートしていますが、状況によってはクライアントサイドレンダリング(CSR)を選択することが適しています。CSRは、ブラウザ上でJavaScriptが実行されて初めて画面が描画される方式で、特にインタラクティブなWebアプリケーションに向いています。

本記事では、NuxtでCSRを利用するメリットや課題、実務での具体的なユースケース、そして注意すべきポイントを詳しく解説します。Nuxtの公式ドキュメントを補完し、より実践的な視点でCSRの理解を深めていただければ幸いです。


まず結論:NuxtでCSRを使う際のポイント

  • 開発がシンプルに:ブラウザ専用API(例:windowdocument)を気にせず使える
  • サーバーコスト削減:静的ホスティングが可能で、サーバー運用コストを抑えられる
  • オフライン対応が容易:完全にクライアントで動作するため、ネットワークがなくても動作可能
  • パフォーマンスに注意:初回ロード時にJavaScriptのダウンロード・解析が必要で遅延が発生しやすい
  • SEO対策が難しい:検索エンジンのインデックス作成に時間がかかるため、SEOが重要なサイトには不向き
  • Nuxt設定はssr: falsenuxt.config.tsでSSRを無効化し、SPAモードに切り替える

いつ使うべきか? 使わない方がよいケースは?

CSRを選ぶべきケース

  • ユーザーが頻繁に操作するインタラクティブなアプリ
    SaaSツールや管理画面、オンラインゲームなど、ユーザーの操作に応じて頻繁にUIが変わる場合に適しています。
  • SEOが重要でない内部ツールや限定公開アプリ
    検索エンジンからの流入が不要な社内システムや会員限定サイトなど。
  • サーバーリソースを節約したい場合
    静的ファイルとしてホスティングできるため、サーバーの負荷やコストを抑えられます。

CSRを避けるべきケース

  • SEOが重要な公開サイトやブログ
    SSRや静的サイト生成(SSG)を使い、検索エンジンに最適化されたHTMLを提供すべきです。
  • 初回表示速度が極めて重要なサイト
    JavaScriptの読み込み・実行待ちがUXに悪影響を与えるため、SSRやプリレンダリングを検討してください。
  • サーバーサイドでのデータフェッチや認証が必須のケース
    クライアントだけで完結しない処理が多い場合は、SSRやAPI連携を組み合わせる必要があります。

実務でよくあるユースケースとサンプルコード

1. SaaSの管理画面

管理画面はユーザーの操作が多く、SEOは不要なためCSRが適しています。ssr: falseに設定し、ブラウザAPIを活用したUIを実装します。

// nuxt.config.ts
export default defineNuxtConfig({
  ssr: false
})
<template>
  <div>
    <h1>管理画面</h1>
    <button @click="toggleSidebar">サイドバー切替</button>
    <Sidebar v-if="sidebarVisible" />
  </div>
</template>

<script setup>
import { ref } from 'vue'

const sidebarVisible = ref(true)
function toggleSidebar() {
  sidebarVisible.value = !sidebarVisible.value
}
</script>

2. オフライン対応のPWA

完全にクライアントで動作するため、ネットワークが不安定な環境でも動作可能です。Service Workerと組み合わせてオフライン対応を強化します。

// nuxt.config.ts
export default defineNuxtConfig({
  ssr: false,
  modules: ['@nuxtjs/pwa'],
  pwa: {
    workbox: {
      offline: true
    }
  }
})

3. 静的ホスティング向けのシンプルSPA

静的ファイルだけでホスティング可能なため、NetlifyやVercelなどのCDNを活用した高速配信が可能です。

// nuxt.config.ts
export default defineNuxtConfig({
  ssr: false,
  target: 'static'
})

よくある落とし穴・注意点

1. 初回ロードのパフォーマンス低下

CSRはJavaScriptのダウンロード・解析・実行が完了するまで画面が表示されません。特にモバイル端末や低速回線では遅延が顕著です。
対策としては、コード分割や遅延読み込み、軽量なライブラリの利用を検討してください。

2. SEOの課題

検索エンジンはJavaScriptの実行を完全にはサポートしていない場合があります。CSRのみのサイトはインデックス作成が遅れ、検索結果に反映されにくいです。
SEOが重要な場合はSSRや静的サイト生成を優先しましょう。

3. ハイドレーションの問題

Nuxtでは通常SSRで生成したHTMLをクライアントでハイドレーション(再利用)しますが、ssr: falseの場合はハイドレーションが発生しません。
そのため、サーバーとクライアントで状態が異なる問題は起きにくいですが、初期表示のローディングUIを用意する必要があります。

4. サーバー機能の制限

CSRモードではサーバーサイドのAPIやエンドポイントは利用できません。サーバー機能が必要な場合は別途APIサーバーを用意し、Nuxtはフロントエンドとして利用する形が一般的です。


まとめ

Nuxtでのクライアントサイドレンダリングは、開発のシンプルさやサーバーコスト削減、オフライン対応など多くのメリットがあります。一方で、初回表示速度やSEOの課題もあるため、用途に応じてSSRや静的生成と使い分けることが重要です。

実務では、管理画面やPWA、静的ホスティング向けのSPAとしてCSRを活用するケースが多く、Nuxtのssr: false設定で簡単に切り替えられます。パフォーマンス最適化やSEO対策を意識しつつ、適切にCSRを選択して快適なユーザー体験を提供しましょう。


CSRを使う場合は、ユーザーに初回ロード中の状態をわかりやすく伝えるローディングUIを用意することがUX向上に繋がります。

ssr: false設定時は、~/app/spa-loading-template.htmlを用意して、ハイドレーション前の表示をカスタマイズできます。


title: 'Nuxtのハイブリッドレンダリングを実務で活かすための補足解説' description: 'Nuxtのハイブリッドレンダリング機能は、ルートごとに異なるレンダリング戦略やキャッシュ設定を柔軟に適用できる強力な機能です。本記事では、そのメリットや使いどころ、実務での具体的なユースケース、注意点を詳しく解説します。'

Nuxtのハイブリッドレンダリングとは?

Nuxtのハイブリッドレンダリングは、アプリケーションの異なるルート(ページ)に対して個別にレンダリング方法やキャッシュ戦略を設定できる機能です。これにより、静的に生成すべきページと動的にレンダリングすべきページを同じアプリ内で共存させられます。

従来はNuxtアプリ全体がユニバーサル(SSR)かクライアントサイドレンダリング(CSR)かのどちらかに固定されていましたが、ハイブリッドレンダリングを使うことで、例えば公開用のコンテンツページは静的にプリレンダリングしつつ、管理画面はCSRで動的に動かすといった柔軟な設計が可能になります。

この機能は、パフォーマンス最適化やユーザー体験の向上、運用コストの削減に大きく貢献します。


まず結論:ハイブリッドレンダリングのポイント

  • ルートごとにレンダリングモード(SSR、CSR、プリレンダリング)やキャッシュ戦略を細かく設定可能
  • routeRulesで設定し、Nuxtサーバーが自動的に適切なミドルウェアやキャッシュ処理を適用
  • 静的コンテンツはビルド時にプリレンダリングし、高速配信が可能
  • 動的コンテンツはオンデマンド生成やキャッシュ付き再検証(SWR/ISR)で最新性を保つ
  • 管理画面などはSSRを無効にしてクライアントサイドレンダリングに切り替え可能
  • CDNやリバースプロキシのキャッシュ制御も柔軟に設定できる
  • デプロイ先のプラットフォーム(Netlify、Vercelなど)に最適化された挙動を自動適用

いつ使うべきか?使わない方がよいケース

使うべきケース

  • 公開サイトと管理画面を同一アプリで運用したい
    公開ページは高速な静的配信、管理画面は動的な操作性を優先したい場合に最適です。

  • ページごとに更新頻度や動的性が異なる
    例えばブログ記事は頻繁に更新されるが、トップページはほぼ固定。こうした差を活かしてキャッシュ戦略を分けられます。

  • パフォーマンスと最新性のバランスを取りたい
    SWR(stale-while-revalidate)やISR(Incremental Static Regeneration)を使い、古いキャッシュを返しつつ裏で最新化する運用が可能です。

  • CDNキャッシュを活用したい
    CDNのキャッシュTTLをルート単位で制御し、効率的な配信を実現できます。

使わない方がよいケース

  • 単純な静的サイトや完全SSRのみのアプリ
    すべてのページが同じレンダリング戦略で問題ない場合は設定が不要です。

  • nuxt generateコマンドを使った完全静的生成を前提にしている場合
    ハイブリッドレンダリングはnuxt generateでは利用できません。

  • 複雑なルール管理が不要な小規模アプリ
    ルートルールの管理コストがかえって負担になることがあります。


実務でよくあるユースケースとサンプルコード

1. 静的コンテンツ+管理画面の共存

公開ページはビルド時にプリレンダリングし、管理画面はCSRに切り替える例です。

export default defineNuxtConfig({
  routeRules: {
    '/': { prerender: true },          // トップページは静的生成
    '/about': { prerender: true },     // Aboutページも静的生成
    '/admin/**': { ssr: false }        // 管理画面はCSRのみ
  }
})

この設定により、管理画面はサーバー負荷を抑えつつクライアントで動的に動作し、公開ページは高速に配信されます。

2. SWRを使った動的キャッシュ制御

商品一覧ページをオンデマンドで生成しつつ、バックグラウンドで再検証して最新情報を保つ例です。

export default defineNuxtConfig({
  routeRules: {
    '/products': { swr: true },        // キャッシュは期限なしでstale-while-revalidate
    '/products/**': { swr: 3600 }      // 個別商品ページは1時間キャッシュ
  }
})

これにより、ユーザーは高速にキャッシュ済みページを受け取りつつ、裏で最新データが取得されます。

3. ISRを使ったCDNキャッシュ連携

ブログ記事をCDNにキャッシュしつつ、更新時に自動で再生成する例です。

export default defineNuxtConfig({
  routeRules: {
    '/blog': { isr: 3600 },            // CDNで1時間キャッシュ
    '/blog/**': { isr: true }          // 個別記事は次のデプロイまでキャッシュ
  }
})

NetlifyやVercelのCDNと連携し、パフォーマンスと最新性を両立します。


よくある落とし穴・注意点

SSRとCSRの切り替えによるHydration問題

ssr: falseでCSRに切り替えたルートはサーバーでHTMLが生成されないため、初回表示時に空のHTMLが返ることがあります。
これにより、Hydration(クライアント側でのVueの再活性化)時にUIのちらつきやレイアウト崩れが起きることがあるため、UI設計に注意が必要です。

キャッシュ設定の誤用による古い情報の表示

SWRやISRはキャッシュを返しつつ裏で再生成する仕組みですが、TTLや設定を誤るとユーザーに古い情報が長時間表示されるリスクがあります。
特に動的データが頻繁に変わる場合は、TTLを短めに設定し、必要に応じて手動でキャッシュクリアを検討してください。

nuxt generateとの非互換性

ハイブリッドレンダリングはnuxt generateコマンド(完全静的サイト生成)では利用できません。
静的サイト生成を前提にしている場合は、ルートルールの設定が無効になるため注意してください。

パフォーマンスへの影響

複雑なルートルールを大量に設定すると、サーバーのミドルウェア処理が増え、レスポンス遅延の原因になることがあります。
必要最低限のルールに絞り、パフォーマンス計測を行いながら調整しましょう。


まとめ

Nuxtのハイブリッドレンダリングは、ルート単位でレンダリングモードやキャッシュ戦略を柔軟に設定できる強力な機能です。
これにより、静的コンテンツと動的コンテンツを同一アプリで効率的に運用でき、パフォーマンスとユーザー体験の両立が可能になります。

ただし、SSR/CSRの切り替えによるUIのHydration問題やキャッシュ設定の誤用には注意が必要です。
実務では公開ページはプリレンダリング、管理画面はCSR、動的ページはSWRやISRで最新性を保つといった使い分けが典型的です。

NuxtのrouteRulesを活用して、最適なレンダリング戦略を設計し、快適で高速なWebアプリケーションを構築しましょう。