在 Nuxt 3 中使用 Vue 3 Composition API 做服务端渲染时,有几个容易忽略的环境差异问题。下面结合几个常见场景,从生命周期、客户端依赖、数据序列化和异步请求方面说一说操作取舍和检查点。
生命周期处理
在 Nuxt 3 的服务端渲染环境中,Composition API 的 onMounted、onUpdated 等生命周期钩子只在客户端执行,服务端渲染阶段不会触发。因此,如果你在 onMounted 内依赖 DOM 操作或浏览器 API,建议先通过 process.client 判断当前环境,或直接将其放在客户端专用组件中。一个常见的坑是直接在 setup 顶层调用异步请求并更新响应式数据,这样会导致服务端和客户端状态不一致,正确的做法是将异步逻辑放在 onMounted 或 useAsyncData 中。
适用场景:需要操作 DOM 或监听事件时。操作动作:在 onMounted 内部添加 if (process.client) 保护,或者将组件用
客户端检查
Composition API 的 setup 函数在服务端和客户端都会执行,但 window、document 等浏览器全局对象在服务端不存在。访问这些对象前,务必使用 process.client 进行条件判断。例如,创建一个响应式的窗口宽度时,应写为 const width = ref(process.client ? window.innerWidth : 0); 并在 onMounted 中更新。如果直接引用 window,Nuxt 3 会在构建时报错或产生运行时错误。建议将浏览器特有的逻辑封装到插件或组件中,并通过 definePageMeta 的 middleware 进行环境隔离。
这里有一个判断逻辑:如果逻辑只在客户端需要,可以放在 plugins/client 目录下,Nuxt 会自动只打包到客户端代码。检查点:观察构建时的控制台输出,如果有类似 window is not defined 的错误,说明需要添加 process.client 判断。操作取舍:对于简单的浏览器 API 引用,用条件判断即可;对于复杂的第三方库(如 Chart.js),建议封装成客户端组件并配合 definePageMeta 中的 middleware 来避免服务端执行。
数据序列化
使用 ref 或 reactive 定义的数据在服务端渲染后会被序列化为 JSON,嵌入到 HTML 中。如果数据包含循环引用、函数、Symbol 或 Map/Set 等非序列化值,客户端水合时会出现错误。检查方法是在开发模式下观察控制台警告,或使用 JSON.parse(JSON.stringify()) 测试数据的可序列化性。风险边界是避免在响应式数据中存储复杂的原型链对象。对于需要共享但不可序列化的数据,考虑使用 useState 或纯字符串标识。
操作动作:在开发环境下打开浏览器控制台,如果水合时报错“Failed to hydrate”并指向某个属性,多半是序列化问题。可以先用 JSON 转换测试一下数据。适用场景:当数据来自后端接口或复杂对象时。验证方式:在服务端渲染后的页面 HTML 中搜索 __NUXT__ 内的 JSON 字符串,检查是否有 undefined 或循环引用标记。风险边界:不要将 Vue 组件实例或 DOM 引用存入响应式状态,它们肯定无法序列化。
异步数据获取
在服务端渲染时,如果直接在 setup 顶层使用 await 获取数据,不仅会导致服务端响应变慢,还可能造成瀑布式请求。正确的做法是使用 Nuxt 3 提供的 useAsyncData 或 useFetch,它们会在服务端预取数据并注入到页面的 payload 中,然后客户端跳过重复请求。常见坑是忘记设置 key 或未处理错误状态。推荐使用 const { data, pending, error } = useAsyncData('uniqueKey', () => myApiCall()); 并配合 Suspense 组件实现加载状态。
操作动作:将 setup 中的异步逻辑改为 useAsyncData,并传入一个唯一 key 来避免重复请求。验证方式:在浏览器中查看 Network 面板,如果页面加载时只有一次 API 请求(来自服务端),客户端没有重复请求,说明配置正确。风险边界:useAsyncData 的 handler 函数必须返回 Promise,并且 key 在同一个页面中不能重复。如果 key 冲突,会导致数据覆盖或缓存混乱。还要注意服务端和客户端环境差异,例如在 handler 中不要依赖 window。
这几个点都是在迁移到 Nuxt 3 + Composition API 时容易遗漏的。建议在开发模式下多观察控制台警告和网络请求,并且可以手动检查生成的 HTML 中的 payload 是否正确。根据项目版本和具体配置,行为可能略有差异,需要结合环境确认。