middleware (прослойки)
В Nuxt есть настраиваемый маршрутный мидлвар для выполнения кода перед переходом на маршрут.
Типы маршрутного мидлвара:
- Анонимный (инлайновый) — объявляется прямо на странице.
- Именованный — файлы в
app/middleware/, подгружаются асинхронно при использовании на странице. - Глобальный — файлы в
app/middleware/с суффиксом.global, выполняются при каждой смене маршрута.
Первый и второй типы задаются в definePageMeta.
myMiddleware → my-middleware.Использование
Маршрутный мидлвар — это навигационный guard, он получает текущий и следующий маршрут.
export default defineNuxtRouteMiddleware((to, from) => {
if (to.params.id === '1') {
return abortNavigation()
}
if (to.path !== '/') {
return navigateTo('/')
}
})
Nuxt предоставляет два глобальных хелпера, которые можно вернуть из мидлвара:
navigateTo— редирект на указанный маршрутabortNavigation— отмена навигации (опционально с сообщением об ошибке)
В отличие от navigation guards vue-router, третьего аргумента next() нет — редирект и отмена задаются возвращаемым значением.
Возможные возвращаемые значения:
- ничего (
returnили без return) — навигация не блокируется, выполняется следующий мидлвар или завершается переход return navigateTo('/')— редирект (на сервере код302Found)return navigateTo('/', { redirectCode: 301 })— редирект с кодом301Moved Permanentlyreturn abortNavigation()— остановка навигацииreturn abortNavigation(error)— отмена навигации с ошибкой
Порядок мидлваров
- Глобальный мидлвар
- Мидлвары страницы (при массиве — в указанном порядке)
Пример:
-| middleware/
---| analytics.global.ts
---| setup.global.ts
---| auth.ts
<script setup lang="ts">
definePageMeta({
middleware: [
function (to, from) {
// Инлайновый мидлвар
},
'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 для однозначных номеров.Когда выполняется мидлвар
При SSR или статической генерации мидлвар первой страницы выполняется и при рендере, и затем на клиенте. Это нужно, если мидлвар зависит от браузера (localStorage, кэш и т.д.).
Чтобы избежать двойного запуска:
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, чтобы проверить, обрабатывается ли ошибка.Доступ к маршруту в мидлваре
Используйте параметры to и from. Не используйте композабл useRoute() в мидлваре: в мидлваре нет «текущего» маршрута — навигация может быть отменена или перенаправлена, и useRoute() будет некорректен.
useRoute(), тоже может вызвать это предупреждение и ту же проблему. Лучше передавать маршрут в функцию аргументом.// @errors: 2304
export default defineNuxtRouteMiddleware((to) => {
doSomethingWithRoute(to)
callsRouteInternally()
})
export function doSomethingWithRoute (route = useRoute()) {
// ...
}
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'],
// или 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 ||= {}
page.meta.middleware = ['named']
}
if (page.children) {
setMiddleware(page.children)
}
}
}
setMiddleware(pages)
},
},
})