Nuxt项目首屏加载太慢,怎么优化? IT人玉娟 提问于 2026-03-15 05:45:18 阅读 121 框架 我用 Nuxt 3 搭了个博客,部署后发现首屏白屏时间特别长,Lighthouse 评分才 40 多分。试过开启 experimental.renderJsonPayloads,也用了 nuxt/image 做图片懒加载,但效果不明显。 页面里有几个异步组件是通过 defineAsyncComponent 加载的,数据都是在 useAsyncData 里请求的。是不是 SSR 渲染阻塞了?有没有办法让关键内容先出来,其他部分再懒加载? 我来解答 赞 14 收藏 分享 生成中... 手机扫码查看 复制链接 生成海报 反馈 发表解答 您需要先 登录/注册 才能发表解答 2 条解答 Tr° 庆娇 Lv1 先说个暴论:你这情况大概率不是 SSR 阻塞的问题,而是 useAsyncData 没 await 加上异步组件没配置好,导致 hydration 阶段炸了。 我之前踩过一模一样的坑,博客首屏 6 秒, Lighthouse 30 分,后来搞到 1 秒多,说下我的排查思路和解决办法。 第一个坑:useAsyncData 没正确 await 很多人这么写: const { data } = await useAsyncData('posts', () => fetchPosts()) 这没问题,但如果你在组件里用了异步组件,同时 useAsyncData 没正确处理,会导致服务端渲染出来的 HTML 和客户端 hydration 不匹配,浏览器会重新渲染一遍,白屏就这么来的。 检查你的代码,确保 useAsyncData 的 key 在整个应用里是唯一的,而且返回的数据结构是稳定的。 第二个坑:defineAsyncComponent 的正确用法 你用了 defineAsyncComponent,这本身是对的,但 Nuxt 3 有个坑:如果不配置 loading 组件,异步组件加载期间会闪一下或者卡住。 const AsyncComponent = defineAsyncComponent({ loader: () => import('./HeavyComponent.vue'), loadingComponent: LoadingSpinner, // 加这个 delay: 200, suspensible: false // Nuxt 3 建议设 false }) 还有个关键点:Nuxt 3 的异步组件在 SSR 阶段默认会等待加载完成才渲染内容,这反而会阻塞首屏。如果你某些组件不需要 SEO,最好改成纯客户端渲染: // 在组件里加这个 definePageMeta({ ssr: true // 全局 SSR }) // 或者特定组件用 ClientOnly 包裹 第三个容易被忽略的:payload 提取 你说试了 experimental.renderJsonPayloads,这确实有用,但还有个更直接的优化: // nuxt.config.ts export default defineNuxtConfig({ experimental: { payloadExtraction: true // 这个默认是 false,开启后能减少请求数 } }) 这个配置开启后,Nuxt 会把 payload 提取成独立的 JSON 文件,客户端直接加载,不用每次都跑一遍 API。 第四个:检查你的依赖库 如果你用了 moment.js、lodash 完整版、ant-design 这种大家伙,即使 tree-shaking 做得不好,也会拖慢首屏。用 moment 的话换成 dayjs,用 lodash 改成按需引入: // 不要这样 import _ from 'lodash' // 要这样 import debounce from 'lodash/debounce' 最后说个快速验证的方法: 打开 Chrome DevTools 的 Performance 面板,勾选 JS 和 Network,重新加载页面,看看到底是哪个阶段卡住了——是 TTFB(服务端响应)还是 FCP(首次内容绘制)。 如果是 TTFB 慢,那就是服务端的问题,考虑加缓存或者用 nitro 的 preset 优化。如果是 FCP 慢,基本就是 JS 解析和 hydration 的问题,按我上面说的排查。 你先试试,重点检查 useAsyncData 有没有正确 await,以及异步组件有没有加 loading 状态。这两个改完应该能见效。 回复 点赞 2026-03-19 22:39 瑞云 Dev Lv1 问题不在SSR阻塞,是你把太多东西放首屏渲染了。 非关键数据全部加 lazy: true 改成客户端加载,别让服务端等这些数据: // 改成这样 const { data } = await useAsyncData('list', () => fetchList(), { lazy: true, server: false // 完全不SSR这个数据 }) 首屏不显示的组件用 <ClientOnly> 包裹起来,别浪费SSR时间。 骨架屏必须整上,用户看到加载状态比看到白屏体验好一百倍: <template> <div> <div v-if="pending" class="skeleton">...骨架屏...</div> <article v-else>...内容...</article> </div> </template> 还有,把 experimental.renderJsonPayloads 关掉,这个反而会增加payload体积。开启 experimental.payloadExtraction 让payload可以缓存。 最后跑一下 npx nuxi analyze 看看打包体积分布,大部分情况都是某个库太大了。 回复 点赞 2026-03-17 19:06 加载更多 相关推荐 2 回答 61 浏览 Nuxt 项目首屏加载太慢,怎么优化? 我用 Nuxt 3 搭了个博客,首页要加载十几篇文章的摘要,现在首屏白屏时间特别长,Lighthouse 评分才 40 多分。试过 lazy: true 和 suspense,但效果不明显。 数据是通... Mc.小敏 框架 2026-03-04 20:02:20 2 回答 33 浏览 Nuxt项目首屏加载太慢,该怎么优化? 我用 Nuxt 3 搭了个博客,部署后发现首屏白屏时间特别长,Lighthouse 跑出来 TTI 都快 5 秒了。页面其实没多少内容,就是首页拉个文章列表。 试过开 experimental.ren... Prog.玉楠 框架 2026-03-02 01:07:20 2 回答 85 浏览 Nuxt动态路由页面中asyncData获取不到params参数导致数据加载失败怎么办? 在Nuxt3项目里做文章详情页时遇到了问题,页面路径是pages/post/_id.vue 我按照文档用了asyncData获取参数,但控制台显示params是空对象,导致API请求失败。尝试过把as... ♫奕洳 框架 2026-02-08 12:47:33 1 回答 52 浏览 Nuxt 3中调用Server API返回404是怎么回事? 我在Nuxt 3项目里按照文档在server/api目录下建了个test.get.ts,但前端调用$fetch('/api/test')一直报404,路径应该没错啊? 本地开发环境,Nuxt版本是3.... UI瑞雪 框架 2026-03-26 13:05:19 2 回答 29 浏览 Nuxt插件里怎么正确引入全局CSS样式? 我在Nuxt 3项目里写了一个插件,想通过它注入一些全局的CSS变量,但发现样式没生效。我试过在插件里用import '@/assets/css/variables.css',也试过在nuxt.con... Code°依依 框架 2026-03-15 16:56:22 1 回答 63 浏览 Nuxt 3 中怎么自定义全局 loading 样式不生效? 我在 Nuxt 3 项目里想自定义页面切换时的 loading 条,但改了 CSS 好像没反应。官方文档说加个 .nuxt-progress 类就行,但我试了没效果,是写法不对吗? 我目前在 app.... 宇文怡轩 框架 2026-03-11 03:20:26 1 回答 36 浏览 Nuxt 3 中怎么正确使用 useAsyncData 获取 API 数据? 我在 Nuxt 3 项目里用 useAsyncData 调接口,但页面一直显示 pending 状态,数据也拿不到,是不是写法有问题? 我试过这样写: const { data, pending } ... 程序员玉霞 框架 2026-03-10 15:52:22 2 回答 33 浏览 Nuxt Image 本地图片路径为啥不生效? 我在 Nuxt 3 项目里用 @nuxt/image 显示本地图片,但一直加载不出来。图片放在 public/images 目录下,按文档写的是这样: <NuxtImg src="/images... FSD-玉茂 框架 2026-03-07 18:36:17 2 回答 34 浏览 Nuxt中间件里怎么获取路由参数? 我在写一个Nuxt 3的项目,想在middleware里根据路由参数做权限判断,但发现ctx.route.params是空的。我试过用defineNuxtRouteMiddleware,也打印了rou... 秀丽(打工版) 框架 2026-03-04 22:58:21 2 回答 77 浏览 Nuxt页面切换时过渡动画不生效是怎么回事? 我在 Nuxt 3 项目里给页面加了 transition,但切换路由时完全没看到动画效果,好像直接跳转了。明明在 pages/index.vue 里写了 definePageMeta({ pageT... 辽源🍀 框架 2026-02-24 05:17:20
我之前踩过一模一样的坑,博客首屏 6 秒, Lighthouse 30 分,后来搞到 1 秒多,说下我的排查思路和解决办法。
第一个坑:useAsyncData 没正确 await
很多人这么写:
这没问题,但如果你在组件里用了异步组件,同时 useAsyncData 没正确处理,会导致服务端渲染出来的 HTML 和客户端 hydration 不匹配,浏览器会重新渲染一遍,白屏就这么来的。
检查你的代码,确保 useAsyncData 的 key 在整个应用里是唯一的,而且返回的数据结构是稳定的。
第二个坑:defineAsyncComponent 的正确用法
你用了 defineAsyncComponent,这本身是对的,但 Nuxt 3 有个坑:如果不配置 loading 组件,异步组件加载期间会闪一下或者卡住。
还有个关键点:Nuxt 3 的异步组件在 SSR 阶段默认会等待加载完成才渲染内容,这反而会阻塞首屏。如果你某些组件不需要 SEO,最好改成纯客户端渲染:
第三个容易被忽略的:payload 提取
你说试了 experimental.renderJsonPayloads,这确实有用,但还有个更直接的优化:
这个配置开启后,Nuxt 会把 payload 提取成独立的 JSON 文件,客户端直接加载,不用每次都跑一遍 API。
第四个:检查你的依赖库
如果你用了 moment.js、lodash 完整版、ant-design 这种大家伙,即使 tree-shaking 做得不好,也会拖慢首屏。用 moment 的话换成 dayjs,用 lodash 改成按需引入:
最后说个快速验证的方法:
打开 Chrome DevTools 的 Performance 面板,勾选 JS 和 Network,重新加载页面,看看到底是哪个阶段卡住了——是 TTFB(服务端响应)还是 FCP(首次内容绘制)。
如果是 TTFB 慢,那就是服务端的问题,考虑加缓存或者用 nitro 的 preset 优化。如果是 FCP 慢,基本就是 JS 解析和 hydration 的问题,按我上面说的排查。
你先试试,重点检查 useAsyncData 有没有正确 await,以及异步组件有没有加 loading 状态。这两个改完应该能见效。
非关键数据全部加
lazy: true改成客户端加载,别让服务端等这些数据:首屏不显示的组件用
<ClientOnly>包裹起来,别浪费SSR时间。骨架屏必须整上,用户看到加载状态比看到白屏体验好一百倍:
还有,把
experimental.renderJsonPayloads关掉,这个反而会增加payload体积。开启experimental.payloadExtraction让payload可以缓存。最后跑一下
npx nuxi analyze看看打包体积分布,大部分情况都是某个库太大了。