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 会自动执行应用首次进入时及每次路由导航前的全局中间件。命名和匿名中间件仅在对应页面组件中通过 middleware 属性指定的路由上执行。

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

任何在服务器上的重定向都会向浏览器发送 Location: 头,浏览器随后会对新地址发起新的请求。发生此情况时,所有应用状态将被重置,除非以 Cookie 形式持久保存。

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

第 6 步:渲染页面和组件

Nuxt 会渲染页面及其组件,并使用 useFetchuseAsyncData 获取所需数据。由于服务器端不存在动态更新和 DOM 操作,Vue 生命周期钩子如 onBeforeMountonMounted 及后续钩子不会在 SSR 中执行。

默认情况下,Vue 在 SSR 期间暂停依赖追踪以提升性能。

服务器端无响应性,因为 Vue SSR 是自顶向下将应用渲染为静态 HTML,无法回头修改已经渲染的内容。
应避免在 <script setup> 的根作用域中书写需清理的副作用代码。例如使用 setInterval 设置定时器。在仅客户端代码中,我们可能在 onBeforeUnmountonUnmounted 钩子中销毁定时器,但 SSR 期间这些卸载钩子不会被调用,定时器会永久存在。为避免此问题,应将副作用代码放入 onMounted 中。
观看 Daniel Roe 讲解服务器渲染和全局状态的视频。

第 7 步:生成 HTML 输出

所有数据获取完成并渲染组件后,Nuxt 会结合 unhead 的配置生成完整的 HTML 文档。此 HTML 及相关数据随后发送回客户端,完成 SSR 流程。

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

客户端(浏览器)

无论你选择何种 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 应用及 Hydration

调用 app.mount('#__nuxt') 将 Vue 应用挂载到 DOM。如果使用 SSR 或 SSG 模式,Vue 会执行 hydration 流程,使客户端应用可交互。hydration 过程中,Vue 会重新创建应用(不含服务器组件),将每个组件与其对应 DOM 节点匹配,并绑定 DOM 事件监听器。

为保证 hydration 正确性,服务器和客户端数据需保持一致。对于 API 请求,推荐使用 useAsyncDatauseFetch 或其他 SSR 友好的组合函数,这些方法确保服务端获取的数据在 hydration 时复用,避免重复请求。新请求应仅在 hydration 后触发,防止 hydration 出错。

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

第 5 步:Vue 生命周期

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