middleware
Nuxt は、アプリケーション全体で使用できるカスタマイズ可能なルートミドルウェアフレームワークを提供します。これは、特定のルートに移動する前に実行したいコードを抽出するのに最適です。
ルートミドルウェアには3種類あります
- 匿名(またはインライン)ルートミドルウェアは、ページ内で直接定義されます。
app/middleware/に配置された名前付きルートミドルウェアは、ページで使用されると非同期インポートによって自動的にロードされます。app/middleware/に.globalサフィックスを付けて配置されたグローバルルートミドルウェアは、すべてのルート変更で実行されます。
最初の2種類のルートミドルウェアは、definePageMeta で定義できます。
myMiddleware は my-middleware になります。使用方法
ルートミドルウェアは、現在のルートと次のルートを引数として受け取るナビゲーションガードです。
export default defineNuxtRouteMiddleware((to, from) => {
if (to.params.id === '1') {
return abortNavigation()
}
// In a real app you would probably not redirect every route to `/`
// however it is important to check `to.path` before redirecting or you
// might get an infinite redirect loop
if (to.path !== '/') {
return navigateTo('/')
}
})
Nuxt は、ミドルウェアから直接返せる2つのグローバルなヘルパーを提供します。
navigateTo- 指定されたルートにリダイレクトしますabortNavigation- オプションのエラーメッセージを付けてナビゲーションを中止します。
とは異なりナビゲーションガードvue-router からは3番目の next() 引数は渡されず、リダイレクトまたはルートキャンセルはミドルウェアから値を返すことで処理されます。
可能な戻り値は次のとおりです。
- 何も返さない(単に
returnするか、全く返さない) - ナビゲーションをブロックせず、存在すれば次のミドルウェア関数に進むか、ルートナビゲーションを完了します。 return navigateTo('/')- 指定されたパスにリダイレクトし、リダイレクトコードを302Foundリダイレクトがサーバー側で発生した場合return navigateTo('/', { redirectCode: 301 })- 指定されたパスにリダイレクトし、リダイレクトコードを301Moved Permanentlyリダイレクトがサーバー側で発生した場合return abortNavigation()- 現在のナビゲーションを停止しますreturn abortNavigation(error)- エラーで現在のナビゲーションを拒否します
ミドルウェアの順序
ミドルウェアは次の順序で実行されます
- グローバルミドルウェア
- ページで定義されたミドルウェアの順序(配列構文で複数のミドルウェアが宣言されている場合)
たとえば、次のミドルウェアとコンポーネントがあると仮定します。
-| middleware/
---| analytics.global.ts
---| setup.global.ts
---| auth.ts
<script setup lang="ts">
definePageMeta({
middleware: [
function (to, from) {
// Custom inline middleware
},
'auth',
],
})
</script>
ミドルウェアは次の順序で実行されると予想できます。
analytics.global.tssetup.global.ts- カスタムインラインミドルウェア
auth.ts
グローバルミドルウェアの順序付け
デフォルトでは、グローバルミドルウェアはファイル名に基づいてアルファベット順に実行されます。
ただし、特定の順序を定義したい場合があります。たとえば、最後のシナリオでは、setup.global.ts は analytics.global.ts の前に実行する必要があるかもしれません。その場合は、グローバルミドルウェアに「アルファベット順」の番号をプレフィックスとして付けることをお勧めします。
-| middleware/
---| 01.setup.global.ts
---| 02.analytics.global.ts
---| auth.ts
10.new.global.ts は 2.new.global.ts の前に来ます。これが、例で一桁の数字に 0 をプレフィックスとして付けている理由です。ミドルウェアの実行時期
サイトがサーバーサイドレンダリングまたは生成されている場合、最初のページのミドルウェアは、ページのレンダリング時と、その後クライアントでも再度実行されます。これは、ミドルウェアがブラウザ環境を必要とする場合、たとえば生成されたサイトがあり、応答を積極的にキャッシュする場合、またはローカルストレージから値を読み取りたい場合に必要になることがあります。
ただし、この動作を避けたい場合は、次のようにできます。
export default defineNuxtRouteMiddleware((to) => {
// skip middleware on server
if (import.meta.server) {
return
}
// skip middleware on client side entirely
if (import.meta.client) {
return
}
// or only skip middleware on initial client load
const nuxtApp = useNuxtApp()
if (import.meta.client && nuxtApp.isHydrating && nuxtApp.payload.serverRendered) {
return
}
})
これは、サーバー側でミドルウェアでエラーをスローし、エラーページがレンダリングされた場合でも当てはまります。ミドルウェアはブラウザで再度実行されます。
useError を使用できます。ミドルウェアでのルートへのアクセス
ミドルウェアで次のルートと前のルートにアクセスするには、必ず to および from パラメータを使用してください。このコンテキストでは、useRoute() コンポーザブルの使用は完全に避けてください。ミドルウェアではナビゲーションを中止したり、別のルートにリダイレクトしたりできるため、ミドルウェアには「現在のルート」の概念がありません。useRoute() コンポーザブルは、このコンテキストでは常に不正確になります。
useRoute() を使用するコンポーザブルを呼び出すと、この警告がトリガーされることがあります。これは上記と同じ問題につながるため、ミドルウェアで使用する場合は、ルートを引数として受け入れるように関数を構造化する必要があります。export default defineNuxtRouteMiddleware((to) => {
// passing the route to the function to avoid calling `useRoute()` in middleware
doSomethingWithRoute(to)
// ❌ this will output a warning and is NOT recommended
callsRouteInternally()
})
// providing the route as an argument so that it can be used in middleware correctly
export function doSomethingWithRoute (route = useRoute()) {
// ...
}
// ❌ this function is not suitable for use in middleware
export function callsRouteInternally () {
const route = useRoute()
// ...
}
ミドルウェアの動的な追加
グローバルまたは名前付きルートミドルウェアは、addRouteMiddleware() ヘルパー関数を使用して、たとえばプラグイン内から手動で追加できます。
export default defineNuxtPlugin(() => {
addRouteMiddleware('global-test', () => {
console.log('this global middleware was added in a plugin and will be run on every route change')
}, { global: true })
addRouteMiddleware('named-test', () => {
console.log('this named middleware was added in a plugin and would override any existing middleware of the same name')
})
})
例
-| middleware/
---| auth.ts
ページファイルで、このルートミドルウェアを参照できます。
<script setup lang="ts">
definePageMeta({
middleware: ['auth'],
// or middleware: 'auth'
})
</script>
これで、そのページへのナビゲーションが完了する前に、auth ルートミドルウェアが実行されます。
ビルド時におけるミドルウェアの設定
各ページで definePageMeta を使用する代わりに、pages:extend フック内で名前付きルートミドルウェアを追加できます。
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 */ Math.random() > 0.5) {
page.meta ||= {}
// Note that this will override any middleware set in `definePageMeta` in the page
page.meta.middleware = ['named']
}
if (page.children) {
setMiddleware(page.children)
}
}
}
setMiddleware(pages)
},
},
})