web.dev の Fast load times を読んだ
パフォーマンス改善のための基礎知識をつけるべく,Chrome Dev Summit 2018 で紹介された web.dev に書かれているドキュメントのうちパフォーマンスに関するもの
を一通り読んだので,簡単なまとめとして読書メモを書いた.
デブサミには幸運にも会社から派遣メンバーとして選ばれて参加したが,全体的にパフォーマンスに関する話題が多く,Google としてもパフォーマンス向上に力を入れていることが強いメッセージとして伝わってきた. web.dev はその啓蒙活動の一環としてドキュメントと Lighthouse の Web 版が提供されている.
Discover performance opportunities with Lighthouse
- lighthouse は metrics (現在のページのパフォーマンスの状態を表す指標) と opportunities (パフォーマンスの改善ポイント) を提供する
- web.dev または Chrome の DevTools から実行できる
- スコアについての詳細は https://developers.google.com/web/tools/lighthouse/v3/scoring に書かれている
- https://web.dev/measure から Profile にサイトを登録することで, daily に Lighthouse のレポートを測定してくれるようになる
Use Imagemin to compress images
- imagemin で適切に画像を圧縮する話
- ビルド時に毎回圧縮するのは無駄が多いので,画像追加時に一回だけやりたい
- PR 時に適切に圧縮されているかどうか調べたい
- GitHub Actions でチェックできるかも?
Replace animated GIFs with video for faster page loads
- ffmpeg で gif を webm/mp4 に変換して
video
タグに置き換えればファイルサイズがずっと小さくなる(例では1/10になっている)
Use lazysizes to lazyload images
- 画像を lazyload することについて
- Intersection Observer の活用を頑張らなければ...
Serve Responsive Images
- viewport の大きさごとに最適なサイズの画像を配信することについて
- sharp や ImageMagick を使うことで画像のリサイズが可能
img
要素のsrcset
属性で width descriptors を使うことでブラウザに画像サイズを伝えることができる- ブラウザ側が最適な大きさの画像を取得してくれる
- デバイスの解像度に応じて画像を変える density descriptors もある
- width descriptors を使う場合は
sizes
属性も同時に使う必要がある- 画像が表示される大きさをブラウザに伝える
picture
要素を使うとより細かい制御が行える
Serve images with correct dimensions
- 適切な画像サイズをどう判断したら良いかについて
- まずは不適切なサイズの画像を探す: Lighthouse の "Properly size images" audit で調べられる
- Good approach
- Better approach
- 絶対単位で大きさが指定されている場合
srcset
とsizes
属性を使ってデバイスの解像度に応じた適切な画像が配信されるようにする- おそらく density descriptors のことを指している
- 相対単位で大きさが指定されている場合
srcset
とsizes
属性を使ってスクリーンサイズに応じた適切な画像が配信されるようにする- おそらく width descriptors のことを指している
- 絶対単位で大きさが指定されている場合
Use WebP images
- webp は 25-35% ファイルサイズが小さく,YouTube ではページ読み込みが 10% 早くなった
- cwebp または Imagemin で生成可能
picture
要素を使って配置する- Lighthouse の "Serve images in next-gen formats" audit で調査可能
Apply instant loading with the PRPL pattern
- critical なリソースを preload する
<link rel=preload>
- リソースのリクエスト優先度をあげることができる
- First Paint をできる限り早く render する
- critical path にある JS, above-the-fold の CSS を inline 化する
- メンテナンスが難しい
- キャッシュが効かない
- https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery
- SSR する
- TTI が悪化する
- critical path にある JS, above-the-fold の CSS を inline 化する
- Service Worker を用いてアセットを pre-cache する
- 必要ないリソースは lazyload する
- Code splitting することで JS を lazyload できる
- 重要度の高い chunk は preload の設定をする
- 画像も lazyload できる
- Code splitting することで JS を lazyload できる
Preload critical assets to improve loading speed
<link rel=preload>
で優先度を上げられる- ブラウザがリソースを発見するのに時間がかかるものの first paint に重要なリソースに対して使うと効果が高い
- 例:
@font-face
に指定されるリソースは CSS のパースが終わらないとブラウザが認識できない
- 例:
- webpack は
/* webpackPreload: true */
を使うと preload を挿入できる
- ブラウザがリソースを発見するのに時間がかかるものの first paint に重要なリソースに対して使うと効果が高い
<link rel=prefetch>
: 現在のページのリクエストが全て完了した後に,次のページ遷移を高速化するための準備を定義できる/* webpackPrefetch: true */
もある
Reduce JavaScript payloads with code-splitting
- Code-splitting について
- route もしくは component レベルで splitting するのがシンプルな方法
Remove unused code
- Lighthouse の "Unused JavaScript" audit で実行されなかったコードを解析できる
- webpack-bundle-analyzer でバンドルに含まれるモジュールを可視化できる
- import する対象を限定したり,ライブラリ自体を使わないようにすることでコード量を減らせる
Minify and compress network payloads
- Minification
- UglifyJS
- Data compression
Serve modern code to modern browsers for faster page loads
@babel/preset-env
<script type=module>
- preset-env で
targets: esmodules: true
を設定すると ESM が使えるブラウザのみをターゲットにできる type=module
をセットすれば ESM を解釈できるブラウザのみを対象にファイルを配信できる
- preset-env で
Avoid invisible text during font loading
- "flash of invisible text" の代わりに "flash of unstyled text" を目指す
font-display: swap;
を使う- 対応ブラウザが限られる
- フォントファイルが読み込まれるまで system font を適用しておき,読み込まれたことをトリガーにして custom font を当てるようにする
Using the Chrome UX Report to look at performance in the field
- CrUX はオプトインしたユーザーから収集した実際の First Contentful Paint (FCP), DOM Content Loaded (DCL), First Input Delay (FID) のデータセット
- CrUX Dashboard, PageSpeed Insights, BigQuery の3つ手段でデータにアクセスできる
- CrUX Dashboard
- Data Studio を使ったパフォーマンスの時間変化を可視化できるツール
- PageSpeed Insights
- URL を指定すると直近30日間のデータを集約して表示する
- API もある
- BigQuery
- 自前でいろいろ分析したい時に
Using the CrUX Dashboard on Data Studio
- Data Studio の Community Connectors を基に作られているツール
- https://g.co/chromeuxdash にページの origin URL を入れれば dashboard を作成できる
- dashboard は FCP, デバイス分布,接続状況分布から構成されている
- FCP
- Fast (<1s), Average (1~2.5s), Slow (>2.5s) の比率が表示される
- デバイス分布
- 接続状況分布
- 4G, 3G, 2G, Slow 2G, Offline の比率が表示される
- これ以外のメトリクスや国ごとのデータなどを見たい場合は BigQuery を使う必要がある
Using the Chrome UX Report on PageSpeed Insights
- PageSpeed Insights は Lighthouse と CrUX の結果を一度に見られるようにしたもの
- Lab data (Lighthouse の結果) と Field data (CrUX のデータ) に分かれて表示される
- Field data には FCP と FID が Fast, Average, Slow に分けて表示される
- FCP: Fast (<1s), Average (1-2.5s), Slow (>2.5s)
- FID: Fast (<50ms), Average (50-250ms), Slow (>250ms)
- 入力したページのデータの他に, origin の結果(そのページが属する origin の全てのページのデータを集約したもの)も表示される
- PSI のデータは過去30日のもの.これは月単位でデータを集約する BigQuery とは集計の仕方が異なっているので注意する必要がある
- PSI は以下の利点がある
- ページ単位でのパフォーマンスが見られる唯一のツール
- 日単位でデータを集計してくれる唯一のツール
- API がある
- その代わり過去のデータは見られないし,メトリクスも FCP と FID しかない
Using the Chrome UX Report on BigQuery
- SQL を使って生データを解析できる
- 国ごとのデータ,月ごとのデータがテーブルとして提供されている
- 無料の範囲は1ヶ月あたり 1TB で,それ以降は $5/TB の料金がかかる
Performance budgets 101
- performance budgets
- パフォーマンスに影響するメトリクスに対する制限
- 設定した制限が,機能追加・デザイン・技術選定・ライブラリ選定を行う際の判断基準の一つになる
- 定量的なメトリクス
- Milestone timings
- ルールベースのメトリクス
- Lighthouse, WebPageTest が提供するスコア
- どうやって目標値を決定するのか?
- まずは計測してみる.競合のサイトのスコアも計測してみよう.
- もしそうした調査にかける時間がない場合には,TTI 5秒以下,critical path のリソースが 170KB 以下というのが一つの目安
- これは 3G の通信環境を考慮に入れて考えられた数字
- performance budget の値はページごとに異なりうる
- 使えるツール
- 継続的に数値を追うのがよい
Your first performance budget
Performance Budget の決め方について
- 最も重要なページがどこかを決める
- そのページのメトリクスを Lighthouse で測定する
- 競合のメトリクスを調査する
- 10サイトくらいは調査した方がいい
- milestone timings の budget を決める
- 20% ルールが有効
- レスポンスタイムに 20% の違いがあるとユーザーが気がつくという研究に基づく
- initial はまず現在の値から 20% 改善を目指し,最終的には競合より 20% よい値を目指す
- 他の種類の budget を決める
- 定量的メトリクス
- 一般的に critical path のリソースは 170KB 以下に保つべき
- 低スペックで 3G な環境でも快適になる
- 4G をターゲットにするならもう少し余裕ができる(表を参照)
- コンテンツの種類によっても変わってくるので,最終的な値はその辺りを考慮して決める必要がある
- e-commerce で画像が多いなら JS の制限をきつくするなど
- 一般的に critical path のリソースは 170KB 以下に保つべき
- ルールベースのメトリクス
- Lighthouse で 85 点以上など
- 優先度を考える
- ニュースサイトであれば FCP, 検索サイトであれば TTI など重要なメトリクスはサイトによって異なる
- CrUX で競合サイトの状況を見てみるのもよい
Incorporate performance budgets into your build process
Performance Budget をビルドプロセスに組み込む方法について
- Webpack Performance Hints
- 非圧縮のサイズなのに注意
- ただし圧縮は転送速度を早めるだけで,特にモバイルで顕著に影響する parse の速度を早めることはないので,非圧縮のサイズを気にすることも大事
- Bundlesize
- Lighthouse Bot
- Travis でしか使えないが,budget に違反している PR を block できる
Using bundlesize with Travis CI
- Travis で bundlesize を使う方法
- このページは正直 bundlesize の ReadMe を見れば充分 😗