2026年5月20日

2026年5月20日

WordPressのJavaScriptを最小化・遅延読み込みする方法

はじめに

JavaScriptはCSSと並んでレンダリングブロックの主な原因です。deferasync 属性を付与することでHTMLのパースをブロックしなくなり、PageSpeed InsightsのTBT(Total Blocking Time)とFID/INPスコアを改善できます。

症状・原因

  • PageSpeed Insightsで「レンダリングブロックリソースの除外」を指摘される
  • TBT(Total Blocking Time)やINPのスコアが低い
  • プラグインのJSがすべてのページで読み込まれている
  • jQueryが不要なのにheadで読み込まれている

解決手順

ステップ1:WordPress 6.3以降のdefer/async対応を使う

// functions.php

// WordPress 6.3以降: strategy パラメータで defer/async を指定
function mytheme_enqueue_scripts(): void {
    // defer: DOMが構築された後に実行(順序保証あり)
    wp_enqueue_script(
        'mytheme-main',
        get_template_directory_uri() . '/assets/js/main.min.js',
        [],                      // 依存なし(jQueryに依存しない場合)
        filemtime(get_template_directory() . '/assets/js/main.min.js'),
        ['strategy' => 'defer']  // WordPress 6.3以降の新記法
    );

    // async: 読み込み完了次第即実行(順序保証なし)
    wp_enqueue_script(
        'mytheme-analytics',
        get_template_directory_uri() . '/assets/js/analytics.min.js',
        [],
        '1.0.0',
        ['strategy' => 'async', 'in_footer' => true]
    );
}
add_action('wp_enqueue_scripts', 'mytheme_enqueue_scripts');

ステップ2:WordPress 6.2以前でdefer/asyncを追加する

// functions.php

// script_loader_tag フィルターで defer/async を付与
function mytheme_add_script_attributes(string $tag, string $handle): string {
    $defer_scripts = ['mytheme-main', 'mytheme-slider'];
    $async_scripts  = ['mytheme-analytics', 'mytheme-gtm'];

    if (in_array($handle, $defer_scripts, true)) {
        return str_replace('<script ', '<script defer ', $tag);
    }

    if (in_array($handle, $async_scripts, true)) {
        return str_replace('<script ', '<script async ', $tag);
    }

    return $tag;
}
add_filter('script_loader_tag', 'mytheme_add_script_attributes', 10, 2);

ステップ3:不要なJavaScriptを削除する

// functions.php

function mytheme_dequeue_unused_scripts(): void {
    // jQueryをフロントエンドで無効化(独自JSがVanillaの場合)
    // ※ プラグインがjQueryに依存している場合は削除しないこと
    if (!is_admin() && !is_user_logged_in()) {
        // wp_dequeue_script('jquery'); // 慎重に判断
    }

    // Emojiスクリプトを削除(不要な場合)
    remove_action('wp_head', 'print_emoji_detection_script', 7);
    remove_action('wp_print_styles', 'print_emoji_styles');
    wp_dequeue_script('wp-emoji-release');

    // Contact Form 7のJSをフォームページ以外で無効化
    if (!is_page('contact')) {
        wp_dequeue_script('contact-form-7');
    }

    // oEmbedスクリプトを削除(埋め込みを使わない場合)
    wp_deregister_script('wp-embed');
}
add_action('wp_enqueue_scripts', 'mytheme_dequeue_unused_scripts', 100);

ステップ4:TerserでJavaScriptをMinifyする

// package.json
{
  "scripts": {
    "build:js": "terser src/js/main.js -o assets/js/main.min.js --compress --mangle",
    "build:js:all": "find src/js -name '*.js' -exec sh -c 'terser {} -o assets/js/$(basename {} .js).min.js --compress --mangle' \\;",
    "watch:js": "nodemon --watch src/js --ext js --exec 'npm run build:js'"
  },
  "devDependencies": {
    "terser": "^5.0.0",
    "nodemon": "^3.0.0"
  }
}
// webpack.config.js(Webpackを使う場合)
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
    mode: 'production',
    entry: './src/js/main.js',
    output: {
        filename: 'main.min.js',
        path: __dirname + '/assets/js',
    },
    optimization: {
        minimizer: [
            new TerserPlugin({
                terserOptions: {
                    compress: { drop_console: true }, // console.logを削除
                    mangle: true,
                },
            }),
        ],
    },
};

ステップ5:jQueryを最適化する

// functions.php

// jQueryをCDNから読み込んでキャッシュヒット率を上げる
function mytheme_use_cdn_jquery(): void {
    if (is_admin()) {
        return;
    }

    wp_deregister_script('jquery');
    wp_register_script(
        'jquery',
        'https://code.jquery.com/jquery-3.7.1.min.js',
        [],
        '3.7.1',
        ['strategy' => 'defer']
    );
    wp_enqueue_script('jquery');
}
// add_action('wp_enqueue_scripts', 'mytheme_use_cdn_jquery');
// ※ SRIハッシュの設定も検討すること

// jQueryをフッターに移動(ヘッダーでのブロックを防ぐ)
function mytheme_move_jquery_to_footer(): void {
    if (!is_admin()) {
        wp_scripts()->add_data('jquery', 'group', 1);     // フッターに移動
        wp_scripts()->add_data('jquery-core', 'group', 1);
        wp_scripts()->add_data('jquery-migrate', 'group', 1);
    }
}
add_action('wp_enqueue_scripts', 'mytheme_move_jquery_to_footer');

注意事項

  • deferasync の違いを理解してください。defer はDOMが準備できてから実行・順序保証あり。async はダウンロード完了次第即実行・順序保証なし。jQueryに依存するスクリプトは async にするとjQueryの読み込み前に実行される可能性があります
  • jQueryを完全に削除する前に、使用しているすべてのプラグインがjQueryに依存していないか確認してください
  • CDNからjQueryを読み込む場合は、CDNが障害を起こした際のフォールバックも検討してください

まとめ

WordPress 6.3以降は wp_enqueue_script の第5引数に ['strategy' => 'defer'] を渡すだけでdeferが付与されます。古いバージョンは script_loader_tag フィルターで対応します。不要なEmoji・oEmbedスクリプトは削除し、TerserでMinifyしたファイルを filemtime でバージョン管理します。

お気軽にご相談ください

お見積りへ お問い合わせへ