Lighthouseのパフォーマンスの各指標についてまとめる

# Lighthouseのパフォーマンスの各指標
Lighthouseのパフォーマンスを構成する6つのMETRICSについてまとめて、CyberAgentさんが作成してくださっているweb-speed-hackthonのwebアプリケーションを少しだけ改善していきたいと思います。

![スクリーンショット 2022-11-26 17.32.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154845/a258a50b-92ef-c195-d2a4-cc760469724f.png)

## First Contentful Paint (FCP)とは？

> First Contentful Paint (FCP) 指標は、ページの読み込みが開始されてからページ内のコンテンツのいずれかの部分が画面上にレンダリングされるまでの時間を測定します。この指標における "コンテンツ" は、テキスト、画像 (背景画像を含む)、<svg> 要素、白以外の <canvas> 要素のことを指しています。

https://web.dev/fcp/


測定されるAPIの説明は以下

https://w3c.github.io/paint-timing/#previously-reported-paints


>  First Contentful Paint
To know whether Document document should report first contentful paint, perform the following steps:
> 1. If document’s previously reported paints contains "first-contentful-paint", then return false.
> 2. If document contains at least one element that is both paintable and contentful, then return true.
> 3. Otherwise, return false.

ページの読み込みが開始されてからページ内のコンテンツのいずれかの部分が画面上にレンダリングされるまでの時間で良さそうです。

### FCPにおける良いスコアとは？
> 良好なユーザー体験を提供するために、サイトは First Contentful Paint が 1.8 秒以下になるように努力する必要があります。

### 改善
- レンダリングをブロックするリソースを排除する
- CSS を圧縮する
- 使用されていない CSS を削除する
- 必要なオリジンに事前接続する
- サーバーの応答時間 (TTFB) を短縮する
- 複数のページ リダイレクトを避ける
- キー リクエストを事前に読み込む
- 過大なネットワーク ペイロードを回避する
- 効率的なキャッシュ ポリシーを使用して静的なアセットを配信する
- 過大な DOM サイズを回避する
- クリティカルなリクエストの深さを最小化する
- Web フォントの読み込み中にテキストが表示されたままになっていることを確認する
- リクエスト数を少なく、転送サイズを小さく維持する

## Largest Contentful Paint (LCP)とは？
> Largest Contentful Paint (LCP) 指標は、ビューポート内に表示される最も大きい画像またはテキスト ブロックのレンダリング時間を、ページの初期読み込み開始タイミングと比較してレポートします。

https://web.dev/lcp/

LCPはビューポート内の最大コンテンツ要素が画面にレンダリングされる時間を、ページの初期読み込み開始タイミングと比較してスコア化します。なのでFCPについての改善もLCPに影響します。

### LCPにおける良いスコアとは？
> 良好なユーザー体験を提供するために、サイトは Largest Contentful Paint が 2.5 秒以下になるように努力する必要があります。

### 改善
https://web.dev/optimize-lcp/

- サーバーを最適化する
- ユーザーを近くの CDN にルーティングする
- アセットをキャッシュする
- HTML ページをキャッシュファーストで配信する
- サードパーティの接続を早期に確立する
- Signed Exchange (SXG) を使用する


## Speed Index（SI）とは？
Speed Indexはページロードの経過時間に対するコンテンツのレンダリング量をプロットし、レンダリングされなかった領域面積をスコア化します。よって、SpeedIndexは値が小さいほど優れていることになります。
また、ブラウザのAPI等から取得できる値ではなく、経過時間に対するコンテンツレンダリング量をスクリーンキャプチャなどから得てスコア化します。

lighthouseでは以下のモジュールを使用してスコアを生成しているようです。

https://github.com/paulirish/speedline

### 改善
https://developer.chrome.com/docs/lighthouse/performance/speed-index/

改善には、ページの読み込み速度を改善することがSpeed Indexのスコア向上に影響します。
以下の問題を中心に改善すると良いようです。（lighthouseで）
- Minimize main thread work（メインスレッドの作業を最小化）
- Reduce JavaScript execution time（JavaScriptの実行時間の短縮）
- Ensure text remains visible during webfont load（ウェブフォントのロード中にテキストが表示されたままになるようにする）


## Time to Interactive (TTI) とは
> Time to Interactive (操作可能になるまでの時間、TTI) は、読み込みの応答性を測定するために重要となるラボ環境での指標です。

https://web.dev/tti/

### TTIにおける良いスコアとは？
> 優れたユーザー エクスペリエンスを提供するためには、平均的なモバイル ハードウェアでテストを行った場合に、Time to Interactive を 5 秒以下に抑えるよう努力する必要があります。

## 改善
- JavaScript を圧縮する
- 必要なオリジンに事前接続する
- キー リクエストを事前に読み込む
- サードパーティ製コードの影響を減らす
- クリティカルなリクエストの深さを最小化する
- JavaScript の実行にかかる時間を短縮する
- メイン スレッドの作業を最小限に抑える
- リクエスト数を少なく、転送サイズを小さく維持する

## Total Blocking Time (TBT)とは？
> Total Blocking Time (TBT) 指標は、長時間に渡りメイン スレッドがブロックされ、入力の応答性が妨げられることで発生する First Contentful Paint (視覚コンテンツの初期表示時間、FCP) と Time to Interactive (操作可能になるまでの時間、TTI) の間の時間の合計を測定します。

> タスクの処理にかなり長く時間がかかっている場合 (例: 50 ms 以上)、ユーザーはその遅延に気付き、ページが遅い、または質が低いと感じてしまう可能性があります。
特定の長いタスクのブロック時間は、50ミリ秒を超える期間です。また、ページの合計ブロック時間は、FCPとTTIの間で発生する各長いタスクのブロック時間の合計です。

https://web.dev/tbt/

### TBTにおける良いスコアとは？
> 優れたユーザー エクスペリエンスを提供するためには、平均的なモバイル ハードウェアでテストを行った場合に、Total Blocking Time を 300 ミリ秒以下に抑えるよう努力する必要があります。

### 改善
- サードパーティ製コードの影響を減らす
- JavaScript の実行にかかる時間を短縮する
- メイン スレッドの作業を最小限に抑える
- リクエスト数を少なく、転送サイズを小さく維持する


## Cumulative Layout Shift (CLS)とは？
> Cumulative Layout Shift (累積レイアウト シフト数、CLS) は、視覚的な安定性を測定するための重要なユーザーを中心とした指標です。これは、ユーザーが予期しないレイアウト シフトに遭遇する頻度の数値化に役立つ指標であり、CLS が低ければ低いほど、そのページが快適であることが保証されます。

CLSが低下する要因
- サイズが指定されていない画像
- サイズが指定されていない広告、埋め込み要素、iframe
- 動的に挿入されたコンテンツ
- FOIT/FOUT の原因となる Web フォント
- ネットワークの応答を待ってから DOM を更新するアクション

https://web.dev/cls/

### CLSにおける良いスコアとは？
> 良好なユーザー体験を提供するために、サイトは CLS スコアが 0.1 以下になるように努力する必要があります。

### 改善
- 画像要素に必ず size（height, width）を指定する
- CSS を駆使したアスペクト比対応ボックスなどの手法を用いて必要なスペースを確保する
- ユーザーの操作に応じる場合を除き、既存のコンテンツの上側にコンテンツを挿入しない
- レイアウト変更のトリガーとなるプロパティを利用したアニメーションよりも、transform アニメーションを優先する

https://web.dev/optimize-cls/

## 実際に改善してみる
CyberAgentさんが作成してくださった。素晴らしいリポジトリがあるので、こちらを拝借させていただきます。

https://github.com/CyberAgentHack/web-speed-hackathon-2022

ローカル環境では以下で動くと思います。
```
$ yarn
$ yarn dev
```

## まずは測定
Chromeのデベロッパーツールのlighthouseタブの `Analyze page load` をポチッとするだけです。
![スクリーンショット 2022-11-26 17.14.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154845/5e4b6154-6f0e-32e2-1d35-83b896bd353b.png)



## 改善
改善について見るには、OPPORTUNITESにヒントがあります。
改善できそうな順に、改善していきます。

### Enable text compression
ネットワークからlocalhostのResponseヘッダーを見ると、圧縮されていないことがわかります。

![スクリーンショット 2022-11-26 17.24.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154845/7fd75e88-8b94-4562-4cb1-241d4ef69837.png)

fastifyでbuildされたリソースを配信しているので、fastifyのutilライブラリでgzipで配信してみましょう

https://github.com/fastify/fastify-compress


```js
server.register(
  import('@fastify/compress'),
  { encodings: ['gzip'] }
)
```

再起動後、確認してみるとgzipでencodingされていることがわかります。
![スクリーンショット 2022-11-26 17.29.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154845/c84bfb4f-9d56-80d9-670e-98f10c87c994.png)


### Minify JavaScript
JavaScriptのファイルが大きいので小さくするべきという指摘です。

bundle analyzer等で不要なライブラリを消したり、他プラグイン・ツールでビルドファイル自体を圧縮等が必要です。

https://github.com/webpack-contrib/webpack-bundle-analyzer

![スクリーンショット 2022-11-26 17.36.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154845/b5748a14-78f9-c70a-8ced-d9e3be69c808.png)

この記事中ではやりませんが、lodashを使わないように書き換えたり、moment.jsをDateAPIやday.js等に書き換えてビルドファイルの大きさを小さくすることが有効です。

# さいごに
アプリケーションのパフォーマンスというのはとても重要です。
web.devではパフォーマンスとビジネスの関係性についても具体例とともにパフォーマンスが高いことによる成果を報告しています。

> パフォーマンスとは、ユーザーを手放さないこと

https://web.dev/why-speed-matters/


## 具体例
> Pinterestは、知覚される待ち時間を40％削減し、検索エンジンのトラフィックと登録数を15％増加させました。
> COOKは、ページ読み込みの平均時間を850ミリ秒短縮し、コンバージョンを7％増加させ、バウンス率を7％減少させ、セッションあたりのページ数を10％増加させました。
> また、いくつかの調査では、パフォーマンスの悪さがビジネス目標に悪影響を与える可能性が示唆されています。たとえば、BBCは、サイトの読み込みにかかる時間が1秒増えるだけで、サイトを去るユーザーの数が10％増加していることを発見しました。

# 参考
https://web.dev/user-centric-performance-metrics/#types-of-metrics