WordPress
2022.09.01(更新)
ページロード遅延が改善 !レンダリングブロックを防ぐ方法【WordPress / JavaScript編】
WordPressでJavaScriptファイルを非同期で読み込みたいんだけど、どうやったらいいの?
こんなお悩みに答えていきます。
本記事の内容
- レンダリングブロックの仕組み
- スクリプト処理の流れ
- JavaScriptファイルを非同期で読み込む具体的な方法
本記事を対象とする方
- フロントエンドエンジニアを目指す方
- Webディレクターを目指す方
- SEO施策担当者
この記事を書いている僕はプログラミング歴2年です。webエンジニアとして”社内転職”しました。
レンダリングブロックの仕組み
こちらの記事にも書いたのですが、おさらいの意味をこめて解説します。
ブラウザがWebページにアクセスすると、htmlファイルのソースを上から順番に読み込んでいきます。
読み進めながらDOMツリー構築を行い、ブラウザにその結果を表示することレンダリングと言います。
<head>タグ内には様々なサブリソースファイルがあり、ブラウザはサブリソースファイルを見つける度に読み込みを一旦ストップし、ファイルをダウンロードして、そのファイルのソースを実行し、それが終了した後に読み込みを再開します。
これがレンダリングブロックの仕組みです。
当然ながら、JavaScriptファイルのスクリプト処理もレンダリングブロックの対象になります。
ただし、CSSファイルと違ってスタイリングを行うものではないので、JavaScriptファイルは基本<body>タグが閉じる直前で読み込みます。
余談ですが、CSSファイルも<body>タグ直前で読み込み可能です。
しかしその場合、DOM構築後にスタイルが適用されるので、レイアウトが崩れたデザインが先に表示されます。これをFOUC=Flash Of Unstyled Content と言います。
<head>タグ内にあるCSSファイルを非同期で読み込んだ場合も、このFOUCが起こります。
スクリプト処理の流れ
ブラウザがJavaScriptファイルを読み込んでから処理をするには以下の3つの流れがあります。
通常、ブラウザがスクリプト処理を読み込む場合、そのリソースファイルをダウンロードし、スクリプト処理を行う間、DOM構築処理をブロックします。
しかし、<script>要素にasyncもしくはdefer属性を与えると、その要素のダウンロードは非同期で行われ、DOM構築処理をブロックしません。
asyncは、「asynchronous」の略語で「非同期の」という意味です。deferは、略語ではなく「延期する」という意味があります。
プログラムにおけるasyncとdefer属性の違いですが、asyncの場合、ファイルのダウンロードが完了するとスクリプト処理まで行います。
一方deferの場合、ファイルがダウンロードされてもスクリプト処理は行わず、DOM構築処理を優先します。スクリプト処理はDOM構築完了後になります。
よって、asyncは少なからずページロードに影響を与えます。
CSSもJavaScriptも同じですが、ページのメインコンテンツ表示に関わる重要なソースはインラインで<head>タグに読み込ませ、それ以外の優先度の低い処理は、
タグの閉じる直前で非同期で読み込ませるのが、DOM構築に影響を与えない方法となります。JavaScriptファイルを非同期で読み込む具体的な方法
ではJSファイルを非同期で読み込みましょう。それにはフィルターフックという機能を使います。
先程説明したように、<script>要素にasyncもしくはdefer属性を付けます。
両者には違いがあるので、スクリプト処理の内容によってどちらかを選択するべきですが、ページのメインコンテンツの表示をインライン形式で記述しているのであれば、それ以外のスクリプト処理の実行はDOM構築完了後でも十分でしょう。それを前提としてこの例ではdefer属性を選択するものとします。
今回はWordPress編ですから、functions.phpに以下のコードを追加します。
- function scriptLoaderJs($tag, $handle, $src) {
- if (is_admin()) {
- return $tag;
- }
- $tag = sprintf('<script src="%s" type="text/javascript" async=""></script>' . "\n", $src);
- return $tag;
- }
- add_filter('script_loader_tag', 'scriptLoaderJs', 10, 3);
※コードを実行する際は必ずバックアップを取ってください。予期せぬエラーが起こっても責任を負えません。
フィルターフックのscript_loader_tagを使います。ファイルターフックとは、WordPress上の何らかの出力や処理(関数実行)をカスタマイズする機能です。これにより、デフォルトで設定されている内容を上書きすることができます。
ファイルターフックは様々なものが用意されているので、興味のある方はWordPress Codexをご覧ください。
では順番に説明していきます。
まずは関数を登録します。名前はなんでも良いですが、今回はscriptLoaderJsとしておきます。この関数は$tag,$handle,$srcの3つパラメーターを取ります。
- function scriptLoaderJs($tag, $handle, $src)
$tag: | 通常出力される<script>タグ |
$handle: | wp_enqueue_styleで登録したハンドル |
$href: | サブリソースファイルにアクセスするURL |
WordPressの管理画面ページではレンダリングブロックをする必要がないので、フックをかけず通常の<script>タグを出力させます。
- if (is_admin()) {
- // 管理画面ページでは非同期読み込みを適用しない
- return $tag;
- }
ここからがカスタマイズする内容、つまりasyncもしくはdefer属性を付与するコードです。
- $tag = sprintf('<script src="%s" type="text/javascript" defer=""></script>' . "\n", $src);
- return $tag;
asyncを付けたい場合は、defer=””の部分をasync=””に修正すれば変更できます。
returnしているsprintf()は、PHPの組み込み関数で、フォーマット化された文字列を返すことができます。
詳細はPHPマニュアルで確認できるので興味のある方は確認してみてください。
最後にフィルターフックの関数を実行して終了です。
- add_filter('script_loader_tag', 'scriptLoaderJs’, 10, 3);
1番目のパラメーターは、WordPressの組み込み関数である’script_loader_tag’が入ります。
2番目のパラメーターは、定義したメソッド’styleLoaderJs’を入れます。これはコールバック関数と呼ばれています。
3番目のパラメーターには10が入っていますが、これは同一フックに複数の関数が登録された時に呼び出される優先順位で数字が低いほど先に呼ばれます。デフォルト値は10です。
4番目のパラメーターは、コールバック関数に指定した引数の数が入ります。今回は$tag, $handle, $srcの3つを設定しているので3となっています。
では、chromeのDevToolsを開いてソースを確認してみましょう。
しっかりdefer属性が付与されています。この結果、サードパーティー(プラグイン)製含め、そのテーマで読み込んでいる全てのJavaScriptファイルにdefer属性が付くことになります。
deferが機能しているかどうかはPageSpeed Insightで、”レンダリングを妨げるリソースの除外”の項目を確認するのが良いでしょう。
今回のまとめ
今回はJavaScriptファイルのレンダリングブロックを防ぐ方法について紹介しました。細かく突き詰めていくと、ページ毎に読み込むJSファイルを限定する処置をしないと、無駄にリソースファイルを実行することになるので、時間がある時にそうしたこともやっておくと良いでしょう。最後まで読んで頂きありがとうございました。
functions.phpにフィルターフック’script_loader_tag’を設定する
PHP組み込み関数のsprintf()を使い、設定したい文字列をフォーマット形式にする
defer設定後は、PageSpeed Insightsで結果を確認する