HTML のクライアントサイド レンダリングとインタラクティビティ

JavaScript を使用した HTML のレンダリングは、サーバーから送信された HTML のレンダリングとは異なるため、パフォーマンスに影響する可能性があります。このガイドでは、その違いと、ウェブサイトのレンダリング パフォーマンスを維持するために、特にインタラクションが懸念される場合に何ができるかについて説明します。

HTML の解析とレンダリングは、「従来のページ読み込み」と呼ばれる、ブラウザに組み込まれたナビゲーション ロジックを使用するウェブサイトにおいて、デフォルトで適切に行われる処理です。「ハードなナビゲーション」を 避ける必要がありますこのようなウェブサイトは、マルチページ アプリケーション(MPA)と呼ばれることもあります。

ただし、デベロッパーはアプリケーションのニーズに応じてブラウザのデフォルト設定を回避する場合があります。これはシングルページ アプリケーション(SPA)パターンを使用しているウェブサイトの場合ではありますが、このパターンでは、JavaScript によって HTML や DOM の大部分が動的に動的に作成されます。クライアントサイド レンダリングはこのデザイン パターンの名前で、作業が過剰な場合は、ウェブサイトの Interaction to Next Paint(INP) に影響を与える可能性があります。

このガイドでは、サーバーからブラウザに送信される HTML を使用する場合と、クライアントで JavaScript を使用して HTML を作成する場合の違いや、重要な場面でインタラクションのレイテンシが増大するかどうかを検討するのに役立ちます。

サーバーから提供された HTML をブラウザがレンダリングする方法

従来のページ読み込みで使用されるナビゲーション パターンでは、ナビゲーションのたびにサーバーから HTML を受け取る必要があります。ブラウザのアドレスバーに URL を入力するか、MPA のリンクをクリックすると、次の一連のイベントが発生します。

  1. ブラウザは、指定された URL へのナビゲーション リクエストを送信します。
  2. サーバーは HTML をチャンク形式で応答します。

その最後のステップが鍵となります。また、サーバーとブラウザの交換における最も基本的なパフォーマンス最適化の 1 つで、ストリーミングと呼ばれます。サーバーができるだけ早く HTML の送信を開始でき、ブラウザが応答全体の到着を待たないと、ブラウザは到着時に HTML をチャンクに分割して処理できます。

<ph type="x-smartling-placeholder">
</ph> サーバーから送信された HTML の解析を示す Chrome DevTools のパフォーマンス パネルのスクリーンショット。HTML がストリーミングされると、そのチャンクが複数の短いタスクで処理され、レンダリングが段階的に行われます。 <ph type="x-smartling-placeholder">
</ph> サーバーから提供された HTML の解析とレンダリング(Chrome DevTools のパフォーマンス パネルに表示されているとおり)。HTML の解析とレンダリングに関わるタスクは、いくつかのチャンクに分割されます。

ブラウザで行われるほとんどのことと同様に、HTML の解析はタスク内で行われます。HTML がサーバーからブラウザにストリーミングされるとき、ブラウザはストリームの一部がチャンクで到着するにつれて、少しずつ HTML の解析を最適化します。その結果、ブラウザは各チャンクの処理後に定期的にメインスレッドに戻るため、長時間のタスクを回避できます。つまり、HTML の解析中に他の処理(ページをユーザーに表示するために必要な増分レンダリング作業や、ページの重要な起動期間中に発生する可能性のあるユーザー操作の処理など)が発生する可能性があります。このアプローチにより、ページの Interaction to Next Paint(INP) スコアが向上します。

つまり、サーバーから HTML をストリーミングすると、HTML の段階的な解析とレンダリング、およびメインスレッドへの自動変換が無料で行われます。これは、クライアントサイド レンダリングでは得られません。

JavaScript により提供される HTML をブラウザがレンダリングする方法

ページへのナビゲーション リクエストには毎回、サーバーからある程度の HTML が必要になりますが、一部のウェブサイトでは SPA パターンが使用されます。このアプローチでは多くの場合、サーバーによって提供される HTML の初期ペイロードが最小限で済みますが、その後、クライアントはサーバーから取得したデータで構成された HTML をページのメイン コンテンツ領域に入力します。その後のナビゲーション(「ソフト ナビゲーション」と呼ばれることもあります)すべて JavaScript によって処理され、ページに新しい HTML が挿入されます。

クライアントサイド レンダリングは、HTML が JavaScript を通じて DOM に動的に追加される、より限定的なケースで、SPA 以外でも行われることがあります。

一般的に、HTML を作成する方法や JavaScript を使用して DOM に追加する方法はいくつかあります。

  1. innerHTML プロパティを使用すると、ブラウザが解析して DOM に変換する文字列を使って、既存の要素のコンテンツを設定できます。
  2. document.createElement メソッドを使用すると、ブラウザの HTML 解析を行わずに、DOM に追加する新しい要素を作成できます。
  3. document.write メソッドを使用すると、ドキュメントに HTML を書き込むことができます(1 つ目の方法と同様に、ブラウザがそれを解析します)。ただし、さまざまな理由により、document.write は使用しないことを強くおすすめします。
で確認できます。 <ph type="x-smartling-placeholder">
</ph> Chrome DevTools のパフォーマンス パネルに表示された、JavaScript でレンダリングされた HTML の解析結果のスクリーンショット。処理は、メインスレッドをブロックする単一の長いタスクで行われます。
Chrome DevTools のパフォーマンス パネルに表示されているような、クライアント上の JavaScript による HTML の解析とレンダリング。解析とレンダリングに関連するタスクがチャンク化されないため、メインスレッドをブロックするタスクが長くなります。

クライアントサイドの JavaScript を使用して HTML/DOM を作成すると、次のような影響が生じる可能性があります。

  • ナビゲーション リクエストに応じてサーバーがストリーミングする HTML とは異なり、クライアント上の JavaScript タスクは自動的にチャンク化されないため、長いタスクがメインスレッドをブロックする可能性があります。つまり、クライアントで一度に作成する HTML/DOM の数が多すぎると、ページの INP に悪影響が及ぶ可能性があります。
  • 起動時にクライアントで HTML が作成されている場合、クライアント内で参照されているリソースはブラウザのプリロード スキャナで検出されません。これは、ページの Largest Contentful Paint(LCP)に間違いなく悪影響を及ぼします。これはランタイム パフォーマンスの問題ではありませんが(重要なリソースの取得におけるネットワーク遅延の問題)、この基本的なブラウザ パフォーマンスの最適化を回避することでウェブサイトの LCP に影響が及ぶことは望ましくありません。

クライアント側レンダリングのパフォーマンスへの影響に対して可能な対応

ウェブサイトがクライアントサイド レンダリングに大きく依存しており、フィールド データの INP 値が低い場合は、クライアントサイド レンダリングが問題に関係しているかどうか疑問に思うかもしれません。たとえば、ウェブサイトが SPA の場合、フィールド データからかなりのレンダリング処理に関与しているインタラクションが明らかになることがあります。

いずれにせよ、事象を軌道に乗せるために役立つ可能性のある原因をいくつか紹介します。

サーバーからの HTML をできるだけ多く提供する

前述のように、ブラウザはサーバーからの HTML をデフォルトで非常に高いパフォーマンスで処理します。HTML の解析とレンダリングを分割して長いタスクを避け、メインスレッドの合計時間を最適化します。このため、Total Blocking Time(TBT)が短くなり、TBT は INP と強く相関します

ウェブサイトの構築にフロントエンド フレームワークを使用している可能性があります。サーバー上でコンポーネント HTML をレンダリングするようにしてください。これにより、ウェブサイトで最初に必要となるクライアントサイド レンダリングの量が制限され、エクスペリエンスが向上します。

  • React では、Server DOM API を使ってサーバー上で HTML をレンダリングできます。ただし、サーバーサイド レンダリングの従来の方法は同期アプローチを使用しているため、Time to First Byte(TTFB)が長くなり、First Contentful Paint(FCP)や LCP などの指標が長くなる可能性があります。サーバーができるだけ早くブラウザへの HTML のストリーミングを開始できるように、可能な限り Node.js またはその他の JavaScript ランタイム用のストリーミング API を使用するようにしてください。Next.js は React ベースのフレームワークであり、デフォルトで多くのベスト プラクティスを提供しています。サーバーで HTML を自動的にレンダリングするだけでなく、ユーザーのコンテキスト(認証など)に応じて変化しないページの HTML を静的に生成することもできます。
  • Vue は、デフォルトでクライアント側のレンダリングも実行します。ただし、React と同様に、Vue でもサーバー上でコンポーネントの HTML をレンダリングできます。可能であれば、これらのサーバーサイド API を活用するか、ベスト プラクティスを実装しやすくするために、Vue プロジェクトで上位レベルの抽象化を検討してください。
  • Svelte はデフォルトでサーバーで HTML をレンダリングしますが、コンポーネントのコードでブラウザ専用の名前空間(window など)にアクセスする必要がある場合、そのコンポーネントの HTML をサーバー上でレンダリングできないことがあります。クライアント側で不必要なレンダリングが発生しないように、できる限り別の方法を検討しましょう。SvelteKit(Svelte にとっては Next.js は React 向け)であり、Svelte プロジェクトにできるだけ多くのベスト プラクティスが組み込まれているため、Svelte のみを使用するプロジェクトで起こり得る問題を回避できます。
で確認できます。

クライアントで作成する DOM ノードの数を制限する

DOM が大きい場合、そのレンダリングに必要な処理は増大する傾向があります。ウェブサイトが本格的な SPA である場合も、MPA とのやり取りの結果として既存の DOM に新しいノードを挿入する場合も、その DOM はできる限り小さくすることを検討します。これにより、クライアントサイド レンダリングで HTML を表示するために必要な作業が減り、ウェブサイトの INP を低く抑えることができます。

ストリーミング Service Worker アーキテクチャを検討する

これは高度な手法であり、すべてのユースケースで簡単に機能するわけではありませんが、ユーザーがページ間を移動したときに MPA が瞬時に読み込まれるようなウェブサイトに変えることができます。Service Worker を使用してウェブサイトの静的部分を CacheStorage に事前キャッシュし、ReadableStream API を使用してページの残りの HTML をサーバーから取得できます。

この手法がうまく機能すると、クライアント上で HTML を作成しなくても、キャッシュからコンテンツの一部を即座に読み込むことで、サイトが迅速に読み込まれるように見えます。このアプローチを採用しているウェブサイトは SPA のように感じられますが、クライアントサイド レンダリングの欠点はありません。また、サーバーにリクエストする HTML の量を減らすこともできます。

要するに、ストリーミング Service Worker アーキテクチャは、ブラウザに組み込まれたナビゲーション ロジックを取ってするものではありません。追加します。Workbox でこれを実現する方法について詳しくは、ストリームによる複数ページのアプリケーションを高速化するをご覧ください。

まとめ

ウェブサイトで HTML を受信してレンダリングする方法は、パフォーマンスに影響します。ウェブサイトの機能に必要な HTML のすべて(または大部分)の送信をサーバーに依存している場合は、増分解析とレンダリング、長いタスクを回避するためのメインスレッドへの自動 yield など、多くの機能を無料で利用できます。

クライアントサイドの HTML レンダリングでは、多くの場合、回避可能なパフォーマンス上の潜在的な問題が発生します。ただし、個々のウェブサイトの要件により、完全に回避できるとは限りません。クライアントサイトでの過度なレンダリングによって生じる時間のかかるタスクを軽減するには、可能な限り多くのウェブサイトの HTML をサーバーから送信し、クライアントでレンダリングする必要がある HTML の DOM サイズをできる限り小さくします。また、サーバーから読み込まれる HTML の段階的な解析とレンダリングを活用すると同時に、クライアントへの HTML の配信を高速化できる代替アーキテクチャを検討してください。

ウェブサイトのクライアントサイド レンダリングを最小限に抑えることができれば、ウェブサイトの INP だけでなく、LCP、TBT、場合によっては TTFB などの他の指標も改善されます。

Unsplash のヒーロー画像(Maik Jonietz