# Nuxt 3: SSR と静的生成 完全ガイド > Nuxt 3 で SSR と静的生成を使いこなしましょう。useFetch から route rules まで、Vue.js アプリケーションのパフォーマンスを最適化する方法を解説します。 - Published: 2026-02-11 - Updated: 2026-04-28 - Author: SharpSkill - Tags: nuxt 3, vue.js, ssr, 静的生成, Web パフォーマンス - Reading time: 12 min --- Nuxt 3 は、さまざまなユースケースに適した複数のレンダリングモードを提供することで、Vue.js アプリケーションの構築方法を大きく変えています。Server-Side Rendering(SSR)から静的生成、ハイブリッドレンダリングまで、このフレームワークはパフォーマンスと SEO を最適化するために優れた柔軟性を提供します。 > **前提条件** > > このチュートリアルは、Vue 3 と Composition API の基本的な知識を前提としています。サーバーサイドレンダリングの概念に慣れていると役立ちますが、必須ではありません。基礎的な内容はガイド全体を通じて解説していきます。 ## Nuxt 3 のレンダリングモードを理解する コードに入る前に、利用できるレンダリングモードの違いを理解することが重要です。各モードは、パフォーマンス、SEO、ユーザー体験の面でそれぞれ特定のニーズに応えます。 SSR(Server-Side Rendering)はリクエストごとにサーバー上で HTML を生成します。静的生成(SSG)はビルド時にすべてのページを事前生成します。ハイブリッドモードでは、これらのアプローチをページ単位で組み合わせることができます。 ```typescript // nuxt.config.ts // 各種レンダリングモードの設定 export default defineNuxtConfig({ // SSR はデフォルトで有効(SEO のために推奨) ssr: true, // 静的生成: すべてのページを事前レンダリング // ビルドには 'npm run generate' を使用 // target: 'static', // Nuxt 2 の構文 // ハイブリッドモード: ルートごとに設定可能 routeRules: { // トップページ: 事前レンダリング & キャッシュ '/': { prerender: true }, // ブログ: 静的生成 '/blog/**': { prerender: true }, // ダッシュボード: クライアントサイドのみのレンダリング '/dashboard/**': { ssr: false }, // API: 事前レンダリングなし '/api/**': { prerender: false } } }) ``` この設定はハイブリッドモードの威力を示しています。アプリケーションの各セクションが、それぞれのニーズに最も適したレンダリングモードを使用しています。 ## useFetch と useAsyncData によるデータ取得 Nuxt 3 はアイソモルフィックなデータ取得のために、2 つの主要な composable を提供しています。これらの composable はサーバー側でもクライアント側でも動作し、ハイドレーションを自動的に管理します。 `useFetch` は `useAsyncData` のラッパーで、HTTP 呼び出しをシンプルにします。`useAsyncData` は高度なユースケースに対してより細かい制御を提供します。 ```vue ``` より細かい制御が必要な場合、`useAsyncData` は任意の非同期関数を実行できます。 ```vue ``` これらの composable は二重フェッチを防ぎます。サーバーで取得されたデータは HTML ペイロードにシリアライズされ、クライアントのハイドレーション時に再利用されます。 ## サーバーフックによる SSR のカスタマイズ Nuxt 3 の SSR はサーバーフックを通じてカスタマイズできます。これらのフックを使うことで、レンダリングサイクルのさまざまな段階に介入し、デフォルトの挙動を変更できます。 ```typescript // server/plugins/render-hooks.ts // SSR レンダリングをカスタマイズするためのサーバープラグイン export default defineNitroPlugin((nitroApp) => { // 各ページのレンダリング前に実行されるフック nitroApp.hooks.hook('render:html', (html, { event }) => { // スクリプトやメタデータを注入 html.head.push(` `) }) // レンダリングキャッシュの管理用フック nitroApp.hooks.hook('render:response', (response, { event }) => { // カスタムキャッシュヘッダを追加 const path = event.path if (path.startsWith('/blog/')) { // ブログ記事には長めのキャッシュ response.headers['Cache-Control'] = 'public, max-age=3600, s-maxage=86400' } else if (path.startsWith('/api/')) { // API ではキャッシュしない response.headers['Cache-Control'] = 'no-store' } }) }) ``` > **SSR のパフォーマンス** > > `render:response` フックは HTTP キャッシュ戦略を実装するのに最適です。SSR と Cache-Control ヘッダを尊重する CDN を組み合わせることで、事前レンダリング済みのページを提供しつつ、キャッシュの無効化も維持できます。 ## nuxt generate による静的生成 静的生成では、ビルド時にすべてのページを事前構築します。このアプローチはブログ、ドキュメント、マーケティングサイトのように、内容が安定したサイトに最適です。 動的ルートでは、Nuxt が生成すべきすべての URL を把握する必要があります。`prerender:routes` フックでこれらのルートをプログラム的に定義できます。 ```typescript // nuxt.config.ts // 静的生成のための完全な設定 export default defineNuxtConfig({ // 静的生成を有効化 nitro: { prerender: { // リンクの自動クロールを有効化 crawlLinks: true, // 常に含めるルート routes: ['/', '/about', '/contact'], // 一部のルートを無視 ignore: ['/admin', '/api'] } }, hooks: { // 動的ルートを生成するためのフック async 'prerender:routes'(ctx) { // API または DB から記事を取得 const articles = await fetch('https://api.example.com/articles') .then(res => res.json()) // 記事のルートを追加 for (const article of articles) { ctx.routes.add(`/blog/${article.slug}`) } // カテゴリを取得 const categories = await fetch('https://api.example.com/categories') .then(res => res.json()) for (const category of categories) { ctx.routes.add(`/category/${category.slug}`) } } } }) ``` ページ数の多いプロジェクトでは、自動クローラーでは不十分な場合があります。専用の設定ファイルを使ったより堅牢なアプローチを示します。 ```typescript // server/utils/generate-routes.ts // 動的ルートのリストを生成するユーティリティ import { prisma } from './prisma' export async function getAllStaticRoutes(): Promise { const routes: string[] = [] // ブログ記事 const articles = await prisma.article.findMany({ where: { published: true }, select: { slug: true, category: { select: { slug: true } } } }) for (const article of articles) { routes.push(`/blog/${article.category.slug}/${article.slug}`) } // 商品ページ const products = await prisma.product.findMany({ where: { active: true }, select: { slug: true } }) for (const product of products) { routes.push(`/products/${product.slug}`) } // タグページ const tags = await prisma.tag.findMany({ select: { slug: true } }) for (const tag of tags) { routes.push(`/tags/${tag.slug}`) } return routes } ``` ## routeRules によるハイブリッドレンダリング ハイブリッドレンダリングは Nuxt 3 の目玉機能です。ルートごとに異なるレンダリングルールを定義し、SSR と SSG の長所を組み合わせることができます。 ```typescript // nuxt.config.ts // ハイブリッドレンダリングの高度な設定 export default defineNuxtConfig({ routeRules: { // マーケティングページ: 事前レンダリングし、長期間キャッシュ '/': { prerender: true }, '/pricing': { prerender: true }, '/features/**': { prerender: true }, // ブログ: ISR (Incremental Static Regeneration) // 1 時間ごとに再検証 '/blog/**': { isr: 3600, prerender: true }, // ドキュメント: 再検証付きの CDN キャッシュ '/docs/**': { swr: 86400, // Stale-while-revalidate prerender: true }, // EC: 短いキャッシュ付きの SSR '/products/**': { ssr: true, cache: { maxAge: 60, staleMaxAge: 300 } }, // カートとチェックアウト: クライアントサイドのみ '/cart': { ssr: false }, '/checkout/**': { ssr: false }, // ダッシュボード: SPA モード '/dashboard/**': { ssr: false, // 事前レンダリングを無効化 prerender: false }, // API ルート: デフォルトでキャッシュなし '/api/**': { cors: true, headers: { 'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE' } } } }) ``` この設定は典型的なモダンアプリケーションのアーキテクチャを示しています。公開ページは SSG により SEO 向けに最適化され、インタラクティブなセクションはクライアントサイドレンダリングを利用しています。 ## データキャッシュによるパフォーマンス最適化 ページキャッシュに加えて、Nuxt 3 では取得したデータをキャッシュできます。この戦略により API 負荷を軽減し、応答時間を改善できます。 ```typescript // server/api/articles/[slug].get.ts // データキャッシュ付きの API エンドポイント import { getArticleBySlug } from '~/server/utils/articles' export default defineCachedEventHandler( async (event) => { const slug = getRouterParam(event, 'slug') if (!slug) { throw createError({ statusCode: 400, message: 'slug がありません' }) } const article = await getArticleBySlug(slug) if (!article) { throw createError({ statusCode: 404, message: '記事が見つかりません' }) } return article }, { // slug ベースのキャッシュキー getKey: (event) => `article-${getRouterParam(event, 'slug')}`, // キャッシュ時間: 1 時間 maxAge: 3600, // Stale-while-revalidate: 更新中も古いキャッシュを提供 staleMaxAge: 7200, // タグベースの無効化 tags: ['articles'] } ) ``` コンテンツが変更された際にキャッシュを無効化するため、Nuxt はタグシステムを提供しています。 ```typescript // server/api/articles/[slug].put.ts // キャッシュ無効化を伴う記事の更新 import { updateArticle } from '~/server/utils/articles' export default defineEventHandler(async (event) => { const slug = getRouterParam(event, 'slug') const body = await readBody(event) // 記事を更新 const article = await updateArticle(slug, body) // この記事のキャッシュを無効化 await useStorage('cache').removeItem(`nitro:handlers:article-${slug}`) // あるいはタグベースの無効化(全記事) // await useStorage('cache').clear('articles') return article }) ``` > **分散キャッシュ** > > 複数インスタンスのプロダクション環境では、インメモリキャッシュは不十分です。インスタンス間の整合性を保つため、Nitro 設定経由で Redis などの分散システムを構成することをお勧めします。 ## SEO とメタデータの管理 SSR ではメタデータをサーバー側で生成することで SEO を最適化できます。Nuxt 3 はメタタグを動的に管理するための複数のアプローチを提供しています。 ```vue ``` 静的なページの場合、メタデータをコンポーネント内で直接定義できます。 ```vue ``` ## デプロイと本番環境での考慮事項 デプロイの選択は使用するレンダリングモードによって異なります。主要な選択肢とその設定を紹介します。 ```typescript // nuxt.config.ts // 各種デプロイ環境向けの設定 export default defineNuxtConfig({ nitro: { // ターゲットプラットフォームに応じたプリセット // preset: 'vercel', // Vercel // preset: 'netlify', // Netlify // preset: 'cloudflare-pages', // Cloudflare // preset: 'node-server', // 一般的な Node.js // 本番環境の Node.js 向け設定 preset: 'node-server', // レスポンスの圧縮 compressPublicAssets: true, // キャッシュストレージの設定 storage: { cache: { driver: 'redis', url: process.env.REDIS_URL } } }, // ランタイムの環境変数 runtimeConfig: { // シークレット(クライアントには公開されません) apiSecret: process.env.API_SECRET, // 公開設定 public: { apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api' } } }) ``` 静的デプロイでは、`npm run generate` コマンドが `.output/public` フォルダを生成し、任意の静的ファイルホストにそのままデプロイできます。 ```bash # 静的生成 npm run generate # .output/public の内容は次の場所にデプロイできます: # - Vercel(自動検出) # - Netlify(自動設定) # - GitHub Pages # - S3 + CloudFront # - 任意の CDN または静的ファイルサーバー ``` ## まとめ Nuxt 3 は Vue.js アプリケーションをレンダリングするための優れた柔軟性を提供します。SSR、SSG、ハイブリッドレンダリングのいずれを選ぶかは、プロジェクトごとの具体的なニーズによって決まります。 **重要なポイント:** ✅ **SSR**: 良好な SEO が必要な動的コンテンツに最適(EC、ニュースサイト) ✅ **SSG**: 安定したコンテンツに最適(ブログ、ドキュメント、マーケティングサイト) ✅ **ハイブリッド**: さまざまなニーズを持つ複雑なアプリケーションに最適なアプローチ ✅ **useFetch/useAsyncData**: 自動ハイドレーションとキャッシュ管理 ✅ **routeRules**: 各ルートの挙動をきめ細かく設定 ✅ **キャッシュ**: 本番環境のパフォーマンスを最適化する複数の戦略 ハイブリッドレンダリングと十分に練られたキャッシュ戦略を組み合わせることで、SEO に最適化された高速なアプリケーションを構築しつつ、Single Page Applications のインタラクティブ性も維持できます。 --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/ja/blog/vue-nuxt/nuxt-3-ssr-static-generation