useNuxtApp
useNuxtApp
是一个内置的可组合函数,它提供了一种访问Nuxt共享运行时上下文的方式,该上下文在客户端和服务器端都可用。它帮助你访问Vue应用程序实例、运行时钩子、运行时配置变量和内部状态,如ssrContext
和payload
。
<script setup lang="ts">
const nuxtApp = useNuxtApp()
</script>
方法
provide (name, value)
nuxtApp
是一个运行时上下文,你可以使用Nuxt插件来扩展它。使用provide
函数创建Nuxt插件,以使值和辅助方法在你的Nuxt应用程序中的所有组合函数和组件中都可用。
provide
函数接受name
和value
参数。
const nuxtApp = useNuxtApp()
nuxtApp.provide('hello', (name) => `Hello ${name}!`)
// 输出 "Hello name!"
console.log(nuxtApp.$hello('name'))
如上面的示例所示,$hello
已成为nuxtApp
上下文的新的自定义部分,并且在所有可以访问nuxtApp
的地方都可用。
hook(name, cb)
nuxtApp
中可用的钩子允许你自定义Nuxt应用程序的运行时方面。你可以在Vue.js组合函数和Nuxt插件中使用运行时钩子来钩入渲染生命周期。
hook
函数用于在特定点上的渲染生命周期中添加自定义逻辑。当创建Nuxt插件时,通常使用hook
函数。
有关Nuxt调用的可用运行时钩子,请参阅运行时钩子。
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.hook('page:start', () => {
/* 在这里添加你的代码 */
})
nuxtApp.hook('vue:error', (..._args) => {
console.log('vue:error')
// if (process.client) {
// console.log(..._args)
// }
})
})
callHook(name, ...args)
使用callHook
调用任何现有钩子时,它会返回一个promise。
await nuxtApp.callHook('my-plugin:init')
属性
useNuxtApp()
公开了以下属性,你可以使用它们来扩展和自定义你的应用程序并共享状态、数据和变量。
vueApp
vueApp
是全局Vue.js应用程序实例,你可以通过nuxtApp
访问它。
一些有用的方法:
component()
- 如果同时传递名称字符串和组件定义,则注册一个全局组件,否则如果只传递名称,则检索已经注册的组件。directive()
- 如果同时传递名称字符串和指令定义,则注册一个全局自定义指令,否则如果只传递名称,则检索已经注册的指令(示例)。use()
- 安装一个**Vue.js插件** (示例)。
ssrContext
ssrContext
在服务器端渲染期间生成,只在服务器端可用。
Nuxt通过ssrContext
公开以下属性:
url
(字符串)- 当前请求的URL。event
(unjs/h3请求事件)- 访问当前路由的请求和响应。payload
(对象)- NuxtApp的负载对象。
payload
payload
将服务器端的数据和状态变量暴露给客户端。在从服务器端传递这些数据后,以下键将在客户端上可用:
serverRendered
(布尔值)- 表示响应是否是服务器端渲染的。data
(对象)- 当你使用useFetch
或useAsyncData
从API端点获取数据时,可以从payload.data
中访问结果负载。这些数据被缓存,帮助你在多次发出相同请求时避免重复获取相同的数据。<script setup lang="ts"> const { data } = await useAsyncData('count', () => $fetch('/api/count')) </script>
在上面的示例中,使用useAsyncData
获取count
的值后,如果访问payload.data
,你将在那里看到记录的{ count: 1 }
。
当从ssrcontext
中访问相同的payload.data
时,你也可以在服务器端访问相同的值。state
(对象)- 当你使用useState
在Nuxt中设置共享状态时,可以通过payload.state.[name-of-your-state]
访问该状态数据。plugins/my-plugin.tsexport const useColor = () => useState<string>('color', () => 'pink') export default defineNuxtPlugin((nuxtApp) => { if (process.server) { const color = useColor() } })
还可以使用更高级的类型,如ref
、reactive
、shallowRef
、shallowReactive
和NuxtError
。
你还可以使用特殊的插件辅助函数添加自定义类型:plugins/custom-payload.ts/** * 这种类型的插件在Nuxt生命周期的早期运行,早于负载的恢复。 * 你将无法访问到路由器或其他Nuxt注入的属性。 */ export default definePayloadPlugin((nuxtApp) => { definePayloadReducer('BlinkingText', data => data === '<blink>' && '_') definePayloadReviver('BlinkingText', () => '<blink>') })
isHydrating
使用nuxtApp.isHydrating
(布尔值)检查Nuxt应用程序是否在客户端进行水合。
export default defineComponent({
setup (_props, { slots, emit }) {
const nuxtApp = useNuxtApp()
onErrorCaptured((err) => {
if (process.client && !nuxtApp.isHydrating) {
// ...
}
})
}
})
runWithContext
runWithContext
方法用于调用一个函数并为其提供一个显式的Nuxt上下文。通常情况下,Nuxt上下文会在组件之间隐式传递,无需担心。然而,在中间件/插件中处理复杂的async
/await
场景时,可能会遇到异步调用后当前实例已被取消设置的情况。
export default defineNuxtRouteMiddleware(async (to, from) => {
const nuxtApp = useNuxtApp()
let user
try {
user = await fetchUser()
// Vue/Nuxt编译器在这里丢失了上下文,因为try/catch块中进行了操作。
} catch (e) {
user = null
}
if (!user) {
// 将正确的Nuxt上下文应用于我们的`navigateTo`调用。
return nuxtApp.runWithContext(() => navigateTo('/auth'))
}
})
用法
const result = nuxtApp.runWithContext(() => functionWithContext())
functionWithContext
:任何需要当前Nuxt应用程序上下文的函数。此上下文将自动正确应用。
runWithContext
将返回functionWithContext
返回的任何内容。
上下文的更深入解释
Vue.js组合式API(以及类似的Nuxt可组合函数)依赖于隐式上下文。在生命周期中,Vue将当前组件的临时实例(Nuxt的nuxtApp临时实例)设置为全局变量,并在同一时钟周期内取消设置。在服务器端渲染时,有来自不同用户和nuxtApp的多个请求在同一个全局上下文中运行。因此,Nuxt和Vue会立即取消设置此全局实例,以避免在两个用户或组件之间泄漏共享引用。
这意味着什么?组合API和Nuxt Composables仅在生命周期内和在任何异步操作之前的同一时钟周期内可用:
// --- Vue内部 ---
const _vueInstance = null
const getCurrentInstance = () => _vueInstance
// ---
// Vue/Nuxt在调用setup()时设置一个全局变量,引用当前组件实例(nuxtApp)
async function setup() {
getCurrentInstance() // 可用
await someAsyncOperation() // Vue在同一时钟周期内的异步操作之前取消设置上下文!
getCurrentInstance() // null
}
解决方案是将当前实例缓存到本地变量中,例如const instance = getCurrentInstance()
,并在下一个可组合函数调用中使用它。但问题是,现在任何嵌套的可组合函数调用都需要显式接受实例作为参数,并且不依赖于组合式API的隐式上下文。这是可组合函数的设计限制,而不是问题本身。
为了克服这个限制,Vue在编译我们的应用程序代码时做了一些幕后工作,并在每次调用<script setup>
后恢复上下文:
const __instance = getCurrentInstance() // 由Vue编译器生成
getCurrentInstance() // 可用!
await someAsyncOperation() // Vue取消设置上下文
__restoreInstance(__instance) // 由Vue编译器生成
getCurrentInstance() // 仍然可用!
有关Vue实际执行的工作的更好描述,请参阅unjs/unctx#2(评论)。
解决方案
这就是runWithContext
用于恢复上下文的方式,类似于<script setup>
的工作方式。
Nuxt 3内部使用unjs/unctx来支持类似于Vue的插件和中间件的可组合函数。这使得像navigateTo()
这样的可组合函数可以在不直接传递nuxtApp
的情况下工作,从而将Composition API的DX和性能优势带给整个Nuxt框架。
Nuxt可组合函数与Vue Composition API具有相同的设计,因此需要类似的解决方案,以便在调用上下文恢复时自动进行此转换。请查看unjs/unctx#2(建议)、unjs/unctx#4(转换实现)和nuxt/framework#3884(集成Nuxt)。
Vue目前仅支持<script setup>
中异步上下文恢复的支持。在Nuxt 3中,已添加了对defineNuxtPlugin()
和defineNuxtRouteMiddleware()
的转换支持,这意味着当你使用它们时,Nuxt会自动进行上下文恢复的转换。
剩余问题
自动恢复上下文的unjs/unctx
转换似乎在包含await
的try/catch
语句中存在问题,这个问题最终需要解决,以消除上面提到的解决方法的要求。
原生异步上下文
使用一个新的实验性功能,可以启用原生异步上下文支持,使用Node.js AsyncLocalStorage
和新的unctx支持,使异步上下文本地可用于任何嵌套的异步可组合函数,无需转换或手动传递/调用上下文。