Nuxt 生命周期

了解 Nuxt 应用的生命周期可以帮助你更深入地理解该框架的运作方式,特别是在服务端渲染和客户端渲染方面。

本章旨在提供框架各个部分的概览、它们的执行顺序以及它们如何协同工作。

服务端生命周期

在服务端,针对应用的每一次初始请求,都会执行以下步骤:

服务端插件 仅一次

Nuxt 由Nitro(一个现代服务端引擎)驱动。

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

  • 捕获并处理整个应用的错误。
  • 注册在 Nitro 关闭时执行的钩子。
  • 为请求生命周期事件注册钩子,例如修改响应。
Nitro 插件仅在服务器启动时执行一次。在无服务器(serverless)环境中,服务器会在每次传入请求时启动,Nitro 插件也会随之启动。不过,它们不会被等待(awaited)。
详见 文档 > 4 X > 目录结构 > 服务端#服务端插件

服务端中间件

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

从中间件返回一个值将终止请求并将该返回值作为响应发送。通常应避免这种行为,以确保请求处理正确!
详见 文档 > 4 X > 目录结构 > 服务端#服务端中间件

应用插件

首先创建 Vue 和 Nuxt 实例。随后,Nuxt 执行其应用插件。这包括:

  • 内置插件,例如 Vue Router 和 unhead
  • app/plugins/ 目录下的自定义插件,包括无后缀插件(例如 myPlugin.ts)以及带有 .server 后缀的插件(例如 myServerPlugin.server.ts)。

插件按特定顺序执行,且可能存在依赖关系。有关执行顺序和并行处理的详细信息,请参阅 插件文档

在此步骤之后,Nuxt 调用 app:created 钩子,可用于执行额外的逻辑。
在 **文档 > 4 X > 目录结构 > App > 插件** 中阅读更多内容。

路由验证

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

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

有关详细信息,请参阅 路由验证文档

详见 文档 > 4 X > 入门 > 路由#路由验证

应用中间件

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

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

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

Nuxt 在初始页面加载时(服务端和客户端均会执行)以及随后的每一次客户端导航前执行所有全局中间件。命名和匿名中间件仅在页面组件中定义的路由元信息(page meta)的 middleware 属性中指定时才会执行。

关于每种类型的详情及示例,请参阅 中间件文档

服务端上的任何重定向都会导致浏览器收到一个 Location: 响应头;浏览器随后会向该新位置发起新的请求。发生这种情况时,除非保存在 Cookie 中,否则所有应用状态都将被重置。

文档 > 4.x > 目录结构 > App > Middleware 中阅读更多内容。

页面与组件

在此步骤中,Nuxt 渲染页面及其组件,并使用 useFetchuseAsyncData 获取所需数据。由于在服务端没有动态更新且不涉及 DOM 操作,因此 Vue 的生命周期钩子(如 onBeforeMountonMounted 及后续钩子)在 SSR 期间**不会**执行。

默认情况下,为了获得更好的性能,Vue 会在 SSR 期间暂停依赖跟踪。

服务端没有响应式,因为 Vue SSR 是以自顶向下的方式将应用渲染为静态 HTML,这使得它无法回头修改已渲染的内容。
你应该避免在 <script setup> 的根作用域中编写产生副作用且需要清理的代码。此类副作用的一个例子是使用 setInterval 设置定时器。在仅限客户端的代码中,我们可以设置一个定时器并在 onBeforeUnmountonUnmounted 中销毁它。然而,由于卸载(unmount)钩子在 SSR 期间永远不会被调用,这些定时器将永久存在。为避免这种情况,请改将副作用代码移至 onMounted 中。
观看 Daniel Roe 讲解服务端渲染和全局状态的视频。

HTML 输出

在获取所有必需数据并渲染组件后,Nuxt 将渲染出的组件与来自 unhead 的设置结合,生成完整的 HTML 文档。该 HTML 连同相关数据一并发送回客户端,以完成 SSR 过程。

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

客户端生命周期

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

应用插件

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

app/plugins/ 目录下的自定义插件(例如无后缀插件 myPlugin.ts 或带有 .client 后缀的插件 myClientPlugin.client.ts)会在客户端执行。

在此步骤之后,Nuxt 调用 app:created 钩子,可用于执行额外的逻辑。
在 **文档 > 4 X > 目录结构 > App > 插件** 中阅读更多内容。

路由验证

此步骤与服务端执行相同,如果 definePageMeta 函数中定义了 validate 方法,则包含该方法。

应用中间件

Nuxt 中间件同时在服务端和客户端运行。如果你希望某些代码在特定环境中运行,请考虑通过在客户端使用 import.meta.client、在服务端使用 import.meta.server 来进行拆分。

详见 文档 > 4 X > 目录结构 > 应用 > 中间件#中间件何时运行

挂载 Vue 应用并注水(Hydrate)

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

为确保正确的注水,保持服务端和客户端数据的一致性至关重要。对于 API 请求,建议使用 useAsyncDatauseFetch 或其他 SSR 友好的组合式函数。这些方法可确保在服务端获取的数据在注水期间被复用,避免重复请求。任何新的请求都应仅在注水完成后触发,以防止注水错误。

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

Vue 生命周期

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