Node.js: как рекурсивно сжать все изображения на сайте за 1 час


31-08-2018
Денис Л.
JavaScript
11
3804
Node.js: как рекурсивно сжать все изображения на сайте за 1 час

Не так давно я начал работать с Node.js. Отличная штука, скажу я Вам! К примеру, освоив некоторые его основные функции и подключив нужные модули, Вы можете в автоматическом режиме сжимать стили на своём сайте, javascript, изображения и прочее. Сегодня я расскажу про то, как в течении 1 часа я сжал все изображения сайта на 1С-Битрикс, а именно 1215 штук. Все изображения были в папке /upload/medialibrary/, причём каждое находилось в отдельной папке. Эта ситуация знакома пользователям Битрикса, Вордпресса и некоторых других CMS. Системы управления размещают каждую картинку у каждого нового поста в отдельную папку. В моём случае всего было 1200 папок с изображениями. Сделать всё это вручную просто нерационально с точки зрения трудозатрат.

Забегая вперёд, скажу, что до оптимизации вес папки medialibrary был 121 Мб, после оптимизации стал 78 Мб. Разница - 43 Мб. Каждое изображение стало в среднем меньше на 35% и всё это - (!) абсолютно без потери качества!

Если Вы не особо дружите с консолью, то для Вас больше подойдёт мой пост про постраничную оптимизацию изображений: Google PageSpeed Insights: автоматическая оптимизация изображений сайта

Итак, как с помощью Node.js оптимизировать все изображения на сайте

Первым делом, нам понадобится Node.js. Устанавливаем его на сервер. Если Вы не являетесь владельцем выделенного сервера, то Вам придётся устанавливать его к себе в операционную систему и работать с локальными файлами. Я же делал всё через консоль, напрямую на нашем выделенном сервере. Вот сайт, с которого Вы можете скачать и установить Node.js: nodejs.org

Для пользователей Windows рекомендую скачивать наиболее стабильную версию: LTS. Далее для пользователей Windows инструкция будет такой же, с небольшим отличием: предварительно Вам потребуется скачать папку с изображениями на Ваш компьютер. Если у Вас есть root права и Вы проводите работы напрямую на сервере, то, разумеется, ничего скачивать не нужно :)

Подключаемся к серверу через консоль, используя SSH.

Затем устанавливаем Node.js на сервер:

Если у Вас Linux на базе Debian и Ubuntu, то команда в консоли будет следующей:

sudo apt-get install -y nodejs  

Если у Вас другие версии Linux, то вместо apt-get используйте другую команду установки, соответствующую менеджеру пакетов Вашего сервера.

После установки, заходим на один уровень выше корня нашего сайта и выполняем команду:

npm init -y

Этой командой мы создаём файл конфигурационный файл package.json. Данный файл будет хранить сведения об установленных пакетах, а также Вы можете заполнить строки с описанием Вашего проекта, автором и другие. Это на Ваше усмотрение, для выполнения оптимизации этого не требуется.

Далее нас интересует сервис tinypng.com - один из лучших сервисов по сжатию изображений, без потери качества. Заводим учётную запись на данном сервисе. Это необходимо для получения API key, который мы будем использовать чуть позже.

Теперь нам нужно установить модуль tinify для нашего Node. Для этого в консоли выполняем:

npm install --save tinify

После успешной установки, если Вы посмотрите файл package.json, то в разделе "dependencies" у Вас появится запись: "tinify" и номер версии.

После этого, в той же папке, в которой мы находимся, создаём файл, называем его, например: tinifyRecurse.js

Ниже привожу содержимое файла и немного комментариев.


var fs = require('fs');
var tinify = require("tinify");

// Ниже, вместо ... вставляем Ваш tinify.key. Его Вы увидите на странице Account page сервиса tinypng. 
// Чтобы попасть на эту страницу, кликните по названию Вашей учётной записи в верхнем правом углу экрана
tinify.key = "..."; 

function getFiles(dir, files_) {
    files_ = files_ || [];
    var files = fs.readdirSync(dir); // считываем все содержимое файловой системы, начиная с папки, в которой мы будем находиться на момент выполнения скрипта
    for(var i in files) {
        var name = dir + '/' + files[i];
        if(fs.statSync(name).isDirectory()) { // если перебираемый элемент цикла является папкой, то рекурсивно вызываем эту же функцию
            getFiles(name, files_);
        } 
        else { // если перебираемый элемент цикла является файлом и если расширение файла по шаблону ниже
            if(~name.indexOf('.png') || ~name.indexOf('.jpg') || ~name.indexOf('.jpeg') || ~name.indexOf('.JPG')) {
                files_.push(name); // в массив files_ пушим имя этого файла
            }
        }
    }
    return files_;
}

var imgArr = getFiles('.'); // вызываем функцию, в виде параметра передаём папку, в которой мы будем находиться на момент выполнения скрипта

var imgArrLimit = []; // создаём пустой массив для выборки лимита файлов
// дело в том, что на бесплатном аккаунте tinify Вы можете в течении месяца оптимизировать не более 500 изображений
// поэтому, если Вам нужно оптимизировать больше, чем 500 изображений, то Вам потребуется зарегистрировать несколько аккаунтов на разные почтовые ящики

for(let j in imgArr) { // перебираем все изображения нашего сайта
    if(j>=0 && j<500) { // задаём лимит по 500 за раз и делаем выборку изображений от 0-го до 499-го
        imgArrLimit.push(imgArr[j]); // пушим их в массив imgArrLimit
    }
}

for(var i in imgArrLimit) { // перебираем все файлы из массива imgArrLimit и оптимизируем их
    source = tinify.fromFile(imgArrLimit[i]);
    source.toFile(imgArrLimit[i]);
}

// чтобы узнать количество изображений на Вашем сайте, раскомментируйте строку ниже:
// console.log(imgArr.length);

Как только мы создали и сохранили файл, переходим в консоль. Заходим в папку нашего сайта. Либо в корень, либо сразу в папку, в которой Вы знаете, что там лежат все изображений Вашего сайта. И выполняем команду ниже, предварительно указав корректный путь до файла tinifyRecurse.js, исходя их корня Вашего сервера. (Чтобы узнать путь, находясь в папке с файлом tinifyRecurse.js выполните в консоли команду pwd).

После того, как путь известен, выполняем команду ниже, заменив путь до файла на корректный:

node /home/bitrix/tinifyRecurse.js   

Если изображений на нашем сайте больше, чем 500, то после оптимизации первой партии изображений, регистрируем второй аккаунт на tinify.

Далее:

  • В файле tinifyRecurse.js меняем ключ tinify.key на новый;
  • Далее в коде где у нас запускается цикл for(let j in imgArr) ставим вместо 0 и 500 цифры 500 и 1000

Повторяем две операции выше столько раз, сколько нужно в Вашем случае: новый API key --> цикл с проходом по пятиста новым файлам.

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

Буду рад, если у Вас всё получится и Вы сможете провести оптимизацию изображений Вашего сайта!

Подписывайтесь на группу в ВКонтакте, вступайте в сообщество на Facebook, чтобы всегда быть в курсе актуальных выпусков
Web development blog!

Читайте также:

Защищаем JavaScript от копирования

Как запустить Node.js на обычном хостинге

Сохраняем данные формы на сайте при перезагрузке страницы, с помощью JavaScript и sessionStorage