ブラウザのプリロード スキャナに対抗しない

ブラウザのプリロード スキャナとは何か、パフォーマンスにどのように役立つか、そしてその邪魔をしないようにする方法について説明します。

Page Speed の最適化で見落とされがちなのが、ブラウザの内部構造に関する知識です。ブラウザは、デベロッパーができない方法でパフォーマンスを向上させるために特定の最適化を行います。ただし、これらの最適化が意図せず妨げられない限り、

理解しておくべき内部ブラウザの最適化の 1 つに、ブラウザのプリロード スキャナがあります。この記事では、プリロード スキャナの仕組みと、プリロード スキャナの動作を妨げないようにする方法について説明します。

プリロード スキャナとは

すべてのブラウザには、未加工のマークアップをトークン化してオブジェクト モデルに処理するプライマリ HTML パーサーがあります。この処理は、パーサーがブロッキング リソース(<link> 要素で読み込まれたスタイルシートや、async 属性または defer 属性なしで <script> 要素で読み込まれたスクリプトなど)を検出して一時停止するまで続きます。

HTML パーサーの図。
図 1: ブラウザのメインの HTML パーサーがブロックされる仕組みの図。この場合、パーサーは外部 CSS ファイルの <link> 要素に遭遇します。これにより、CSS がダウンロードされて解析されるまで、ブラウザはドキュメントの残りの部分を解析したり、レンダリングしたりできなくなります。

CSS ファイルの場合、スタイルが適用されていないコンテンツのフラッシュ(FOUC)を防ぐために、レンダリングがブロックされます。FOUC とは、スタイルが適用される前に、スタイルが適用されていないバージョンのページが短時間表示される現象です。

スタイルが設定されていない状態(左)とスタイルが設定された状態(右)の web.dev ホームページ。
図 2: FOUC のシミュレーション例。左側は、スタイルが適用されていない web.dev のトップページです。右側は、スタイルを適用した同じページです。スタイルシートのダウンロードと処理中にブラウザがレンダリングをブロックしない場合、スタイルが適用されていない状態が一瞬発生することがあります。

また、ブラウザは、defer 属性または async 属性のない <script> 要素を検出すると、ページの解析とレンダリングをブロックします。

これは、メインの HTML パーサーがまだ処理を行っている間に、特定のスクリプトが DOM を変更するかどうかをブラウザが確実に判断できないためです。そのため、解析とレンダリングのブロックの影響を最小限に抑えるために、ドキュメントの最後に JavaScript を読み込むのが一般的です。

これは、ブラウザが解析とレンダリングの両方をブロックすべき理由として妥当です。しかし、これらの重要なステップのいずれかをブロックすることは、他の重要なリソースの検出を遅らせて表示を遅らせる可能性があるため、望ましくありません。幸いなことに、ブラウザはプリロード スキャナと呼ばれるセカンダリ HTML パーサーを使用して、これらの問題を軽減するために最善を尽くしています。

プライマリ HTML パーサー(左)と、セカンダリ HTML パーサーであるプリロード スキャナ(右)の両方の図。
図 3: プリロード スキャナがメインの HTML パーサーと並行して動作し、アセットを投機的に読み込む仕組みを示す図。この例では、メインの HTML パーサーは、<body> 要素内の画像マークアップの処理を開始する前に CSS を読み込んで処理するため、ブロックされます。しかし、プリロード スキャナは、未加工のマークアップを先読みして画像リソースを見つけ、メインの HTML パーサーのブロックが解除される前に読み込みを開始できます。

プリロード スキャナの役割は推測的です。つまり、未加工のマークアップを調べて、メインの HTML パーサーがリソースを検出する前に、リソースを事前に取得します。

プリロード スキャナが動作しているかどうかを確認する方法

プリロード スキャナは、レンダリングと解析がブロックされるために存在します。これら 2 つのパフォーマンスの問題がなければ、プリロード スキャナはあまり役に立ちません。ウェブページがプリロード スキャナのメリットを得られるかどうかを判断する鍵は、これらのブロッキング現象にあります。これを行うには、リクエストに人工的な遅延を導入して、プリロード スキャナが動作している場所を特定します。

たとえば、スタイルシートを使用した基本的なテキストと画像を含むこちらのページをご覧ください。CSS ファイルはレンダリングと解析の両方をブロックするため、プロキシ サービスを介してスタイルシートに 2 秒の人工的な遅延を導入します。この遅延により、ネットワーク ウォーターフォールでプリロード スキャナが動作している場所を簡単に確認できます。

WebPageTest のネットワーク ウォーターフォール チャートは、スタイルシートに 2 秒の人工的な遅延が課されていることを示しています。
図 4: WebPageTest のネットワーク ウォーターフォール チャート。モバイル デバイスの Chrome で 3G 接続をシミュレートしてウェブページを実行した結果。スタイルシートは、プロキシを介して読み込みが開始されるまで 2 秒間、人為的に遅延されますが、マークアップ ペイロードの後半にある画像はプリロード スキャナによって検出されます。

ウォーターフォールで確認できるように、プリロード スキャナは、レンダリングとドキュメントの解析がブロックされている間でも、<img> 要素を検出します。この最適化を行わないと、ブラウザはブロッキング期間中にリソースをフェッチできず、より多くのリソース リクエストが同時ではなく連続して行われることになります。

この簡単な例を念頭に置いて、プリロード スキャナが機能しない実際のパターンと、それを修正する方法を見てみましょう。

async 個のスクリプトを挿入しました

たとえば、<head> に次のようなインライン JavaScript を含む HTML があるとします。

<script>
  const scriptEl = document.createElement('script');
  scriptEl.src = '/yall.min.js';

  document.head.appendChild(scriptEl);
</script>

挿入されたスクリプトはデフォルトで async であるため、このスクリプトが挿入されると、async 属性が適用されたかのように動作します。つまり、できるだけ早く実行され、レンダリングをブロックしません。最適な方法のように思えますが、しかし、このインライン <script> が外部 CSS ファイルを読み込む <link> 要素の後にあると仮定すると、次のような最適とは言えない結果になります。

この WebPageTest グラフは、スクリプトが挿入されたときにプリロード スキャンが失敗したことを示しています。
図 5: 3G 接続をシミュレートしたモバイル デバイスの Chrome で実行されたウェブページの WebPageTest ネットワーク ウォーターフォール チャート。このページには、1 つのスタイルシートと、挿入された async スクリプトが含まれています。プリロード スキャナは、クライアントに挿入されるため、レンダリング ブロック フェーズ中にスクリプトを検出できません。

ここで何が起きたのかを詳しく見てみましょう。

  1. 0 秒の時点で、メイン ドキュメントがリクエストされます。
  2. 1.4 秒で、ナビゲーション リクエストの最初のバイトが到着します。
  3. 2.0 秒の時点で、CSS と画像がリクエストされます。
  4. パーサーはスタイルシートの読み込みをブロックしており、async スクリプトを挿入するインライン JavaScript は、そのスタイルシートの後の 2.6 秒目に読み込まれるため、スクリプトが提供する機能はすぐには利用できません。

スクリプトのリクエストは、スタイルシートのダウンロードが完了した後にのみ発生するため、これは最適ではありません。これにより、スクリプトの実行が遅延します。一方、<img> 要素はサーバーから提供されるマークアップで検出可能であるため、プリロード スキャナによって検出されます。

では、スクリプトを DOM に挿入するのではなく、async 属性を指定した通常の <script> タグを使用するとどうなるでしょうか。

<script src="/yall.min.js" async></script>

結果は次のとおりです。

HTML スクリプト要素を使用して読み込まれた非同期スクリプトが、ブラウザのメインの HTML パーサーがスタイルシートのダウンロードと処理中にブロックされているにもかかわらず、ブラウザのプリロード スキャナによって検出可能であることを示す WebPageTest ネットワーク ウォーターフォール。
図 6: 3G 接続をシミュレートしたモバイル デバイスの Chrome で実行されたウェブページの WebPageTest ネットワーク ウォーターフォール チャート。ページには、1 つのスタイルシートと 1 つの async <script> 要素が含まれています。プリロード スキャナは、レンダリング ブロック フェーズ中にスクリプトを検出し、CSS と同時に読み込みます。

これらの問題は rel=preload を使用することで解決できると考えるかもしれません。これは確かに機能しますが、副作用が生じる可能性があります。<script> 要素を DOM に挿入しないことで回避できる問題を、rel=preload を使用して修正する必要はありません。

rel=preload リソースヒントを使用して、非同期で挿入されたスクリプトの検出を促進する方法を示す WebPageTest ウォーターフォール。ただし、意図しない副作用が生じる可能性があります。
図 7: 3G 接続をシミュレートしたモバイル デバイスの Chrome で実行されたウェブページの WebPageTest ネットワーク ウォーターフォール チャート。このページには、1 つのスタイルシートと挿入された async スクリプトが含まれていますが、async スクリプトは事前に読み込まれ、より早く検出されるようになっています。

プリロードによってこの問題は「修正」されますが、新たな問題が発生します。最初の 2 つのデモの async スクリプトは、<head> で読み込まれているにもかかわらず、「低」優先度で読み込まれます。一方、スタイルシートは「最高」優先度で読み込まれます。async スクリプトがプリロードされる最後のデモでは、スタイルシートは引き続き「最高」の優先度で読み込まれますが、スクリプトの優先度は「高」に引き上げられています。

リソースの優先度が高くなると、ブラウザはそのリソースに割り当てる帯域幅を増やします。つまり、スタイルシートの優先度が最も高いにもかかわらず、スクリプトの優先度が高くなったことで、帯域幅の競合が発生する可能性があります。これは、接続が遅い場合や、リソースが非常に大きい場合に要因となる可能性があります。

答えは簡単です。起動時にスクリプトが必要な場合は、DOM に挿入してプリロード スキャナを無効にしないでください。必要に応じて、<script> 要素の配置や、defer や async などの属性をテストします。

JavaScript を使用した遅延読み込み

遅延読み込みは、データを節約する優れた方法であり、画像によく適用されます。しかし、いわゆる「スクロールせずに見える範囲」にある画像に遅延読み込みが誤って適用されることがあります。

これにより、プリロード スキャナが関与するリソースの見つけやすさに潜在的な問題が生じ、画像への参照の検出、ダウンロード、デコード、表示にかかる時間が不必要に長くなる可能性があります。たとえば、次の画像マークアップがあるとします。

<img data-src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

data- 接頭辞の使用は、JavaScript を利用した遅延ローダで一般的なパターンです。画像がビューポートにスクロールされると、遅延ローダは data- 接頭辞を削除します。つまり、上記の例では、data-src が src になります。この更新により、ブラウザはリソースを取得するようになります。

このパターンは、起動時にビューポートにある画像に適用されるまでは問題になりません。プリロード スキャナは、src(または srcset)属性と同じ方法で data-src 属性を読み取らないため、画像参照が早期に検出されません。さらに悪いことに、遅延ローダの JavaScript がダウンロード、コンパイル、実行されるまで、画像の読み込みが遅延します。

WebPageTest のネットワーク ウォーターフォール チャート。起動時にビューポート内にある遅延読み込み画像が、ブラウザのプリロード スキャナが画像リソースを見つけられないため、遅延読み込みに必要な JavaScript が読み込まれたときにのみ読み込まれることを示しています。画像が検出されるのが、本来よりもはるかに遅い。
図 8: 3G 接続をシミュレートしたモバイル デバイスの Chrome で実行されたウェブページの WebPageTest ネットワーク ウォーターフォール チャート。画像リソースは、起動時にビューポートに表示されるにもかかわらず、不必要に遅延読み込みされています。これにより、プリロード スキャナが無効になり、不要な遅延が発生します。

画像のサイズ(ビューポートのサイズによって異なる場合があります)によっては、Largest Contentful Paint(LCP)の候補要素になる可能性があります。プリロード スキャナが画像リソースを事前に投機的に取得できない場合(ページのスタイルシートがレンダリングをブロックしている時点など)、LCP に影響します。

この問題を解決するには、画像のマークアップを変更します。

<img src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">

これは、起動時にビューポートに表示される画像に最適なパターンです。プリロード スキャナが画像リソースをより迅速に検出して取得するためです。

起動時にビューポート内の画像を読み込むシナリオを示す WebPageTest ネットワーク ウォーターフォール チャート。画像は遅延読み込みされないため、スクリプトに依存して読み込まれることはありません。つまり、プリロード スキャナは画像をより早く検出できます。
図 9: 3G 接続をシミュレートしたモバイル デバイスの Chrome で実行されたウェブページの WebPageTest ネットワーク ウォーターフォール チャート。プリロード スキャナは、CSS と JavaScript の読み込みが開始される前に画像リソースを検出するため、ブラウザは画像の読み込みを早めに開始できます。

この簡略化された例では、低速接続での LCP が 100 ミリ秒改善されています。これは大きな改善には見えないかもしれませんが、このソリューションがマークアップの簡単な修正であること、そしてほとんどのウェブページがこの一連の例よりも複雑であることを考えると、大きな改善です。つまり、LCP 候補は他の多くのリソースと帯域幅を競合する可能性があるため、このような最適化の重要性が高まっています。

CSS 背景画像

ブラウザのプリロード スキャナはマークアップをスキャンします。background-image プロパティによって参照される画像の取得を伴う CSS など、他のリソースタイプはスキャンされません。

HTML と同様に、ブラウザは CSS を CSSOM と呼ばれる独自のオブジェクト モデルに処理します。CSSOM の構築時に外部リソースが検出された場合、それらのリソースは検出時にリクエストされ、プリロード スキャナによってリクエストされることはありません。

ページの LCP 候補が、CSS background-image プロパティを持つ要素であるとします。リソースの読み込み時に行われる処理は次のとおりです。

background-image プロパティを使用して CSS から読み込まれた LCP 候補を含むページを示す WebPageTest ネットワーク ウォーターフォール チャート。LCP 候補の画像は、ブラウザのプリロード スキャナで検査できないリソースタイプであるため、CSS がダウンロードされて処理されるまでリソースの読み込みが遅れ、LCP 候補の描画時間が遅くなります。
図 10: 3G 接続をシミュレートしたモバイル デバイスの Chrome で実行されたウェブページの WebPageTest ネットワーク ウォーターフォール チャート。ページの LCP 候補は、CSS background-image プロパティを持つ要素です(3 行目)。リクエストする画像は、CSS パーサーが検出するまで取得が開始されません。

この場合、プリロード スキャナは無効化されるというよりは、関与しないことになります。それでも、ページ上の LCP 候補が background-image CSS プロパティからのものである場合は、その画像をプリロードすることをおすすめします。

<!-- Make sure this is in the <head> below any
     stylesheets, so as not to block them from loading -->
<link rel="preload" as="image" href="lcp-image.jpg">

この rel=preload ヒントは小さいですが、ブラウザが画像を通常よりも早く検出するのに役立ちます。

rel=preload ヒントの使用により、CSS 背景画像(LCP 候補)の読み込みが大幅に早くなっていることを示す WebPageTest ネットワーク ウォーターフォール チャート。LCP 時間が約 250 ミリ秒改善されます。
図 11: 3G 接続をシミュレートしたモバイル デバイスの Chrome で実行されたウェブページの WebPageTest ネットワーク ウォーターフォール チャート。ページの LCP 候補は、CSS background-image プロパティを持つ要素です(3 行目)。rel=preload ヒントを使用すると、ヒントを使用しない場合よりも約 250 ミリ秒早くブラウザが画像を検出できます。

rel=preload ヒントを使用すると、LCP 候補がより早く検出され、LCP 時間が短縮されます。このヒントは問題の解決に役立ちますが、より良い方法は、LCP 候補の画像を CSS から読み込む必要があるかどうかを評価することです。<img> タグを使用すると、プリロード スキャナで画像を検出できるようにしながら、ビューポートに適した画像の読み込みをより細かく制御できます。

インライン化するリソースが多すぎる

インライン化とは、リソースを HTML 内に配置することです。<style> 要素内のスタイルシート、<script> 要素内のスクリプト、および base64 エンコードを使用したその他のリソースをインライン化できます。

リソースをインライン化すると、リソースに対して個別のリクエストが発行されないため、ダウンロードするよりも高速になることがあります。ドキュメント内に直接表示され、すぐに読み込まれます。ただし、次のような大きなデメリットがあります。

  • HTML をキャッシュに保存していない場合(HTML レスポンスが動的な場合はキャッシュに保存できません)、インライン リソースはキャッシュに保存されません。インライン化されたリソースは再利用できないため、パフォーマンスに影響します。
  • HTML をキャッシュに保存できる場合でも、インライン リソースはドキュメント間で共有されません。これにより、オリジン全体でキャッシュに保存して再利用できる外部ファイルと比較して、キャッシュ保存の効率が低下します。
  • インライン化しすぎると、インライン化された余分なコンテンツのダウンロードに時間がかかるため、プリロード スキャナがドキュメントの後半でリソースを検出するのが遅くなります。

このページを例に見てみましょう。特定の条件下では、LCP 候補はページ上部の画像であり、CSS は <link> 要素によって読み込まれる別のファイルにあります。このページでは、CSS リソースとは別のファイルとしてリクエストされる 4 つのウェブフォントも使用されています。

4 つのフォントが参照されている外部 CSS ファイルを含むページの WebPageTest ネットワーク ウォーターフォール チャート。LCP 候補の画像は、プリロード スキャナによって適切なタイミングで検出されます。
図 12: 3G 接続をシミュレートしたモバイル デバイスの Chrome で実行されたウェブページの WebPageTest ネットワーク ウォーターフォール チャート。ページの LCP 候補は <img> 要素から読み込まれた画像ですが、プリロード スキャナによって検出されます。これは、ページ読み込みに必要な CSS とフォントが別のリソースで読み込まれるため、プリロード スキャナの処理が遅れることがないためです。

では、CSS とすべてのフォントが base64 リソースとしてインライン化されている場合はどうなるでしょうか。

4 つのフォントが参照されている外部 CSS ファイルを含むページの WebPageTest ネットワーク ウォーターフォール チャート。プリロード スキャナが LCP 画像を検出するまでに大幅な遅延が発生しています。
図 13: 3G 接続をシミュレートしたモバイル デバイスの Chrome で実行されたウェブページの WebPageTest ネットワーク ウォーターフォール チャート。ページの LCP 候補は <img> 要素から読み込まれた画像ですが、CSS とその 4 つのフォント リソースが `` にインライン化されているため、プリロード スキャナが画像を検出するタイミングが、それらのリソースが完全にダウンロードされるまで遅れます。

この例では、インライン化の影響により、LCP に悪影響が及び、パフォーマンス全般にも悪影響が及んでいます。何もインライン化しないバージョンのページでは、LCP 画像が約 3.5 秒で描画されます。すべてをインライン化するページでは、LCP 画像が描画されるまでに 7 秒以上かかります。

ここでは、プリロード スキャナだけではありません。base64 はバイナリ リソースの形式として効率的ではないため、フォントのインライン化は適切な戦略ではありません。もう 1 つの要因は、CSSOM で必要と判断されない限り、外部フォント リソースがダウンロードされないことです。これらのフォントが base64 としてインライン化されている場合、現在のページで必要かどうかにかかわらずダウンロードされます。

プリロードによって改善できるでしょうか?いいね。LCP 画像をプリロードして LCP 時間を短縮することは可能ですが、キャッシュに保存できない可能性のある HTML をインライン リソースで肥大化させると、パフォーマンスに悪影響を及ぼします。First Contentful Paint(FCP)もこのパターンの影響を受けます。何もインライン化されていないバージョンのページでは、FCP は約 2.7 秒です。すべてがインライン化されたバージョンでは、FCP は約 5.8 秒です。

HTML にインライン化する際は、特に base64 でエンコードされたリソースに注意してください。一般的には、非常に小さなリソースを除き、この方法はおすすめしません。インライン化はできるだけ少なくします。インライン化が多すぎると、火遊びをしているようなものです。

クライアントサイドの JavaScript を使用したマークアップのレンダリング

JavaScript が Page Speed に影響することは間違いありません。デベロッパーは、インタラクティブな機能を提供するために JavaScript に依存しているだけでなく、コンテンツ自体の提供にも JavaScript に依存する傾向があります。これは、いくつかの点でデベロッパー エクスペリエンスの向上につながりますが、デベロッパーにとってのメリットが必ずしもユーザーにとってのメリットにつながるとは限りません。

プリロード スキャナを無効にするパターンの 1 つは、クライアントサイドの JavaScript でマークアップをレンダリングすることです。

JavaScript でクライアント上で完全にレンダリングされた画像とテキストを含む基本的なページを示す WebPageTest ネットワーク ウォーターフォール。マークアップが JavaScript 内に含まれているため、プリロード スキャナはリソースを検出できません。JavaScript フレームワークが必要とする追加のネットワークと処理時間により、すべてのリソースがさらに遅延します。
図 14: 3G 接続をシミュレートしたモバイル デバイスの Chrome で実行されたクライアント レンダリング ウェブページの WebPageTest ネットワーク ウォーターフォール チャート。コンテンツは JavaScript に含まれており、レンダリングをフレームワークに依存しているため、クライアント レンダリングされたマークアップ内の画像リソースはプリロード スキャナから隠されます。これと同等のサーバー レンダリングのエクスペリエンスを図 9 に示します。

マークアップ ペイロードがブラウザの JavaScript に含まれ、完全にレンダリングされる場合、そのマークアップ内のリソースはプリロード スキャナから実質的に見えなくなります。これにより、重要なリソースの検出が遅れ、LCP に確実に影響します。これらの例では、JavaScript を必要としない同等のサーバー レンダリング エクスペリエンスと比較して、LCP 画像のリクエストが大幅に遅延します。

この記事の焦点から少し外れますが、クライアントでマークアップをレンダリングすることの影響は、プリロード スキャナを無効にすることだけではありません。たとえば、JavaScript を必要としないエクスペリエンスを強化するために JavaScript を導入すると、不要な処理時間が発生し、Interaction to Next Paint(INP)に影響する可能性があります。クライアントで非常に大量のマークアップをレンダリングすると、サーバーから同じ量のマークアップが送信される場合と比較して、長いタスクが発生する可能性が高くなります。この理由は、JavaScript に伴う追加の処理を除けば、ブラウザがサーバーからマークアップをストリーミングし、長いタスクを制限するような方法でレンダリングをチャンク化するためです。一方、クライアント側でレンダリングされたマークアップは、単一のモノリシックなタスクとして処理されるため、ページの INP に影響する可能性があります。

このシナリオの解決策は、次の質問への回答によって異なります。クライアントでレンダリングするのではなく、サーバーでページのマークアップを提供できない理由があるか?答えが「いいえ」の場合は、可能な限りサーバーサイド レンダリング(SSR)または静的に生成されたマークアップを検討する必要があります。これにより、プリロード スキャナが重要なリソースを事前に検出して、適切なタイミングで取得できるようになります。

ページ マークアップの一部に機能を追加するために JavaScript が必要な場合でも、SSR でバニラ JavaScript を使用するか、ハイドレーションを使用して、両方のメリットを享受できます。

プリロード スキャナを有効に活用する

プリロード スキャナは、起動時にページの読み込みを高速化する、非常に効果的なブラウザ最適化機能です。重要なリソースを事前に検出する機能を妨げるパターンを回避することで、開発が容易になるだけでなく、ウェブに関する指標など、多くの指標でより良い結果をもたらす優れたユーザー エクスペリエンスを実現できます。

この投稿の重要なポイントを以下にまとめます。

  • ブラウザのプリロード スキャナは、メインの HTML パーサーがブロックされた場合に、メインの HTML パーサーよりも前にスキャンして、より早く取得できるリソースを検出するセカンダリ HTML パーサーです。
  • 最初のナビゲーション リクエストでサーバーから提供されたマークアップに存在しないリソースは、プリロード スキャナで検出できません。プリロード スキャナが機能しなくなる原因には、次のようなものがあります(ただし、これらに限定されません)。
    • JavaScript を使用して DOM にリソースを挿入する。リソースがスクリプト、画像、スタイルシート、またはサーバーからの初期マークアップ ペイロードに含める方がよいその他のものである場合。
    • JavaScript ソリューションを使用して、スクロールせずに見える範囲の画像または iframe を遅延読み込みする。
    • JavaScript を使用して、ドキュメントのサブリソースへの参照を含む可能性のあるマークアップをクライアントでレンダリングする。
  • プリロード スキャナは HTML のみをスキャンします。LCP 候補などの重要なアセットへの参照を含む可能性のある他のリソース(特に CSS)の内容は調べません。

なんらかの理由で、プリロード スキャナの読み込みパフォーマンスを高速化する機能を阻害するパターンを回避できない場合は、rel=preload リソースヒントを検討してください。rel=preload を使用している場合は、ラボツールでテストして、目的の効果が得られていることを確認します。最後に、プリロードするリソースが多すぎないようにしてください。すべてを優先すると、何も優先されなくなります。

リソース