Что такое Gulp.js - введение

JavaScript-разработчики уделяют программированию очень мало времени. Большая часть работы включает в себя выполнение рутинных заданий:

  • генерирование HTML из шаблонов и файлов содержимого;
  • сжатие изображений;
  • компиляция Sass в CSS код;
  • удаление значений console и debugger из скриптов;
  • объединение и минификация файлов CSS и JavaScript;
  • развертывание файлов на серверах.

Это очень монотонный, отупляющий процесс.  Разве не лучше было бы потратить свое время на более интересную работу? Для этого вам понадобится сборщик проектов.

Звучит сложно!

Это сложнее, чем выполнять каждую операцию вручную. Но в будущем вы сэкономите время и сократите количество допускаемых ошибок. При использовании сборщика реализуйте правильный подход:

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

Сборщики проектов: варианты

Первым популярным решением подобного рода был Grunt – сборщик проектов, созданный на основе Node.js. Grunt был невероятно популярным. Но низкая скорость работы и сложность настройки были его слабыми местами.

Затем появился Gulp, обладающий следующими преимуществами:

  • Возможность просмотра файлов.
  • Плагины для Gulp просты и предназначены для выполнения одной задачи.
  • Код конфигурации на JavaScript, который легче для понимания.
  • Gulp быстрее из-за того, что использует потоки Node.js для передачи данных через серию плагинов.

Версии Gulp

Gulp.js 3.9.1 был единственной версией много лет. И хотя был доступен Gulp 4, его нужно было устанавливать с помощью npm install gulp@next. Причина этого заключалась в том, что плагины оставались совместимыми. Но Gulp 4 использовал новый синтаксис конфигурации.

10 декабря 2018 года Gulp.js 4.0 был объявлен единственной версией и появился в менеджере пакетов npm. Любой, кто станет использовать npm install gulp, получит версию 4. Эта версия будет использоваться и в данном руководстве.

Шаг 1: установите Node.js

Node.js можно загрузить для Windows, macOS и Linux с nodejs.org/download/. Доступны различные варианты платформы для установки из бинарных файлов, модульных сборщиков и Docker-образов.

Примечание: Node.js и Gulp работают в Windows, но некоторые плагины могут работать некорректно, если они зависят от собственных бинарных файлов Linux. Одним из вариантов решения проблемы в Windows 10 является подсистема Windows для Linux.

После установки запустите командную строку и введите следующую команду. Она позволит узнать номер версии:

node -v

Вскоре вы станете активно использовать npm – менеджер пакетов Node.js, который необходим для установки модулей. Узнайте номер его версии:

npm –v

Примечание: модули Node.js можно устанавливать глобально, чтобы они были доступны во всей ОС. Но большинство пользователей не будут иметь права на запись в глобальные библиотеки, если у команд npm не будет префикса sudo. Существует несколько вариантов, как исправить разрешения npm. Но можно изменить каталог по умолчанию. Например, в Ubuntu/Debian:

cd ~
  mkdir .node_modules_global
  npm config set prefix=$HOME/.node_modules_global
  npm install npm -g

Затем добавьте следующую строку в конце ~/.bashrc:

export PATH="$HOME/.node_modules_global/bin:$PATH"

Снова обновите:

source ~/.bashrc

Шаг 2: установите Gulp глобально

Установите интерфейс командной строки Gulp глобально, чтобы сборщик можно было запустить из любой папки проекта:

npm install gulp-cli -g

Убедитесь, что Gulp установлен, проверив его версию:

gulp -v

Шаг 3: Настройте проект

Примечание: пропустите этот шаг, если у вас уже есть файл конфигурации package.json.

Предположим что, у вас есть новый проект в папке project1. Перейдите в каталог и инициализируйте его с помощью npm:

cd project1
npm init

Затем нажмите «Return», чтобы принять значения по умолчанию. Файл package.json, в котором хранятся параметры конфигурации npm, будет создан автоматически.

Примечание: Node.js устанавливает модули в папку node_modules. Нужно добавить их в свой файл .gitignore, чтобы убедиться, что они не попадут в репозиторий. При развертывании проекта в другой системе можно будет запустить npm install, чтобы их восстановить.

Предполагается, что ваш проект содержит папки, перечисленные ниже.

Папка src: предварительно обработанные исходники

Содержит следующие подкаталоги:

  • html ‒ исходные файлы и шаблоны HTML;
  • images ‒ оригинальные несжатые изображения;
  • js – предварительно обработанные файлы скриптов;
  • css – предварительно обработанные файлы Sass (.scss)

Папка build: скомпилированные/обработанные файлы

Когда понадобится, Gulp создаст файлы и подпапки:

  • html ‒ скомпилированные статические файлы HTML;
  • images ‒ сжатые изображения;
  • js ‒ единственный объединенный и минифицированный файл JavaScript;
  • css – единственный скомпилированный и минифицированный файл CSS.

Примечание: Если вы работаете в Unix-системе, то можете воссоздать структуру исходных папок с помощью следующей команды:

mkdir -p src/{html,images,js,scss}

 Шаг 4: Установите Gulp локально

Теперь можно установить Gulp в папку проекта:

npm install gulp --save-dev

Эта команда устанавливает Gulp как зависимость. После чего раздел «devDependencies» в package.json обновляется соответствующим образом.  В рамках этого руководства предполагается, что Gulp и все плагины являются зависимостями.

Альтернативные варианты развертывания

Зависимости разработки не устанавливаются, если в операционной системе для переменной среды NODE_ENV задано значение production. Обычно это делается на сервере с помощью команды macOS/Linux:

export NODE_ENV=production

В Windows:

set NODE_ENV=production

В этом руководстве предполагается, что ресурсы будут скомпилированы в папку build, переданы в репозиторий Git или загружены непосредственно на сервер.

Чтобы использовать ресурсы на работающем сервере, изменить способ их создания. Например, файлы HTML, CSS и JavaScript сжимаются при использовании, но не в средах разработки. В этом случае удалите --save-dev при установке Gulp и его плагинов. Например:

npm install gulp

Эта команда устанавливает Gulp как зависимость приложения в разделе «dependencies» файла package.json. Сборщик будет установлен при вводе npm install и может быть запущен везде, где развернут проект.

Шаг 4: Создайте файл конфигурации Gulp

Создайте новый файл конфигурации gulpfile.js в корне папки проекта. Добавьте в него базовый код:

// конфигурация Gulp.js

const
  // модули
  gulp = require('gulp'),

  // режим разработки
  devBuild = (process.env.NODE_ENV !== 'production'),

  // папки
  src = 'src/',
  build = 'build/'
  ;

Код ссылается на модуль Gulp, устанавливает для переменной devBuild значение true при запуске в режиме разработки и определяет расположение исходных файлов и папок сборки.

gulpfile.js ничего не сделает до того, пока вы не выполните следующий шаг.

Шаг 5: Создайте таск для Gulp

Сам по себе Gulp ничего не делает. Необходимо:

  1. Установить плагины Gulp.
  2. Написать инструкции (таск), которые они должны выполнить.

Чтобы найти нужные плагины, используйте библиотеку Gulp на gulpjs.com/plugins/, на npmjs.com или используя поисковую систему Google.

Большинство заданий (тасков) будут использовать:

  • src (folder) - для создания потока из файлов в исходной папке;
  • dest (folder) - для вывода потока в виде файлов в целевую папку сборки.

Любое количество методов плагина может быть вызвано с помощью .pipe (plugin) между .src и .dest.

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

Создадим инструкцию (таск), которая сжимает изображения и копирует их в соответствующую папку сборки. Поскольку этот процесс может занять некоторое время, будем сжимать только новые и измененные файлы. Для этого понадобятся два плагина: gulp-newer и gulp-imagemin. Установите их с помощью командной строки:

npm install gulp-newer gulp-imagemin --save-dev

Теперь можно ссылаться на оба модуля в верхней части gulpfile.js:

// конфигурация Gulp.js

const
  // модули
  gulp = require('gulp'),
  newer = require('gulp-newer'),
  imagemin = require('gulp-imagemin'),

Затем определите функцию обработки изображений в конце gulpfile.js:

// обработка изображений
function images() {

  const out = build + 'images/';

  return gulp.src(src + 'images/**/*')
    .pipe(newer(out))
    .pipe(imagemin({ optimizationLevel: 5 }))
    .pipe(gulp.dest(out));

});
exports.images = images;

Этот код делает следующее:

  1. Создает новую функцию таска с именем
  2. Определяет папку out, в которой будут находиться файлы сборки.
  3. Читает поток файлов из папки src/images/. **/*.
  4. Передает все файлы в модуль gulp-newer.
  5. Передает оставшиеся новые или измененные файлы через gulp-imagemin, который устанавливает необязательный аргумент optimisLevel.
  6. Сохраняет сжатые изображения в папку Gulp dest/images/.
  7. Экспортирует таск images, который вызывает функцию images.

Сохраните gulpfile.js и поместите несколько изображений в папку проекта src/images/. Затем запустите задание из командной строки:

gulp images

Все изображения будут сжаты, и вы увидите следующее:

Using file gulpfile.js
Running 'imagemin'...
Finished 'imagemin' in 5.71 ms
gulp-imagemin: image1.png (saved 48.7 kB)
gulp-imagemin: image2.jpg (saved 36.2 kB)
gulp-imagemin: image3.svg (saved 12.8 kB)

Попробуйте снова запустить gulp images. Файлы не обрабатываются, поскольку ни одно из изображений не было изменено.

Задание для HTML

Создадим таск, который копирует файлы из исходной папки HTML. Мы можем сжать HTML-код, чтобы удалить ненужные пробелы и атрибуты, используя плагин gulp-htmlclean.

Также будет установлен плагин gulp-noop. Он не выполняет никакой операции:

npm install gulp-htmlclean gulp-noop --save-dev

Эти модули загружаются в начале gulpfile.js:

const
  // модули
  gulp = require('gulp'),
  noop = require('gulp-noop'),
  newer = require('gulp-newer'),
  imagemin = require('gulp-imagemin'),
  htmlclean = require('gulp-htmlclean'),

Теперь можно экспортировать функцию для обработки html в конец gulpfile.js:

// обработка HTML 
function html() {
  const out = build + 'html/';

  return gulp.src(src + 'html/**/*')
    .pipe(newer(out));
    .pipe(devBuild ? noop() : htmlclean())
    .pipe(gulp.dest(out));
}
exports.html = gulp.series(images, html);

В этом коде:

  1. Мы передаем HTML только через gulp-htmlclean, если NODE_ENV установлен на production. Поэтому HTML остается несжатым во время разработки. Что будет полезно для отладки.
  2. Экспортируемый таск html использует series() для объединения заданий, которые выполняются друг за другом. В этом случае функция images() запускается до функции html(). В результате файлы HTML могут ссылаться на изображения.

Сохраните gulpfile.js и запустите gulp html из командной строки. Будут выполняться оба таска – html и images.

Задание для JavaScript

Обработаем файлы JavaScript, построив сборщик пакетов. Он делает следующее:

  1. Гарантирует, что зависимости будут загружены с помощью плагина gulp-deporder. Анализирует комментарии в верхней части каждого скрипта, чтобы обеспечить правильное упорядочение – например, // requires: defaults.js lib.js.
  2. Объединяет все файлы скриптов в один файл js, используя gulp-concat.
  3. Удаляет значения console и debugging с помощью gulp-strip-debug при работе в режиме разработки.
  4. Минифицирует код с помощью ES6-совместимого gulp-terser.
  5. Добавляет карту источника в режиме разработки с помощью gulp-sourcemaps.

Установите модули плагинов:

npm install gulp-deporder gulp-concat gulp-strip-debug gulp-terser gulp-sourcemaps --save-dev

Затем загрузите их в начало gulpfile.js:

const
  ...
  concat = require('gulp-concat'),
  deporder = require('gulp-deporder'),
  terser = require('gulp-terser'),
  stripdebug = devBuild ? require('gulp-strip-debug') : null,
  sourcemaps = devBuild ? require('gulp-sourcemaps') : null,

Примечание: для большей эффективности модули gulp-strip-debug и gulp-sourcemaps загружаются только в режиме разработки.

Экспортируйте новую функцию задания:

// обработка JavaScript
function js() {

  return gulp.src(src + 'js/**/*')
    .pipe(sourcemaps ? sourcemaps.init() : noop())
    .pipe(deporder())
    .pipe(concat('main.js'))
    .pipe(stripdebug ? stripdebug() : noop())
    .pipe(terser())
    .pipe(sourcemaps ? sourcemaps.write() : noop())
    .pipe(gulp.dest(build + 'js/'));

}
exports.js = js;

Функция sourcemap.init() вызывается до преобразования кода, а sourcemaps.write() - после завершения.

Добавьте файлы JavaScript в папку src/js/. Затем запустите gulp js.

Задание для CSS

Создадим задание (таск), которое будет компилировать файлы Sass (.scss) в один файл .css, используя gulp-sass. Это плагин Gulp для node-sass, который связан с LibSass C/C++ . Предполагается, что ваш основной файл Sass scss/main.scss отвечает за загрузку всех файлов.

Инструкция также будет использовать PostCSS через плагин gulp-postcss. PostCSS требуется собственный набор плагинов:

  • postcss-assets – предназначен для управления ресурсами. Он позволяет использовать такие свойства, как background: resolve ('image.png'); разрешить пути к файлам или к background: inline ('image.png'); встроить изображения с закодированными данными.
  • autoprefixer – предназначен для автоматического добавления вендорных префиксов в свойства CSS.
  • css-mqpacker – для упаковки нескольких ссылок на один и тот же медиа запрос CSS в одно правило.
  • cssnano – для минификации кода CSS.

Source Map будет добавлена ​​в файл CSS при повторном запуске в режиме разработки с помощью gulp-sourcemaps.

Установите все модули:

npm install gulp-sass gulp-postcss postcss-assets autoprefixer css-mqpacker cssnano --save-dev

Загрузите их в начало gulpfile.js:

const
  ...
  sass = require('gulp-sass'),
  postcss = require('gulp-postcss'),
  assets = require('postcss-assets'),
  autoprefixer = require('autoprefixer'),
  mqpacker = require('css-mqpacker'),
  cssnano = require('cssnano'),

Теперь можно экспортировать новый таск в конец gulpfile.js. Обратите внимание, что задание images установлено ​​как зависимость, потому что плагин postcss-assets может ссылаться на изображения в процессе сборки:

// обработка CSS
function css() {

  return gulp.src(src + 'scss/main.scss')
    .pipe(sourcemaps ? sourcemaps.init() : noop())
    .pipe(sass({
      outputStyle: 'nested',
      imagePath: '/images/',
      precision: 3,
      errLogToConsole: true
    }).on('error', sass.logError))
    .pipe(postcss([
      assets({ loadPaths: ['images/'] }),
      autoprefixer({ browsers: ['last 2 versions', '> 2%'] }),
      mqpacker,
      cssnano
    ]))
    .pipe(sourcemaps ? sourcemaps.write() : noop())
    .pipe(gulp.dest(build + 'css/'));

}
exports.css = gulp.series(images, css);

При этом .on('error', sass.logError) гарантирует, что Sass выводит синтаксические ошибки на консоль, не останавливая работу Gulp.

Сохраните файл, добавьте файлы Sass .scss и запустите таск из командной строки:

gulp css

Шаг 6: Автоматизируйте выполнение заданий

Чтобы запустить все задания в одной команде, экспортируйте таск build в gulpfile.js:

// запустить все таски
exports.build = gulp.parallel(exports.html, exports.css, exports.js);

Метод gulp.parallel() выполняет все задания одновременно. Его можно комбинировать с gulp.series() для создания сложных цепочек зависимостей. В этом примере exports.html, exports.css и exports.js запускаются параллельно. Но каждый из них может иметь последовательности зависимостей, включая таск images.

Введите в командной строке gulp build, чтобы выполнить все таски.

Кроме этого Gulp предоставляет метод .watch(), который может запускать соответствующий таск при каждом изменении файла. Он передает набор файлов или папок для мониторинга, любые и функцию таска для запуска (необязательно в методах gulp.series() ли gulp.parallel() ).

Экспортируем новый таск watch в конец gulpfile.js:

// следим за изменениями файлов
function watch(done) {

  // изменениями изображений
  gulp.watch(src + 'images/**/*', images);

  // изменениями html
  gulp.watch(src + 'html/**/*', html);

  // изменениями css
  gulp.watch(src + 'scss/**/*', css);

  // изменениями js
  gulp.watch(src + 'js/**/*', js);

  done();

}
exports.watch = watch;

Gulp нужно знать, когда будет завершена функция таска. Этого можно добиться, используя JavaScript Promise, транслятор событий, дочерний процесс или функцию обратного вызова. В данном примере мы используем функцию обратного вызова done(), чтобы указать, что все задания  watch() были настроены.

Вместо того чтобы запустить gulp watch немедленно, добавим таск по умолчанию. Его можно выполнить, запустив gulp без дополнительных аргументов:

// таск по умолчанию
exports.default = gulp.series(exports.build, exports.watch);

Сохраните gulpfile.js и введите в командной строке gulp. Ваши изображения, HTML, CSS и JavaScript будут обработаны. Затем Gulp продолжит проверку обновлений и будет повторно выполнять задания по мере необходимости. Нажмите Ctrl/Cmd + C, чтобы прервать мониторинг и вернуться в командную строку.

Шаг 7: Пожинаем плоды!

Другие плагины, которые могут быть полезны:

  • gulp-load-plugins: загружает все модули плагинов Gulp автоматически;
  • gulp-preprocess: простой препроцессор HTML и JavaScript;
  • gulp-less: плагин препроцессора Less CSS;
  • gulp-stylus: плагин препроцессора Stylus CSS;
  • gulp-size: отображает размеры файлов;
  • gulp-nodemon: использует nodemon для автоматического перезапуска приложений Node.js при их изменении.

Таски Gulp могут запускать любой JavaScript- код или модули Node.js. Они не обязательно должны быть плагинами. Например:

  • browser-sync: автоматически перезагружает ресурсы, когда происходят изменения;
  • del: удаляет файлы и папки (может очищать папку build в начале каждого запуска).

Преимущества Gulp:

  • множество плагинов;
  • конфигурация с использованием pipe легко читаема и понятна;
  • js можно адаптировать для использования в других проектах;
  • упрощает развертывание;

Полезные ссылки:

После применения описанных выше процессов к простому сайту его общий вес уменьшился более чем на 50%.

Что такое Gulp.js? Gulp – это отличный вариант для автоматического запуска заданий и упрощения процесса разработки.

Ангелина Писанюкавтор-переводчик статьи «An Introduction to Gulp.js»