この Codelab では、いくつかのリソースをプリロードしてプリフェッチすることで、次のウェブページのパフォーマンスを向上させます。
測定
最適化を追加する前に、まずウェブサイトのパフォーマンスを測定します。
- サイトをプレビューするには、[アプリを表示] を押してから、全画面表示 を押します。
ライブ版の Glitch で、Lighthouse のパフォーマンス監査([Lighthouse] > [Options] > [Performance])を実行します(Lighthouse でパフォーマンスの機会を見つけるもご覧ください)。
Lighthouse では、遅れて取得されたリソースについて次の不合格の監査が表示されます。
- Ctrl+Shift+J キー(Mac の場合は Command+Option+J キー)を押して DevTools を開きます。
- [Network] タブをクリックします。
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>
アプリケーションを再読み込みして、[Network] パネルを確認します。ウェブページで使用されていない場合でも details.css
の取得リクエストが行われます。
プリロードされたリソースが、読み込み後数秒以内にそのページで使用されなくなると、Chrome の [コンソール] パネルに警告が表示されます。
この警告は、プリロード済みリソースのうち、ウェブページですぐには使用されていないものがあるかどうかを確認する際に使用します。これで、このページの不要なプリロード リンクを削除できます。
<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.css
を取得するために details.html
でリンク要素が使用されるため、リソースに対するリクエストが想定どおりに行われます。
DevTools で details.css
ネットワーク リクエストをクリックして、詳細を表示します。ファイルはブラウザのディスク キャッシュから取得されます。
ブラウザのアイドル時間を利用して、プリフェッチは別のページに必要なリソースに対する早期リクエストを行います。これにより、ブラウザでアセットをより早くキャッシュに保存し、必要に応じてキャッシュから提供できるため、今後のナビゲーション リクエストが高速化されます。
Webpack によるプリロードとプリフェッチ
コード分割で JavaScript ペイロードを削減するの投稿では、動的インポートを使用してバンドルを複数のチャンクに分割する方法について説明しています。これは、フォームの送信時に Lodash からモジュールを動的にインポートするシンプルなアプリを使用して示します。
このアプリケーションの Glitch にはこちらからアクセスできます。
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 の [要素] パネルで確認できます。
[ネットワーク] パネルでリクエストを観察すると、他のすべてのリソースがリクエストされた後、このチャンクが低優先度で取得されていることもわかります。
このユースケースではプリフェッチのほうが理にかなっていますが、webpack は動的にインポートされるチャンクのプリロードもサポートしています。
import(/* webpackPreload: true */ 'module')
まとめ
この Codelab では、特定のアセットのプリロードまたはプリフェッチによってサイトのユーザー エクスペリエンスがどのように向上するかについて、しっかりと理解できたはずです。これらの手法はすべてのリソースに使用するべきではなく、誤って使用するとパフォーマンスに悪影響を及ぼす可能性があることに留意することが重要です。プリロードまたはプリフェッチのみを選択することで、最良の結果が得られます。
まとめ
- 後で検出されたものの、現在のページにとって不可欠なリソースには、プリロードを使用します。
- 今後のナビゲーション ルートやユーザー アクションに必要なリソースには、プリフェッチを使用します。
現在、すべてのブラウザがプリロードとプリフェッチの両方をサポートしているわけではありません。つまり、アプリケーションのすべてのユーザーがパフォーマンスの向上を実感できるわけではありません。
プリロードとプリフェッチがウェブページに与える影響について詳しくは、以下の記事をご覧ください。