Nuxt 生命周期
理解 Nuxt 应用的生命周期,可以帮助你更深入地了解框架是如何运作的,尤其是在服务端渲染和客户端渲染两方面。
本章的目标是,从高层视角概述框架的各个组成部分、它们的执行顺序,以及它们如何协同工作。
服务端生命周期
在服务端,针对应用的每个初始请求会执行以下步骤:
服务端插件 once
Nuxt 由 Nitro 驱动,这是一个现代的服务端引擎。
当 Nitro 启动时,它会初始化并执行 /server/plugins 目录下的插件。这些插件可以:
- 捕获并处理应用级别的运行时错误。
- 注册在 Nitro 关闭时执行的钩子。
- 为请求生命周期事件(例如修改响应)注册钩子。
服务端中间件
初始化 Nitro 服务器之后,会针对每个请求执行 server/middleware/ 下的中间件。中间件可用于认证、日志记录或请求转换等任务。
应用插件(App plugins)
首先创建 Vue 和 Nuxt 实例。之后,Nuxt 执行它的应用插件。这包括:
- 内置插件,例如 Vue Router 和
unhead。 - 位于
app/plugins/目录中的自定义插件,包括没有后缀的(例如myPlugin.ts)以及带.server后缀的(例如myServerPlugin.server.ts)。
插件以特定的顺序执行,并且可能彼此存在依赖。更多关于执行顺序和并行性的细节,请参阅 插件文档。
app:created 钩子,可用于执行额外的逻辑。路由校验(Route validation)
在初始化插件之后、执行中间件之前,如果 definePageMeta 函数中定义了 validate 方法,Nuxt 会调用它。validate 方法可以是同步的也可以是异步的,常用于校验动态路由参数。
- 如果参数有效,
validate函数应返回true。 - 如果校验失败,它应返回
false,或一个包含status和/或statusText的对象来终止请求。
更多信息,请参阅 路由校验文档。
应用中间件(App middleware)
中间件允许你在导航到某个特定路由之前运行代码。它常用于认证、重定向或日志记录等任务。
在 Nuxt 中,有三种类型的中间件:
- 全局路由中间件
- 具名路由中间件
- 匿名(或内联)路由中间件
Nuxt 在初始页面加载时(服务端和客户端都会)执行所有全局中间件,然后在任何客户端导航之前再次执行。具名和匿名中间件只在对应页面组件中定义的页面(路由)meta 的 middleware 属性所指定的路由上执行。
关于每种类型及示例的细节,请参阅 中间件文档。
在服务端发生的任何重定向,都会向浏览器发送一个 Location: 头;随后浏览器会向这个新位置发起一个全新的请求。发生这种情况时,除非持久化在 cookie 中,否则所有应用状态都会被重置。
页面与组件
Nuxt 在此步骤渲染页面及其组件,并使用 useFetch 和 useAsyncData 获取所需的任何数据。由于服务端没有动态更新、也不会发生 DOM 操作,像 onBeforeMount、onMounted 这样的 Vue 生命周期钩子以及后续的钩子在 SSR 期间不会执行。
默认情况下,Vue 在 SSR 期间会暂停依赖追踪以获得更好的性能。
你应该避免在 <script setup> 的根作用域中编写会产生需要清理的副作用的代码。此类副作用的一个例子是使用 setInterval 设置定时器。在仅客户端的代码中,我们可能会设置一个定时器,然后在 onBeforeUnmount 或 onUnmounted 中将其拆除。然而,由于卸载钩子在 SSR 期间永远不会被调用,定时器将永远存在。为避免此问题,请将你的副作用代码移入 onMounted 中。
HTML 输出
在获取了所有所需数据并渲染了组件之后,Nuxt 会将渲染好的组件与来自 unhead 的设置结合,生成一个完整的 HTML 文档。这个 HTML 连同相关数据一起被发回客户端,以完成 SSR 过程。
app:rendered 钩子。render:html 钩子。这个钩子允许你操作生成的 HTML,例如注入额外的脚本或修改 meta 标签。客户端生命周期
无论你选择了哪种 Nuxt 模式,生命周期的这一部分都完全在浏览器中执行。
应用插件
这一步骤与服务端执行类似,包含内置插件和自定义插件。
app/plugins/ 目录中的自定义插件,例如没有后缀的(例如 myPlugin.ts)和带 .client 后缀的(例如 myClientPlugin.client.ts),会在客户端执行。
app:created 钩子,可用于执行额外的逻辑。路由校验
此步骤与服务端执行相同,包含 definePageMeta 函数中定义的 validate 方法(如果定义)。
应用中间件
Nuxt 中间件运行在服务端和客户端。如果你希望某些代码只在特定环境运行,考虑通过使用 import.meta.client 用于客户端、import.meta.server 用于服务端来拆分它。
挂载 Vue 应用并水合
调用 app.mount('#__nuxt') 将 Vue 应用挂载到 DOM 上。如果应用使用 SSR 或 SSG 模式,Vue 会执行水合步骤,使客户端应用变得可交互。在水合期间,Vue 会重新创建应用(服务端组件 除外),将每个组件与其对应的 DOM 节点匹配,并附加 DOM 事件监听器。
为确保正确的水合,保持服务端和客户端数据的一致性很重要。对于 API 请求,建议使用 useAsyncData、useFetch 或其他 SSR 友好的组合式函数。这些方法确保服务端获取的数据在水合期间被复用,避免重复请求。任何新的请求都应该只在水合之后触发,以防止水合错误。
app:beforeMount 钩子。app:mounted 钩子。Vue 生命周期
与服务端不同,浏览器会执行完整的 Vue 生命周期。