はじめに

今月の目標に このサイトの Lighthouse で スコアを全部緑色にする もあったので、改善を行った。 気を付けた点などをまとめていく

基本方針

  • できるだけロードを遅延する
  • レスポンスサイズを小さくする
  • JS をできるだけ動かさない
  • レイアウトシフトを起こさない

逆を返すと上記の問題があったためスコアが悪かったようだった。

できるだけロードを遅延する

画像の lazy load を実装した。つくりはそんなに難しくなくて、

  1. デフォルトでは 1px のプレースホルダイメージ (base64 エンコードしてインラインに記述している) を表示しておく。
  2. IntersectionObserver を使って ViewPort に入ったら Image オブジェクトを生成して対象画像をロードする。
  3. ロードが完了したら (Image オブジェクトの onload コールバック) 、画像の URL を差し替えればいい。
  4. IntersectionObserver の Observe を解除する

JS も基本的に Dynamic import するようにしているけど、それほどたくさんの JS 処理を要求しているわけではないので、そんなに効いていないと思う。

レスポンスサイズを小さくする

もともと、先日の改良で tailwindcss + PurgeCSS + scoped-css を使って、必要な CSS だけにしていた。 しかし、以下が気になっていた。

  • クラスがたくさんついている
  • クラス名が長い (BEM に比べれば短いけど)

ブラウザの処理でどれくらいの時間を占めるのかは正直詳しくわかっていないけど、 複数のクラスのルールを解釈して割り当てるよりも単一のクラスがついているほうが早かろうと思った。

あと、クラス数が減れば HTML のサイズが小さくなる。 (クラスの種類が減ればその分ルールが増えるのでその辺がどうなるかはその時によるだろうけど)

以下のようにした。

  • css-module に変更して、クラス名を 4 文字に変換させる
  • @applytailwindcss のルールを利用する

これで、 tailwindcss の恩恵を受けながら大半のエレメントに対して一つのクラスだけがついている状態になった。

JS をできるだけ動かさない

SSR について詳しくなかったのだけど、サーバサイドで HTML を生成してからクライアントサイドで、Vue コンポーネントをレンダリングされた HTML にマウントさせるようだった (こうしないとクライアントサイドでコンポーネントが動かない)。

これをハイドレーションというらしい。当然このタイミングで JS の処理が走るのでこれが大きいようならパフォーマンスに影響がでる。 動的に変化しないコンポーネントについては、そもそもハイドレーションを発生させないことでパフォーマンスの改善ができる。 あるいは、遅延させることで FCP などに対して寄与する。

以下のライブラリを使って、スタティックで問題ないコンポーネントについては、ハイドレーションをさせないようにした。

https://github.com/maoberlehner/vue-lazy-hydration

また、 JS のダイナミックインポートもここに寄与する。

レイアウトシフトを起こさない

一度ブラウザにレイアウトさせた後に、データの更新などで、表示を置き換える必要があるとパフォーマンスに影響がある。

このサイトは大体スタティックだから関係ないと思っていたのだけどレイアウトシフトが起きていた。

具体的には、マークアップがおかしいところがあってそれで発生していた。

<a>
  <div>foo</div>
  <div>
    <a>bar</a>
  </div>
</a>

こんなマークアップしてしまうと、アンカータグの中にアンカータグが入ってはいけないので、

<a>
  <div>foo</div>
</a>
<div>
  <a>bar</a>
</div>

ブラウザではこんな風になってしまった。 で、いったんこの状態でレンダリングされた後で、JS の処理とかが入って、再レンダリングされて元の意図した状態になる。 みたいな感じになっていた。

つまり、最初のレンダリング結果は意図したものじゃないのに、いったんレンダリングされてしまい、画面は崩れた状態にいったんなる。 それで、しばらく時間がたったら意図した状態に直る。みたいな動きしてた。

具体的にはブログページの記事一覧がその状態だった。記事のタグを表示していたのだけど、これがリンクだったということを意識していなくて、リンクが入れ子になってしまっていた。

そのほか

いい機会だったのでCI で Lighthouse 動かすようにした。

Lighthouse CI を使ってもよかったのだけど、外部ストレージにレポートを置けなかったり自分でレポートサーバを用意できないこともあると思うので、あえて CLI の lighthouse を使って自分でレポート出すようにした。

まとめ

使用していないスクリプトの削除などの指摘は nuxt に対するものなので解消できないけど、やることやったら改善できることが分かってよかった。

以下に、各ページのスコアを貼っておく。

  • トップページ
  • ブログ一覧ページ
  • About ページ

いずれも Page Speed Insights でとった。

sterashima78

Web Frontend Engineer


© 2020 - 2021 — Terashima Shin