Lighthouseで100点取るためにやったこと

こんにちは。 カンカクでフロントエンドエンジニアをしているzi(@Ryozi_zi)です。
最近はやりたいゲームが多くて、日々取捨選択を迫られています。

カンカクは現在フロントエンドエンジニア3人によるチーム体制で活動しています。 お互いに興味範囲が少しずつずれていて、いい刺激を与え合いながら開発を進めています。
最近の話題としては「パフォーマンス」と「アクセシビリティ」がよく上がります。

数年前に「Core Web Vitals」が発表され、それ以降パフォーマンスはSEO対策にも必須項目となりました。またインクルーシブなウェブを実現するという目的のためにもアクセシビリティを強化していくことをチームで話合い決めています。

そんな中、GOOD EAT CLUBで新ブランド「PROPPO」を出すためにブランドのLPページを作って欲しいとの依頼がありました。

「これはパフォーマンス、アクセシビリティともに良いページを作るぞ!」と意気込んで作った結果...









Lighthouseで満点を取ることができました!

今回は、Lighthouseで高得点を取るためにやったことをまとめていきます! *1

技術選定

今回のLP制作は、「astro」というライブラリを使い実装しました。 最近、カンカクではReactを使った実装が多かったため、多少のJavaScriptを含む実装ならば、なるべくReactを使いたいという共通認識がフロントエンドチーム内でありました。

宣言的UIに慣れ親しみすぎた体に手続型のJavaScriptを書かせるのは苦痛だったので、Reactで書ける静的サイト生成のフレームワークを探した結果、「JavaScriptをビルド時になるだけ削除し、パフォーマンスを向上させる」という「astro」が良さそうという結論になりました。

また、CSSも静的型付けができるTypeScriptで実装できるものが良さそうだったので、zero runtimeを謳う「vanilla extract」を採用しました。

実装

実装時には、なるべくアクセシビリティを意識した実装を心がけました。

単純ではありますが、画像のalt属性WAI-ARIA属性、HTMLタグの付け方などに気を使って開発しました。

astroは、React以外にも独自拡張子の.astroとつく独自ファイルでも書けるのですが、そちらは素のHTMLとほぼ同じなので開発自体はかなりやりやすかったです。

パフォーマンス改善

初期の実装が終わり、一旦ページとして完成した時に一度Lighthouseを実行したのですが、結果はパフォーマンスがいいとは言えない状態でした。

アクセシビリティに関しては、意識して開発していたので高得点でしたが、パフォーマンス面では以下の課題が挙げられていました。

  • 使用していないJavaScriptがある
  • 使用していないCSSがある
  • 画像ファイルが重い
  • テキスト圧縮が無効になっている

「むむむ...。」と思いながらも、ここからは愚直に上記に挙げられたものを改善していきました。

使用していないJavaScript & CSS

始めて結果を見たときは「astro使っているのになんで?」という気持ちになりましたが、ビルドされた結果や実行時の挙動を見てみると明らかに必要ない箇所でReactによるクライアントレンダリングとvanilla extractにより生成された使っていないJavaScriptがありました。

Reactを使ってクライアント側でJavaScriptを実行する場合、当たり前ですが、React本体のコードを必要とします。そのためastroはReactを使用する場合、React本体のコードを配信するようにJavaScriptをビルドします。そして、そのReactのコードを全て利用するわけではないため一部利用していないコードが発生してしまっていました。

ただ、今回は「宣言的UIを使った実装が楽だから」という理由でReactを使えるよう実装してきていたので、ここは開発の楽さとのトレードオフとして見送りました。

一方で、vanilla extractに関しては改善できる部分がありました。 今回、実装時にもパフォーマンス改善にこだわった部分として、vanilla extractの「sprinkles」という機能を利用していました。

sprinklesは端的にいうとユーティリティクラスを生成する機能で、tailwind cssのようなユーティリティクラスを独自で作れるようになります。
これにより重複するCSSを減らせると思い使っていたのですが、使い方が微妙でした。
Reactのクライアントレンダリングと組み合わさった時、ビルド時にsprinklesで生成したCSSをDOMに適用するための全てのユーティリティクラスの情報を持ったJavaScriptが生成されていました。

今回は、sprinklesの旨みも使いたかったため、Reactによるクライアントレンダリングが必要な箇所にはsprinklesを利用しないという方針にしました。

また、実装時に必要そうなユーティリティクラスを大まかに生成していたため、使用していないユーティリティクラスも多少発生していました。こちらは、PurgeCSSというライブラリを使い、HTMLとJavaScriptを精査して、ビルド後に不要なものを削除してもらいました。

画像ファイルが重い

画像ファイルは主にpngを使っていたので、次世代フォーマットのwebpにsquoosh cliを使い、一括でwebpに置き換えました。

テキスト圧縮が無効

テキスト圧縮に関しては、もともと把握はしていたのですが、上記のPurgeCSSを利用している関係で、ビルド時にgzip化することが工数との兼ね合いで難しく悩んでいました。

ですがある日、ここまでのパフォーマンス改善のためにやったことをEngineering Mondayで話していたところ、バックエンドエンジニアの通称「おさかなさん」から、「インフラでcloudfront使ってるなら、cloudfrontの機能でgzip配信できる」と聞き、実施してみたところ思いの外簡単にテキスト圧縮がされた状態での配信が実現しました。Engineering Mondayについては、過去記事になっているのでぜひこちらの記事もご覧ください。

おわりに

他のチームの方の助けも得ながら、コツコツパフォーマンス改善をしてみた結果、冒頭の通りLighthouseで満点が出るまで改善できました。 それぞれは地味ですが、結果として積み上げていくと着実にパフォーマンス改善できることを改めて実感できました。

冒頭さらっと流してしまいましたが、新規の技術であってもチームで話し合って採用できる柔軟性はカンカクの強みだと感じています。
興味お持ちいただけた方は、ぜひ以下のリンクをご覧ください!
カジュアル面談からできますので、ご応募お待ちしております。

*1:Lighthouseの仕様で毎回満点とは限らないです。🙇