Lighthouse 分數提高攻略 - Next.js

2025-04-221.08Front EndNextjsPerformanceReactLighthouse 分數提高攻略 - Next.js

最近在開發公司日本官網,研究了一番 Lighthouse 提高分數的方法,Lighthouse 分數對網站品質的影響非常直接,不只工程師自己會參考,連顧客看到網站體驗好不好,來檢視公司產出的品質。它幾乎就是評估網站品質的最直觀量化依據之一。

其中 Lighthouse 的四大項目中,「效能(Performance)」是最難搞的一個。其他像是「無障礙(Accessibility)」、「最佳做法(Best Practices)」、「SEO」老實說都還算容易加分(至少可以照 checklist 改),但效能這塊,完全是另一回事。

先講無障礙、SEO、Best Practices(比較容易處理)

這三個項目其實照著工具或官方建議就蠻容易滿分 :

無障礙(Accessibility)

我是用 shadcn/ui 的元件庫,它天生就有考慮很多無障礙的東西,像是:

  • 元件都有 aria-* 屬性

  • Dialog、Popover 這類互動元件有正確的 focus 管理

  • 支援鍵盤操作

不過還是有遇到一些地方要跟 UI 設計師協調,例如文字與背景對比不夠、hover 狀態太不明顯等,以這次開發為例,我們就有針對某些字體顏色做微調,這點真的得溝通協作才能搞好。

Best Practices

其實用 Next.js 的話大致上沒太大問題,很多安全性或結構上的東西框架都幫你處理好了,例如:

  • 自動防範 path traversal 攻擊

  • 有內建的 Image 最佳化

  • 禁止 inline script 等等

SEO

這邊要提醒的是:

  • 每頁只能有一個 h1(這個不少開發者都沒注意)

  • h2 ~ h6 標籤要順序遞增,不能亂跳,不要 h2h4 這種

  • meta 標籤該寫的要寫,像 descriptionog:imagerobots 等等


接下來進入正題:效能(Performance)

這一項分數難拉的原因有幾個:

  1. 牽涉到使用者裝置、網路速度

  2. 不是單靠設定可以解決,需要針對真實瀏覽體驗做細緻調整

  3. 你可能在某個地方塞了一個字體、圖片或套件,整體分數就被拖垮

以下是這次實戰中踩到的一些坑,還有具體怎麼優化:


一 、避免大量網路資源

這一項是我在 Lighthouse 最常看到被扣分的項目之一,因為它直接關係到首屏載入時間,下面幾個東西特別容易出事:

1. 字體

為了日文排版美觀,引用了 Google Fonts 裡幾個日文字體,結果 Lighthouse 一測直接大扣分。因為單是字體就佔了整體傳輸資源的 50~60%

文章圖片
使用 google font 時,lighthouse 分數

 

文章圖片
拔除 google font 時,lighthouse 分數

解法是這樣的:

  • 若真的要用 Google Fonts,請只載入需要的字重和子集,不要整包。
    → 我採用的是 Next.js 內建的 next/font/google,可以選擇只載你需要的部分。

  • 更好的做法自託管字體,只打包你要的部分,完全不經外部請求,穩又快。

  • 或乾脆改用系統字體 stack:日文可參考這個組合 → "游ゴシック体", "Yu Gothic", "Hiragino Kaku Gothic ProN", sans-serif

2. 首屏加載的圖片

因為公司官網本身圖片就偏多,如果一進頁面就全部載入,勢必影響這個項目評分。

解法:

  • 使用 lazy load:不要一進來就載圖,讓瀏覽器「看到再載」。
    Next.js 的 <Image> 元件預設就已經有 lazy loading 功能,基本上拿來用就很夠用。

3. 第三方插件

reCAPTCHA 這類第三方服務,只是為了某一個功能(像是底部的聯絡我們表單),但它本身會引入一堆額外 JS,而且大多是同步載入,會嚴重拖累效能。

解法:

  • 我自己封裝了一個 useIntersectionObserver 的 hook,搭配 ref 去監聽表單區塊的出現時機;

    只有當使用者「真的滑到底部」看到表單時,才會動態載入 reCAPTCHA 的 script。

文章圖片
第三方插件按需載入

二 、最大內容繪製元素(LCP)

LCP(Largest Contentful Paint)指的是「畫面中最主要的內容載入完成的時間」,通常是一張 Hero 圖或大的標題文字。

常見問題:

  • Hero 圖是用 <img src="..."> 而不是 <Image />

  • 太大張沒壓縮,或直接塞了一張 4K 畫質的背景圖

解法:

  • Hero 圖建議用 Next.js 的 <Image /> 並加上 priority ,會幫我們做 preload

  • 採用 mobile-first 的圖片策略,讓不同螢幕尺寸載入不同大小的圖片

  • 轉成 WebP 

文章圖片
針對Hero圖片進行多項性能優化

三 、 DOM 結構不要太複雜

有時候 UI 太動態、太多巢狀層級會讓 DOM 太大,尤其是用了什麼無限列表、複雜的元件樹:

  • DOM 元素總數盡量控制在幾千以內

  • 深層巢狀不要超過 10 層

  • 沒必要的 div、span,請勇敢刪掉(不要為了排版加一堆 wrapper)


四 、減少無用的 CSS

過去使用大型 UI library(像 MUI、Ant Design)時,常常會引入一大堆你根本沒用到的 CSS,結果造成首屏載入 CSS 體積爆炸,Lighthouse 效能分數低落。

這次我選擇使用 shadcn,它的最大優點就是「你用什麼,就只引入什麼」。所有元件都是 base on Tailwind + Radix 的組合,不像 UI 庫會一次塞一包。

換句話說:

  • 沒有多餘的樣式,載入快

  • 所有樣式都在你控制範圍內,要客製也方便

  • 不怕 purgeCSS 或 Tailwind 把你沒用到的 class 清不掉

簡單來說,shadcn 的設計哲學很接近「按需載入」,比起傳統 UI 庫,在 Lighthouse 的 CSS audit 裡會輕鬆很多。

文章圖片
成果

總結一下

效能優化真的是一場持久戰,不要指望一次搞定、一測就 100 分,因為每個專案都有不同的效能難關需要克服。

幾個我自己踩雷後得到的心得:

  • Lighthouse 分數 ≠ 使用體驗,但它還是一個不錯的參考。像我們這次就靠它找到一些資源過重的問題。

  • 能省就省,字體、圖片、第三方腳本,全部都是能優化的地方。

  • 善用 Next.js 提供的好工具,像是:

    • <Image> 幫你處理 lazy load + size 最佳化

    • <Script strategy="lazyOnload"> 控制 script 加載時機

    • dynamic() 延遲載入非首要元件

    • <Head> 處理 meta / SEO 等設定

  • 組件設計階段就考慮 accessibility、標籤結構,這真的很重要,等到開發完再補救,通常會很痛苦

額外補充一些可考慮的手段:

  • 頁面可以考慮用 SSG (Static Site Generation),讓內容先在 build 時就生成好,使用者打開網頁時不用等伺服器跑。

  • 圖片、自託管字體、甚至 JS lib 都可以考慮搭配 CDN 或 edge-based hosting,效果非常有感。

  • 可以搭配 VS Code 的 Import Cost 插件,幫你即時看到每個 import 進來的套件大小,在下載套件前,先考慮一番

  • 使用 @next/bundle-analyzer 檢查你的 bundle 裡面塞了什麼,是否不小心 import 整包 lodash 或 date-fns,或是引用了專案非必要的套件


效能優化的細節實在太多了,很難在一篇文章裡全部講完。以後有機會我會再慢慢分享。
希望這篇能讓你在優化的路上少走一些冤枉路,哪怕只是 Lighthouse 多拿個 10 分,也絕對值得!
 

參考

https://jp.twjoin.com/

https://nextjs.org/