性能の予算を Lighthouse CI で決める:効いたこと、効かなかったこと
「速い」ことを見せるサイトなので、性能が劣化したら CI で止めたい。Lighthouse CI で予算を決め、改善の過程も記録してきた。判断の全文は ADR-0006 にある。
予算の決め方
主要 5 ページ(トップ、About、ブログ一覧、ブログ記事、Work 詳細)を、各 3 回計測する。予算を超えたら、CI を失敗させる。
- トップ: 性能スコア 0.9 以上、LCP 2.8s 以内、JS 195KB 以内、総転送 410KB 以内
- 他のページ: スコア 0.75 以上、LCP 5s 以内、総転送 1.4MB 以内
- 全ページ: CLS 0.1 以下、TBT 200ms 以内
予算は、実測に余裕を足した値にしている。改善したら、引き下げる。
トップを速くした過程
トップは、性能 0.91 から 0.96〜0.97、LCP 3.5s から 2.6〜2.7s、未使用 JS 101KiB から 29KiB に改善した。効いたことは、次のとおり。
- zod をホームの JS から外した。絞り込みの部品が、zod を含むスキーマから定数を読んでいたためだった。
- お問い合わせフォームを、遅延読み込みにした。
- 先頭の画像を優先して読み込み、
sizesを指定した。
効かなかったこと、採らなかったことも、記録してある。experimental.inlineCss は、HTML が 12KB から 599KB に膨らみ、FCP も LCP も悪化した。DaisyUI を外すと、CSS は半分になるが、LCP は変わらなかった。
CI(Linux)では、CLS が予算を超えた。日本語の代替フォントが無いランナーで、Web フォントの差し替えが起きたためだった。display: optional に変えて解消した。
残った 29KiB の正体
#34 で、残りの未使用 JS を調べた。29KiB は、すべて 1 つのチャンク(転送 72.8KB)の中にあった。中身は React DOM と Next の起動コードで、アプリのコードは含まない。
トップが読む script は 11 本、転送 169KB で、React DOM と Next の実行環境が約 156KB(92%)、アプリ自身のチャンクが約 13KB(8%)だった。アプリ側で削れる未使用の JS は、これ以上ない。削るにはフレームワークの変更が要るので、採らないことにした。
日本語フォントの案の比較
Work 詳細とブログ記事は、性能が低い。原因は、日本語フォントの断片の読み込みだった。next/font は、日本語の断片すべての @font-face を持ち、ページに出た文字の分だけ(約 20KB ずつ)読み込む。display: optional なので、間に合わなければ使われないが、帯域は使われる。模擬回線では、この帯域の取り合いで LCP が遅れる。
5 回ずつ測った中央値は、次のとおり。
- 今の設定: Work 詳細は性能 0.78・LCP 6.0s(フォント 624KB)、ブログ記事は性能 0.79・LCP 5.7s(913KB)
- 重みを 400 だけにする: Work 詳細は 0.87・4.1s(381KB)、ブログ記事は 0.90・3.8s(550KB)
- システムのフォントだけにする: Work 詳細は 0.96・2.8s(62KB)、ブログ記事は 0.93・3.2s(80KB)
速さと見た目のどちらを取るかは、まだ決めていない。見た目に関わる判断なので、Issue にして残してある。決めたら、予算を引き下げる。