WordPressでscript要素をまるっとサクッと非同期化する方法

ちょっと久々にWordPressネタ。
今回はwp_head()関数とwp_footer()関数から出力されるscript要素を非同期化しようじゃないかというお話です。

いわゆるレンダリングブロックの原因になるjavascriptの読み込みを遅延させて体感速度を上げていきます。

code.close()
code.close() Photo by ruiwen

async属性を使おう

async属性をざっくり説明すると、script要素に指定することで実効タイミングを指定することができる論理属性です。
asyncを付与すると、利用可能になった時点でスクリプトを実行します。

<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22%2Fjs%2Fscript.js%22%20async%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="&lt;script&gt;" title="&lt;script&gt;" />

記述としては上の通り。
javascriptの実行時にレンダリングブロックせず、非同期で実行されます。

WordPressでasync属性を使う

そんなasync属性をWordPressで使うには、ちょっとゴニョっといじらないといけません。このゴニョっといじるのがイヤだという人は、同種の働きをしてくれるプラグインを使えばいいと思います。

思いますが、プラグインによっては思い通りの実行ができなかったり、依存関係にあるスクリプト全てにasyncが付与されて動かなくなったりするケースもあるので、個人的にはプラグインレスがオススメ。

functions.phpの中にadd_filter()関数を使ってゴニョります。

if (!(is_admin() )) {
function add_async_to_enqueue_script( $url ) {
    if ( FALSE === strpos( $url, '.js' ) ) return $url;
    if ( strpos( $url, 'jquery.min.js' ) ) return $url;
    return "$url' async charset='UTF-8";
}
add_filter( 'clean_url', 'add_async_to_enqueue_script', 11, 1 );
}

基本、これをまるっとコピペしてしまえばいいだけです。

if ( strpos( $url, 'jquery.min.js' ) ) return $url;の部分はasyncを付与しないスクリプトを指定しています。
上記をコピペしてみて、スクリプトの実行がおかしい、あるいは実行されないという状態になった場合は、原因と思われるスクリプトを指定して除外するようにしてください。

大概は問題ないかと思いますが、Syntaxhighlighter系のプラグインが引っかかるかもしれませんね。まぁ自分のサイトに応じて変えてくださいませ。

async属性ではなくdefer属性にする

非同期化するにあたって、async属性ではなくdefer属性を利用したいというケースがあるかもしれません。

defer属性はHTMLの読み込みが完了、正確にはDOMContentLoaderイベントの前に、スクリプトを実行するよう指定する属性です。

if (!(is_admin() )) {
function add_defer_to_enqueue_script( $url ) {
    if ( FALSE === strpos( $url, '.js' ) ) return $url;
    if ( strpos( $url, 'jquery.min.js' ) ) return $url;
    return "$url' defer charset='UTF-8";
}
add_filter( 'clean_url', 'add_defer_to_enqueue_script', 11, 1 );
}

asyncdeferに書き換えただけですが、defer属性を利用したいという場合は、こちらをペロッとコピペしてください。

当ブログではasync属性を付与するようにしましたが、やっぱり体感的な速度は上ったかなぁという印象。
まぁ、そもそもサーバーの応答速度が遅いので、本気で改善するならサーバーを乗り換えるべきなんですけどね。。