Nuxt 生命周期

理解 Nuxt 应用的生命周期可以帮助你更深入地了解框架的运行方式,尤其是针对服务器端和客户端渲染。

Geprüfte Übersetzung ·0 % geprüft

本章的目标是提供框架中不同部分的高级概览,讲解它们的执行顺序以及它们如何协同工作。

Server 生命周期

在服务器端,每个初始请求到应用时,都会执行以下步骤:

服务器插件 once

Nuxt 由 Nitro 驱动,这是一个现代的服务器引擎。

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

  • 捕获并处理应用级错误。
  • 注册在 Nitro 关闭时执行的钩子。
  • 为请求生命周期事件注册钩子,例如修改响应。
Nitro 插件仅在服务器启动时执行一次。在无服务器(serverless)环境中,服务器会在每个传入请求时启动,Nitro 插件也会随之执行。然而,这些插件的执行不会被等待。
Weitere Informationen findest du unter Docs > Directory Structure > Server#server Plugins.

服务器中间件

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

从中间件返回一个值将终止请求并将返回值作为响应发送。通常应避免这种行为以确保请求得到正确处理!
Weitere Informationen findest du unter Docs > Directory Structure > Server#server Middleware.

应用插件

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

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

插件按特定顺序执行,并且可能相互依赖。有关执行顺序和并行性的更多详情,请参阅插件文档。

此步骤之后,Nuxt 会调用 app:created 钩子,可用于执行其他逻辑。
Weitere Informationen findest du unter Docs > Directory Structure > App > Plugins.

路由验证

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

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

更多信息,请参阅路由验证文档。

Weitere Informationen findest du unter Docs > Getting Started > Routing#route Validation.

应用中间件

中间件允许你在路由跳转前运行代码,常用于身份认证、重定向或日志记录等任务。

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

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

Nuxt 会在初始页面加载时(服务器端和客户端均执行)以及之后任意客户端导航之前执行所有全局中间件。命名和匿名中间件仅在对应页面组件的路由元信息 middleware 属性指定的路由上执行。

有关每种类型的详情和示例,请参阅中间件文档。

在服务器端发生重定向时,会向浏览器发送 Location: 头,浏览器随后会发起对该新地址的全新请求。此时所有应用状态都会被重置,除非用 Cookie 进行了持久化。

Weitere Informationen findest du unter Docs > Directory Structure > App > Middleware.

页面与组件

Nuxt 在此步骤中渲染页面及其组件,并使用 useFetch 和 useAsyncData 获取所需数据。由于服务器端不存在动态更新也不会进行 DOM 操作,Vue 生命周期钩子如 onBeforeMount、onMounted 及后续钩子在 SSR 期间不会被执行。

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

服务器端无响应式支持,因为 Vue SSR 会将应用自顶向下渲染成静态 HTML,渲染完成后无法修改已渲染内容。
应避免在 <script setup> 根作用域中放置需要清理的副作用代码。例如使用 setInterval 创建的定时器。客户端代码中通常在 onBeforeUnmount 或 onUnmounted 钩子销毁这些定时器,但 SSR 期间卸载钩子不会被调用,定时器会永久存在。为避免此问题,应将副作用代码移至 onMounted 中。
观看 Daniel Roe 讲解服务器渲染和全局状态的视频。

HTML 输出

在获取全部所需数据并渲染组件后,Nuxt 会将渲染结果与 unhead 设置结合,生成完整的 HTML 文档。然后将该 HTML 及关联数据发送给客户端,完成 SSR 过程。

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

客户端生命周期

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

应用插件

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

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

此步骤之后,Nuxt 会调用 app:created 钩子,可用于执行其他逻辑。
Weitere Informationen findest du unter Docs > Directory Structure > App > Plugins.

路由验证

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

应用中间件

Nuxt 中间件在服务器和客户端都会运行。如果你希望某些代码只在特定环境中运行,可以使用 import.meta.client(仅客户端)和 import.meta.server(仅服务器)区分代码。

Weitere Informationen findest du unter Docs > Directory Structure > App > Middleware#when Middleware Runs.

挂载 Vue 应用并水合

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

为确保水合正确,需要保持服务器端和客户端数据一致。针对 API 请求,推荐使用 useAsyncData、useFetch 或其他 SSR 友好的组合式函数。这些方法确保服务器端获取的数据在水合期间可以复用,避免重复请求。任何新的请求应在水合完成后触发,以防止水合失败。

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

Vue 生命周期

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