こんにちは、Plex Job開発チームの高岡です。
この記事は、 PLEX Advent Calendar 2024の16日目の記事です。
以前投稿した入社エントリーでReactにおけるパフォーマンスチューニングについてお話する旨を記載してから、早半年が経過しました...
そのお話をする前に、パフォーマンス改善に向き合うための基礎知識をまとめましたので、こちらからお話ししていきたいと思います。
Reactでのパフォーマンス改善の具体的なお話は気長にお待ちいただけますと嬉しいです 🙏
対象読者
- パフォーマンスに興味を持ち始めた方
- Webパフォーマンスの指標を勉強したい方
背景
Plex Job開発チームでは、Next.jsのSSG(静的サイト生成)を利用する中で、ページ数が多くVercelのビルド時間を超過したり、デプロイ完了までの時間が長くなってしまうといった技術的な課題に直面しています。 この課題を解決するためには、ビルドプロセスのチューニングが重要ですが、そもそも以下のような疑問が生じています。
これらの疑問を解消するためには、パフォーマンスの計測と評価を適切に行い、その結果を基にアプローチを決定する必要があります。
そこで、今回Webパフォーマンスの指標とその計測方法に関してまとめ、今後の改善に役立てることを目的としています。
Webパフォーマンスとは
MDNでは下記のように記載されています。
ウェブパフォーマンスとは、サイトが読み込まれるまでの時間、操作可能・応答可能になるまでの時間、そしてユーザーが操作する際のコンテンツのスムーズさを意味します。スクロールはスムーズか、ボタンはクリックしやすいか、ポップアップはすぐに読み込まれて表示されるか、表示の際にスムーズにアニメーションするか。
Webパフォーマンスを改善する目的は、大きく下記の2つの理由があります。
これらの要素はユーザーの離脱を防ぎ、コンバージョン率の向上に寄与します。そのほか、検索エンジンでの上位表示により新規ユーザーの獲得機会が増加し、ビジネスの成長を促進します。
Webパフォーマンスがどのように重要かを理解したところで、次は具体的に何を基準に改善を進めるべきかを見ていきます。Googleが提唱する「Core Web Vitals」という指標が、その指針となります。
現在のCore Web Vitals
Core Web Vitalsとは3つのユーザー中心のパフォーマンス指標です。ページの読み込みパフォーマンス、インタラクティブ性、視覚的安定性に関する実際のユーザー体験に焦点を当てています。これらの指標を理解し、最適化することで、優れたユーザー体験を提供することができます。 それぞれの指標について簡単に説明します。
Largest Contentful Paint (LCP)
LCP は、ウェブページの読み込みパフォーマンスを評価するための指標の1つです。ユーザーがページを訪れた際に、視覚的に最も大きなコンテンツ(画像やテキストブロックなど)が表示されるまでの時間を測定します。良好なLCPは2.5秒以下とされています。
これまでは、初回ペイント後の読み込み体験をより正確に把握するために、First Meaningful Paint(FMP) や Speed Index(SI) などのパフォーマンス指標が推奨されていました。しかし、これらの指標は計測が複雑で説明が難しく、結果にばらつきが生じやすいため、メインコンテンツがいつ正確に読み込まれたのかを特定することが困難でした。
そこで、ページのメインコンテンツが読み込まれたタイミングをより正確に測定するために、最も大きな要素がレンダリングされたタイミングを確認する方法としてLCPがCore Web Vitalsの指標に加えられました。
▼ LCPの要素になり得るもの
img
要素(GIFやアニメーションPNGのようなアニメーションコンテンツには、最初のフレーム表示時間が使用されます。)svg
要素内のimage
要素video
要素(ポスター画像のロード時間と動画の最初のフレーム表示時間のどちらか早い方を使用します。)- CSSの
url()
関数を使用して読み込まれた背景画像を持つ要素 - テキスト・ノードまたは他のインライン・レベルのテキスト要素の子を含むブロック・レベル要素。
今後、調査が進むにつれて要素が追加される可能性があるそうです。
Cumulative Layout Shift (CLS)
CLS は、ウェブページの視覚的な安定性を評価するための指標の1つです。ユーザーがページを読み込んでいる間に発生する予期しないレイアウトの変動(シフト)の総合スコアを測定します。良好なCLSスコアは0.1以下とされています。
CLSは、ページのライフサイクル全体で発生したすべてのレイアウトシフトのスコアを合計して算出されます。各レイアウトシフトのスコアは、影響率と距離の割合の積になります。
レイアウトシフトスコア = 影響の割合 × 距離の割合
下記の図を例に、それぞれ影響率と距離の割合を説明します。
影響の割合は、そのフレームと前のフレームのすべての不安定な要素の可視領域を、ビューポートの合計領域の割合として組み合わせたものです。
1つのフレームでビューポートの半分を占有する要素があり、レイアウトシフト後に、要素はビューポートの高さの25%下方に移動します。赤い点線の長方形は、両方のフレームにおける要素の可視領域の結合を示しています。この場合、可視領域はビューポートの合計の75%であるため、影響の割合は0.75です。距離の割合は、不安定な要素が移動した際のビューポートからの相対距離を測定します。下方に25%移動したので、0.25になります。
この例では、影響の割合が0.75、距離の割合が0.25であるため、レイアウトシフトスコアは0.75 × 0.25 = 0.1875です。
当初、レイアウトシフトスコアは影響率のみに基づいて計算されていました。距離の割合は、大きな要素がわずかにシフトした場合に過度なペナルティが適用されないように導入されたそうです。
Interaction to Next Paint (INP)
INPは、ユーザーのインタラクション(例えばクリックやタップ)に対するページの全体的な応答性を評価するための指標です。200ミリ秒未満だとページの応答性が良好とされています。 INPの意図は、インタラクションの最終的な効果(ネットワークフェッチや他の非同期操作によるUIの更新など)をすべて測定することではなく、次の描画がブロックされている時間を測定することです。なので、時間のかかるインタラクションでは、最初の視覚的なフィードバックを素早く提示することが重要です。
INPは、First Input Delay(FID)の後継指標で、どちらも応答性の指標ですが、FIDはページでの最初の操作の入力遅延のみを測定していました。INPは、入力遅延からイベントハンドラの実行時間、ブラウザが次のフレームをペイントするまでのページ上のすべてのインタラクションをモニタリングすることで、FIDを改善します。
その他のCore Web Vitalsに関わる重要な数値
前述したCore Web Vitals以外にも重要な指標がいくつかあるので、その指標を説明していきます。
First Contentful Paint (FCP)
FCPは、ユーザーがページに初めて移動してから、ページのコンテンツのいずれかの部分が画面上にレンダリングされるまでの時間を測定します。この指標の「コンテンツ」とは、テキスト、画像(背景画像を含む)、svg
要素、白色以外の canvas
要素を指します。
上記の画像の2番目のフレームまでの時間がFCPを指します。
LCPとは違って、読み込みのごく初期の段階しか捉えません。
ページにスプラッシュ画面や読み込みインジケーターが表示されている場合、それらの表示までを計測しており、実際に使用が可能になっているわけではなく、FCPが短いからといって、必ずしもユーザー体験が優れているとは言えません。
Total Blocking Time (TBT)
TBTは、FCP後にメインスレッドが入力に応答できないほど長くブロックされた合計時間を測定します。この時間が長いほど、ユーザーがページとインタラクションを取るまでの遅延が大きくなります。200ミリ秒未満が良好とされる値です。
Time to First Byte (TTFB)
TTFBは、ユーザーがリクエストを送信してからサーバーが最初のバイトをブラウザに返すまでの時間を測定します。下記の画像のstartTimeからresponseStartまでの経過時間になります。
これはクリティカルレンダリングパスより前の工程です。
HTMLの最初のリクエストはいくつかのステップがあり、各ステップにかかる時間を短縮することで、TTFBを短縮することができます。
ページの読み込みの速さに関しては、TTFBだけが注目すべき指標ではありませんが、TTFBが高いと、LCPやFCPなどの指標で指定された良好な値に到達するのが難しくなります。
Speed Index(SI)
Speed Indexは、Lighthouseレポートのパフォーマンスセクションで追跡される5つの指標のうちの1つです。ページの読み込み中にコンテンツが視覚的に表示される速度を測定します。スコアは3.4秒以下が良好とされています。
個人的には、その他の指標と比べると定義が少し曖昧に感じています。改善の指標としては、具体的な改善ポイントがあるその他の指標を目安にする方が良いかと思います。
パフォーマンス計測方法
すでに使用されている方も多いかと思いますが、普段使用しているパフォーマンスを計測する3つのツールの概要を説明します。
Google Search Console
ウェブパフォーマンスに関する主な指標では、モバイル・PCともに、低速(不良)、改善が必要、良好のステータス別にURLをレポートします。
このレポートは、実際のユーザーデータで測定される3つの指標(LCP、INP、CLS)に基づいています。レポート内のURLは、ユーザーエクスペリエンスが類似するページにグループ化されているため、個別のURLでは確認できません。
PageSpeed Insights
GoogleのPageSpeed Insightsでは、実際のページを読み込んで課題を検出します。
下記のページにアクセスして、分析するURLを入力するとパフォーマンスを計測できます。
https://pagespeed.web.dev/
Vercelを利用している場合は、Vercelが提供しているSpeed Insightsを利用することが可能です。それぞれのパスやルートごとに数値が算出可能で、特定の日付での絞り込みを行えるので利便性が高いです。
計測している指標や算出方法は下記のドキュメントに詳しく記載されていますので、ご参考ください。
Speed Insights Metrics
Google Chrome DevTools
開発者が頻繁に使用する検証ツールです。パフォーマンスの計測に使用される主なパネルについて説明します。
Lighthouse
LighthouseはPageSpeed Insightsと類似の機能を持ち、パフォーマンス以外にもアクセシビリティやSEOの観点からの計測が可能です。NetworkパネルでブロッキングされたリソースやSourcesパネルのOverride機能でAPIレスポンスやCSSの書き換えを反映した状態で計測が可能です。
計測値は様々な要因で変動するため、複数回の結果の中央値を確認することを推奨します。
Lighthouse の概要 | Chrome for Developers
Performance
Performanceパネルでは、ページの読み込みやユーザー操作に伴うイベントを詳細に分析できます。タイムラインの記録と再生により、ページロードや操作時の問題箇所を特定し、フレームごとのレンダリング時間やスクリプト実行時間を確認することでボトルネックを見つけることができます。また、メモリ使用状況の監視やJavaScriptのパフォーマンス分析も行えます。
パフォーマンス パネル: ウェブサイトのパフォーマンスを分析する | Chrome DevTools | Chrome for Developers
Network
Networkパネルでは、ネットワークを通じたリソースのタイムラインを詳細に確認できます。個別のリソースの詳細では、サーバーへのリクエスト時間やレスポンス時間をさらに細かく見ることができます。リクエスト数が多い場合は、カテゴリごとに絞り込みや名前でフィルターをかけることができ、操作性を高めて効率的に分析できます。
ネットワーク パネル: ネットワークの負荷とリソースを分析する | Chrome DevTools | Chrome for Developers
まとめ
今回の記事では、Webパフォーマンスの重要な指標とその指標の計測方法について紹介しました。パフォーマンス改善にはトレードオフが伴うため、エンジニアとして最適な実装を判断するためには、基礎知識をしっかりと身につけておくことが不可欠です。
フレームワークが進化し続ける中で、新機能を導入する際にはその機能が「何を改善し、ユーザー体験にどのような恩恵があるか、そしてそのトレードオフは何か」を正しく理解するための基盤として、今回の知識が役立ちます。
次回以降の記事では、計測した数値に基づいて仮説を立て、具体的な改善策を実施します。その過程でReactのパフォーマンスチューニングについても詳しく解説する予定ですので、お楽しみに!
▼ 参考文献
web.dev
https://www.amazon.co.jp/Webフロントエンド-ハイパフォーマンス-チューニング-久保田-光則/dp/4774189677
おわりに
現在プレックスではソフトウェアエンジニア、フロントエンドエンジニアを募集しています。 この記事を見て一緒にパフォーマンス改善を行いたい方がいればお気軽にご連絡をお願いいたします!