一个 Next.js WebGL 小游戏从 Lighthouse 40+ 到 97 的性能优化记录

发布于

最近做了一个基于 Next.js 、React 和 PixiJS 的网页小游戏 [Color Tiles](https://colortilesgame.net/)。

页面看起来不复杂:一个 WebGL 棋盘、几个控制按钮,加上一些玩法介绍。但第一次跑移动端 Lighthouse 时只有四十多分。最初的报告没有保存下来,目前仓库里能复核的中间结果是 59 分:

- LCP:11.36 s
- TBT:625 ms
- 首屏传输量:2.33 MB

经过几轮优化后,生产构建的移动端 Lighthouse 达到 97 分,桌面端 100 分:

- LCP:2.29 s ,下降约 80%
- TBT:135 ms ,下降约 78%
- 首屏传输量:509 KB ,下降约 78%
- CLS:保持为 0

这次比较有效的改动主要有这些:

1. 不再整包引入 `pixi.js-legacy`,改为从 `@pixi/core`、`@pixi/display`、`@pixi/sprite` 等模块按需引入,并直接使用 WebGL Renderer 。
2. 把只能在浏览器运行的游戏模块改成动态加载,同时保留尺寸稳定的 loading 界面,避免布局跳动。
3. 把教程 GIF 转成 MP4 ,并延迟到用户真正打开教程时再加载。
4. 图片转为 WebP ,补全响应式 `sizes`,并通过 Cloudflare Image Resizing 输出适合设备尺寸的版本。
5. 把图片迁移到独立的 [img.colortilesgame.net](http://img.colortilesgame.net/) CDN 子域名,静态资源缓存延长到一年,并使用 `immutable`。同时用 `preconnect` 提前完成新域名的连接。
6. 开启 Next.js 的实验性 `inlineCss`,把 CSS 放进 HTML ,减少首次渲染中的一次阻塞请求。
7. 排行榜 API 改为接近视口或游戏结束后再请求,不再与棋盘初始化争抢首屏资源。

过程中也踩了几个坑。例如,一开始 preload 了完整背景图,以为可以改善 LCP ,结果大图反而提前占用网络。后来只 preload 4.8 KB 的占位图,效果更合理。

另一个体会是,不要只盯着 Lighthouse 总分。中间报告的 FCP 已经不到 1 秒,真正的问题是 11 秒的 LCP 、主线程阻塞和过大的资源量。把非关键工作移出首屏,比继续抠 FCP 更有效。

线上版本:
[https://colortilesgame.net/](https://colortilesgame.net/)
更完整的过程、代码片段、数据和取舍写在 Medium:
[https://medium.com/@winterscott999/from-the-40s-to-97-how-we-cut-the-initial-load-of-a-next-js-webgl-game-by-nearly-80-d04e803a27ac](https://medium.com/@winterscott999/from-the-40s-to-97-how-we-cut-the-initial-load-of-a-next-js-webgl-game-by-nearly-80-d04e803a27ac)
欢迎交流 WebGL 游戏、Next.js 或 Lighthouse 优化方面的经验。

---

原文链接:[点击查看](https://www.v2ex.com/t/1228871)

评论(2)

玩了下感觉滑动的时候稍微有点卡顿,整体还可以。

· 0 个赞

回复

收到反馈,我回头查一下,应该是再缩短一下加载时间就能解决。

· 0 个赞