本章的目标是提供框架中不同部分的高级概览,讲解它们的执行顺序以及它们如何协同工作。
在服务器端,每个初始请求到应用时,都会执行以下步骤:
Nuxt 由 Nitro 驱动,这是一个现代的服务器引擎。
当 Nitro 启动时,会初始化并执行 /server/plugins 目录下的插件。这些插件可以:
在初始化 Nitro 服务器之后,server/middleware/ 下的中间件会在每个请求上执行。中间件可用于身份认证、日志记录或请求转换等任务。
Vue 和 Nuxt 实例首先被创建。随后,Nuxt 执行其应用插件。这包括:
unhead。app/plugins/ 目录下的自定义插件,包括无后缀(例如 myPlugin.ts)和带 .server 后缀(例如 myServerPlugin.server.ts)的插件。插件按特定顺序执行,且可能互有依赖。关于执行顺序和并行相关的详情,请参阅 插件文档。
app:created 钩子,可用于执行额外逻辑。在初始化插件并且执行页面中间件之前,如果在 definePageMeta 中定义了 validate 方法,Nuxt 会调用该方法。validate 方法可以是同步或异步的,通用于验证动态路由参数。
validate 函数应返回 true。false 或包含 statusCode 和/或 statusMessage 的对象以终止请求。更多信息请参见路由验证文档。
中间件允许你在路由跳转前运行代码,常用于身份认证、重定向或日志记录等任务。
在 Nuxt 中,存在三种类型的中间件:
Nuxt 会在初始页面加载时(服务器端和客户端均执行)以及之后任意客户端导航之前执行所有全局中间件。命名和匿名中间件仅在对应页面组件的路由元信息 middleware 属性指定的路由上执行。
详细类型说明及示例,请见中间件文档。
在服务器端发生重定向时,会向浏览器发送 Location: 头,浏览器随后会发起对该新地址的全新请求。此时所有应用状态都会被重置,除非用 Cookie 进行了持久化。
Nuxt 在此步骤中渲染页面及其组件,并使用 useFetch 和 useAsyncData 获取所需数据。由于服务器端不存在动态更新也不会进行 DOM 操作,Vue 生命周期钩子如 onBeforeMount、onMounted 及后续钩子在 SSR 期间不会被执行。
默认情况下,为了提升性能,Vue 会在 SSR 期间暂停依赖追踪。
<script setup> 根作用域中放置需要清理的副作用代码。例如使用 setInterval 创建的定时器。客户端代码中通常在 onBeforeUnmount 或 onUnmounted 钩子销毁这些定时器,但 SSR 期间卸载钩子不会被调用,定时器会永久存在。为避免此问题,应将副作用代码移至 onMounted 中。在获取全部所需数据并渲染组件后,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(仅服务器)区分代码。
调用 app.mount('#__nuxt') 会将 Vue 应用挂载到 DOM。如果应用使用了 SSR 或 SSG 模式,Vue 会执行水合步骤使客户端应用具有交互性。在水合期间,Vue 会重新创建应用(不包括 服务器组件),匹配每个组件与其对应的 DOM 节点,并附加 DOM 事件监听器。
为确保水合正确,需要保持服务器端和客户端数据一致。针对 API 请求,推荐使用 useAsyncData、useFetch 或其他 SSR 友好的组合式函数。这些方法确保服务器端获取的数据在水合期间可以复用,避免重复请求。任何新的请求应在水合完成后触发,以防止水合失败。
app:beforeMount 钩子。app:mounted 钩子。与服务器端不同,浏览器会执行完整的 Vue 生命周期。