WebFrontendローカルパフォーマンス改善支援ツールを作ってみた。

この記事は、Merpay Advent Calendar 2021 の21日目の記事です。

はじめに

こんにちは。メルペイのFrontendエンジニアのtoshickです。 メルペイフロントエンドチームではパフォーマンスに関するアクションも行っています。本記事ではその活動報告を投稿します。

概要

昨今Webサイトの閲覧時のパフォーマンスは重要視されています。そのパフォーマンスを定量的に可視化するための標準的な指標がWebVitalsとしてGoogleから提唱されています。 このスコアに基づいて自分のサイトの現状を把握し、それを改善していくことができます。

ただ、パフォーマンス改善の開発には面倒な部分がありコストがかかることがわかってきました。 そのためのサポートツールをつくってみた、というのが今回のお話です。

lhciコマンド

実際の計測にはlighthouseコマンド(lhci)を利用します。これは対象のページに対してパフォーマンステストを実行し、WebVitalsに基づいたスコアを算出してくれるGoogle制のツールです。 あるメトリクス(LCP等)に対して実際に何ミリ秒かかったのか、その秒数はWebVitalsの標準からすると100点満点中何点かの結果をjsonとして出力してくれます。

現在の状況

メルペイフロントエンドチームでは現在Lookerを利用したデータの可視化により、コードカバレッジやパフォーマンスの状況のモニタリングを行っています。 パフォーマンスについては各プロジェクトごといくつかのurlをターゲットとしてWebVitalsのメトリクスをグラフとして表示しています。

Lookerグラフ

上のようなグラフがurlごと存在しており、WebVitalsで定められた基準の水平グリーンラインを目指すことにしています。(スコアが良すぎると目盛りの表示範囲の関係上水平グリーンラインが出現しないことがあります) 青い棒グラフが100点満点スコアなので「グラフ全体が青色で覆われていれば高得点だな」と直感的に把握できるようになっています。 つまり上記グラフのurlとしてはTBTのスコアがかなり低めなため、ここを改善する必要があると判断できるわけです。

課題

Lookerのグラフ確認は改善イテレーションには不向き

  • Lookerグラフにより現在のパフォーマンスは把握できますがローカルマシン上でのパフォーマンス改善のためのトライアンドエラーには使えません。
  • なぜならCI上の実行とローカルマシンとでは同じバージョンのサイトでも結果が違うためです。(マシンスペックや通信環境が違うため。)
  • Lookerグラフデータ生成はCI上のマシンにより作成されており、深夜に実行されます。
  • 日毎の結果がまとめて集計されるため、画面に出現する結果は何月何日の任意の回数の実行結果の平均値であるためにローカルマシンで改善したバージョンをCIにpushしたとしてもその結果をピンポイントで反映することはできません。(朝2時などの深夜実行分のデータとマージされてしまうためその改善がどの程度影響したのかがあいまいです。)
  • つまりその改善がうまくいったかどうか改善バージョンのスコアを確認するためには次の日まで待つ必要があります。

ローカルでの改善確認に手間がかかる

  • lhciの出力結果はぶれがあるため一度の実行結果だけを信用することは危険です。
  • 同じマシンで連続して結果を出力しても違う結果がでます。つまり同じ環境での二度(もしくはそれ以上)の実行結果の”平均”を現状スコアとするべきです。
  • 改善策でのスコアを従来のスコアと比較する必要がありますが、平均を計算してメモしながらの作業がかなり面倒でした。

改善の確認には何が必要か

改善結果の確認ではなるべく同じ環境における実行結果を比較する必要があり、ローカル環境でトライアンドエラーを行うには次のステップの繰り返しが必要となります。

  1. まず現状のスコア(複数回の平均値)を出力する。(これは一度だけでよい)
  2. 改善策を複数回実行し平均スコアを算出する。
  3. 両者を比較して効果を検証する。

割とシンプルだなと思うかもしれないですが、まず現状のスコアをどこかにメモしておき試行錯誤をして改善を確認するときに

「あれ、スコアが改善した!」
「いやでも一度だとわからないからもう一度やってみよう」
「2つの平均はこれくらいかな」
「そもそも改善前のスコアってどれだっけ」
「あ、やっぱりここははずしてここだけでもう一度試してみよう」
「あれ、この結果ってどれのやつだっけ」
「このスコアって1回のものだっけ?それとも2回の平均だっけ?」
「さっきのだとここがスコアおちているけど今は改善しているきがする。あれ、これってさっきのXX改善のやつだよな?」

というようなカオスな状態が発生しました。 この検証、一度実行するのに1秒ならばまだよいですがlhciはそんなに早くありません。 lhciのテスト実行(2回実行設定)に40秒くらいかかります。 そこから平均の算出作業が都度発生します。

改善ツールに求めるもの

カオスな状況の中、これではいけないと思いヒストリーページを自動生成できないかと考えました。 このツールの目的は以下です。

  • 現状はどのような状態か、複数回の平均実行結果がグラフとして見える。
  • 複数回の平均のグラフが出力されるため現状のスコアとすぐ比較ができる。
  • 施策を任意の数実行し蓄積していくことができる。
  • 後からみてわかりやすいタイトルを付与することができる。(たとえばbranch名とか)
  • WebVitalの実行数値および100点スコアの両方が確認できる。
  • スコアごとに評価コメントなどのメモが残せる。
  • これらをhtmlとして出力し1ファイルとして保存しておくことができる。(外部に依存するjsonなどのストアを持たない)

Perf Local Check Tool

結果として以下のようなhtmlを出力するツールを作成しました。 名前は確定ではないですが「Perf Local Check Tool(仮)」としておきます。

結果html

Perf Local Check Tool利用の流れ

  1. まずターゲットとなるWebページを閲覧可能な状態で起動する。(例:http://localhost:9999等
  2. lhciの設定ファイル(.lighthouserc.js)に上記対象urlをセットする。
  3. description.js にtitleで設定した文字列をキーにして説明文を入れておく。(結果htmlビルド時にここを読んで説明文がhtmlに出力される)
//description.js
module.exports = {
  page: 'XXXのページ',
  url: 'http://localhost:3000/merchants/72057594038927937/detail',
  //全体のメモ
  memo:
    'XXXのページ\nためしに事業者情報以外を v-if=false にしてみたらTBTは30点ほど上昇\n情報以外を全削除してみても同様\nなぜかFCPとLCPが悪化する',
  //titleのキーに対応するコメント
  graphs: {
    develop: 'ベース',
    'v-if':
      'ZZZ情報以外を v-if=false にしてみた。\nなぜかFCPとLCPが悪化する',
    remove_vif_part:
      'ZZZ情報以外を削除してみた。\nFCPとLCP変わらず悪化のまま',
   ...
  },
};
  1. npm run local-lhci-html --title=mybranch を実行すると、title名のグラフブロック(mybranch)が追加された結果のhtmlが起動します。(前述の茶色画面)
  2. 結果を観察し「プロダクトコードを修正、次のタイトルを付与して実行」を繰り返して何が成功し何が失敗だったのかを振り返ります。具体的な内容はdescription.js内の説明文に入力して第三者でも理解できるようにしておくとよいです。
  3. html生成のソースとなるjsonファイルは.lighthouseci-htmlディレクトリにどんどんたまっていきます。別ページの開発をする場合やすべてリセットする場合は.lighthouseci-htmlディレクトリを一度削除すればよいです。

ツールの仕組み

登場人物

  • description.js
  • htmlに説明を付与する
  • make_lhci_result.js
    • lhci結果の平均を結果jsonとして出力し、それらと出力されている全jsonから結果htmlも出力する
  • template-result.html
    • 結果htmlのテンプレート
  • .lighthouseci
    • 毎回クリア、生成されてlhciコマンドのレポートjsonが格納されるディレクトリ
  • .lighthouseci-html
    • 実行ごとにタイトル名の平均スコアデータjsonが格納されるディレクトリ。明示的に消さない限り平均のjsonデータが蓄積されていく。

説明

  1. まず対象のページに対してlhciが設定値の回数分テストを実行し、その回数分の結果jsonが .lighthouseci ディレクトリに出力されます。
  2. make_lhci_result.jsにてそれらを読み込み、結果の平均値を算出したjsonを.lighthouseci-html ディレクトリに生成します。
  3. make_lhci_result.jsが引き続き結果htmlを生成しファイルとして出力します。
  4. htmlはdescription.jsにある説明文等を反映した形で生成されます。

.lighthouseci-htmlディレクトリには実行のたびに平均jsonが出力され、それらを読み込んでhtml生成が走るため結果のグラフはどんどん増えていきます。 これがヒストリーとして機能します。 すべてリセットするためには.lighthouseci-htmlディレクトリを削除すればよいです。

今後

まだこのPerf Local Check Toolを使って「このメトリクスをこのように改善することに成功した」という体験は得られていませんが、その足がかりになるだろうことは確信しています。

基本的にはWebVitalsが示してくれているGreenスコア(一般的理想スコア)を目指してはいますが、様々な要因もありすぐには達成できるかわからないという場合もあるかと思います。 そういう場合、闇雲にGreenスコアを目指すのではなく「ページのボディ部分全部消しても40点にしかならないんだからまずはボディを消さずに40点になることを目指そう」というような目標設定もありなのではないでしょうか。

その他チームメンバーに「現在このページはこのようなスコアになっていて、このメトリクスを改善しようとしているんだ、このような施策をためしてみたんだ」ということを明確に伝えるためにこのhtmlはとても有効ではないかと思います。

今後はこのツールを別チームでも利用してもらい、パフォーマンス改善のツールとしての実績が生まれたらゆくゆくはOSSとして外部へ公開できればうれしいです。

引き続きメルペイのFrontendパフォーマンス改善をより低コストで続けられるように改善を加えていきます。 読んでいただきありがとうございました。