Оптимизация и ускорение загрузки страницы товара сайта codan.com.ua (Opencart) техническая часть

Продолжение статьи «Оптимизация и ускорение загрузки страницы товара сайта codan.com.ua (Opencart)».

Техническая часть

Продолжим, для тех, кто желает технических деталей…

Хочу заметить, что работы по ускорению загрузки этого сайта мной уже проводились в начале 2018 года.

На VPS-сервер мной был установлен и настроен серверный модуль от Google — mod_pagespeed. Тогда, не было упора на мобильные страницы, мы получили увеличение некоторое скорости загрузки страниц раза в 2, и на этом успокоились. Теперь этим уже не обойтись, необходима максимальная скорость загрузки страниц именно на мобильных устройствах, и это обещает сэкономить деньги на рекламе… придется переделывать верстку, логику страницы, загрузку JavaScript-библиотек, CSS стили…

Начнем работу с рекомендаций сайта-тестера Google Page Speed Insights.

Самое простое — это уменьшить трафик за счет уменьшения размера изображений в пикселях, до необходимого, на странице при мобильном разрешении.

На странице товара, в инспекторе Chrome определяем необходимый размер изображений для каждой картинки при мобильном разрешении — 360 рх:

 

Нынешний размер

Необходимый размер

 

 

Файл изображения

Разрешение

Размер файла (byte)

Разрешение

Размер файла (byte)

Экономия (byte)

Уменьшено в %

Размер большого изображения товара

14778.jpg

800 х 800рх

193593

400 х 400рх

13006

180587

1488

Карусели «Ранее просмотренные товары» и «Сопутствующие товары»

132238.jpg

200 х 200рх

8806

130 х 130рх

4708

4098

187

 

В данной теме Opencart необходимые размеры картинок выставляются в настройках темы:

Модули ⇒ Расширения ⇒ Темы ⇒ Інтернет-магазин Кодан ⇒ Размер большого изображения товара = 400 х 400

Модули ⇒ Расширения ⇒ Темы ⇒ Інтернет-магазин Кодан ⇒ Размер дополнительных изображений товара = 80 х 80

Модули ⇒ Расширения ⇒ Темы ⇒ Інтернет-магазин Кодан ⇒ Размер изображения аналогичных товаров= 130 х 130

 

Остальные картинки, пока не представляют особого интереса для оптимизации, ввиду небольшого размера и последующего сжатия\конвертации модулем mod_pagespeed в .webp формат и кеширования в браузере пользователя.

Для того, чтобы еще уменьшить первоначально загружаемый объем графических файлов применил технологию Lazy Load — в этом случае загружаются только видимые на первом экране графические файлы.

В данном проекте для всех слайдеров товаров используется  библиотека slick.js

Для реализации технологии Lazy Load для slick.js необходимы следующие настройки:


$('.product-full').slick({   //основное большое изображение товара
    lazyLoad: 'ondemand',
    slidesToShow: 1,
    slidesToScroll: 1,
    arrows: false,
    fade: true,
    asNavFor: '.product-full3'
  });

Аналогичные настройки при инициализации всех остальных слайдеров и каруселей.

При выводе изображений товара в макете страницы товара используем атрибут data-lazy:


<img data-lazy="<?php echo $image['thumb']; ?>" title="<?php echo $heading_title; ?>" alt="<?php echo $heading_title; ?>" />

Аналогично выводим изображения товаров на всех остальных слайдерах и каруселях «Ранее просмотренные товары» и «Сопутствующие товары».

Применение технологии Lazy Load позволяет не только снизить объем трафика данных, а и уменьшает количество начальных запросов к серверу, что в свою очередь уменьшает TTFB страницы.

CSS

Следующим этапом будет оптимизация загрузки файлов CSS.

Огромный основной файл стилей style.css загружается около секунды, поэтому я выделил в отдельный файл style_for_head.css  только стили, необходимые на первом экране мобильной страницы. Его размер в 10 раз меньше размера основного style.css. Именно его я и подключаю в первую очередь.  Дополнительно, для того, что-бы модуль mod_pagespeed не объединял этот файл стилей с остальными, я его добавляю в исключения для mod_pagespeed. Приходится бороться за каждую миллисекунду…

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

Подключение файла search_an.css, а он подключался в хедере,  перенес из модуля (модификатора) search_an.ocmod.xml в шаблон footer.tpl.

 

Следующая рекомендация Google Page Speed Insights:

Сокращение структуры DOM до оптимизации

Для уменьшения размера кода страницы (размер структуры Dom), возникла идея подгружать мобильное меню с категориями уже после загрузки всей страницы. Посчитал, все пункты меню(категории товаров) и получилось 70 пунктов, а если на каждый пункт используется 3-4 Dom-элемента — получится экономия 200-300 Dom-элемента…
Написал ajax функцию :


function LoadMobilMenu(){
  console.log('mobil-menu');
  var div = $(this);
  $.ajax({
    method: "POST",
    url: "/index.php?route=common/header/get_mobmenu",
    data: {},
    cache: false,
    dataType: 'json',
    success: function(json) {
        if (json['success']) {
            $('.mob-categories li:first').before(json['content']);
        }
      }
    })
  }

 

Php-обработчик common/header/get_mobmenu приводить не буду, ввиду его громоздкости…
В результате требование «Сократите размер структуры Dom» исчезло…

Сокращение структуры DOM после оптимизации

и аудит «Сокращение размера структуры Dom» появился в успешных аудитах:

Сокращение структуры DOM в успешных аудитах

За счет этой, конечно не очень простой операции, удалось сократить структуру Dom на 1099 – 729 = 370 элементов. Дополнительно, на несколько килобайт уменьшился и размер html страницы, а это все время…  

И вот, чего мы достигли в результате этих действий:

Pagespeed, промежуточный этап

А теперь облегчим работу для процессора смартфона, он хоть и 8-ми ядерный (у некоторых продвинутых моделей ), но не у всех. И скорей он заточен на энергосбережение, чем на производительность, и больше всего его нагружает JavaScript код, который на первой, видимой части страницы, очень редко когда нужен.

Оптимизация JavaScript

На первом видимом экране, в нашем случае, основным элементом для Google является большое изображение товара:

Самый большой видимый элемент

Этот элемент выводится слайдером товара. Поэтому нам нужно загрузить и проинициализировать этот слайдер как можно раньше.

Для этого я применил предварительную загрузку контента при помощи rel=»preload»:


<link rel="preload" href="catalog/view/js/slick.min.js" as="script">
<link rel="preload" href="catalog/view/js/slick-init.js" as="script">

 

Выделил из common.js эту часть кода, отвечающую за инициализацию — slick-init.js для ранней инициализации слайдера товара.

А теперь постараемся вынести весь остальной JavaScript-код в футер, или, что еще лучше, в отложенную загрузку. И чем меньше JavaScript будет в <head> части сайта, тем лучше будут показатели в Google PageSpeed.
Этот процесс самый сложный и занимает больше всего времени.
Потому, что изменение порядка чередования JavaScript файлов может полностью нарушить работоспособность какого-то функционала сайта, причем на этой, оптимизируемой странице все может работать, а например на странице оформления заказа может не работать или работать не так, как хотелось-бы .

Смотрим… какие «лишние» JavaScript-файлы грузятся в самом начале и распределяем их кого куда:

Смотрим какие «лишние» JavaScript-файлы грузятся в самом начале и распределяем их кого куда

Дальше все просто  

Находим в каком модуле, плагине загружается каждый файл и переставляем, если это возможно, загрузку его в нужное место. Нужно полностью понимать для чего нужен этот файл и к чему приведет его перестановка в другое место…
После каждого изменения кода необходимо проверить не появились ли ошибки в консоли JavaScript и не нарушилось функционирование ВСЕХ страниц сайта…
Для отложенной загрузки использовал такой код:


$(window).load(function () { //сформирована абсолютно вся страница и загружены все картинки и другие мультимедийные элементы.
 setTimeout(function() { 
   loadJScript("./catalog/view/js/ion.js");
   loadJScript("./catalog/view/javascript/cookiespolicy.js");
   loadJScript("./catalog/view/javascript/inputmask.min.js"); 
.........
   }, an_javascript_aside );

function loadJScript(src) {
  let script = document.createElement('script');
  script.src = src;
  document.body.append(script);
  }
});

Переменная an_javascript_aside вводится а административной части в настройках обновленного модуля Сервис_An и называется — Отложить загрузку некоторых JavaScript на (мСек).
В отложенную загрузку были помещены следующие JavaScript:
— cookiespolicy.js
— inputmask.min.js
— magnific-popup.min.js
— ion.js
— classie.js

Скрипт по выбору отделений Новой почты убрал из общего common.js и перенес на страницу Checkout.
Скрипт notice_an.js перенес их хедера в футер, для этого пришлось доработать модуль Notice_An.

В процессе анализа файлов был обнаружен абсолютно не нужный на странице товара файл JavaScript — ajax-product-page-loader.js. Пришлось переделать модификатор модуля An Category Product Ajax Loader by Andrey_An (2018) с целью загрузки нужных скриптов только на странице категорий.

Google Tag Manager

Это отдельная категория JavaScript файлов. Хотя они и загружаются асинхронно, но они все равно, по мнению САМОГО Google PageSpeed, почему-то сильно тормозят загрузку. Посему решено было их забросить в отложенную загрузку посредством все того-же setTimeout(function() {…
Для этого типа скриптов в админке ввел свою задержку.

Web шрифты

В данном проекте используются шрифты Open Sans и Roboto, которые грузились с внешнего ресурса fonts.googleapis.com, а это дополнительное время на соединение, скачивание… Эти шрифты были скачаны и установлены на сервер. Также, для ускорения отрисовки страницы, ко всем шрифтам был добавлен параметр swap, с помощью которого, не дожидаясь загрузки красивого и тяжёлого внешнего шрифта, показывает текст в браузере сразу, используя встроенный в этот же браузер шрифт (например sans-serif). Это сразу же убирает один из ошибок в Google Page Speed.

CLS (Cumulative Layout Shift)

Большое совокупное смещение макета(CLS) приводит к дерганию элементов страницы в процессе загрузки. За счет более раннего подключения нужных стилей, ранней инициализации слайдеров товара удалось сократить этот показатель с 0,921 до 0,068, т.е. в 13.5 раз.

Минификация файлов JavaScript и CSS

Ввиду того, что мне приходится постоянно что-то делать с сайтом, изменять \ дорабатывать файлы шаблонов, JavaScript , CSS… , то исходные файлы решил не минифицировать, а эту функцию минификации я решил возложить на модуль mod_pagespeed. Посему еще тогда был написан модуль для управления mod_pagespeed посредством оперативного изменения файла .htaccess. Этот модуль был написан ранее, еще при внедрении самого mod_pagespeed, но тогда там было минимум настроек:

Модуль до доработки

Сейчас же я решил включить туда еще некоторые дополнительные настройки:

Модуль после доработки

Модифицированный модуль позволяет управлять серверным модулем mod_pagespeed из админ-панели сайта:
— включить\выключить модуль mod_pagespeed;
— очистить cash модуля mod_pagespeed;
— вывод контейнера GTM можно отключить или отложить его подключение по времени;
— включить\выключить cash браузера;
— объединять JavaScript-файлы;
— minифицировать(сжимать) JavaScript-файлы;
— отложить подключение по времени некоторых JavaScript-файлов;
— объединять CSS;
— min-ифицировать(сжимать) CSS;
— конвертировать jpeg, png в webp;
— включить\выключить ленивую загрузка изображений (lazyload_images);
— не обрабатывать файлы(список файлов через ; )

Сервер

При анализе работы сервера, было обнаружено несколько узких мест:
— в файле .htaccess было Header set Cache-Control «max-age=2592003» — 30 дней
ставим 33696039 30 дней * 13 = 1 год + и еще добавил туда woff2. Аудит стал успешным;

— в файле .htaccess было обнаружено более 200 строк 301-редиректов, так понимаю это с старого, несуществующего уже сайта на нынешний. Также я выяснил, что последний раз это дело менялось почти 2 года назад — 17.10.18., а каждый запрос к серверу,а их около сотни на каждую страницу (любая картинка или файл) пробегает всю эту цепочку… Заказчик дал добро на удаление этих редиректов. Так мы сэкономили еще немного времени;
— Для дальнейшего увеличения скорости загрузки необходим протокол HTTP/2, который уже поддерживают все браузеры и который позволяет сильно ускорить обмен данными между браузером и сервером. Наш сервер был создан почти 4 года назад и имеет: Ubuntu 16 в качестве системы , Apache 2.4.18 в качестве вебсервера, PHP Version 7.0… Вообщем это сильно устаревшие на сегодняшний день продукты. Для поддержки протокола HTTP/2 необходим вебсервер Apache с версии 2.4.24. Поэтому в дальнейшем мы переходим на новый сервер с Ubuntu 20 и всеми новыми серверными продуктами. Но это уже другая история…
Работы были начаты 25.07.2020 и закончены 17.08.2020.