FCP太慢了,首屏加载白屏好几秒怎么办?
我们首页上线后 Lighthouse 报 FCP 超过 4 秒,用户一进来就是白屏,体验很差。已经做了图片懒加载和代码分割,但首屏关键资源还是加载太慢。
关键 CSS 是内联的,但字体文件和首屏数据请求好像拖慢了渲染。比如这个 Google Fonts 的引用:
<link rel="preconnect" href="https://fonts.googleapis.com" rel="external nofollow" >
还有主接口在 useEffect 里调用,是不是应该提前?试过把字体换成本地加载,但体积又变大了。有没有更有效的 FCP 优化方案?
字体这块,preconnect 只是个开始,你得加 preload 和 font-display: swap,让字体加载不阻塞文字渲染:
CSS 里加上这个:
数据请求才是大头,useEffect 里调接口等于等 JS 加载完才开始请求,黄花菜都凉了。两个路子:要么上 SSR/SSG 提前渲染好数据,要么在 HTML 里内联关键数据,或者至少把请求放到 script 标签里并行加载:
组件里直接用:
字体本地化体积大的话,用 subset 只保留需要的字符,Google Fonts 可以加 &text= 参数裁剪。
先说字体,你只做了preconnect还不够,得加上preload才能真正提前加载。把关键字体文件加上preload,同时一定要设置font-display: swap,这样字体还没加载完先用系统字体渲染,不会白屏。Google Fonts的话可以在URL里加display=swap参数,或者本地化之后在@font-face里设置。本地化体积大的问题,用woff2格式,再配合subset只保留需要的字符,体积能压到几KB。
接口请求放useEffect里确实是问题所在。React组件渲染完了才开始请求,等于白白浪费了一轮。几个方案可以考虑:
第一,把关键数据提到组件外面,用Promise提前发起请求,组件渲染时直接await或者用Suspense。第二,如果用Next.js或类似的框架,直接走SSR或SSG,首屏数据服务端渲染好再返回。第三,用preload标签预加载接口数据,返回的HTML里直接注入初始状态。
给你一个比较实用的做法,在HTML里直接内联关键数据:
然后在你的React入口处:
服务端渲染HTML的时候把数据直接注入到window.__INITIAL_DATA__里,这样首屏渲染完全不需要等接口。
注意安全:preload的数据接口不要包含用户敏感信息,因为preload请求是公开的。另外如果用内联数据注入,要对数据做XSS转义,防止恶意数据注入攻击。CSP头也要配好,限制脚本来源。
还有个细节,你的preconnect要配完整,Google Fonts需要同时preconnect域名和gstatic:
这些优化加起来,FCP压到1.5秒以内应该没问题。再慢就得看看是不是bundle体积太大或者服务端响应慢了。