この Codelab では、いくつかのリソースをプリロードしてプリフェッチすることで、次のウェブページのパフォーマンスを改善します。
測定
最適化を追加する前に、まずウェブサイトのパフォーマンスを測定します。
- サイトをプレビューするには、[アプリを表示] を押してから、[全画面表示] を押します。
Glitch の公開版で Lighthouse パフォーマンス監査([Lighthouse] > [Options] > [Performance])を実行します(Lighthouse でパフォーマンス改善の機会を見つけるも参照)。
Lighthouse では、遅れて取得されたリソースに対して、次の失敗した監査が表示されます。
- Ctrl+Shift+J(Mac の場合は Command+Option+J)キーを押して DevTools を開きます。
- [ネットワーク] タブをクリックします。
main.css
ファイルは、HTML ドキュメントに配置された Link 要素(<link>
)によって取得されません。別の JavaScript ファイル fetch-css.js
が、window.onLoad
イベントの後に Link 要素を DOM に接続します。つまり、ファイルは、ブラウザが JS ファイルの解析と実行を完了した後にのみ取得されます。同様に、main.css
内で指定されたウェブフォント(K2D.woff2
)は、CSS ファイルのダウンロードが完了した後にのみフェッチされます。
クリティカル リクエスト チェーンは、ブラウザによって優先順位が付けられ、フェッチされるリソースの順序を表します。このウェブページは現在、次のようになっています。
├─┬ / (initial HTML file)
└── fetch-css.js
└── main.css
└── K2D.woff2
CSS ファイルはリクエスト チェーンの 3 番目のレベルにあるため、Lighthouse では遅く検出されたリソースとして識別されています。
重要なリソースをプリロードする
main.css
ファイルは、ページの読み込み直後にすぐに必要な重要なアセットです。このリソースのような重要なファイルがアプリの後半でフェッチされる場合は、リンク プリロード タグを使用して、ドキュメントのヘッドに Link 要素を追加し、ブラウザに早めにダウンロードするよう指示します。
このアプリのプリロード タグを追加します。
<head>
<!-- ... -->
<link rel="preload" href="main.css" as="style">
</head>
as
属性は、フェッチされるリソースのタイプを識別するために使用され、as="style"
はスタイルシート ファイルをプリロードするために使用されます。
アプリを再読み込みし、DevTools の [Network] パネルを確認します。
ブラウザが、CSS ファイルの取得を担当する JavaScript の解析が完了する前に CSS ファイルを取得していることに注目してください。プリロードでは、ブラウザはリソースがウェブページにとって重要であると想定して、リソースを先行フェッチします。
プリロードを適切に使用しないと、使用されていないリソースを不必要にリクエストしてパフォーマンスに悪影響を及ぼす可能性があります。このアプリケーションでは、details.css
はプロジェクトのルートにある別の CSS ファイルですが、別の /details route
に使用されます。プリロードが誤って使用される例を示すため、このリソースにもプリロード ヒントを追加します。
<head>
<!-- ... -->
<link rel="preload" href="main.css" as="style">
<link rel="preload" href="details.css" as="style">
</head>
アプリケーションを再読み込みして、[ネットワーク] パネルを確認します。ウェブページで使用されていないにもかかわらず、details.css
の取得リクエストが実行される。
プリロードされたリソースが読み込み後数秒以内にページで使用されない場合、Chrome の [Console] パネルに警告が表示されます。
この警告は、ウェブページですぐに使用されていないプリロード リソースがあるかどうかを特定するための指標として使用します。これで、このページの不要なプリロード リンクを削除できます。
<head>
<!-- ... -->
<link rel="preload" href="main.css" as="style">
<link rel="preload" href="details.css" as="style">
</head>
フェッチできるリソースのすべてのタイプと、as
属性に使用すべき正しい値については、プリロードに関する MDN の記事をご覧ください。
将来のリソースをプリフェッチする
プリフェッチは、別のナビゲーション ルートに使用されるアセットのリクエストを行うために使用できる別のブラウザ ヒントです。ただし、現在のページに必要な他の重要なアセットよりも優先度は低くなります。
このウェブサイトでは、画像をクリックすると別の details/
ルートに移動します。
別の CSS ファイル details.css
には、このシンプルなページに必要なすべてのスタイルが含まれています。このリソースをプリフェッチするには、index.html
にリンク要素を追加します。
<head>
<!-- ... -->
<link rel="prefetch" href="details.css">
</head>
これがファイルのリクエストをトリガーする仕組みを確認するには、DevTools で [ネットワーク] パネルを開き、[キャッシュを無効にする] オプションのチェックを外します。
アプリケーションを再読み込みすると、他のすべてのファイルがフェッチされた後に、details.css
に対して非常に低い優先度のリクエストが実行されます。
DevTools を開き、ウェブサイト上の画像をクリックして details
ページに移動します。details.html
でリンク要素を使用して details.css
を取得するため、リソースに対して想定どおりにリクエストが送信されます。
DevTools で details.css
ネットワーク リクエストをクリックして、詳細を表示します。ファイルはブラウザのディスク キャッシュから取得されます。
プリフェッチは、ブラウザのアイドル状態を利用して、別のページに必要なリソースを早期にリクエストします。これにより、ブラウザがアセットをより早くキャッシュに保存し、必要に応じてキャッシュから提供できるため、今後のナビゲーション リクエストが高速化されます。
webpack によるプリロードとプリフェッチ
Code Splitting による JavaScript ペイロードの削減の投稿では、動的インポートを使用してバンドルを複数のチャンクに分割する方法について説明しています。これは、フォームが送信されたときに Lodash からモジュールを動的にインポートするシンプルなアプリケーションで示されています。
このアプリの Glicth はこちらからアクセスできます。
src/index.js,
にある次のコードブロックは、ボタンがクリックされたときにメソッドを動的にインポートします。
form.addEventListener("submit", e => {
e.preventDefault()
import('lodash.sortby')
.then(module => module.default)
.then(sortInput())
.catch(err => { alert(err) });
});
バンドルを分割すると、初期サイズが小さくなるため、ページの読み込み時間が短縮されます。webpack バージョン 4.6.0 では、動的にインポートされるチャンクのプリロードまたはプリフェッチがサポートされています。このアプリを例に取ると、lodash
メソッドはブラウザのアイドル時間にプリフェッチできます。ユーザーがボタンを押しても、リソースの取得に遅延が生じません。
特定のチャンクをプリフェッチするには、動的インポート内で特定の webpackPrefetch
コメント パラメータを使用します。この特定のアプリケーションでは、次のように表示されます。
form.addEventListener("submit", e => {
e.preventDefault()
import(/* webpackPrefetch: true */ 'lodash.sortby')
.then(module => module.default)
.then(sortInput())
.catch(err => { alert(err) });
});
アプリケーションが再読み込みされると、webpack はリソースのプリフェッチ タグをドキュメントのヘッダーに挿入します。これは、DevTools の [要素] パネルで確認できます。
[Network] パネルでリクエストを見ると、このチャンクは他のすべてのリソースがリクエストされた後に低い優先度でフェッチされていることがわかります。
このユースケースではプリフェッチが適切ですが、webpack は動的にインポートされるチャンクのプリロードもサポートしています。
import(/* webpackPreload: true */ 'module')
まとめ
この Codelab では、特定のアセットをプリロードまたはプリフェッチすることでサイトのユーザー エクスペリエンスを改善する方法について理解を深めます。ただし、これらの手法はすべてのリソースに使用できるわけではなく、誤って使用するとパフォーマンスに悪影響を与える可能性があります。最適な結果を得るには、プリロードまたはプリフェッチを必要に応じて行う必要があります。
まとめ
- 遅れて検出されたものの、現在のページにとって重要なリソースにはプリフェッチを使用します。
- 今後のナビゲーション ルートやユーザー操作に必要なリソースには、プリフェッチを使用します。
現時点では、すべてのブラウザがプリロードとプリフェッチの両方をサポートしているわけではありません。つまり、アプリのすべてのユーザーがパフォーマンスの向上に気づくとは限りません。
プリロードとプリフェッチがウェブページに与える影響の具体的な側面について詳しくは、以下の記事を参照してください。