Nuxt 生命周期

理解 Nuxt 应用程序的生命周期可以帮助您深入了解框架的运作方式,尤其是在服务器端和客户端渲染方面。

本章的目标是提供框架各个部分的高层次概述,了解它们的执行顺序以及如何协同工作。

服务器

在服务器上,针对每个初始请求,应用程序执行以下步骤:

步骤 1: 设置 Nitro 服务器和 Nitro 插件(仅一次)

Nuxt 基于 Nitro 运行,这是一个现代的服务器引擎。

当 Nitro 启动时,它会初始化并执行 /server/plugins 目录下的插件。这些插件可以:

  • 捕获并处理全应用程序的错误。
  • 注册在 Nitro 关闭时执行的钩子。
  • 注册请求生命周期事件的钩子,例如修改响应。
Nitro 插件仅在服务器启动时执行一次。在无服务器的环境下,服务器会在每个传入请求时启动,Nitro 插件也是如此。但是,它们不会被等待。
Read more in Docs > Guide > Directory Structure > Server#server Plugins.

步骤 2: Nitro 服务器中间件

在初始化 Nitro 服务器后,每个请求都会执行位于 server/middleware/ 下的中间件。中间件可用于身份验证、日志记录或请求转换等任务。

从中间件返回值将终止请求,并将返回的值作为响应发送。为确保适当的请求处理,此行为通常应避免!
Read more in Docs > Guide > Directory Structure > Server#server Middleware.

步骤 3: 初始化 Nuxt 和执行 Nuxt 应用插件

首先创建 Vue 和 Nuxt 实例。然后,Nuxt 执行其服务器插件。这包括:

  • 内置插件,例如 Vue Router 和 unhead
  • 位于 plugins/ 目录中的自定义插件,包括没有后缀的插件(例如 myPlugin.ts)和带有 .server 后缀的插件(例如 myServerPlugin.server.ts)。

插件按特定顺序执行,并可能相互依赖。有关详细信息,包括执行顺序和并行性,请参见 插件文档

在此步骤之后,Nuxt 调用 app:created 钩子,可用于执行额外的逻辑。
Read more in Docs > Guide > Directory Structure > Plugins.

步骤 4: 路由验证

在初始化插件后和执行中间件之前,如果 definePageMeta 函数中定义了 validate 方法,Nuxt 将调用该方法。validate 方法可以是同步或异步的,通常用于验证动态路由参数。

  • 如果参数有效,validate 函数应返回 true
  • 如果验证失败,则应返回 false 或包含 statusCode 和/或 statusMessage 的对象,以终止请求。

有关更多信息,请参见 路由验证文档

Read more in Docs > Getting Started > Routing#route Validation.

步骤 5: 执行 Nuxt 应用中间件

中间件允许您在导航到特定路由之前运行代码。通常用于身份验证、重定向或日志记录等任务。

在 Nuxt 中,有三种类型的中间件:

  • 全局路由中间件
  • 命名路由中间件
  • 匿名(或内联)路由中间件

Nuxt 自动在首次进入应用程序时执行全局中间件,并在每次路由导航之前执行。命名和匿名中间件仅在对应页面组件的页面(路由)元数据中的中间件属性指定的路由上执行。

有关每种类型及示例的详细信息,请参见 中间件文档

在服务器上的任何重定向将导致 Location: 头发送至浏览器;浏览器随后对这个新位置发起新请求。当发生这种情况时,所有应用程序状态将重置,除非保存在 cookie 中。

Read more in Docs > Guide > Directory Structure > Middleware.

步骤 6: 设置页面和组件

在此步骤中,Nuxt 初始化页面及其组件,并使用 useFetchuseAsyncData 获取所需数据。由于在服务器上没有动态更新,也没有 DOM 操作,因此在 SSR 中不会执行 Vue 生命周期钩子,如 onBeforeMountonMounted 和后续钩子。

您应避免在 <script setup> 的根作用域中产生需要清理的副作用的代码。一个副作用的例子是使用 setInterval 设置计时器。在仅客户端的代码中,我们可以设置一个计时器,然后在 onBeforeUnmountonUnmounted 中摧毁它。然而,由于在 SSR 中不会调用卸载钩子,因此计时器将永远存在。为避免这种情况,请将副作用代码移动到 onMounted 中。

步骤 7: 渲染并生成 HTML 输出

在所有组件初始化和数据获取后,Nuxt 将组件与 unhead 中的设置结合起来生成完整的 HTML 文档。该 HTML 及其相关数据将发送回客户端,以完成 SSR 过程。

在将 Vue 应用程序渲染为 HTML 后,Nuxt 调用 app:rendered 钩子。
在最终化并发送 HTML 之前,Nitro 将调用 render:html 钩子。该钩子允许您操作生成的 HTML,例如注入额外的脚本或修改元标签。

客户端(浏览器)

无论您选择哪种 Nuxt 模式,此生命周期的此部分在浏览器中完全执行。

步骤 1: 初始化 Nuxt 和执行 Nuxt 应用插件

此步骤与服务器端执行相似,包括内置和自定义插件。

位于 plugins/ 目录中的自定义插件,例如没有后缀的插件(例如 myPlugin.ts)和带有 .client 后缀的插件(例如 myClientPlugin.client.ts),在客户端执行。

在此步骤之后,Nuxt 调用 app:created 钩子,可用于执行额外的逻辑。
Read more in Docs > Guide > Directory Structure > Plugins.

步骤 2: 路由验证

此步骤与服务器端执行相同,并包括在 definePageMeta 函数中定义的 validate 方法。

步骤 3: 执行 Nuxt 应用中间件

Nuxt 中间件在服务器和客户端上运行。如果您希望某些代码在特定环境中运行,请考虑使用 import.meta.client 为客户端,使用 import.meta.server 为服务器进行分割。

Read more in Docs > Guide > Directory Structure > Middleware#when Middleware Runs.

步骤 4: 挂载 Vue 应用程序和水合

调用 app.mount('#__nuxt') 将 Vue 应用程序挂载到 DOM。如果应用程序使用 SSR 或 SSG 模式,Vue 会执行水合步骤以使客户端应用程序具有交互性。在水合过程中,Vue 重新创建应用程序(不包括 服务器组件),将每个组件与其对应的 DOM 节点匹配,并附加 DOM 事件监听器。

为确保适当的水合,在服务器和客户端之间保持数据的一致性是重要的。对于 API 请求,建议使用 useAsyncDatauseFetch 或其他适合 SSR 的组合。这些方法确保在服务器端获取的数据在水合过程中得以重用,从而避免重复请求。所有新的请求应仅在水合后触发,以防止水合错误。

在挂载 Vue 应用程序之前,Nuxt 调用 app:beforeMount 钩子。
在挂载 Vue 应用程序后,Nuxt 调用 app:mounted 钩子。

步骤 5: Vue 生命周期

与服务器上不同,浏览器执行完整的 Vue 生命周期