brand logo

ドキュメント

pages

Nuxtは、ファイルベースのルーティングを提供し、ウェブアプリケーション内でルートを作成します。

アプリケーションのバンドルサイズを削減するために、このディレクトリはオプションです。つまり、app.vueのみを使用する場合、vue-routerは含まれません。ページシステムを強制するには、nuxt.configpages: trueを設定するか、app/router.options.tsを使用してください。

使用法

ページはVueコンポーネントであり、Nuxtがサポートする任意の有効な拡張子を持つことができます(デフォルトでは.vue.js.jsx.mjs.ts、または.tsx)。

Nuxtは、~/pages/ディレクトリ内のすべてのページに対して自動的にルートを作成します。

<template>
  <h1>インデックスページ</h1>
</template>

pages/index.vueファイルは、アプリケーションの/ルートにマッピングされます。

app.vueを使用している場合は、現在のページを表示するために<NuxtPage/>コンポーネントを使用してください。

app.vue
<template>
  <div>
    <!-- すべてのページで共有されるマークアップ、例: ナビゲーションバー -->
    <NuxtPage />
  </div>
</template>

ページは、ページ間のルート遷移を可能にするために単一のルート要素を持たなければなりません。HTMLコメントも要素と見なされます。

これは、ルートがサーバーレンダリングまたは静的生成されるときにその内容を正しく見ることができますが、クライアントサイドのナビゲーション中にそのルートに移動すると、ルート間の遷移が失敗し、ルートがレンダリングされないことを意味します。

単一のルート要素を持つページの例を以下に示します。

<template>
  <div>
    <!-- このページは正しく単一のルート要素を持っています -->
    ページコンテンツ
  </div>
</template>

動的ルート

角括弧内に何かを配置すると、それは動的ルートパラメータに変換されます。複数のパラメータを組み合わせたり、ファイル名やディレクトリ内で動的でないテキストを混在させることもできます。

パラメータを_オプション_にしたい場合は、二重角括弧で囲む必要があります。例えば、~/pages/[[slug]]/index.vueまたは~/pages/[[slug]].vueは、//testの両方にマッチします。

ディレクトリ構造
-| pages/
---| index.vue
---| users-[group]/
-----| [id].vue

上記の例では、コンポーネント内で$routeオブジェクトを介してgroup/idにアクセスできます。

pages/users-[group\
<template>
  <p>{{ $route.params.group }} - {{ $route.params.id }}</p>
</template>

/users-admins/123に移動すると、次のようにレンダリングされます。

<p>admins - 123</p>

Composition APIを使用してルートにアクセスしたい場合は、Options APIのthis.$routeのようにルートにアクセスできるグローバルなuseRoute関数があります。

const route = useRoute()

if (route.params.group === 'admins' && !route.params.id) {
  console.log('警告!ユーザーが認証されていることを確認してください!')
}

名前付き親ルートはネストされた動的ルートよりも優先されます。/foo/helloルートの場合、~/pages/foo.vue~/pages/foo/[slug].vueよりも優先されます。:br /foo/foo/helloを異なるページでマッチさせるには、~/pages/foo/index.vue~/pages/foo/[slug].vueを使用してください。

キャッチオールルート

キャッチオールルートが必要な場合は、[...slug].vueのように名前を付けたファイルを使用して作成します。これにより、そのパスの下の_すべての_ルートにマッチします。

pages/[...slug\
<template>
  <p>{{ $route.params.slug }}</p>
</template>

/hello/worldに移動すると、次のようにレンダリングされます。

<p>["hello", "world"]</p>

ネストされたルート

<NuxtPage>を使用してネストされたルートを表示することができます。

例:

ディレクトリ構造
-| pages/
---| parent/
-----| child.vue
---| parent.vue

このファイルツリーは次のルートを生成します。

[
  {
    path: '/parent',
    component: '~/pages/parent.vue',
    name: 'parent',
    children: [
      {
        path: 'child',
        component: '~/pages/parent/child.vue',
        name: 'parent-child'
      }
    ]
  }
]

child.vueコンポーネントを表示するには、pages/parent.vue内に<NuxtPage>コンポーネントを挿入する必要があります。

pages/parent.vue
<template>
  <div>
    <h1>私は親ビューです</h1>
    <NuxtPage :foobar="123" />
  </div>
</template>
pages/parent/child.vue
const props = defineProps(['foobar'])

console.log(props.foobar)

子ルートキー

<NuxtPage>コンポーネントが再レンダリングされるタイミングをより制御したい場合(例えば、トランジションのため)、pageKeyプロップを介して文字列または関数を渡すか、definePageMetaを使用してkey値を定義できます。

pages/parent.vue
<template>
  <div>
    <h1>私は親ビューです</h1>
    <NuxtPage :page-key="route => route.fullPath" />
  </div>
</template>

または、次のようにします。

pages/parent/child.vue
definePageMeta({
  key: route => route.fullPath
})
サンプルコードの編集とプレビューexamples > routing > pages

ルートグループ

場合によっては、ファイルベースのルーティングに影響を与えない方法で一連のルートをグループ化したいことがあります。この目的のために、括弧で囲まれたフォルダにファイルを配置できます - ()

例:

ディレクトリ構造
-| pages/
---| index.vue
---| (marketing)/
-----| about.vue
-----| contact.vue

これにより、アプリ内で//about/contactページが生成されます。marketingグループはURL構造の目的では無視されます。

ページメタデータ

アプリ内の各ルートにメタデータを定義したい場合があります。これを行うには、definePageMetaマクロを使用します。これは<script>および<script>の両方で機能します。

definePageMeta({
  title: '私のホームページ'
})

このデータは、その後、アプリの他の部分でroute.metaオブジェクトからアクセスできます。

const route = useRoute()

console.log(route.meta.title) // 私のホームページ

ネストされたルートを使用している場合、これらのルートのページメタデータはすべて単一のオブジェクトにマージされます。ルートメタについての詳細は、vue-routerのドキュメントを参照してください。

defineEmitsdefinePropsVueドキュメントを参照)と同様に、definePageMetaコンパイラマクロです。コンポーネント内で参照することはできません。代わりに、渡されたメタデータはコンポーネントの外に持ち上げられます。 したがって、ページメタオブジェクトはコンポーネントを参照できません。ただし、インポートされたバインディングや、ローカルで定義された純粋な関数を参照することはできます。

リアクティブデータや副作用を引き起こす関数を参照しないようにしてください。これにより予期しない動作が発生する可能性があります。

import { someData } from '~/utils/example'

function validateIdParam(route) {
  return route.params.id && !isNaN(Number(route.params.id))
}

const title = ref('')

definePageMeta({
  validate: validateIdParam,
  someData,
  title,    // これはしないでください。refはコンポーネントの外に持ち上げられます
})

特殊なメタデータ

もちろん、アプリ全体で独自の使用のためにメタデータを定義することは歓迎されます。しかし、definePageMetaで定義された一部のメタデータには特定の目的があります。

alias

ページのエイリアスを定義できます。これにより、異なるパスから同じページにアクセスできます。これは、vue-routerのドキュメントで定義されているように、文字列または文字列の配列にすることができます。

keepalive

definePageMetakeepalive: trueを設定すると、NuxtはページをVueの<KeepAlive>コンポーネントで自動的にラップします。これは、例えば、動的な子ルートを持つ親ルートで、ルート変更時にページの状態を保持したい場合に便利です。

親ルートの状態を保持することが目的の場合は、この構文を使用します: <NuxtPage keepalive />。また、<KeepAlive>に渡すプロップを設定することもできます(完全なリストを参照)。

このプロパティのデフォルト値をあなたのnuxt.configで設定できます。

key

上記を参照

layout

ルートをレンダリングするために使用されるレイアウトを定義できます。これは、任意のレイアウトを無効にするためのfalse、文字列、または何らかの方法でリアクティブにしたい場合はref/computedにすることができます。レイアウトについての詳細

layoutTransitionpageTransition

ページとレイアウトをラップする<transition>コンポーネントのトランジションプロパティを定義することができます。または、そのルートの<transition>ラッパーを無効にするためにfalseを渡すことができます。渡すことができるオプションのリストを参照するか、トランジションの動作についての詳細を読むことができます。

これらのプロパティのデフォルト値をあなたのnuxt.configで設定できます。

middleware

このページを読み込む前に適用するミドルウェアを定義できます。これは、任意の親/子ルートで使用される他のすべてのミドルウェアとマージされます。これは、文字列、関数(グローバルbeforeガードパターンに従った匿名/インラインミドルウェア関数)、または文字列/関数の配列にすることができます。名前付きミドルウェアについての詳細

name

このページのルートの名前を定義できます。

path

ファイル名で表現できるよりも複雑なパターンがある場合、パスマッチャーを定義できます。詳細はvue-routerのドキュメントを参照してください。

props

ページコンポーネントに渡されるプロップとしてルートparamsにアクセスできるようにします。詳細はvue-routerのドキュメントを参照してください。

カスタムメタデータの型付け

ページにカスタムメタデータを追加する場合、型安全な方法で行いたいかもしれません。definePageMetaで受け入れられるオブジェクトの型を拡張することが可能です。

index.d.ts
declare module '#app' {
  interface PageMeta {
    pageType?: string
  }
}

// 型を拡張する際には、何かをインポート/エクスポートすることを常に確認することが重要です
export {}

ナビゲーション

アプリのページ間をナビゲートするには、<NuxtLink>コンポーネントを使用する必要があります。

このコンポーネントはNuxtに含まれているため、他のコンポーネントのようにインポートする必要はありません。

pagesフォルダ内のindex.vueページへのシンプルなリンク:

<template>
  <NuxtLink to="/">ホームページ</NuxtLink>
</template>
こちらも参照 api > components > nuxt-link

プログラムによるナビゲーション

NuxtはnavigateTo()ユーティリティメソッドを通じてプログラムによるナビゲーションを許可します。このユーティリティメソッドを使用すると、アプリ内でユーザーをプログラム的にナビゲートできます。これは、ユーザーからの入力を受け取り、アプリケーション全体を動的にナビゲートするのに最適です。この例では、ユーザーが検索フォームを送信したときに呼び出されるnavigate()というシンプルなメソッドがあります。

常にnavigateToawaitするか、関数から返すことでその結果をチェーンすることを確認してください。

const name = ref('');
const type = ref(1);

function navigate(){
  return navigateTo({
    path: '/search',
    query: {
      name: name.value,
      type: type.value
    }
  })
}

クライアント専用ページ

.client.vueサフィックスを付けることで、ページをクライアント専用として定義できます。このページのコンテンツはサーバー上でレンダリングされません。

サーバー専用ページ

.server.vueサフィックスを付けることで、ページをサーバー専用として定義できます。クライアントサイドのナビゲーションを使用してページに移動できますが、vue-routerによって制御され、サーバーコンポーネントで自動的にレンダリングされます。つまり、ページをレンダリングするために必要なコードはクライアントサイドのバンドルには含まれません。

サーバー専用ページは単一のルート要素を持たなければなりません。(HTMLコメントも要素と見なされます。)

カスタムルーティング

アプリが大きくなり、より複雑になると、ルーティングにより多くの柔軟性が必要になるかもしれません。このため、Nuxtはルーター、ルート、およびルーターオプションをさまざまな方法でカスタマイズするために直接公開しています。

こちらも参照 guide > recipes > custom-routing

複数のページディレクトリ

デフォルトでは、すべてのページはプロジェクトのルートにある1つのpagesディレクトリにあるべきです。

ただし、Nuxt Layersを使用して、アプリのページをグループ化することができます。

ディレクトリ構造
-| some-app/
---| nuxt.config.ts
---| pages/
-----| app-page.vue
-| nuxt.config.ts
some-app/nuxt.config.ts
// some-app/nuxt.config.ts
export default defineNuxtConfig({
})
nuxt.config.ts
export default defineNuxtConfig({
  extends: ['./some-app'],
})
こちらも参照 guide > going-further > layers

tips

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

Nuxtのpagesディレクトリとは? 〜何が嬉しいのか〜

Nuxtのpagesディレクトリは、ファイルベースのルーティングを自動で生成してくれる仕組みです。これにより、ルート設定を手動で書く必要がなくなり、開発効率が大幅に向上します。
特に中〜大規模なアプリケーションでは、ルートの追加や変更が頻繁に発生しますが、pagesディレクトリを使うことでファイルを作成・編集するだけでルーティングが反映されるため、ミスや設定漏れを減らせます。

また、動的ルートやネストされたルート、キャッチオールルートなど複雑なルーティングも直感的に実装可能です。
一方で、pagesディレクトリはオプションであり、使わずにapp.vueのみでルーティングをカスタマイズすることもできます。用途やプロジェクトの規模に応じて使い分けられる柔軟性も魅力です。


まず結論:pagesディレクトリのポイント

  • pagesディレクトリ内のファイルが自動的にルートとして登録される
  • ファイル名やフォルダ構造がURLパスに対応し、動的ルートは角括弧で表現可能
  • ページコンポーネントは単一のルート要素を持つ必要がある(複数ルート要素はNG)
  • ネストされたルートは親ページ内でNuxtPageコンポーネントを使って子ページを表示
  • ルートグループ(括弧付きフォルダ)でURLに影響を与えずにファイルを整理可能
  • pagesはオプションで、nuxt.configで明示的に有効化も可能

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

使うべきケース

  • ルーティング設定をシンプルに保ちたい初心者〜中級者
  • ページ数が多く、手動でルート管理するとミスが起きやすいプロジェクト
  • 動的ルートやネストルートを直感的に扱いたい場合
  • チーム開発でルーティングの共通理解を促進したい場合

使わない方がよいケース

  • ルーティングを完全にカスタマイズしたい高度な要件がある場合
  • ルーティングの挙動を細かく制御したい場合(例:特定の条件でルートを動的に切り替える)
  • pagesディレクトリの自動生成が不要な小規模アプリや単一ページアプリ

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

1. 基本的なページ作成

pages/index.vueを作成すると自動的に/ルートにマッピングされます。

<template>
  <h1>ホームページ</h1>
</template>

2. 動的ルートの利用

ユーザーIDなど動的なパラメータをURLに含めたい場合、ファイル名に角括弧を使います。

pages/
  users/
    [id].vue
<template>
  <p>ユーザーID: {{ $route.params.id }}</p>
</template>

/users/123にアクセスすると123が表示されます。

3. ネストされたルートの実装

親子関係のページを作る場合、親ページ内で子ページを表示するためにNuxtPageを使います。

pages/
  parent.vue
  parent/
    child.vue

parent.vue:

<template>
  <div>
    <h1>親ページ</h1>
    <NuxtPage />
  </div>
</template>

child.vue:

<template>
  <p>子ページの内容</p>
</template>

/parent/childにアクセスすると親ページの中に子ページがレンダリングされます。


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

1. 単一のルート要素を必ず持つこと

ページコンポーネントは必ず単一のルート要素でラップしてください。
複数のルート要素やHTMLコメントがトップレベルにあると、クライアントサイドのナビゲーション時にページが正しくレンダリングされません。

<!-- NG例 -->
<template>
  <div>要素1</div>
  <div>要素2</div>
</template>
<!-- OK例 -->
<template>
  <div>
    <div>要素1</div>
    <div>要素2</div>
  </div>
</template>

2. SSRとHydrationのズレに注意

動的ルートやネストルートで、サーバーとクライアントでレンダリング結果が異なるとHydrationエラーが発生します。
特に動的パラメータの扱いや条件付きレンダリングは慎重に実装しましょう。

3. パフォーマンスへの影響

pagesディレクトリが大きくなりすぎるとビルド時間やバンドルサイズに影響が出ることがあります。
必要に応じてルートグループや動的インポートを活用し、不要なページは分割しましょう。


まとめ

Nuxtのpagesディレクトリは、ファイルベースルーティングを簡単に実現し、開発効率を大幅に向上させる強力な機能です。
動的ルートやネストルートも直感的に扱えるため、多くのプロジェクトで標準的に使われています。
ただし、単一ルート要素の遵守やSSRとの整合性など、いくつかの注意点もあります。
これらを理解し、適切に使いこなすことで、より安定したNuxtアプリケーション開発が可能になります。


pagesディレクトリはオプションなので、必要に応じてnuxt.configpages: trueを設定し、明示的に有効化することもできます。


title: 'Nuxtのページメタデータ管理を深掘り:実務で役立つ使い方と注意点' description: 'NuxtのdefinePageMetaによるページメタデータ管理の基本から実務的なユースケース、よくある落とし穴までを丁寧に解説。SSRやCSRの違いを踏まえた最適な使い方を紹介します。'

Nuxtのページメタデータ管理を深掘り:実務で役立つ使い方と注意点

Nuxtでのページメタデータ管理は、SEO対策やページごとの動的な設定に欠かせない機能です。definePageMetaを使うことで、ページ単位でタイトルやレイアウト、ミドルウェアなどの情報を簡単に定義できます。しかし、実務で使いこなすには、どのような場面で使うべきか、また注意すべきポイントを理解することが重要です。

本記事では、Nuxtのページメタデータ管理のメリットや活用シーン、具体的なコード例、そしてよくある落とし穴を丁寧に解説します。初〜中級者の方が実務で迷わず使えるようになることを目指しています。


1. まず結論:ページメタデータ管理の要点

  • definePageMetaはページごとのメタ情報(タイトル、レイアウト、ミドルウェアなど)を宣言的に設定できるコンパイラマクロ
  • ページ間でメタデータはマージされ、ネストされたルートでも一貫した管理が可能
  • メタデータはコンポーネントの外に持ち上げられるため、リアクティブな値や副作用のある関数は使えない
  • SEOやUX向上のためにページタイトルやトランジション、キャッシュ保持(keepalive)などを柔軟に制御できる
  • 実務では動的ルートのバリデーションやミドルウェア適用、レイアウト切り替えなどに活用される

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

使うべきケース

  • ページごとに異なるタイトルやメタ情報を設定したいとき
  • ページ単位でレイアウトやトランジションを切り替えたいとき
  • 動的ルートのパラメータ検証やミドルウェアをページ単位で適用したいとき
  • ページの状態をルート変更後も保持したい(keepalive)場合
  • SEO対策としてページタイトルやメタタグを動的に管理したい場合

使わない方がよいケース

  • リアクティブな状態や副作用を伴う値をメタデータに含めたい場合(definePageMetaは静的な値のみ受け付ける)
  • ページ外のグローバルな状態管理や動的なデータフェッチに依存する設定をしたい場合
  • ページコンポーネント内で直接参照・操作したい場合(メタデータはコンポーネント外に持ち上げられるため)

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

ユースケース1:ページタイトルの設定とSEO対策

ページごとにタイトルを設定し、route.metaから参照して動的にタイトルタグを更新する例です。

definePageMeta({
  title: 'ユーザープロファイル'
})
const route = useRoute()
watch(() => route.meta.title, (title) => {
  if (title) document.title = title
})

ユースケース2:動的ルートのパラメータ検証

URLパラメータの妥当性をページメタデータで検証し、不正なアクセスを防止します。

function validateId(route) {
  return route.params.id && !isNaN(Number(route.params.id))
}

definePageMeta({
  validate: validateId
})

ユースケース3:ページの状態保持(keepalive)

親ルートで子ルートの状態を保持し、ユーザー体験を向上させる例です。

definePageMeta({
  keepalive: true
})

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

1. リアクティブデータをメタデータに含めない

definePageMetaはコンパイラマクロであり、メタデータはコンポーネントの外に持ち上げられます。そのため、refreactiveなどのリアクティブな値や副作用を伴う関数を含めると、予期しない動作やエラーの原因になります。

2. SSRとCSRの違いに注意

サーバーサイドレンダリング(SSR)時にはメタデータが静的に評価されるため、動的に変化する値を使うと不整合が生じます。クライアントサイドレンダリング(CSR)でのみ動的に変えたい場合は、route.metaを監視して動的に処理する方法が適切です。

3. Hydrationエラーの回避

ページ遷移時にメタデータが不整合だと、VueのHydrationエラーが発生することがあります。特にトランジションやレイアウトの切り替えで発生しやすいので、メタデータの値は安定したものを設定しましょう。

4. パフォーマンスへの影響

keepaliveを多用するとメモリ使用量が増加し、パフォーマンスに影響を与える可能性があります。状態保持が本当に必要なページに限定して使うことが望ましいです。


5. まとめ

NuxtのdefinePageMetaは、ページごとのメタデータ管理をシンプルかつ強力に実現する機能です。SEO対策やUX向上、動的ルートの制御など、実務で役立つ場面が多くあります。一方で、リアクティブな値を含められないことやSSR/CSRの違いによる注意点もあります。

本記事で紹介したユースケースや注意点を踏まえ、適切に使い分けることで、Nuxtアプリの品質と開発効率を高められるでしょう。


ページメタデータは静的な情報を中心に管理し、動的な処理はroute.metaの監視やミドルウェアで補完するのがベストプラクティスです。