Что такое Gulp и для чего он нужен?
WebDEVОптимизация ресурсов сайта и тестирование дизайна в разных браузерах, конечно, не самая занятная часть процесса разработки. К счастью, она состоит из повторяющихся задач, которые могут быть автоматизированы с помощью правильных инструментов, что повысит вашу эффективность.
Gulp — это инструмент сборки веб-приложения, позволяющий автоматизировать повторяющиеся задачи, такие как сборка и минификация CSS- и JS-файлов, запуск тестов, перезагрузка браузера и т.д. Тем самым Gulp ускоряет и оптимизирует процесс веб-разработки. В статье мы рассмотрим основы использования этого инструмента.
Gulp построен на Node.js, и файл сборки пишется на JavaScript. Сам по себе Gulp умеет не очень много, но имеет огромное количество плагинов, которые можно найти на странице со списком плагинов или просто поиском на npm. Например, есть плагины для запуска JSHint, компиляции CoffeeScript, запуска тестов и даже для обновления номера версии сборки.
Работа с Gulp
Установка Gulp крайне проста. Сначала установите его глобально:
npm install -g gulp
А потом для приложения:
npm install --save-dev gulp
Cоздадим первый таск для минификации JavaScript файлов (предположим, у нас есть один файл app.js в директории js). Для этого необходимо создать файл gulpfile.js в корне проекта, именно отсюда мы будем запускать таск с помощью команды gulp. Поместим в файл gulpfile.js следующий код:
var gulp = require('gulp'), uglify = require('gulp-uglify'); gulp.task('minify', function () { gulp.src('js/app.js') .pipe(uglify()) .pipe(gulp.dest('build')); });
Теперь установим плагин gulp-uglify:
npm install --save-dev gulp-uglify
И запустим команду gulp minify. Можно убедиться, что в директории build создана минифицированная версия app.js.
Теперь давайте разберемся с тем, что мы сделали. Во-первых, в нашем файле gulpfile.js мы загружаем gulp и плагин gulp-uglify:
var gulp = require('gulp'), uglify = require('gulp-uglify');
Дальше мы определяем таск ‘minify’, а действия, которые будем выполнять в этой задаче, описываем в переданной во втором параметре функции.
gulp.task('minify', function() { ... });
И наконец, мы описываем действия, которые должен совершать наш таск.
gulp.src('js/app.js') .pipe(uglify()) .pipe(gulp.dest('build'));
В простом случае функции gulp.task передается только два параметра: название таска и функция. Таск также может включать в себя выполнение других тасков. К примеру, мы можем определить таск build, который будет запускать выполнение двух других тасков: css и js:
gulp.task('build', ['css', 'js']);
Таски css и js будут выполняться асинхронно, поэтому нельзя гарантировать, что один из тасков выполнить раньше другого. Если требуется проверить, что таск завершился, перед запуском следующего, можно определить зависимость следующим образом:
JavaScript
gulp.task('css', ['js'], function() { ... });
Теперь Gulp будет запускать таск js и ждать его завершения перед запуском таска css.
Также Gulp позволяет определить таск по умолчанию, который будет запускаться по команде gulp:
gulp.task('default', function() { ... });
Функция gulp.src() в качестве параметра принимает маску файлов и возвращает поток, представляющий эти файлы, который уже может быть передан на вход плагинам. Примерами таких масок могут быть:
js/app.js
js/*.js
js/**/*.js
!js/app.js
— исключает определенный файл*.+(js|css)
— все файлы в корневой директории с расширениями .js или .css
Например, чтобы задать маску для всех файлов .js в директории js, кроме уже минифицированных, можно использовать маску:
gulp.src(['js/**/*.js', '!js/**/*.min.js'])
Потоки
Потоки позволяют передать некоторые данные последовательно от одной функции к другой, каждая из которых выполняет некоторые действия с этими данными.
В приведенном выше примере, функция gulp.src() принимает строку, которая соответствует некоему файлу или группе файлов, и создает поток объектов, представляющих эти файлы. Дальше эти объекты передаются функции uglify(), которая возвращает новые объекты минифицированных файлов. И наконец, функция gulp.dest() сохраняет измененные файлы.
Рассмотрим теперь следующий код:
gulp.task('js', function() { return gulp.src('js/*.js') .pipe(jshint()) .pipe(jshint.reporter('default')) .pipe(uglify()) .pipe(concat('app.js')) .pipe(gulp.dest('build')); });
В этом таске, кроме gulp и gulp-uglify используются плагины gulp-concat и gulp-jshint, для его запуска необходимо установить эти плагины. Этот таск берет файлы по маске ‘js/*.js’ (файлы с расширением .js в директории js) и запускает JSHint. Дальше выводит результат, потом минимизирует файлы, объединяет их в один файл app.js и и только потом сохраняет его в директории build.
Вот что происходит в виде схемы:
Отслеживание файлов
Gulp имеет возможность следить за изменением файлов и выполнять задачу или задачи при обнаружении изменений. Эта функция удивительно полезна. Вы можете сохранить Less-файл, а Gulp превратит его в CSS и обновит браузер без каких-либо действий с вашей стороны.
Для слежения за файлом или файлами используйте функцию gulp.watch(), которая принимает шаблон файлов или их массив (такой как gulp.src()), либо массив задач для их запуска или выполнения функции обратного вызова.
Предположим, что у нас есть задача build, она превращает наши файлы шаблонов в HTML и мы хотим определить задачу watch, которая отслеживает изменение шаблонов и запускает задачу для преобразования их в HTML. Мы можем использовать функцию watch следующим образом:
gulp.task('watch', function () { gulp.watch('templates/*.tmpl.html', ['build']); });
Теперь при изменении файла шаблона будет запущена задача build, которая создаст HTML.
Вы также можете указать для watch функцию обратного вызова вместо массива задач. В этом случае функция получает объект event содержащий информацию о событии, которое вызвало функцию:
gulp.watch('templates/*.tmpl.html', function (event) { console.log('Event type: ' + event.type); // добавлено, изменено или удалено console.log('Event path: ' + event.path); // путь к файлу });
Другой отличительной особенностью gulp.watch() является то, что она возвращает watcher. Используйте его для прослушивания дополнительных событий или для добавления файлов в watch. Например, чтобы одновременно запустить список задач и вызвать функцию, вы можете добавить слушателя в событие change при возвращении watcher:
var watcher = gulp.watch('templates/*.tmpl.html', ['build']); watcher.on('change', function (event) { console.log('Event type: ' + event.type); // добавлено, изменено или удалено console.log('Event path: ' + event.path); // путь к файлу });
В дополнение к событию change вы можете прослушивать ряд других событий:
- end
Срабатывает, когда watcher завершается (это означает, что задачи и функции обратного вызова не будут больше вызываться при изменении файлов).
- error
Срабатывает, когда происходит ошибка.
- ready
Срабатывает, когда файлы были найдены и готовы к отслеживанию.
- nomatch
Срабатывает, когда запросу не соответствует ни один файл.
Объект watcher также содержит некоторые методы, которые можно вызывать:
- watcher.end()
Останавливает watcher (при этом задачи или функции обратных вызовов не будут больше вызываться).
- watcher.files()
Возвращает список файлов за которыми следит watcher.
- watcher.add(glob)
Добавляет файлы в watcher, которые соответствуют указанному шаблону glob (также принимает необязательную функцию обратного вызова в качестве второго аргумента).
- watcher.remove(filepath)
Удаляет определённый файл из watcher.
LiveReload
LiveReload сочетается с расширениями браузера (в том числе расширениями Chrome) для перезагрузки браузера при обнаружении изменения в файле. Он может быть использован с плагином gulp-watch или с помощью встроенной функции gulp.watch().
BrowserSync
Альтернативой LiveReload является BrowserSync. Он также отображает изменения в браузере, но содержит гораздо больше возможностей.
Когда вы изменяете код, BrowserSync перезагружает страницу или, если это CSS, вносит в него изменения и страница не обновляется. Это довольно полезно, если ваш сайт не устойчив к обновлению. Предположим, вы совершаете четыре щелчка в одностраничном приложении, тогда при обновлении вы вернётесь к стартовой странице. С LiveReload вам потребуется каждый раз щёлкать четыре раза при внесении изменения. BrowserSync, однако, просто вносит изменения при модификации CSS, так что вам не придётся щёлкать «Назад».
BrowserSync также синхронизирует между браузерами щелчки, действия с формой и положение прокрутки. Вы можете открыть пару браузеров на настольном компьютере, а другой на iPhone и затем перемещаться по сайту. Ссылки будут открываться во всех браузерах, а когда вы прокрутите страницу вниз, страницы на всех устройствах также прокрутятся вниз (обычно также плавно!). При вводе текста в форме он будет набираться в каждом окне. И это поведение всегда можно отключить при желании.
BrowserSync не требует плагина для браузера, потому что он работает с вашими файлами и обслуживается скриптом, который открывает сокет между браузером и сервером.