async & defer – это очень полезные механики, которые позволяют существенно ускорить загрузку страниц, скриптов и стилей. Рассмотрим новые интерфейсы для внедрения этих стратегий в WordPress & WooCommerce.
Простые решения перед тем как идти в детали
В целом все что будет далее – это достаточно сложные решения про тех кто понимает что делать.
Для новичков есть простые правила:
- выбираем грамотные и проверенные темы – где большая часть проблем уже решена
- ставим плагины типа WP Rocket (все в одном) или комбинации типа WP Super Cache + Autoptimize
- можно иногда правильно настроить CloudFlare или аналоги – которые позволяет сильно ускорять отдачу сайта и TTFB (нужно почти всегда для международных сайтов и для SEO ориентированны)
Проверяем через Google PageSpeed или через установку плагина SiteKit для WordPress – который позволяет видеть результаты по ходу работы с сайтом.
Если все сделано правильно – скорость сайта становится максимально высокой.
Если нет – читаем далее и готовимся к приключениям или заказываем консультацию.
Как делали раньше
Для предыдущего/существующего использования функций wp_register_script() и wp_enqueue_script(), использующих булев параметр $in_footer, обратная совместимость сохраняется с помощью логики, которая явно задает группу скриптов для применимого значения вывода в подвале или заголовке на основе булевого значения, переданного в новый/перегруженный параметр $args.
Описание метода wp_script_add_data есть тут https://developer.wordpress.org/reference/functions/wp_script_add_data/
Это было примерно так:
add_action( 'wp_enqueue_scripts', function(){
wp_enqueue_script( 'wpdemo-respond', get_template_directory_uri().'/js/respond.min.js' );
wp_script_add_data( 'wpdemo-respond', 'conditional', 'lt IE 9' );
wp_enqueue_script( 'wpdemo-html5shiv',get_template_directory_uri().'/js/html5shiv.js');
wp_script_add_data( 'wpdemo-html5shiv', 'defer', true );
});
//add support for async and defer params
add_filter( 'script_loader_tag', function($tag, $handle){
if ( wp_scripts()->get_data( $handle, 'defer' ) ) {
$tag = str_replace( '></', ' defer></', $tag );
}
if ( wp_scripts()->get_data( $handle, 'async' ) ) {
$tag = str_replace( '></', ' async></', $tag );
}
return $tag;
}, 10, 2 );
Можно посмотреть как внедряют async & defer в теме для WordPress TwentyTwenty https://github.com/WordPress/twentytwenty/pull/30/files
В новой версии WP сохранили обратную совместимость и можно делать также. Но при этом добавили новые возможности указания стратегии.
Начиная с версии WP 6.3 доступные дополнительные опции указания стратегии загрузки скриптов
- Асинхронные скрипты – Скрипты, помеченные для асинхронного выполнения с помощью атрибута
async
, выполняются сразу после их загрузки браузером. Асинхронные скрипты не имеют гарантированного порядка выполнения, так как скрипт B (хотя добавлен в DOM после скрипта A) может выполниться первым, поскольку он может завершить загрузку раньше скрипта A. Такие скрипты могут выполняться как до полной конструкции DOM, так и после события DOMContentLoaded. - Отложенные скрипты – Скрипты, помеченные для отложенного выполнения с помощью атрибута
defer
, выполняются только после полной загрузки дерева DOM (но до событий DOMContentLoaded и window load). Отложенные скрипты выполняются в том же порядке, в котором они были добавлены в DOM, в отличие от асинхронных скриптов.
пример
wp_register_script(
'foo',
'/path/to/foo.js',
array(),
'1.0.0',
array(
'strategy' => 'defer'
)
);
Асинхронная загрузка стилей
Тут мы разберемся как отложить некритичный CSS с целью оптимизации критического пути рендеринга (Critical Rendering Path, CRP) и улучшения первой контентной отрисовки (First Contentful Paint, FCP).
Во первых это опасная практика и каких то простых решений тут нет. Можно наломать дров без подготовки.
Во вторых – перед тем как сюда погружаться – надо изучить что такое Critical CSS и как его готовить https://web.dev/articles/extract-critical-css
Ряд плагинов для WP это умеют – типа Autoptimize & Rocket.
Как это работает с учетом рекомендаций Google
Детально тут https://web.dev/articles/defer-non-critical-css
Критический CSS должен загружаться как тег style
Например:
<style type="text/css">
.accordion-btn {background-color: #ADD8E6;color: #444;cursor: pointer;padding: 18px;width: 100%;border: none;text-align: left;outline: none;font-size: 15px;transition: 0.4s;}.container {padding: 0 18px;display: none;background-color: white;overflow: hidden;}h1 {word-spacing: 5px;color: blue;font-weight: bold;text-align: center;}
</style>
Не критические стили грузятся как файлы по другой схеме
link rel="preload" as="style"
запрашивает таблицу стилей асинхронно. Дополнительную информацию о предварительной загрузке можно найти в руководстве Preload critical assets guide.- Атрибут
onload
в теогеlink
позволяет обрабатывать CSS после завершения загрузки.
Пример
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>
Как уже сказано выше – многие плагины оптимизации для WP это умеют делать автоматически.
Пример аналогичного решения для шрифтов
function enqueue_font_preload() {
wp_enqueue_style('example-font-handle', 'https://domain.com/wp-content/font-file.woff2', array(), null);
}
add_action('wp_enqueue_scripts', 'enqueue_font_preload');
function style_loader_tag_filter_preload($html, $handle) {
if($handle === 'example-font-handle') {
$new_html = str_replace("text/css", "font/woff2", $html);
return str_replace("rel='stylesheet'", "rel='preload' as='font' crossorigin='anonymous'", $new_html);
}
return $html;
}
add_filter('style_loader_tag', 'style_loader_tag_filter_preload', 10, 2);
Источники
- Дока в команде Make https://make.wordpress.org/core/2023/07/14/registering-scripts-with-async-and-defer-attributes-in-wordpress-6-3/
- Defer non-critical CSS https://web.dev/articles/defer-non-critical-css