useNuxtApp
useNuxtApp — встроенный композабл для доступа к общему контексту выполнения Nuxt (контекст Nuxt) на клиенте и сервере (но не в маршрутах Nitro). Через него доступны экземпляр Vue-приложения, runtime-хуки, runtimeConfig и внутреннее состояние вроде ssrContext и payload.
<script setup lang="ts">
const nuxtApp = useNuxtApp()
</script>
Если контекст выполнения недоступен, useNuxtApp выбросит исключение. Для проверки без ошибки или для композаблов, где nuxtApp не обязателен, используйте tryUseNuxtApp.
Методы
provide (name, value)
nuxtApp — это контекст времени выполнения, который вы можете расширить с помощью Nuxt-плагинов. Используйте функцию provide для создания плагинов Nuxt, чтобы сделать значения и вспомогательные методы доступными для всех композаблов и компонентов вашего приложения Nuxt.
Функция provide принимает параметры name и value.
const nuxtApp = useNuxtApp()
nuxtApp.provide('hello', name => `Привет, ${name}!`)
// Выведет «Привет, мир!»
console.log(nuxtApp.$hello('мир'))
Как в примере выше, $hello становится частью nuxtApp и доступен везде, где есть контекст Nuxt.
hook(name, cb)
Хуки, доступные в nuxtApp, позволяют вам настраивать аспекты времени выполнения вашего Nuxt-приложения. Вы можете использовать runtime-хуки в композаблах Vue.js и Nuxt-плагинах, чтобы подключиться к жизненному циклу рендеринга.
hook подключает вашу логику к этапам рендеринга; чаще всего его вызывают из Nuxt-плагинов.
Смотрите хуки жизненного цикла для получения информации о доступных runtime-хуках, вызываемых Nuxt.
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.hook('page:start', () => {
/* ваш код находится здесь */
})
nuxtApp.hook('vue:error', (..._args) => {
console.log('хук vue:error')
// только клиент (пример):
// if (import.meta.client) {
// console.log(..._args)
// }
})
})
callHook(name, ...args)
callHook возвращает промис при вызове любого из существующих хуков.
await nuxtApp.callHook('my-plugin:init')
Свойства
Функция useNuxtApp() открывает следующие свойства, которые вы можете использовать для расширения и настройки вашего приложения, а также для обмена состоянием, данными и переменными.
vueApp
vueApp — это глобальный экземпляр приложения Vue.js, к которому вы можете получить доступ через nuxtApp.
Некоторые полезные методы:
component()— Регистрирует глобальный компонент, если передаётся имя в виде строки и определение компонента, или извлекает уже зарегистрированный компонент, если передаётся только имя.directive()— Регистрирует глобальную пользовательскую директиву, если передаётся имя в виде строки и определение директивы, или извлекает уже зарегистрированную, если передано только имя (пример).use()— подключает плагин Vue (пример).
ssrContext
ssrContext генерируется во время рендеринга на сервере и доступен только на сервере.
Nuxt предоставляет через ssrContext:
url(string) — URL текущего запроса;event(объект события h3) — доступ к запросу и ответу;payload(object) — объект payload приложения Nuxt.
payload
payload передаёт данные и переменные состояния с сервера на клиент. Следующие ключи будут доступны клиенту после того, как они будут переданы с сервера:
serverRendered(boolean) — ответ уже отрисован на сервере;data(object) — при загрузке черезuseFetchилиuseAsyncDataрезультат попадает вpayload.data; записи кэшируются, чтобы не дублировать одинаковые запросы.<script setup lang="ts"> const { data } = await useAsyncData('count', (_nuxtApp, { signal }) => $fetch('/api/count', { signal })) </script>export default defineEventHandler((event) => { return { count: 1 } })
После получения значенияcountс помощьюuseAsyncDataв примере выше, если вы обратитесь кpayload.data, вы увидите{ count: 1 }, записанные в нём.
Обращаясь к тем жеpayload.dataизssrContext, на сервере вы получите то же значение.state(object) — при использованииuseStateобщее состояние доступно какpayload.state.<ключ-состояния>.plugins/my-plugin.tsexport const useColor = () => useState<string>('color', () => 'pink') export default defineNuxtPlugin((nuxtApp) => { if (import.meta.server) { const color = useColor() } })
Также можно использовать более сложные типы, такие какref,reactive,shallowRef,shallowReactiveиNuxtError.
Пользовательский редьюсер / ревайвер
С Nuxt v3.4 можно задать свой редьюсер и ревайвер для типов, которые Nuxt не сериализует по умолчанию.
В примере ниже мы определяем редьюсер (или сериализатор) и ревайвер (или десериализатор) для класса Luxon DateTime, используя плагин полезной нагрузки.
/**
* Такого рода плагины запускаются в самом начале жизненного цикла Nuxt, до того, как мы получим полезную нагрузку.
* У вас не будет доступа к маршрутизатору или другим внедряемым свойствам Nuxt.
*
* Обратите внимание, что строка "DateTime" является идентификатором типа и должна
* быть одинаковой как на редьюсере, так и на ревайвере.
*/
export default definePayloadPlugin((nuxtApp) => {
definePayloadReducer('DateTime', (value) => {
return value instanceof DateTime && value.toJSON()
})
definePayloadReviver('DateTime', (value) => {
return DateTime.fromISO(value)
})
})
isHydrating
Используйте nuxtApp.isHydrating (boolean), чтобы проверить, гидрируется ли приложение Nuxt на клиенте.
export default defineComponent({
setup (_props, { slots, emit }) {
const nuxtApp = useNuxtApp()
onErrorCaptured((err) => {
if (import.meta.client && !nuxtApp.isHydrating) {
// ...
}
})
},
})
runWithContext
Nuxt instance unavailable). Пожалуйста, используйте этот метод осторожно и сообщайте о примерах, вызывающих проблемы, чтобы в конечном итоге их можно было решить на уровне фреймворка.Метод runWithContext предназначен для вызова функции и передачи ей явного контекста Nuxt. Обычно контекст Nuxt передаётся неявно, и вам не нужно беспокоиться об этом. Однако в сложных сценариях с async/await в middleware или плагинах контекст может сброситься после асинхронного шага.
export default defineNuxtRouteMiddleware(async (to, from) => {
const nuxtApp = useNuxtApp()
let user
try {
user = await fetchUser()
// компилятор Vue/Nuxt теряет контекст из-за try/catch с await
} catch (e) {
user = null
}
if (!user) {
// а теперь применяем к нашему вызову `navigateTo` правильный Nuxt-контекст.
return nuxtApp.runWithContext(() => navigateTo('/auth'))
}
})
Использование
const result = nuxtApp.runWithContext(() => functionWithContext())
functionWithContext— любая функция, которой нужен текущий контекст Nuxt; контекст подставится автоматически.
runWithContext вернёт то, что вернёт functionWithContext.
Более глубокое объяснение контекста
Composition API Vue (и композаблы Nuxt) опираются на неявный контекст: в ходе жизненного цикла Vue кладёт текущий компонент (а Nuxt — nuxtApp) в глобальную переменную и снимает её в том же тике. На сервере параллельно идут запросы разных пользователей при одном процессе, поэтому Nuxt и Vue сразу снимают глобальный экземпляр, чтобы не смешивать контексты.
Итог: композаблы доступны только в том же тике, до первой асинхронной операции:
// --- Внутренняя часть Vue ---
const _vueInstance = null
const getCurrentInstance = () => _vueInstance
// ---
// Vue / Nuxt устанавливает глобальную переменную, ссылающуюся на текущий компонент, в _vueInstance при вызове setup()
async function setup () {
getCurrentInstance() // Работает
await someAsyncOperation() // Vue отменяет контекст в том же тике перед async-операцией!
getCurrentInstance() // null
}
Классический обход — сохранить const instance = getCurrentInstance() и передавать экземпляр явно во вложенные вызовы, но тогда композаблы перестают опираться на неявный контекст — это компромисс дизайна, а не «баг» Vue.
Чтобы преодолеть это ограничение, Vue выполняет некоторую закулисную работу при компиляции кода нашего приложения и восстанавливает контекст после каждого вызова <script setup>:
const __instance = getCurrentInstance() // Генерируется компилятором Vue
getCurrentInstance() // Работает!
await someAsyncOperation() // Vue "снимает" контекст
__restoreInstance(__instance) // Генерируется компилятором Vue
getCurrentInstance() // снова работает
Для лучшего описания того, что на самом деле делает Vue, смотрите unjs/unctx#2 (комментарий).
Решение
Именно здесь можно использовать runWithContext для восстановления контекста, аналогично тому, как работает <script setup>.
Внутри Nuxt использует unjs/unctx, чтобы плагины и прослойки маршрутов (middleware) вели себя как композаблы Vue: navigateTo() и аналоги работают без явной передачи nuxtApp.
У Nuxt-композаблов та же модель, что у Composition API, поэтому нужна такая же поддержка контекста. См. unjs/unctx#2, unjs/unctx#4 и nuxt/framework#3884.
Vue пока поддерживает восстановление async-контекста для <script setup> при использовании async/await. В Nuxt добавлена трансформация для defineNuxtPlugin() и defineNuxtRouteMiddleware(): при их использовании Nuxt автоматически применяет восстановление контекста.
Остающиеся проблемы
Автовосстановление контекста в unctx пока некорректно ведёт себя с try/catch, внутри которых есть await; со временем это должно убрать необходимость в обходных путях вроде runWithContext.
Нативный async-контекст
Используя новую экспериментальную возможность, можно включить нативную поддержку асинхронного контекста, используя AsyncLocalStorage Node.js и новую поддержку unctx, чтобы сделать асинхронный контекст доступным нативно для любого вложенного асинхронного композабла без необходимости преобразования или ручной передачи/вызова контекста.
tryUseNuxtApp
Эта функция работает точно так же, как и useNuxtApp, но вместо исключения возвращает null, если контекст недоступен.
Вы можете использовать её для композаблов, которые не требуют nuxtApp, или для простой проверки наличия или отсутствия контекста без исключения.
Пример использования:
export function useStandType () {
// Всегда работает на клиенте
if (tryUseNuxtApp()) {
return useRuntimeConfig().public.STAND_TYPE
} else {
return process.env.STAND_TYPE
}
}