nuxt logo

ドキュメント翻訳(非公式)

middleware

Nuxtは特定のルートに移動する前にコードを実行するためのミドルウェアを提供します。

Nuxtは、アプリケーション全体で使用できるカスタマイズ可能なルートミドルウェアフレームワークを提供しており、特定のルートに移動する前に実行したいコードを抽出するのに理想的です。

ルートミドルウェアには3種類あります:

  1. 匿名(またはインライン)ルートミドルウェアはページ内で直接定義されます。
  2. 名前付きルートミドルウェアは app/middleware/ に配置され、ページで使用されると非同期インポートを介して自動的にロードされます。
  3. グローバルルートミドルウェアは app/middleware/.global サフィックスを付けて配置され、すべてのルート変更時に実行されます。

最初の2種類のルートミドルウェアは definePageMeta で定義できます。

ミドルウェアの名前はケバブケースに正規化されます:myMiddlewaremy-middleware になります。

ルートミドルウェアはNuxtアプリのVue部分内で実行されます。名前は似ていますが、サーバーミドルウェアとは完全に異なり、アプリのNitroサーバー部分で実行されます。

使用法

ルートミドルウェアは、現在のルートと次のルートを引数として受け取るナビゲーションガードです。

middleware/my-middleware.ts
export default defineNuxtRouteMiddleware((to, from) => {
  if (to.params.id === '1') {
    return abortNavigation()
  }
  // 実際のアプリではすべてのルートを `/` にリダイレクトすることはおそらくありませんが、
  // リダイレクトする前に `to.path` を確認することが重要です。
  // そうしないと無限リダイレクトループに陥る可能性があります。
  if (to.path !== '/') {
    return navigateTo('/')
  }
})

Nuxtは、ミドルウェアから直接返すことができる2つのグローバルに利用可能なヘルパーを提供します。

  1. navigateTo - 指定されたルートにリダイレクトします
  2. abortNavigation - ナビゲーションを中止し、オプションでエラーメッセージを表示します。

vue-routerナビゲーションガードとは異なり、3番目の next() 引数は渡されず、リダイレクトやルートのキャンセルはミドルウェアから値を返すことで処理されます

返すことができる値は次のとおりです:

  • 何も返さない(単純な return または何も返さない) - ナビゲーションをブロックせず、次のミドルウェア関数に移動するか、ルートナビゲーションを完了します
  • return navigateTo('/') - 指定されたパスにリダイレクトし、サーバーサイドでリダイレクトが発生した場合はリダイレクトコードを 302 Found に設定します
  • return navigateTo('/', { redirectCode: 301 }) - 指定されたパスにリダイレクトし、サーバーサイドでリダイレクトが発生した場合はリダイレクトコードを 301 Moved Permanently に設定します
  • return abortNavigation() - 現在のナビゲーションを停止します
  • return abortNavigation(error) - エラーで現在のナビゲーションを拒否します
こちらも参照 api > utils > navigate-to こちらも参照 api > utils > abort-navigation

リダイレクトやナビゲーションの停止を行うには、上記のヘルパー関数を使用することをお勧めします。vue-routerのドキュメントで説明されている他の可能な戻り値は動作するかもしれませんが、将来的に破壊的な変更があるかもしれません。

ミドルウェアの順序

ミドルウェアは次の順序で実行されます:

  1. グローバルミドルウェア
  2. ページで定義されたミドルウェアの順序(配列構文で複数のミドルウェアが宣言されている場合)

例えば、次のようなミドルウェアとコンポーネントがあるとします:

app/middleware/ directory
-| middleware/
---| analytics.global.ts
---| setup.global.ts
---| auth.ts
pages/profile.vue
definePageMeta({
  middleware: [
    function (to, from) {
      // カスタムインラインミドルウェア
    },
    'auth',
  ],
});

ミドルウェアは次の順序で実行されることが期待されます:

  1. analytics.global.ts
  2. setup.global.ts
  3. カスタムインラインミドルウェア
  4. auth.ts

グローバルミドルウェアの順序付け

デフォルトでは、グローバルミドルウェアはファイル名に基づいてアルファベット順に実行されます。

しかし、特定の順序を定義したい場合があります。例えば、前述のシナリオでは、setup.global.tsanalytics.global.ts の前に実行される必要があるかもしれません。その場合、グローバルミドルウェアに「アルファベット」番号を付けることをお勧めします。

Directory structure
-| middleware/
---| 01.setup.global.ts
---| 02.analytics.global.ts
---| auth.ts

「アルファベット」番号付けに不慣れな場合、ファイル名は数値としてではなく文字列としてソートされることを覚えておいてください。例えば、10.new.global.ts2.new.global.ts の前に来ます。これが、例で一桁の数字に 0 を付けている理由です。

ミドルウェアが実行されるとき

サイトがサーバーレンダリングまたは生成されている場合、初期ページのミドルウェアはページがレンダリングされるときとクライアントで再度実行されます。これは、ミドルウェアがブラウザ環境を必要とする場合、例えば生成されたサイトがある場合、レスポンスを積極的にキャッシュする場合、またはローカルストレージから値を読み取りたい場合に必要かもしれません。

しかし、この動作を避けたい場合は次のようにできます:

middleware/example.ts
export default defineNuxtRouteMiddleware(to => {
  // サーバーでミドルウェアをスキップ
  if (import.meta.server) return
  // クライアント側で完全にミドルウェアをスキップ
  if (import.meta.client) return
  // または初期クライアントロード時のみミドルウェアをスキップ
  const nuxtApp = useNuxtApp()
  if (import.meta.client && nuxtApp.isHydrating && nuxtApp.payload.serverRendered) return
})

これは、サーバー上でミドルウェアでエラーをスローし、エラーページがレンダリングされる場合でも当てはまります。ミドルウェアはブラウザで再度実行されます。

エラーページをレンダリングすることは完全に別のページロードであり、登録されたミドルウェアは再度実行されます。ミドルウェアで useError を使用してエラーが処理されているかどうかを確認できます。

ミドルウェアでのルートへのアクセス

常にミドルウェアで tofrom パラメータを使用して次のルートと前のルートにアクセスしてください。このコンテキストで useRoute() コンポーザブルを使用することは避けてください。 ミドルウェアには**「現在のルート」という概念はありません**。ミドルウェアはナビゲーションを中止したり、別のルートにリダイレクトしたりすることができるためです。このコンテキストでは useRoute() コンポーザブルは常に不正確になります。

時々、内部で useRoute() を使用するコンポーザブルを呼び出すことがあり、ミドルウェア内で直接呼び出していなくてもこの警告を引き起こすことがあります。 これは上記と同じ問題を引き起こすため、ミドルウェアで使用されるときにルートを引数として受け取るように関数を構成する必要があります。

// @errors: 2304
export default defineNuxtRouteMiddleware(to => {
  // ミドルウェアで `useRoute()` を呼び出さないようにルートを関数に渡す
  doSomethingWithRoute(to)
    
  // ❌ これは警告を出力し、推奨されません
  callsRouteInternally()
})

ミドルウェアの動的追加

グローバルまたは名前付きルートミドルウェアを、プラグイン内などで addRouteMiddleware() ヘルパー関数を使用して手動で追加することが可能です。

export default defineNuxtPlugin(() => {
  addRouteMiddleware('global-test', () => {
    console.log('このグローバルミドルウェアはプラグインで追加され、すべてのルート変更時に実行されます')
  }, { global: true })

  addRouteMiddleware('named-test', () => {
    console.log('この名前付きミドルウェアはプラグインで追加され、同じ名前の既存のミドルウェアを上書きします')
  })
})

Directory Structure
-| middleware/
---| auth.ts

ページファイル内で、このルートミドルウェアを参照できます:

definePageMeta({
  middleware: ["auth"]
  // または middleware: 'auth'
})

これで、そのページへのナビゲーションが完了する前に、auth ルートミドルウェアが実行されます。

サンプルコードの編集とプレビューexamples > routing > middleware

ビルド時にミドルウェアを設定する

各ページで definePageMeta を使用する代わりに、pages:extend フック内で名前付きルートミドルウェアを追加できます。

nuxt.config.ts
import type { NuxtPage } from 'nuxt/schema'

export default defineNuxtConfig({
  hooks: {
    'pages:extend' (pages) {
      function setMiddleware (pages: NuxtPage[]) {
        for (const page of pages) {
          if (/* some condition */ true) {
            page.meta ||= {}
            // これはページ内の `definePageMeta` で設定されたミドルウェアを上書きすることに注意してください
            page.meta.middleware = ['named']
          }
          if (page.children) {
            setMiddleware(page.children)
          }
        }
      }
      setMiddleware(pages)
    }
  }
})