コアWebバイタルをどのように改善したか(ケーススタディ)
公開: 2022-03-10昨年、グーグルはコアウェブバイタルの重要性と、それらがウェブ上のサイトを訪問するときの人の実際の経験をどのように反映するかを強調し始めました。 パフォーマンスは、当社のインスタントドメイン検索のコア機能であり、その名のとおりです。 私たちのバイタルスコアが多くの人にとって素晴らしいものではなかったことがわかったときの驚きを想像してみてください。 私たちの高速コンピューターとファイバーインターネットは、実際の人々が私たちのサイトで経験することを覆い隠していました。 Google検索コンソールの赤い「悪い」と黄色の「改善が必要」の通知の海が私たちの注意を必要とするようになるまで、そう長くはかかりませんでした。 エントロピーが勝ったので、ジャンクをクリーンアップする方法を見つけ、サイトを高速化する必要がありました。
私は2005年にInstantDomainSearchを設立し、Facebookでソフトウェアエンジニアとして働く前に、Y Combinatorの会社(Snipshot、W06)で働いている間、サイドハッスルとしてそれを維持しました。 私たちは最近、主にカナダのビクトリアに拠点を置く小さなグループに成長し、新機能とパフォーマンスの改善の長いバックログに取り組んでいます。 私たちの貧弱なウェブバイタルスコアと迫り来るグーグルアップデートは、これらの問題を見つけて修正することに私たちの焦点をもたらしました。
サイトの最初のバージョンが立ち上げられたとき、私はPHP、MySQL、およびXMLHttpRequestを使用してサイトを構築していました。 Internet Explorer 6は完全にサポートされ、Firefoxはシェアを獲得し、Chromeは発売からまだ何年も経っていました。 時間の経過とともに、さまざまな静的サイトジェネレーター、JavaScriptフレームワーク、およびサーバーテクノロジーを通じて進化してきました。 現在のフロントエンドスタックは、Next.jsで提供されるReactと、ドメイン名検索に応答するための組み込みのRustであるバックエンドサービスです。 CDNを介してできる限り多くのサービスを提供し、サードパーティのスクリプトをできるだけ避け、ビットマップPNGの代わりに単純なSVGグラフィックを使用することで、ベストプラクティスに従うようにしています。 それは十分ではありませんでした。
Next.jsを使用すると、ReactとTypeScriptでページとコンポーネントを作成できます。 VS Codeと組み合わせると、開発エクスペリエンスは素晴らしいものになります。 Next.jsは通常、Reactコンポーネントを静的HTMLおよびCSSに変換することで機能します。 このようにして、最初のコンテンツをCDNから提供し、次にNextがページを「ハイドレイト」して要素を動的にすることができます。 ページがハイドレイトされると、私たちのサイトは、人々がドメイン名を検索して生成できる単一ページのアプリに変わります。 Next.jsに依存してサーバー側の作業を行うことはほとんどありません。コンテンツの大部分は、CDNから提供されるHTML、CSS、およびJavaScriptとして静的にエクスポートされます。
誰かがドメイン名の検索を開始すると、ページのコンテンツが検索結果に置き換えられます。 検索を可能な限り高速化するために、フロントエンドは、ドメインのルックアップと提案用に大幅に最適化されたRustバックエンドに直接クエリを実行します。 多くのクエリは即座に回答できますが、一部のTLDでは、解決に1〜2秒かかる可能性のある低速のDNSクエリを実行する必要があります。 これらの遅いクエリの一部が解決したら、新しい情報が入ってくるとUIを更新します。結果ページは人によって異なり、各人がサイトをどのように体験するかを正確に予測するのは難しい場合があります。
Chrome DevToolsは優れており、パフォーマンスの問題を追跡するときに開始するのに適した場所です。 パフォーマンスビューには、HTTPリクエストが送信されるタイミング、ブラウザがJavaScriptの評価に時間を費やす場所などが正確に表示されます。
今後の検索アルゴリズムの更新でサイトをランク付けするためにGoogleが使用する3つのコアWebバイタルメトリックがあります。 Googleは、実際のユーザーがサイトで持っているLCP、FID、およびCLSスコアに基づいて、エクスペリエンスを「良い」、「改善が必要」、「悪い」に分類します。
- LCP (Largest Contentful Paint)は、最大のコンテンツ要素が表示されるまでにかかる時間を定義します。
- FID (First Input Delay)は、インタラクションに対するサイトの応答性(インターフェイスでのタップ、クリック、またはキー押下とページからの応答の間の時間)に関連しています。
- CLS (累積レイアウトシフト)は、キーボードやクリックイベントなどのアクションがない場合に、要素がページ上でどのように移動またはシフトするかを追跡します。
Chromeは、ログインしているすべてのChromeユーザーにわたってこれらの指標を追跡するように設定されており、サイトでの顧客エクスペリエンスを要約した匿名の統計情報をGoogleに送信して評価します。 これらのスコアは、Chromeユーザーエクスペリエンスレポートからアクセスでき、PageSpeedInsightsツールを使用してURLを検査すると表示されます。 スコアは、過去28日間にそのURLにアクセスしたユーザーの75パーセンタイルエクスペリエンスを表しています。 これは、アップデートでサイトをランク付けするために使用する番号です。
75パーセンタイル(p75)メトリックは、パフォーマンス目標の妥当なバランスを取ります。 たとえば、平均を取ると、人々が経験する多くの悪い経験を隠すことになります。 中央値、つまり50パーセンタイル(p50)は、当社の製品を使用している人々の半数がより悪い経験をしていることを意味します。 一方、95パーセンタイル(p95)は、接続が不安定な古いデバイスで極端な外れ値を多くキャプチャするため、構築が困難です。 75パーセンタイルに基づくスコアリングは、満たすのに適切な基準であると考えています。
スコアを管理するために、まずChromeに組み込まれ、web.dev /measure/とPageSpeedInsightsでホストされている優れたツールをLighthouseに依頼しました。 これらのツールは、私たちのサイトに関するいくつかの広範な技術的問題を見つけるのに役立ちました。 Next.jsがCSSをバンドルし、最初のレンダリング時間を遅くして、FIDに影響を与えていることがわかりました。 最初の簡単な勝利は、実験的なNext.js機能であるoptimizeCssからもたらされました。これは、一般的なパフォーマンススコアを大幅に向上させるのに役立ちました。
Lighthouseは、静的アセットの一部がCDNから提供されない原因となるキャッシュの設定ミスも検出しました。 Google Cloud Platformでホストされており、Google Cloud CDNでは、Cache-Controlヘッダーに「public」が含まれている必要があります。 Next.jsでは、出力するすべてのヘッダーを構成できないため、Goに実装されている軽量のHTTPプロキシサーバーであるCaddyの背後にNext.jsサーバーを配置してヘッダーをオーバーライドする必要がありました。 また、CDNがオリジン(Next.jsサーバー)からバックグラウンドで非同期にコンテンツをフェッチできるようにする、最新のブラウザーでの比較的新しいstale-while-revalidateサポートで可能なことを確実に提供する機会を得ました。
npmから製品に必要なほとんどすべてのものを追加するのは簡単です(多分簡単すぎるかもしれません)。 バンドルサイズが大きくなるのにそれほど時間はかかりません。 大きなバンドルは低速ネットワークでのダウンロードに時間がかかり、75パーセンタイルの携帯電話は、ダウンロードしたばかりのすべてのコードを理解しようとする間、メインUIスレッドのブロックに多くの時間を費やします。 npmパッケージがバンドルに追加する依存関係とバイト数を表示する無料ツールであるBundlePhobiaが気に入りました。 これにより、多くのreact-springを利用したアニメーションを削除するか、より単純なCSSトランジションに置き換えることになりました。
BundlePhobiaとLighthouseを使用することで、サードパーティのエラーロギングおよび分析ソフトウェアがバンドルサイズとロード時間に大きく貢献していることがわかりました。 これらのツールを削除して、sendBeaconやpingなどの最新のブラウザーAPIを利用する独自のクライアント側ロギングに置き換えました。 ロギングと分析を独自のGoogleBigQueryインフラストラクチャに送信します。このインフラストラクチャでは、既成のツールが提供できるよりも詳細に関心のある質問に答えることができます。 これにより、多くのサードパーティCookieも排除され、クライアントからログデータを送信する方法とタイミングをはるかに細かく制御できます。
私たちのCLSスコアには、まだ改善の余地があります。 GoogleがCLSを計算する方法は複雑です。最初のページの読み込みから、またはキーボードやクリック操作から5秒を上限として、1秒のギャップがある最大の「セッションウィンドウ」が与えられ、サイト内で物事を移動し終えます。 。 このトピックをさらに深く読むことに興味がある場合は、このトピックに関する優れたガイドをご覧ください。 これにより、サイトにアクセスした直後に表示される多くの種類のオーバーレイやポップアップにペナルティが課せられます。 たとえば、コンテンツを移動する広告や、過去の広告をスクロールしてコンテンツに到達したときに表示される可能性のあるアップセル。 この記事では、CLSスコアの計算方法とその背後にある理由について優れた説明を提供します。
私たちはこの種のデジタルクラッターに根本的に反対しているので、Googleが私たちにどれだけの改善の余地があると主張したかを見て驚いた。 ChromeにはWebVitalsオーバーレイが組み込まれており、コマンドメニューを使用して「CoreWebVitalsオーバーレイを表示」することでアクセスできます。 ChromeがCLS計算でどの要素を考慮するかを正確に確認するには、設定のChromeWebVitals拡張機能の「コンソールログ」オプションがより役立つことがわかりました。 有効にすると、このプラグインは現在のページのLCP、FID、およびCLSスコアを表示します。 コンソールから、ページ上のどの要素がこれらのスコアに関連しているかを正確に確認できます。 私たちのCLSスコアには、改善の余地が最もありました。
3つのメトリックのうち、CLSは、ページを操作するときに蓄積される唯一のメトリックです。 Web Vitals拡張機能には、製品との対話中にCLSを引き起こす要素を正確に示すロギングオプションがあります。 Smashing Magazineのホームページをスクロールすると、CLSメトリックがどのように追加されるかを確認してください。
グーグルは時間の経過とともにCLSの計算方法を調整し続けるので、グーグルのウェブ開発ブログをフォローして最新情報を入手することが重要です。 Chrome Web Vitals拡張機能などのツールを使用する場合、より現実的なエクスペリエンスを得るには、CPUとネットワークのスロットリングを有効にすることが重要です。 モバイルCPUをシミュレートすることにより、開発者ツールを使用してこれを行うことができます。
あるデプロイから次のデプロイまでの進行状況を追跡する最良の方法は、Googleと同じ方法でページエクスペリエンスを測定することです。 Google Analyticsを設定している場合、これを行う簡単な方法は、Googleのweb-vitalsモジュールをインストールし、それをGoogleAnalyticsに接続することです。 これにより、進捗状況の大まかな測定値が提供され、GoogleAnalyticsダッシュボードに表示されます。
これが私たちが壁にぶつかったところです。 CLSスコアを確認できました。大幅に改善しましたが、まだやるべきことがありました。 CLSスコアは約0.23であり、これを0.1未満、できれば0まで下げる必要がありました。ただし、この時点では、どのページのどのコンポーネントがまだスコアに影響を与えているかを正確に示すものは見つかりませんでした。 ChromeはCoreWebVitalsツールで多くの詳細を公開しましたが、ロギングアグリゲーターが最も重要な部分、つまり問題の原因となったページ要素を正確に破棄したことがわかりました。
必要なすべての詳細をキャプチャするために、ブラウザからWebバイタルデータをキャプチャするサーバーレス関数を構築しました。 データに対してリアルタイムクエリを実行する必要がないため、データをGoogleBigQueryのストリーミングAPIにストリーミングして保存します。 このアーキテクチャは、生成できる限り多くのデータポイントを安価にキャプチャできることを意味します。
Web VitalsとBigQueryを使用していくつかのレッスンを学んだ後、この機能をバンドルし、これらのツールをvitals.devでオープンソースとしてリリースすることにしました。
Instant Vitalsを使用すると、BigQueryでWebVitalsスコアの追跡を開始できます。 作成するBigQueryテーブルスキーマの例を次に示します。
インスタントバイタルとの統合は簡単です。 クライアントライブラリと統合して、バックエンドまたはサーバーレス関数にデータを送信することから始めることができます。
import { init } from "@instantdomain/vitals-client"; init({ endpoint: "/api/web-vitals" });
次に、サーバー上でサーバーライブラリと統合して、回路を完成させることができます。
import fs from "fs"; import { init, streamVitals } from "@instantdomain/vitals-server"; // Google libraries require service key as path to file const GOOGLE_SERVICE_KEY = process.env.GOOGLE_SERVICE_KEY; process.env.GOOGLE_APPLICATION_CREDENTIALS = "/tmp/goog_creds"; fs.writeFileSync( process.env.GOOGLE_APPLICATION_CREDENTIALS, GOOGLE_SERVICE_KEY ); const DATASET_; init({ datasetId: DATASET_ID }).then().catch(console.error); // Request handler export default async (req, res) => { const body = JSON.parse(req.body); await streamVitals(body, body.name); res.status(200).end(); };
リクエストの本文と指標の名前を指定してstreamVitals
を呼び出すだけで、指標をBigQueryに送信できます。 ライブラリは、データセットとテーブルの作成を処理します。
1日分のデータを収集した後、次のようにこのクエリを実行しました。
SELECT `<project_name>.web_vitals.CLS`.Value, Node FROM `<project_name>.web_vitals.CLS` JOIN UNNEST(Entries) AS Entry JOIN UNNEST(Entry.Sources) WHERE Node != "" ORDER BY value LIMIT 10
このクエリは、次のような結果を生成します。
価値 | ノード |
---|---|
4.6045324800736724E-4 | /html/body/div[1]/main/div/div/div[2]/div/div/blockquote |
7.183070668914928E-4 | /html/body/div[1]/header/div/div/header/div |
0.031002668277977697 | /html/body/div[1]/footer |
0.035830703317463526 | /html/body/div[1]/main/div/div/div[2] |
0.035830703317463526 | /html/body/div[1]/footer |
0.035830703317463526 | /html/body/div[1]/main/div/div/div[2] |
0.035830703317463526 | /html/body/div[1]/main/div/div/div[2] |
0.035830703317463526 | /html/body/div[1]/footer |
0.035830703317463526 | /html/body/div[1]/footer |
0.03988482067913317 | /html/body/div[1]/footer |
これにより、どのページのどの要素がCLSに最も影響を与えるかがわかります。 それは私たちのチームが調査して修正するためのパンチリストを作成しました。 インスタントドメイン検索では、モバイル接続が遅いか悪い場合、検索結果の一部を読み込むのに500ミリ秒以上かかることがわかります。 これらのユーザーのCLSへの最悪の貢献者の1つは、実際には私たちのフッターでした。
レイアウトシフトスコアは、移動する要素のサイズとその移動距離の関数として計算されます。 検索結果ビューでは、デバイスが検索結果を受信してレンダリングするのに一定以上の時間がかかる場合、結果ビューはzero-height
に折りたたまれ、フッターが表示されます。 結果が表示されると、フッターがページの下部に押し戻されます。 ここまで移動する大きなDOM要素は、CLSスコアに多くを追加しました。 これを適切に処理するには、検索結果の収集とレンダリングの方法を再構築する必要があります。 低速の接続でフッターが跳ね返るのを防ぐための簡単なハックとして、検索結果ビューのフッターを削除することにしました。
現在、このレポートを定期的に確認して、どのように改善しているかを追跡し、前進するにつれて減少する結果と戦うために使用しています。 私たちは、サイトで新しくリリースされた機能や製品に特別な注意を払うことの価値を目の当たりにし、コアバイタルが私たちのランキングに有利に働いていることを確認するための一貫したチェックを運用しました。 Instant Vitalsを共有することで、他の開発者がCoreWebVitalsのスコアに取り組むのに役立つことを願っています。
GoogleはChromeに組み込まれた優れたパフォーマンスツールを提供しており、それらを使用して多くのパフォーマンスの問題を見つけて修正しました。 Googleから提供されたフィールドデータは、p75の進捗状況の良い要約を提供していることを知りましたが、実用的な詳細はありませんでした。 どのDOM要素がレイアウトシフトと入力遅延を引き起こしているかを正確に特定する必要がありました。 XPathクエリを使用して独自のフィールドデータの収集を開始すると、サイトでのすべてのユーザーのエクスペリエンスを向上させる特定の機会を特定することができました。 6月のページエクスペリエンスの更新に備えて、ある程度の努力を払って、実際のCoreWebVitalsフィールドスコアを許容範囲に下げました。 これらの数字が右下に下がるのを見てうれしいです!