【視聴メモ】Speed at Scale: Web Performance Tips and Tricks from the Trenches (Google I/O ’19)

この記事は Google I/O '19 のセッションの視聴メモです。
想定読者は自分なので正確性や網羅率には問題があるかもしれません。

---

## References

https://www.youtube.com/watch?v=YJGCZCaIZkQ

Speaker(s): Addy Osmani and Katie Hempenius

## Abstract

> Getting your site fast and keeping it fast can be a challenge at scale. Learn 15 tips and tricks that real, production sites use to get great scores on Lighthouse and improve core business metrics. Understand a spectrum of optimizations from latency optimization to JavaScript, preloading, prefetching, data-fetching, and more.

雰囲気訳

> Webサイトを速くして、それをキープするのはとても難しいです。このセッションでは実際のサービスがLighthouseで良スコアをキープし、ビジネス指標を向上させた15のチップスとトリックを学べます。また、JavaScriptのlatency optimizationや、preloading, prefetching, data-fetchingを理解できます。

## Contents

### Buttons

* 世の中には3種類の人間がいる
    * ボタンを押す人間と
    * ボタンを幼い人間、
    * そしてボタンを何十回も押すような人間だ
* Akamaiの調査によるとユーザーは表示にかかった時間の1.3倍の時間がかかる頃にはページが入力を受け付けることを期待している

### Performance budget

* 約40%のブランドがリリース後6ヶ月でパフォーマンスの悪化を招いている
* Performance budgetsはリソースサイズなどに超えてはいけない限度を設定することでユーザーに一定以上のサイトパフォーマンスを提供するという考え
    * 時間の例: < 2 second TTI
    * リソースの例: < 150KB JS
    * Lighthouseによる例: 90以上
*  Walmart Groceryの事例ではPRが1%以上のメインJSのファイルサイズ上昇を含んでいる場合、マージできずパフォーマンスエンジニアにIssueとして投げられるそう
*  TwitterではPRごとにどのページに影響を及ぼすか詳細に確認できるようになっている
*  **LightWallet**
    *  Lighthouseを用いてPerformance Budgetsを可視化するツール
    *  budget.jsonファイルであるURLに向けて実行する
        *  image, script, font, document, stylesheet, third-party という項目でリソースサイズとリソースの数を指定できる
*  Performance budget calculator
    *  JSとNon-JSソースの量からTTIを推測できるサービス
    *  TTIから逆算してbudget.jsonの中身を決めるのに使える
    *  下図のような感じ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3387/de5c7eb7-86a2-cee5-e591-c62f73b55c23.png)

### Images

* Lazy loading
    * 初期ロードの76%の画像データ量を削減する
    * すごい削減量だ（下図）
    * Native lazy loading が来ますよ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3387/565bd62f-200f-eed2-7ab2-cd385eeac265.png)

* Responsive Images
    * 画像サイズは表示領域のサイズが、画面の解像度で設定することができる
    * Retinaディスプレイ以上の解像度には対応する必要はない（人間の目の解像度をこえているため）
        * ただしフルスクリーンにしたりズームされる画像だったりした場合はその限りではない
* Image CDN
    * 画像のクエリパラメタにクオリティやサイズを指定できるCDNが多い → 便利

### JavaScript

* 57%の実行時間がサードパーティーのライブラリの実行時間に費やされている
* scriptタグにdeferを指定してHTMLのパースとJSのfetchingを並行して実行しよう
* Chromeの紹介ページで埋め込みビデオをLazyLoadするようにしたら
    * ロード時間が13.6s → 3.1sになった
    * Lighthouse Performance Scoreが27 → 96になった
    * 動画は絶対LazyLoadにしよう…

### 巨大なライブラリの排除

* Goodbye jQuery, moment.js, and Bootstrap
* そしてそれぞれ別のものを使おう
    * 1つの機能を使うためにこれらの巨大なライブラリを使うのは、果実を取るために木を切り倒すようなもの

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3387/a8e18e22-32d4-8495-3e63-3f9b4aa9fa60.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3387/d79de699-17dd-efb8-1414-13735b42e4b6.png)

* Reactの代わりにlit-html, Preact, Svelteを使う
* Reactを15.6.1から16.2.0に上げただけでもロード時間が100ms短くなったりした
    * とにかく最新ライブラリを使おう

### Code-splitting & Component Loading

* Download → Render というシンプルな処理ではなく
    * Download → Render & Download → Render & Download → … と並列に実行したい
    * ネットワークのボトルネックとCPUのボトルネックがあるため
* そしてコンマリ…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3387/0aad5c5d-e98b-bb49-e2f7-3adfd447eebf.png)

### Fonts

* Fontが読み込まれない場合、Safariではテキストは表示されない
    * それ以外のブラウザでも表示までに3秒待つ
* `font-display: swap;` で代替フォントを使おう
* GoogleFontsが`font-display`に対応した
    * クエリパラメタで`font-display=swap`を指定すると`font-display: swap`が指定されたCSSが帰ってくる

### Resource Hints

* quicklinkでページ遷移が2.7s速くなった
* ebayでは検索結果の上位5件をPrefetchしている
    * このコールバックは`requestIdleCallback`でリソースに余裕があるときに実行される
    * ページ遷移が759ms速くなった（1.1s → 0.39s)
* Virgilio Sports
    * ユーザーにもっともクリックされている記事を7分ごとに更新してSWでプリフェッチしている
    * ネットワークが2Gでない場合のみ

### Critical CSS

* First Contentfull Paintに影響を与えるようなCSSがCritical CSS
* TUIはCritical CSSをインライン化することで高速化を図った
* Nikkei
    * URLとデバイスビューポート、またログイン状態、購読状態などに応じてCSSの出し分けを行った
    * Critical CSSは300KB以下に収めた
* Edge Side Inclusion
    * CDNでCritical CSSをインライン化する技術
    * CSSをブラウザレベルではなくCDNレベルでキャッシングできるのが嬉しい
    * NikkeiではFCPが1s改善し、インラインCSSは80%減少した

### Brotli

* Brotliはgzipより優れたテキスト圧縮アルゴリズム
* OYOではJSサイズが15%減少し、37%の遅延時間が改善した

### Adaptive serving

* ネットワークの状況に応じて適切な解像度のリソースを配信するべき
* `navigator.connection.effectiveType` や `navigator.connection.saveData` でどういったネットワークかはわかる
* Twitterのデータセーバーとかがそういう事例
* Twitterはクライアントサイドのイメージ圧縮を行っている
* ebayでは商品の詳細画像についてはネットワークに余裕があるユーザーだけLazyLoadで表示時に読み込んでいる
    * 表示する検索結果の数もネットワークの太さによって変えている

### Get Fast & Stay Fast

* web.dev/fast
* bit.ly/lightwallet-docs

## Memo

* ebayでの`requestIdleCallabck`で検索結果をPrefetchする戦略は一般的なテクとして使えそうで良さそう
* Prefetchの戦略はサービスの特色ごとにまったく異なるので、それを考えるのも面白そう
* ただしPrefetchはネットワークに余裕があるユーザーだけの戦略だということは肝に銘じたい