Nuxt のページ遷移を極める:ファイルベースルーティング攻略法

Nuxt.js の最大の魅力の一つが、ファイルベースルーティングです。従来の Vue Router のように手動でルートを定義する必要がなく、ファイルシステムの構造がそのまま URL 構造になるという革命的な仕組みです。
この記事では、Nuxt のページ遷移を完全に理解し、実践的なプロジェクトで活用できるようになることを目指します。初心者の方でも安心して読み進められるよう、基礎から応用まで段階的に解説していきます。
ファイルベースルーティングをマスターすれば、開発効率が劇的に向上し、保守性の高いアプリケーションを構築できるようになります。一緒に Nuxt の世界を深く探求していきましょう。
ファイルベースルーティングの基本概念
Nuxt のディレクトリ構造とルーティングの関係
Nuxt では、pages
ディレクトリ内のファイル構造が自動的にルーティング構造に変換されます。これがファイルベースルーティングの核心です。
まず、基本的なディレクトリ構造を確認してみましょう:
bashpages/
├── index.vue → /
├── about.vue → /about
├── users/
│ ├── index.vue → /users
│ └── [id].vue → /users/123
└── blog/
├── index.vue → /blog
└── [slug].vue → /blog/my-first-post
この構造を見ると、ファイル名がそのまま URL パスになることがわかります。index.vue
は特別な意味を持ち、ディレクトリのデフォルトページとして機能します。
実際にプロジェクトを作成して確認してみましょう:
bash# Nuxtプロジェクトの作成
$ yarn create nuxt-app my-nuxt-app
$ cd my-nuxt-app
$ yarn dev
pages ディレクトリの役割と命名規則
pages
ディレクトリは、Nuxt アプリケーションの心臓部です。ここに配置されたファイルは自動的にルートとして認識され、Vue コンポーネントとしてレンダリングされます。
基本的な命名規則を理解しましょう:
静的ルート
about.vue
→/about
contact.vue
→/contact
products.vue
→/products
動的ルート
[id].vue
→/123
/456` など[slug].vue
→/my-post
,/another-post
など
ネストしたルート
users/index.vue
→/users
users/[id].vue
→/users/123
実際のコード例を見てみましょう:
vue<!-- pages/index.vue -->
<template>
<div>
<h1>ホームページ</h1>
<p>ようこそ、Nuxtの世界へ!</p>
</div>
</template>
<script setup>
// ページのメタデータを設定
useHead([object Object] title:ホームページ,meta: [
{ name: 'description, content:Nuxtアプリケーションのホームページです' }
]
})
</script>
基本的なページ遷移の実装
静的ルートの作成方法
静的ルートは、最もシンプルなページ遷移の実装方法です。固定の URL でアクセスできるページを作成します。
まず、基本的な静的ページを作成してみましょう:
vue<!-- pages/about.vue -->
<template>
<div class="about-page>
<h1私たちについて</h1>
<p>このページは静的ルートの例です。</p>
<NuxtLink to="/>ホームに戻る</NuxtLink>
</div>
</template>
<script setup>
// ページ固有のロジック
const pageTitle = ref(私たちについて')
// SEO対策
useHead({
title: pageTitle.value,
meta: [
{ name: 'description', content: '私たちの会社について詳しく紹介します' }
]
})
</script>
よくあるエラーと解決策
bash# エラー: Cannot find module ./pages/about.vue# 原因: ファイル名の大文字小文字が間違っている
# 解決策: ファイル名を正確に確認する
# エラー: [nuxt] [request error] Cannot read properties of undefined
# 原因: script setupでrefをimportしていない
# 解決策: import [object Object] ref } from vueを追加
動的ルート(パラメータ付き)の実装
動的ルートは、URL パラメータを受け取って動的にコンテンツを表示する仕組みです。ブログ記事や商品詳細ページなどで活用されます。
vue<!-- pages/users/[id].vue -->
<template>
<div class=user-detail> <h1>ユーザー詳細: [object Object][object Object] user?.name }}</h1<div v-if="pending">読み込み中...</div>
<div v-else-if=error">エラーが発生しました</div>
<div v-else>
<p>ID: {{ $route.params.id }}</p>
<p>名前: [object Object][object Object]user?.name }}</p>
<p>メール: {[object Object] user?.email }}</p>
</div>
</div>
</template>
<script setup>
// ルートパラメータを取得
const route = useRoute()
const userId = route.params.id
// ユーザーデータを取得
const { data: user, pending, error } = await useFetch(`/api/users/${userId}`)
// エラーハンドリング
if (error.value) {
throw createError([object Object] statusCode: 404,
statusMessage: 'ユーザーが見つかりません'
})
}
</script>
動的ルートでよくあるエラー
bash# エラー: [nuxt] [request error] Cannot read properties of undefined (reading 'params')
# 原因: useRoute()をscript setupの外で呼び出している
# 解決策: script setup内でuseRoute()を呼び出す
# エラー: [nuxt] [request error] Cannot read properties of undefined (readingid# 原因: route.paramsがundefined
# 解決策: route.paramsの存在確認を追加
ネストしたルートの構築
ネストしたルートは、階層構造を持つページを作成する際に使用します。親子関係のあるコンテンツを整理できます。
vue<!-- pages/blog/index.vue -->
<template>
<div class=blog-list>
<h1ログ一覧</h1>
<div class="posts">
<article v-for="post in posts" :key="post.id" class=post">
<h2>[object Object][object Object] post.title }}</h2>
<p>{{ post.excerpt }}</p>
<NuxtLink :to="`/blog/$[object Object]post.slug}`">続きを読む</NuxtLink>
</article>
</div>
</div>
</template>
<script setup>
// ブログ記事一覧を取得
const { data: posts } = await useFetch('/api/posts)</script>
vue<!-- pages/blog/[slug].vue -->
<template>
<div class=blog-post>
<h1>{[object Object] post?.title }}</h1>
<div class="meta>
<span>投稿日: {{ formatDate(post?.createdAt) }}</span>
</div>
<div class=content" v-html=post?.content></div>
<NuxtLink to=/blog>←ブログ一覧に戻る</NuxtLink>
</div>
</template>
<script setup>
const route = useRoute()
const slug = route.params.slug
// 記事データを取得
const { data: post } = await useFetch(`/api/posts/${slug}`)
// 日付フォーマット関数
const formatDate = (date) => {
return new Date(date).toLocaleDateString('ja-JP')
}
</script>
高度なページ遷移テクニック
ミドルウェアを使った遷移制御
ミドルウェアは、ページ遷移の前後に実行される処理を定義できます。認証チェックやログ出力などに活用されます。
javascript// middleware/auth.js
export default defineNuxtRouteMiddleware((to, from) =>[object Object]
// ユーザーの認証状態をチェック
const user = useUser()
if (!user.value && to.path.startsWith('/admin')) [object Object] // 未認証の場合はログインページにリダイレクト
return navigateTo(/login')
}
// ログ出力
console.log(`ページ遷移: ${from.path} → ${to.path}`)
})
ページレベルでミドルウェアを適用する場合:
vue<!-- pages/admin/dashboard.vue -->
<template>
<div class="admin-dashboard>
<h1理者ダッシュボード</h1>
<p>認証済みユーザーのみアクセス可能</p>
</div>
</template>
<script setup>
// このページにミドルウェアを適用
definePageMeta([object Object]middleware: ['auth']
})
</script>
ミドルウェアでよくあるエラー
bash# エラー: [nuxt] [request error] Cannot read properties of undefined (reading value)
# 原因: useUser()が未定義
# 解決策: composableを正しく定義する
# エラー: [nuxt] [request error] navigateTo is not defined
# 原因: navigateToをimportしていない
# 解決策: import { navigateTo } from #app を追加
ページ遷移のアニメーション実装
Nuxt では、ページ遷移時にアニメーションを追加できます。ユーザー体験を向上させる重要な要素です。
vue<!-- app.vue -->
<template>
<div>
<NuxtPage />
</div>
</template>
<style>
/* ページ遷移アニメーション */
.page-enter-active,
.page-leave-active {
transition: all 0.3se;
}
.page-enter-from {
opacity: 0;
transform: translateX(20x);
}
.page-leave-to {
opacity: 0;
transform: translateX(-20;
}
</style>
特定のページでアニメーションをカスタマイズする場合:
vue<!-- pages/about.vue -->
<template>
<div class="about-page>
<h1私たちについて</h1>
<p>カスタムアニメーション付きページ</p>
</div>
</template>
<script setup>
// ページ固有のアニメーション設定
definePageMeta([object Object]
pageTransition: [object Object] name:slide-fade',
mode: out-in'
}
})
</script>
<style scoped>
.slide-fade-enter-active,
.slide-fade-leave-active {
transition: all 0.3 ease;
}
.slide-fade-enter-from {
opacity: 0;
transform: translateY(30x);
}
.slide-fade-leave-to {
opacity: 0;
transform: translateY(-30;
}
</style>
プログラムによる遷移制御
JavaScript からプログラム的にページ遷移を制御する方法を学びましょう。
vue<!-- pages/contact.vue -->
<template>
<div class="contact-form">
<h1>お問い合わせ</h1>
<form @submit.prevent="handleSubmit">
<input v-model=form.name" type=text placeholder="お名前" required>
<input v-model="form.email" type="emailplaceholder=メールアドレス" required>
<textarea v-model="form.messageplaceholder="メッセージ" required></textarea>
<button type=submit :disabled="isSubmitting">
[object Object][object Object] isSubmitting ?送信中...' : 送信する }}
</button>
</form>
</div>
</template>
<script setup>
const router = useRouter()
const form = ref({
name: ail:
message:const isSubmitting = ref(false)
const handleSubmit = async () => {
isSubmitting.value = true
try [object Object] // フォーム送信処理
await $fetch(/api/contact,[object Object] method: POST',
body: form.value
})
// 成功時の遷移
await navigateTo('/thank-you, {
replace: true
})
} catch (error) {
console.error('送信エラー:, error)
// エラー時の処理
} finally [object Object]isSubmitting.value = false
}
}
</script>
プログラム遷移でよくあるエラー
bash# エラー: [nuxt] [request error] navigateTo is not a function
# 原因: navigateToを正しくimportしていない
# 解決策: import { navigateTo } from #app' を追加
# エラー: [nuxt] [request error] Cannot read properties of undefined (readingpush)
# 原因: useRouter()の使用方法が間違っている
# 解決策: const router = useRouter() で正しく取得
ファイルベースルーティングの応用パターン
レイアウトを使った共通 UI の実装
Nuxt のレイアウト機能を使って、共通の UI 要素を効率的に管理できます。
vue<!-- layouts/default.vue -->
<template>
<div class="layout">
<header class="header">
<nav>
<NuxtLink to="/">ホーム</NuxtLink>
<NuxtLink to=/about">私たちについて</NuxtLink>
<NuxtLink to="/blog">ブログ</NuxtLink>
<NuxtLink to="/contact>お問い合わせ</NuxtLink>
</nav>
</header>
<main class="main> <slot />
</main>
<footer class=footer>
<p>©2024xt App. All rights reserved.</p>
</footer>
</div>
</template>
<style scoped>
.layout {
min-height:100h;
display: flex;
flex-direction: column;
}
.header [object Object]
background: #f8f9fa;
padding: 1rem;
border-bottom:1px solid #e9ecef;
}
.main {
flex: 1
padding: 2rem;
}
.footer[object Object] background: #343a40;
color: white;
padding: 1rem;
text-align: center;
}
</style>
特定のページでカスタムレイアウトを使用する場合:
vue<!-- layouts/admin.vue -->
<template>
<div class="admin-layout">
<aside class=sidebar">
<nav>
<NuxtLink to="/admin/dashboard">ダッシュボード</NuxtLink>
<NuxtLink to=/admin/users>ユーザー管理</NuxtLink>
<NuxtLink to="/admin/posts>記事管理</NuxtLink>
</nav>
</aside>
<main class=content> <slot />
</main>
</div>
</template>
vue<!-- pages/admin/dashboard.vue -->
<template>
<div class=dashboard>
<h1理者ダッシュボード</h1>
<p>管理画面専用レイアウトを使用しています</p>
</div>
</template>
<script setup>
// カスタムレイアウトを指定
definePageMeta([object Object] layout: 'admin'
})
</script>
エラーページのカスタマイズ
Nuxt では、エラーページをカスタマイズして、ユーザー体験を向上させることができます。
vue<!-- error.vue -->
<template>
<div class="error-page">
<div class="error-content">
<h1>{{ error.statusCode }}</h1>
<h2>{{ error.statusMessage }}</h2>
<p>{{ error.message }}</p>
<div class=actions>
<button @click=handleError>ホームに戻る</button>
<button @click="goBack>前のページに戻る</button>
</div>
</div>
</div>
</template>
<script setup>
const error = useError()
const handleError = () =>[object Object]
// エラーをクリアしてホームページに遷移
clearError({ redirect: /})
}
const goBack = () =>[object Object] // ブラウザの戻るボタンと同じ動作
if (process.client) {
window.history.back()
}
}
</script>
<style scoped>
.error-page[object Object]
display: flex;
align-items: center;
justify-content: center;
min-height: 100text-align: center;
}
.error-content h1
font-size: 6m;
color: #dc3545;
margin: 0actions[object Object] margin-top:2}
.actions button[object Object] margin: 0 0.5rem;
padding: 0.5rem 1rem;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
SEO 対応のためのメタデータ設定
SEO 対策は、Web アプリケーションの成功に不可欠です。Nuxt では、ページごとにメタデータを設定できます。
vue<!-- pages/blog/[slug].vue -->
<template>
<div class=blog-post>
<h1>{[object Object] post?.title }}</h1>
<div class=content" v-html=post?.content></div>
</div>
</template>
<script setup>
const route = useRoute()
const slug = route.params.slug
// 記事データを取得
const { data: post } = await useFetch(`/api/posts/${slug}`)
// 動的なメタデータ設定
useHead({
title: post.value?.title || '記事が見つかりません,meta: [
{ name: 'description', content: post.value?.excerpt || '' },
{ property: 'og:title', content: post.value?.title || '' },
{ property:og:description', content: post.value?.excerpt || '' },
{ property: 'og:image', content: post.value?.featuredImage || }, { name: 'twitter:card', content: 'summary_large_image' }
],
link:
[object Object] rel: canonical, href: `https://example.com/blog/${slug}` }
]
})
</script>
パフォーマンス最適化
遅延読み込み(Lazy Loading)の実装
Nuxt では、ページを遅延読み込みすることで、初期ロード時間を短縮できます。
vue<!-- pages/heavy-page.vue -->
<template>
<div class="heavy-page>
<h1>重いコンテンツのページ</h1>
<div class="content">
<!-- 大量のコンテンツ -->
</div>
</div>
</template>
<script setup>
// 遅延読み込みを有効にする
definePageMeta({
lazy: true
})
// 重い処理を遅延実行
const heavyData = await $fetch(/api/heavy-data,[object Object] lazy: true
})
</script>
プリフェッチの活用
プリフェッチ機能を使って、ユーザーがリンクにホバーした時に次のページを事前に読み込みます。
vue<!-- pages/index.vue -->
<template>
<div class="home">
<h1>ホームページ</h1>
<div class="navigation>
<!-- プリフェッチを有効にする -->
<NuxtLink to=/aboutprefetch>私たちについて</NuxtLink>
<NuxtLink to="/blogprefetch>ブログ</NuxtLink>
<NuxtLink to="/contact" prefetch>お問い合わせ</NuxtLink>
</div>
</div>
</template>
特定の条件下でのみプリフェッチを有効にする場合:
vue<!-- pages/blog/index.vue -->
<template>
<div class=blog-list>
<h1ログ一覧</h1>
<div class="posts">
<article v-for="post in posts" :key="post.id" class=post">
<h2>[object Object][object Object] post.title }}</h2>
<p>{{ post.excerpt }}</p>
<!-- 条件付きプリフェッチ -->
<NuxtLink
:to="`/blog/${post.slug}`"
:prefetch="post.isPopular"
>
続きを読む
</NuxtLink>
</article>
</div>
</div>
</template>
<script setup>
const { data: posts } = await useFetch('/api/posts)</script>
キャッシュ戦略
Nuxt のキャッシュ機能を活用して、パフォーマンスを向上させましょう。
vue<!-- pages/products/[id].vue -->
<template>
<div class=product-detail">
<h1product?.name }}</h1>
<p>{{ product?.description }}</p>
<p>価格: ¥{{ product?.price }}</p>
</div>
</template>
<script setup>
const route = useRoute()
const productId = route.params.id
// キャッシュ付きでデータを取得
const[object Object] data: product } = await useFetch(`/api/products/${productId}`, [object Object] key: `product-${productId}`,
default: () => null,
// 5シュ
server: false,
lazy: true
})
// ページレベルでのキャッシュ設定
definePageMeta({
keepalive: true
})
</script>
パフォーマンス最適化でよくあるエラー
error# エラー: [nuxt] [request error] Cannot read properties of undefined (reading value)
# 原因: キャッシュキーが正しく設定されていない
# 解決策: ユニークなキーを設定する
# エラー: [nuxt] [request error] prefetch is not a function
# 原因: prefetchの使用方法が間違っている
# 解決策: NuxtLinkコンポーネントでprefetchプロパティを使用
まとめ
Nuxt のファイルベースルーティングは、開発効率を劇的に向上させる革新的な仕組みです。この記事で学んだ内容を実践することで、保守性が高く、ユーザー体験の優れた Web アプリケーションを構築できるようになります。
重要なポイントを振り返ると:1. ファイル構造がそのまま URL 構造になる - 直感的で理解しやすい 2. 動的ルートで柔軟なページ作成 - パラメータを活用した動的コンテンツ 3 ミドルウェアで遷移制御 - 認証やログ出力などの処理を自動化 4. アニメーションで UX 向上 - スムーズなページ遷移でユーザー体験を向上 5. SEO 対策とパフォーマンス最適化 - 検索エンジン対応と高速化
実際のプロジェクトでは、これらの機能を組み合わせることで、より高度なアプリケーションを構築できます。エラーが発生した場合は、この記事で紹介した解決策を参考に、一つずつ問題を解決していきましょう。
Nuxt のファイルベースルーティングをマスターすれば、開発の世界が大きく広がります。ぜひ実践的なプロジェクトで活用してみてください。
関連リンク
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来