Оптимизация сайта для PageSpeed

Задача

Провести оптимизацию выдачи контента Битрикс, контроль качества оптимизации провести при помощи PageSpeed Insights.

Решение

Инструменты для проверки скорости

Сервисы оптимизации изображений

Общие рекомендации

  • 1) Привести в соответствие изображения, таким образом, что бы браузеру не приходилось их масштабировать
  • 2) Включить сжатие файлов в nginx
  • 3) При помощи настроек битрикс перенести js и css в конец страницы
  • 4) Минифицировать js и css при помощи gulp или иными средствами
  • 5) Исключить служебные скрипты и стили битрикс из формирования пользовательских страниц сайта
  • 6) Минифицировать html

Перенос js и css в конец страницы

JS

Для корректной работы битрикс с файлами стилей и скриптов их нужно подключать при помощи функций Битрикс:

<?php
$asset = \Bitrix\Main\Page\Asset::getInstance();

// подключение стилей 
$asset->addCss(SITE_TEMPLATE_PATH.'/some.css');

// подключение скриптов
$asset->addJs(SITE_TEMPLATE_PATH.'/some.js');

// подключение произвольных кусков кода
$asset->addString('<link rel="canonical" href="https://'.$_SERVER['HTTP_HOST'].$APPLICATION->GetCurPage(false).'"/>');

Для объединения всех стилей и скриптов в единый файл нужно в настройках Битрикс Настройки -> Настройки продукта -> Настройки модулей -> Главный модуль активировать галки Объединять CSS файлы и Объединять JS файлы

Так же можно проставить галки Создавать сжатую копию объединенных CSS и JS файлов и Переместить весь Javascript в конец страницы

Программно опцию “Переместить весь Javascript в конец страницы” можно активировать так:

$asset->setJsToBody(true);

В случае программной активации галочка в админкеработать не будет, т.е. скрипты всегда будут помещаться в конец страницы.

Не все скрипты нужно помещать в футер. например tagManager от гугла должен быть вверху. Для исключения скрипта из переносимых нужно добавить атрибут data-skip-moving=true в тег script. Пример:

<script data-skip-moving="true">
  // your script code
</script>

CSS

Для переноса CSS в конец страницы у Битрикса нет стандартных средств, но т.к. за вывод css отвечает отдельный метод, то мы можем вывести его в footer.php самостоятельно.

Для этого нужно вместо:

<?php
$APPLICATION->ShowHead();
?>

В файле header.php добавить:

<?php
// вместо $APPLICATION->ShowHead();
$bXhtmlStyle = true;
echo '<meta http-equiv="Content-Type" content="text/html; charset='.LANG_CHARSET.'"'.($bXhtmlStyle? ' /':'').'>'."\n";
$APPLICATION->ShowMeta('robots', false, $bXhtmlStyle);
$APPLICATION->ShowMeta('keywords', false, $bXhtmlStyle);
$APPLICATION->ShowMeta('description', false, $bXhtmlStyle);
$APPLICATION->ShowLink('canonical', null, $bXhtmlStyle);
$APPLICATION->ShowHeadStrings();
$APPLICATION->ShowHeadScripts();
?>

В файле footer.php добавить:

<?php
$APPLICATION->ShowCSS(true, $bXhtmlStyle);
?>

Исключить служебные скрипты и стили битрикс из формирования пользовательских страниц сайта

Для этого нужно добавить обработку контента страницы перед выдачей его из буфера браузеру.

В init.php должно быть добавлено подключение файлов констант, обработчиков и функций, т.к. все действия уже будем совершать с ними.

Пример подключения файлов в init.php:

<?php
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();

// Подключение констант
if(file_exists($_SERVER['DOCUMENT_ROOT'].
'/local/php_interface/include/constants.php'))
{
require_once($_SERVER['DOCUMENT_ROOT'].
'/local/php_interface/include/constants.php');
}

// Подключение обработчиков событий
if(file_exists($_SERVER['DOCUMENT_ROOT'].
'/local/php_interface/include/handlers.php'))
{
require_once($_SERVER['DOCUMENT_ROOT'].
'/local/php_interface/include/handlers.php');
}

// Подключение глобальных функций (чаще всего используется для переноса кода сторонних разработчиков
// при получении проекта на доработку)
if(file_exists($_SERVER['DOCUMENT_ROOT'].
'/local/php_interface/include/functions.php'))
{
require_once($_SERVER['DOCUMENT_ROOT'].
'/local/php_interface/include/functions.php');
}

В файл functions.php добавим функции обработчиков событий:

<?php
// удаляем скрипты ядра при отдаче сайта пользователям
function deleteKernelJs(&$content) {
    global $USER, $APPLICATION;
    if((is_object($USER) && $USER->IsAuthorized()) || strpos($APPLICATION->GetCurDir(), '/bitrix/')!==false) return;
    if($APPLICATION->GetProperty('save_kernel') == 'Y') return;

    $arPatternsToRemove = Array(
        '/<script.+?src=".+?kernel_main\/kernel_main\.js\?\d+"><\/script\>/',
        '/<script.+?src=".+?bitrix\/js\/main\/core\/core[^"]+"><\/script\>/',
        '/<script.+?>BX\.(setCSSList|setJSList)\(\[.+?\]\).*?<\/script>/',
        '/<script.+?>if\(\!window\.BX\)window\.BX.+?<\/script>/',
        '/<script[^>]+?>\(window\.BX\|\|top\.BX\)\.message[^<]+<\/script>/',
    );

    $content = preg_replace($arPatternsToRemove, '', $content);
    $content = preg_replace("/\n{2,}/", "\n\n", $content);
}

// удяляем css ядра при отдаче сайта пользователям
function deleteKernelCss(&$content) {
    global $USER, $APPLICATION;
    if((is_object($USER) && $USER->IsAuthorized()) || strpos($APPLICATION->GetCurDir(), "/bitrix/")!==false) return;
    if($APPLICATION->GetProperty('save_kernel') == 'Y') return;

    $arPatternsToRemove = Array(
        '/<link.+?href=".+?kernel_main\/kernel_main\.css\?\d+"[^>]+>/',
        '/<link.+?href=".+?bitrix\/js\/main\/core\/css\/core[^"]+"[^>]+>/',
        '/<link.+?href=".+?bitrix\/templates\/[\w\d_-]+\/styles.css[^"]+"[^>]+>/',
        '/<link.+?href=".+?bitrix\/templates\/[\w\d_-]+\/template_styles.css[^"]+"[^>]+>/',
    );

    $content = preg_replace($arPatternsToRemove, '', $content);
    $content = preg_replace("/\n{2,}/", "\n\n", $content);
}

В файл handlers.php добавим обработку событий:

<?php
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();

$eventManager = \Bitrix\Main\EventManager::getInstance();

// удяляем скрипты ядра при отдаче сайта пользователям
$eventManager->addEventHandler('main', 'OnEndBufferContent', 'deleteKernelJs');

// удяляем css ядра при отдаче сайта пользователям
$eventManager->addEventHandler('main', 'OnEndBufferContent', 'deleteKernelCss');