Скорость загрузки сайта крайне важный параметр. Тут дело не только в удобстве в работе с ресурсом, но и важный показатель для SEO оптимизации.

Оценка Google PageSpeed Insights «Для компьютеров» перед оптимизацией.

В этой статье расскажу про ускорения лендинга для одного интернет магазина женской одежды работающего на 1с-Битрикс.

Чаше всего есть несколько путей реализовать поставленную задачу. К примеру настроить отдачу картинки в формате webp в место jpg или png можно так:

  • тег html <picture>
  • .htaccess
  • nginx
  • CDN сервис
  • и есть еще.

Я не буду освещать все возможные варианты, а опешу только то что применял сам в конкретном примере. Так же не буду подробно описывать процессы работы. В интернете уже есть куча материалов по всем этим фичам, заново проектировать велосипед не будем.

Архитектура сайта.

Лендинги находятся на поддоменах основного сайта и работаю на одном ядре 1с-Битрикс. Внедрялись посадочные страницы еще до появления «Сайтов24» и были разработаны на стороннем сервисе «Хамелеон». Использовали одно ядро с магазином, что бы подтягивать нужные товары из каталога для демонстрации, и проверять юзеров при потытки зарегистрироваться.

Было решено отказаться от функционала 1с-Битрикс, сайт был полностью переделан в самописную схему MVC.

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

Для загрузки товаров был добавлен отдельный инфоблок. По событию сохранение инфоблока была реализована отправка данных инструментом cURL, на стороне лендинг данные записываются в ною базу.

Второй момент требующий данных с основного сайта это регистрация нового пользователя. Тут все еще проще. Ajax’ом отправляем данные пользователя на сайт, регистрируем стандартным компонентом bitrix:register. Если регистрация не прошла отправляем лиду ошибку регистрации, если регистрация успешна, то перенаправляем пользователя на основной сайт. При перенаправлении передаем get пораметром хук с уникальным кодом, по этому хуку сразу авторизуем нового клиента.

Стили и скрипты.

  1. Отключили все внешние подключения статических данных. В header’е несколько тегов line подгружали шрифты с google fonts. рифты были загружены и подключены в style.css
  2. Асинхронная загрузка. Для скиптов добавили атрибут «async» <script async src="example.js"></script>. Тут важно понять что можно загружать асинхронно, а что необходимо отдавать сразу. Скрипты завязанные с jquery и участвующие в формировании DOM должны подгружаться сразу. Карту с Яндекс.Карты было решено совсем не отображать при загрузке страницы, а отдавать ее ajax’ом по запросу пользователя.
  3. Сжатие и удаление не использующегося кода. Так как сайт старый в статических файлах накопилось много устаревшего кода. Очистку и сжатия реализовали с помощью инструмента на node.js Grunt. Установили Grunt и нужные нам плагины, в корне проекта создаем файл Gruntfile.js в нем подключаем нужные плагины функцией grunt.loadNpmTasks(), при помощи метода registerMultiTask() объявляем нужные нам задачи. Теперь из консоли вызываем нужную задачу и Grunt преобразует наши файлы.

Изображения.

Основная часть веса страницы это конечно изображения. На данным момент формат .webp поддерживается большинством браузеров, в этот формат мы и будем конвертировать с помощью плагина cwebp на том же node.js

Устанавливаем и настраиваем cwebp, под node пишем функцию которая будет выдергивать картинки из нужной нам папки и создавать ее копию в webp рядышком. Приведем код тут, благо он не большой:

var path = require('path');
var fs = require('fs');
var async = require('async');
var webp = require('webp-converter');

function getFiles (dirPath, callback) {
    fs.readdir(dirPath, function (err, files) {
        if (err) return callback(err);
        var filePaths = [];
        async.eachSeries(files, function (fileName, eachCallback) {
            var filePath = path.join(dirPath, fileName);
            fs.stat(filePath, function (err, stat) {
                if (err) return eachCallback(err);
                if (stat.isDirectory()) {
                    getFiles(filePath, function (err, subDirFiles) {
                        if (err) return eachCallback(err);
                        filePaths = filePaths.concat(subDirFiles);
                        eachCallback(null);
                    });
                } else {
                    if (stat.isFile() && /\S+(?:jpg|jpeg|png)$/.test(filePath)) {
                        filePaths.push(filePath);
                    }
                    eachCallback(null);
                }
            });
        }, function (err) {
            callback(err, filePaths);
        });
    });
}

getFiles('/var/www/data/template/img', function (err, files) {

    for(let i=0; i<files.length; i++){
        function ChangePhoto(foto){
            fs.access(foto + ".webp", function (error) {
                if (error != null) {
                    webp.cwebp(error.path.slice(0, -5), error.path, "-q 70", function (status, error) {
                        // if conversion successful status will be '100'
                        // if conversion fails status will be '101'
                    });
                }
            });
        }
        setTimeout(() => { ChangePhoto(files[i]) }, i * 300);
    }
});

Теперь нам важно настроить отдачу webp вместо jpg, в тех браузерах которые поддерживают новый формат изображений. Я посчитал наиболее подходящим настроить настроить подмену на nginx. Конфиг будет выглядеть примерно так:

location ~* ^(.*)(/static/.*)(jpg|jpeg|png)$ {
    set $webp $1$2webp;
    set $rootFile "${document_root}${webp}";
    if ($http_accept ~* "webp"){set $test A;} if (-f $rootFile)
    {set $test "${test}B";}
    if ($test = AB) { add_header Vary Accept; rewrite (.*) $webp break; }
}

Картинки которые еще не попали в поле зрения клиента можно скрыть, и загрузить их поле того как они попадут в область экрана. Я выбрал плагин B-Lazy. Он достаточно легкий, быстро подключается и работает стабильно. Так же есть возможность добавить gif на время загрузки картинки.

Кеширование.

Крайне важный параметр для современных сайтов. Большое наличие стилей, скриптов и медиа нагружает наш сервер, кеширование существенно снизит эту нагрузку.

Что бы объяснить браузеру что данные станицы необходимо занести в кеш мы выставим HTTP-заголовок Expires, и добавим в файл .htaccess, следующие строки:

<IfModule mod_expires.c>
Header append Cache-Control "public"
FileETag MTime Size
ExpiresActive On
ExpiresDefault "access plus 0 minutes"
ExpiresByType image/ico "access plus 1 years"
ExpiresByType text/css "access plus 1 years"
ExpiresByType text/javascript "access plus 1 years"
ExpiresByType image/gif "access plus 1 years"
ExpiresByType image/jpg "access plus 1 years"
ExpiresByType image/jpeg "access plus 1 years"
ExpiresByType image/bmp "access plus 1 years"
ExpiresByType image/png "access plus 1 years"
</IfModule>

Данная конфигурация Apache проверяет наличие модуля mod_expires и, если модуль mod_expires доступен, включает отдачу HTTP-заголовков Expires, в котором мы установили срок жизни кеша.

На этом все. Учитывая то, что на лендинге и так мало данных мы еще максимально облегчили его отказавшись от CMS. В нашем примере таблицы БД не превышали 50 полей. На более тяжелых проектах конечно не получится ограничится только оптимизацией фронтэнда. Там уже необходимо оптимизировать запросы к MySQL, добавлять memcache в бэкенд-архитектуру, рассмотреть связку Nginx + php-fpm, использовать CND и прочее.

Оценка Google PageSpeed Insights «Для компьютеров» после оптимизации.
Malashko
miv-men@mail.ru

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *