WP 6.3: Атрибуты ASYNC и DEFER при регистрации скриптов
В WordPress версии 6.3 появилась поддержка регистрации скриптов с атрибутами async
и defer
. Это улучшение было добавлено в рамках обновления существующего API для работы со скриптами и решает давнюю проблему, описанную в тикете #12009.
Теперь доступны следующие стратегии загрузки скриптов:
- Блокировка — скрипт блокирует загрузку страницы. Это поведение по умолчанию.
- Отложенная загрузка — стратегия
defer
. - Асинхронная загрузка — стратегия
async
.
Содержание
- Зачем это нужно?
- Что изменилось в WordPress
- Пример: отложенная загрузка скрипта в заголовке
- Пример: асинхронная загрузка скрипта в подвале
- Детали реализации
- О зависимостях
- Изменения в параметре $in_footer функций wp_register_script() и wp_enqueue_script()
- wp_script_add_data() - Поддержание совместимости
- Изменение указанной стратегии из-за зависимостей
- Встраиваемые скрипты
- Переход на новый API
Зачем это нужно?
Добавление атрибутов defer
или async
к тегам скриптов позволяет загружать скрипты без "блокировки" загрузки остальной части страницы. Это улучшает производительность сайта, особенно по метрике Largest Contentful Paint (LCP).
Ранее разработчики использовали менее удобные альтернативы, например:
- Прямое фильтрование тегов на этапе вывода с использованием фильтра
script_loader_tag
. - Использование фильтра
clean_url
, что считалось плохой практикой. - Обработка вывода тегов со скриптами через
wp_print_script_tag
.
Все эти подходы не учитывают зависимости скриптов, что может приводить к проблемам совместимости или ошибкам при работе с другими скриптами.
Кратко о различиях между defer
и async
:
-
Отложенные скрипты (
defer
): Скрипты с этим атрибутом выполняются только после полной загрузки DOM-дерева (но до события DOMContentLoaded). Скрипты, помеченныеdefer
, выполняются в порядке их появления в HTML. -
Асинхронные скрипты (
async
): Скрипты с этим атрибутом загружаются без блокировки страницы (браузер не ждет загрузки скрипта) и выполняются сразу после загрузки. Асинхронные скрипты не соблюдают порядок, в котором они появляются в коде.
Что изменилось в WordPress
Изменения можно описать так:
-
WordPress теперь позволяет указывать стратегию загрузки скриптов при вызовах функций
wp_register_script()
иwp_enqueue_script()
. -
Эти функции получили новые сигнатуры — вместо параметра
boolean $in_footer
теперь используется массив$args
, в котором можно указать, как и где должен з��гружаться скрипт. Обратная совместимость с типомboolean
сохранена. -
Стратегию загрузки также можно указать через
wp_script_add_data()
, что может быть полезно для совместимости с предыдущими версиями кода. -
Класс
WP_Scripts
был доработан для поддержки новых стратегий загрузки.
Пример: отложенная загрузка скрипта в заголовке
Стратегию загрузки можно указать, передав массив с параметрами в функцию wp_register_script()
:
wp_register_script(
'my_script',
'https://example.com/path/to/my_script.js',
[],
'1.0',
[
'strategy' => 'defer'
]
);
Пример: асинхронная загрузка скрипта в подвале
Для загрузки в подвал с использованием асинхронного скрипта код будет выглядеть так:
wp_register_script(
'my_script',
'https://example.com/path/to/my_script.js',
[],
'1.0',
[
'in_footer' => true,
'strategy' => 'async',
]
);
Детали реализации
Функция теперь учитывает дерево зависимостей скрипта при выборе подходящей стратегии, чтобы избежать ситуации, когда стратегия подходит одному скрипту, но негативно сказывается на других в дереве. Это было практически невозможно сделать с использованием предыдущих методов.
Реализация загрузки скриптов была выполнена без разрушения существующего API. Улучшения касаются всех функций API скриптов, таких как wp_register_script()
и wp_enqueue_script()
.
О зависимостях
Для ясности давайте разъясним различие между зависимыми скриптами и зависимостями:
-
Зависимые скрипты — это скрипты, которые зависят от текущего скрипта, т.е. они автоматически включают текущий скрипт перед своей загрузкой.
-
Зависимости — это скрипты, от которых зависит текущий скрипт, т.е. их необходимо загрузить до вызова текущего скрипта.
Изменения в параметре $in_footer функций wp_register_script() и wp_enqueue_script()
Наиболее заметным изменением в функциях wp_register_script()
и wp_enqueue_script()
стало изменение сигнатуры, где параметр $in_footer
теперь принят в виде массива $args
с ключами:
- in_footer (bool) — ведет себя так же, как и предыдущая реализация параметра
$in_footer
. - strategy (string) — указывает, какой стратегией следует использовать для загрузки скрипта. В настоящее время доступны два значения:
defer
иasync
.
По умолчанию используется блокирующее поведение, что сохраняет обратную совместимость с существующими регистрациями и вызовами скриптов.
wp_script_add_data() - Поддержание совместимости
Полная обратная совместимость сохраняется для предыдущего использования функций wp_register_script()
и wp_enqueue_script()
с использованием булевого параметра $in_footer
. Это означает, что данное улучшение не нарушает API.
Хотя изменения не критичны, при использовании нового параметра $args
в плагинах или темах, работающих на версиях WordPress < 6.3, возможно недопонимание параметра $in_footer
.
Простой способ избежать таких проблем совместимости — использовать функцию wp_script_add_data()
:
wp_register_script(
'my_script',
'https://example.com/path/to/my_script.js',
[],
'1.0.0',
false
);
wp_script_add_data('my_script', 'strategy', 'defer');
Изменение указанной стратегии из-за зависимостей
Несмотря на то что разработчик может указать определенную стратегию загрузки, итоговая стратегия может отличаться. Это зависит от зависимостей скрипта и встроенных скриптов.
Например, если разработчик зарегистрировал скрипт с атрибутом defer
, но зависимые от него скрипты используют блокирующую стратегию, то скрипт с атрибутом defer
и все его зависимости автоматически станут блокирующими.
Новая логика в классе WP_Scripts
отвечает за выполнение логических проверок, чтобы убедиться, что итоговая стратегия для данного скрипта является оптимальной на основе описанных факторов.
Встраиваемые скрипты
Не забудьте о функции wp_add_inline_script()
для добавления встроенных скриптов.
Существуют некоторые нюансы при применении стратегии загрузки для скриптов, которые зависят от встроенных скриптов. Встроенные скрипты, зарегистрированные в позиции "до", ведут себя почти неизменно, так как они включаются до применения каких-либо стратегий.
Однако встроенные скрипты, зарегистрированные в позиции "после", могут повлиять на финальную стратегию загрузки родительского скрипта, если у него установлены атрибуты async
или defer
. Это может изменить зависимость итогового дерева скриптов.
Для дальнейших обсуждений на эту тему и возможных изменений был открыт дополнительный тикет #58632.
Переход на новый API
Код, использующий устаревшие методы для добавления атрибутов async
или defer
к тегам скриптов, должен перейти на новый API. Это касается и тех скриптов, где атрибуты добавлялись с помощью фильтра script_loader_tag
или фильтра clean_url
.
Пример 1: Добавление атрибута DEFER через script_loader_tag
add_filter('script_loader_tag', 'old_approach', 10, 2);
function old_approach($tag, $handle) {
if ('foo' !== $handle) {
return $tag;
}
return str_replace(' src=', ' defer src=', $tag);
}
Пример 2: Добавление атрибута DEFER через clean_url
add_filter('clean_url', 'old_brittle_approach');
function old_brittle_approach($url) {
if (false === strpos($url, 'foo.js')) {
return $url;
}
return "$url' defer ";
}
Если вы используете подход, подобный описанному выше, для добавления атрибутов defer
или async
, перейдите на новый API, используя один из ранее описанных методов.
Таким образом, в WordPress 6.3 введены важные изменения для улучшения управления загрузкой скриптов, что непосредственно сказывается на производительности сайтов.