Создайте собственный конвейер сборки для минимизации и сжатия ваших активов

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

Что вы получите от этого произведения?

В этой статье мы собираемся создать серверное приложение на Nodejs, реализовав:

  • Минификация и сжатие активов с помощью Gulp и Brotli.
  • Среда разработки, в которой ресурсы уменьшаются и сжимаются в реальном времени.
  • Процесс сборки, позволяющий создавать распределяемые активы для развертывания.

Также вы познакомитесь с Gulp и Brotli. Если ваше приложение не отображается на сервере или производительность не является проблемой для вашего приложения, эта статья может быть для вас не очень информативной.

Настройка приложения:

Создайте новый каталог, инициализируйте npm и установите express и handlebars:

npm i express express-handlebars

Создайте базовый экспресс-сервер с рулем, настроенным как механизм шаблонов.

В строке 15 app.js мы устанавливаем dist как статический каталог для нашего приложения. Этот каталог dist будет автоматически сгенерирован из Gulp. Добавьте каталог представлений в корень вашего проекта и создайте main.hbs макет для нашего приложения. Поместите шаблон HTML в этот шаблон.

Добавьте активы:

Чтобы минимизировать и сжать активы, нам нужны активы. Давайте создадим папку assets в корне проекта и добавим несколько файлов CSS и JS. Структура папок приложения будет выглядеть так:

my-app
├── assets
│   └── css
│       └── styles.css
│   └── js
│       └── main.js
├── node_modules
├── views
│   └── main.hbs
├── app.js
├── package.json
└── package.lock.json

Включите созданные ресурсы в тег head шаблона main.hbs:

<link rel="stylesheet" href="/css/styles.min.css">
<script src="/js/main.min.js"></script>

Обратите внимание, что мы включаем их из каталога dist (заданного как статическая папка), которого еще не существует, но он будет создан gulp. Gulp возьмет наши ресурсы из папки ресурсов, минимизирует их и поместит в новую папку dist с расширениями .min.css или .min.js.

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

Начнем с Gulp:

Gulp - это набор инструментов JavaScript, который позволяет разработчикам автоматизировать рабочие процессы веб-разработки. Он имеет множество плагинов для удовлетворения всех ваших потребностей. Начнем с установки gulp и необходимых плагинов для минификации CSS и JS.

npm i -D gulp gulp-cli gulp-rename gulp-clean-css gulp-uglify-es

Посмотрим, что делают все эти пакеты:

  • gulp: основная библиотека
  • gulp-cli: утилита командной строки для Gulp
  • gulp-rename: плагин gulp для простого переименования файлов в процессе сборки.
  • gulp-clean-css: плагин gulp для минимизации CSS с помощью clean-css.
  • gulp-uglify-es: плагин gulp для минимизации JavaScript (поддерживается es6).

Создайте конвейер сборки:

Что мы хотим от нашего конвейера, так это взять файлы из каталога ресурсов, минимизировать их и сохранить в новом каталоге dist, зафиксировав имена файлов как {filename}.min.{file_extenstion}. Итак, если у нас есть файл CSS в /assets/css/styles.css, тогда dist будет содержать /dist/css/styles.min.css.

Начните с создания gulpfile.js в корне проекта и импортируйте следующие модули:

const { src, dest, parallel, watch } = require('gulp');
const cleanCSS = require('gulp-clean-css');
const uglify = require('gulp-uglify-es').default;
const rename = require('gulp-rename');

Затем создайте объект для путей к исходному и целевому файлам:

const paths = {
  css: {
    src: 'assets/css/*.css',
    dest: 'dist/css/',
  },
  js: {
    src: 'assets/js/*.js',
    dest: 'dist/js/',
  },
};

Теперь создайте задачу gulp, которая в основном представляет собой функцию, которая берет файлы CSS из ресурсов, минимизирует их и сохраняет в dist.

function minifyAndCompressCSS() {
  return src(paths.css.src)
    .pipe(cleanCSS())
    .pipe(rename({ extname: '.min.css' }))
    .pipe(dest(paths.css.dest));
}

Вот что происходит в конвейере:

  1. Сначала мы устанавливаем src файлов CSS.
  2. После этого мы минимизируем файлы CSS, вызывая плагин cleanCSS().
  3. Потом меняем расширение файлов на min.css
  4. Наконец, мы сохраняем уменьшенные файлы в каталог dist с помощью промежуточного программного обеспечения dest() gulp.

Таким же образом создайте задачу и для файлов JavaScript.

function minifyAndCompressJS() {
  return src(paths.js.src)
    .pipe(uglify())
    .pipe(rename({ extname: '.min.js' }))
    .pipe(dest(paths.js.dest));
}

Следите за файлами:

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

function watchFiles() {
  watch(
    paths.css.src,
    { ignoreInitial: false },
    minifyAndCompressCSS
  );
  watch(
    paths.js.src,
    { ignoreInitial: false },
    minifyAndCompressJS);
}

Для просмотра файлов мы используем watch промежуточное ПО, предоставленное gulp. Параметр ignoreInitital: false гарантирует, что конвейер запускается изначально при запуске сервера.

Теперь экспортируйте созданные задачи, чтобы их можно было выполнять из командной строки с помощью gulp-cli

exports.watch = watchFiles;
exports.build = parallel(minifyAndCompressCSS, minifyAndCompressJS);

Здесь экспортируются две задачи watch и build. Как следует из названия, watch - это задача, которая должна выполняться в среде разработки, а build должна выполняться при развертывании приложения. ПО промежуточного слоя parallel выполняет обе задачи одновременно.

Окончательная версия gulpfile.js, которая принимает файлы CSS и JavaScript и выводит их уменьшенные версии, будет выглядеть примерно так:

Автоматизируйте процесс сборки:

Теперь мы создали задачи, которые нам нужны для нашего конвейера, давайте заставим их работать, определив несколько скриптов в package.json. Сначала добавьте две зависимости

npm i -D nodemon concurrently
  • nodemon: инструмент, перезапускающий сервер узлов при обнаружении изменений в файле.
  • одновременно: позволяет выполнять несколько команд одновременно.

Добавьте в package.json следующие сценарии:

"scripts": {
  "start": "node app",
  "dev": "concurrently \"nodemon app\" \"gulp watch\"",
  "build": "gulp build"
},

Объясняющие сценарии:

  • start: сценарий запуска запустит приложение с узлом
  • dev: Этот сценарий выполняет несколько команд одновременно, где nodemon app перезапускает сервер при изменении файлов, а gulp watch выполняет watch задачу, экспортированную из gulpfile.js
  • сборка: этот сценарий можно использовать для создания распространяемых ресурсов при развертывании или когда вы просто хотите создать сборку без запуска сценария разработки.

Пришло время проверить:

Откройте командную строку и запустите npm run dev из корня вашего проекта. Когда вы запустите эту команду, вы увидите, что в ваш проект добавлен новый каталог dist с минимизированными ресурсами.

Теперь измените что-нибудь в /assets/js/main.js, например, добавьте alert('changed'), и вы увидите в командной строке, что minifyAndCompressJS задача запущена, а main.js уменьшена и снова сохранена. Теперь откройте приложение в браузере (localhost: 5000), и вы увидите предупреждающее сообщение из уменьшенного файла.

Добавить сжатие:

До сих пор мы добавляли минимизацию к нашим ресурсам, которая просто изменяет текст, но сжатие дополнительно уменьшает размер ресурсов, полностью переписывая двоичный код в файле. Затем сжатый файл будет распакован браузером. Все современные браузеры поддерживают распаковку ресурсов gzip и brotli. Бротли считается самым эффективным из них, поэтому воспользуемся им.

Установим пакеты, необходимые для сжатия:

npm i -D gulp-brotli zlib
  • gulp-brotli: плагин gulp для сжатия файлов с использованием сжатия brotli.
  • zlib: программная библиотека, используемая для сжатия данных (мы будем использовать эту библиотеку для предоставления некоторых параметров конфигурации gulp-brotli).

Импортируйте эти две библиотеки в gulpfile.js

const gulpBrotli = require('gulp-brotli');
const zlib = require('zlib');

Измените задачи, которые мы создали для минификации ресурсов CSS и JS, примерно так:

function minifyAndCompressCSS() {
  return src(paths.css.src)
    .pipe(cleanCSS())
    .pipe(rename({ extname: '.min.css' }))
    .pipe(gulpBrotli(brotliOptions()))
    .pipe(rename({ extname: '.br' }))
    .pipe(dest(paths.css.dest));
}

Здесь я добавил еще два этапа в конвейер. После минимизации файлов CSS я сжимаю их с помощью плагина gulpBrotli, затем переименовываю расширение файла в .br и сохраняю их в папке назначения dist. Теперь, если у вас есть файл в /assets/css/styles.css, он будет уменьшен, сжат и сохранен как /dist/css/styles.min.css.br.

Здесь я использую функцию brotliOptions, которая передает некоторые параметры конфигурации плагину gulpBrotli, и это:

function brotliOptions() {
  return {
    params: {
      [zlib.constants.BROTLI_PARAM_QUALITY]:
      zlib.constants.BROTLI_MAX_QUALITY,
    },
  };
}

Наконец, gulpfile.js с минимизацией и сжатием выглядят так:

Обслуживать сжатые активы Brotli:

Чтобы предоставить браузеру сжатые ресурсы Brotli, нам нужно выполнить некоторую настройку.

Каждый раз, когда клиент делает запрос на файл CSS или JS, нам нужно изменить URL-адрес запроса, чтобы включить .br в качестве расширения URL-адреса запроса. Предположим, что клиент делает запрос на /dist/styles.min.css, тогда мы изменим URL-адрес запроса на /dist/styles.min.css.br, потому что наш конвейер сборки выводит сжатые ресурсы brotli с расширением .br.

После сопоставления правильного файла сообщите браузеру, что сервер отправляет сжатый ресурс brotli. Для этого нам нужно установить заголовок Content-Encoding: br, который сообщает браузеру, что ресурс необходимо распаковать с помощью алгоритма brotli.

Промежуточное ПО для этого будет выглядеть примерно так:

/* serve Brotli compressed CSS files wheneve there is a request for .css file */
app.get('*.css', (req, res, next) => {
  req.url = req.url + '.br';
  res.set('Content-Encoding', 'br');
  res.set('Content-Type', 'text/css; charset=utf-8');
  next();
});
/* serve Brotli compressed JS files whenever there is a request for .js file */
app.get('*.js', (req, res, next) => {
  req.url = req.url + '.br';
  res.set('Content-Encoding', 'br');
  res.set('Content-Type', 'application/javascript; charset=UTF-8');
  next();
});

Добавьте эти два промежуточного программного обеспечения в свой app.js файл непосредственно перед тем, как установить статическую папку. Теперь удалите ранее созданный каталог dist, снова запустите npm run dev и протестируйте свое приложение в браузере.

Успех! вы создали собственный конвейер для минимизации и сжатия ваших активов с помощью Gulp и Brotli. Этот подход останется неизменным для любого количества / размера активов. Поиграйте с репозиторием приложений здесь.

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