Gulp – инструментарий, облегчающий жизнь веб-разработчика, с его помощью можно задавать различные задачи. Часто используется для таких front-end задач как: поднятие сервера, автоматическое обновление страницы браузера в любой момент сохранения файла, использование препроцессоров как Sass или LESS, оптимизация CSS, JavaScript и изображений.

Это далеко не полный список возможностей Gulp. Если постараться, то можно даже создать генератор статических сайтов (я делал!). Так что да, Gulp это очень мощный инструмент. Однако, если вы хотите в нем разобраться, придется потратить время на изучение Gulp.

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

Приложения на подобие Gulp относятся к так называемым «таск раннерам», так как они используются для запуска задач по сайтостроению. Два саммых популярных менеджера задач на сегодня это Gulp и Grunt. Но кроме названных, конечно, существуют и другие. Broccoli больше используется для компиляции ресурсов, одна из наиболее распространенных задач в таск раннерах.

Существует уже масса статей по поводу различий между Grunt и Gulp, и почему одно приложение стоит использовать, а другое нет. Brunch по типу задач тоже очень похожа на описанные выше программы, также выполняет такие задачи связанные с сервером или проверкой файлов.
Все отличие в том, как вы организуете рабочий процесс в этих программах. Если сравнивать с Grunt, то Gulp намного быстрее и проще настроить, плюс он еще и запускается быстрее. А теперь давайте, собственно, разберемся, как начать работу с Gulp.
Что необходимо настроить

К концу это статьи у вас будет настроенная программа, которая будет способна выполнять описанные в начале статьи задачи:

Поднятие сервера

Компиляция Sass в CSS

Обновление браузера при любом сохранении файлов

Оптимизация всех ресурсов (CSS, JS, шрифты и изображения)

Также вы узнаете, как связать две разные задачи набором простых команд. Начнем с установки Gulp на ваш компьютер.
Установка Gulp

Перед установкой Gulp вам нужно установить Node.js. Если он еще не установлен, то загрузите пакет установки с сайта Node. После того, как вы разберетесь с Node, можно приступить к установке Gulp. Введите следующую команду в командную строку:

$ sudo npm install gulp -g
1

$ sudo npm install gulp -g

Обратите внимание: слово «sudo» требуется вводить только, если у вас Mac. Если вы не хотите использовать sudo, почитайте первый комментарий от Pawel Grzybek. И запомните еще кое-что, символ «$» просто символизирует командную строку. Он не является частью вашей команды.

Команда npm install использует Node Package Manager для установки Gulp на ваш ПК. Флаг –g означает, что Gulp установится для всех пользователей, что позволяет использовать Gulp где угодно. Для пользователей Mac необходимо дополнительное ключевое слово «sudo», так как им нужны права администратора для установки Gulp. Теперь, когда Gulp установлен, давайте создадим проект с помощью Gulp.
Создание проекта в Gulp

Сперва, создадим на сервере папку project, это будет корень проекта. Из этой папки запустите на выполнение следующую команду npm init:

# ... из созданной папки
$ npm init
1
2

# ... из созданной папки
$ npm init

Данная команда создает файл package.json, в котором хранится информация о проекте, такая как зависимости. Npm init предложит следующее:
http://s5.uploads.ru/QUA83.png

Как только создался файл package.json, мы можем установить в наш проект Gulp:

$ npm install gulp --save-dev
1

$ npm install gulp --save-dev

Сейчас мы установили Gulp именно в наш проект, а не глобально. Вот почему команды слегка отличаются. Так как мы не устанавливаем Gulp глобально, то слово «sudo» не требуется, -g также не нужен. Мы добавили —save-dev, что означает – добавить gulp как зависимость разработчика в package.json.
http://sd.uploads.ru/pS6vn.png

Если после выполнения команды проверить папку, то можно заметить, что Gulp создал папку node_modules, внутри которой есть папка gulp
http://sh.uploads.ru/1PFE6.png

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

Gulp может работать с любой структурой папок. Просто нужно понять, как он работает. Для этой статьи мы будет использовать следующую структуру:
http://s8.uploads.ru/2DiJN.png

Папку app мы будем использовать в целях разработки, а в папке dist (distribution) будем хранить оптимизированные файлы. Так как папка app у нас используется для разработки, то и код будет храниться в ней. При настройке конфигурации Gulp надо будет помнить нашу структуру папок. Начнем с первой задачи в gulpfile.js, в этом файле хранятся все настройки Gulp.
Пишем нашу первую задачу

Первым делом нужно подключить Gulp в нашем файле.

var gulp = require('gulp');
1

var gulp = require('gulp');

Require говорит Node.js проверить папку node_modules и найти там папку gulp. Если такая имеется, то ее содержимое записывается в переменную gulp. Теперь можно писать задачи Gulp с нашей переменной. Базовый синтаксис:

gulp.task('task-name', function() {
  // код
});
1
2
3

gulp.task('task-name', function() {
  // код
});

Task-name – имя задачи, будет использоваться когда угодно при запуске задач в Gulp. Также задачу можно запустить через командную строку с помощью gulp task-name. Для теста создадим задачу hello, которая будет говорить Hello Zell!!.

gulp.task('hello', function() {
  console.log('Hello Zell');
});
1
2
3

gulp.task('hello', function() {
  console.log('Hello Zell');
});

Запустить задачу можно из командной строки.

$ gulp hello
1

$ gulp hello

В логах командной строки вернется Hello Zell!!.
http://s8.uploads.ru/s4hWf.png

Задачи в Gulp, обычно, немного сложнее, чем эта. Обычно, в задаче содержится два дополнительных метода Gulp и различные плагины. Ниже показано, как может выглядеть реальная задача:

gulp.task('task-name', function () {
  return gulp.src('source-files') // получаем источники с помощью gulp.src
.pipe(aGulpPlugin()) // прогоняем их через плагин
.pipe(gulp.dest('destination')) // выходные файлы в папке destination
})
1
2
3
4
5

gulp.task('task-name', function () {
  return gulp.src('source-files') // получаем источники с помощью gulp.src
    .pipe(aGulpPlugin()) // прогоняем их через плагин
    .pipe(gulp.dest('destination')) // выходные файлы в папке destination
})

Как можно заметить, настоящая задача использует два дополнительных метода – gulp.src и gulp.dest. Gulp.src говорит, какой файл использовать для задачи, а gulp.dest указывает на папку, куда поместить файлы после завершения задачи. Попробуем создать реальную задачу, скомпилируем Sass в CSS.
Препроцессинг с помощью Gulp

С помощью плагина gulp-sass мы можем скомпилировать Sass в CSS. Установить этот плагин можно так же, как мы делали с помощью npm install. Также следует использовать флаг —save-dev, чтобы быть уверенными в том, что плагин добавился в devDependencies в файле package.json.

$ npm install gulp-sass --save-dev
1

$ npm install gulp-sass --save-dev

Перед тем, как использовать плагин, его надо подключить, как мы делали это с Gulp с помощью require.

var gulp = require('gulp');
// подключаем gulp-sass
var sass = require('gulp-sass');
1
2
3

var gulp = require('gulp');
// подключаем gulp-sass
var sass = require('gulp-sass');

Чтобы использовать gulp-sass необходимо заменить aGulpPlugin() на sass(). Так как задача выполняет компиляцию Sass в CSS, назовем ее sass.

gulp.task('sass', function(){
  return gulp.src('source-files')
.pipe(sass()) // используем gulp-sass
.pipe(gulp.dest('destination'))
});
1
2
3
4
5

gulp.task('sass', function(){
  return gulp.src('source-files')
    .pipe(sass()) // используем gulp-sass
    .pipe(gulp.dest('destination'))
});

Необходимо задать файл источник для задачи sass и папку для сохранения результатов, создадим файл styles.scss в папке app/scss. Этот файл добавится в задачу sass в методе gulp.src. На выходе нам нужен styles.css в папке app/css – это и будет выходным файлом для gulp.dest.

gulp.task('sass', function(){
  return gulp.src('app/scss/styles.scss')
.pipe(sass()) // Конвертируем Sass в CSS с помощью gulp-sass
.pipe(gulp.dest('app/css'))
});
1
2
3
4
5

gulp.task('sass', function(){
  return gulp.src('app/scss/styles.scss')
    .pipe(sass()) // Конвертируем Sass в CSS с помощью gulp-sass
    .pipe(gulp.dest('app/css'))
});

Необходимо протестировать нашу задачу, чтобы сделать это, добавим Sass функцию в наш файл styles.scss.

// styles.scss
.testing {
  width: percentage(5/7);
}
1
2
3
4

// styles.scss
.testing {
  width: percentage(5/7);
}

Если запустить в командной строке gulp sass, то на выходе вы должны увидеть styles.css в папке app/css. Более того, функция percentage(5/7) была переведена в 71.42857%.

/* styles.css */
.testing {
  width: 71.42857%;
}
1
2
3
4

/* styles.css */
.testing {
  width: 71.42857%;
}

Вот так мы и поймем, что наша задача sass работает. Иногда стоит задача скомпилировать больше чем один файл .scss в CSS. В этом нам поможет подстановки Node. К сведению: Gulp-sass использует LibSass для конвертации Sass в CSS. Так намного быстрее, чем с помощью методов, основанных на Ruby. Также можно использовать и Ruby методы gulp-ruby-sass или gulp-compass.
Подстановки в Node

Подстановки позволяют добавить больше одного файла в gulp.src. Это похоже на регулярные выражения, но только для директорий. При использовании подстановок компьютер проверяет имена файлов и путей на совпадение шаблону. Если шаблон существует, то файл найден. Для большинства задач, как правило, требуется 4 различных модели подстановки:

*.scss: Символ * совпадает с любым шаблоном в текущей директории. В нашем случае мы ищем все файлы с окончанием .scss в корневой папке project.

**/*.scss: Это более продвинутый шаблон, который ищет файлы с окончанием .scss в корне и всех дочерних папках.

!not-me.scss: Символ ! указывает, что Gulp исключит из результата совпадений определенный файл. В нашем случае исключен будет not-me.scss.

*.+(scss|sass): Знак + и круглые скобки () помогают создавать множественные шаблоны, шаблоны разделяются символом |. В нашем случае Gulp найдет все файлы с окончанием .scss или .sass в корневой папке.

Теперь, когда мы знаем о подстановках, можно заменить app/scss/styles.scss на шаблон scss/ **/*.scss, данный шаблон совпадает с любым файлом .scss в папке app/scss или дочерней директории.

gulp.task('sass', function() {
  return gulp.src('app/scss/**/*.scss') // Получаем все файлы с окончанием .scss в папке app/scss и дочерних директориях
.pipe(sass())
.pipe(gulp.dest('app/css'))
})
1
2
3
4
5

gulp.task('sass', function() {
  return gulp.src('app/scss/**/*.scss') // Получаем все файлы с окончанием .scss в папке app/scss и дочерних директориях
    .pipe(sass())
    .pipe(gulp.dest('app/css'))
})

Все найденные Sass файлы будут автоматически подключены к задаче sass. Если добавить в проект файл print.scss, то в папке app/css появится файл print.css.
http://s5.uploads.ru/hBWbG.png

Нам удалось скомпилировать все файлы Sass в CSS всего одной командой. А что же собственно хорошего в том, чтобы каждый раз для компиляции самому запускать задачу gulp sass? К счастью мы можем задать автоматический запуск нашей задачи sass при любом пересохранении файла с помощью метода «watching».
Следим за изменениями в Sass файлах

В Gulp есть метод watch, который проверяет файлы на изменения. Синтаксис метода:

// Gulp watch
gulp.watch('files-to-watch', ['tasks', 'to', 'run']);
1
2

// Gulp watch
gulp.watch('files-to-watch', ['tasks', 'to', 'run']);

Если необходимо следить за всеми Sass файлами и запускать задачу sass при любом изменении, то в методе watch необходимо заменить files-to-watch на app/scss/**/*.scss, ['tasks', 'to', 'run'] на [‘sass’]:

// Gulp watch
gulp.watch('app/scss/**/*.scss', ['sass']);
1
2

// Gulp watch
gulp.watch('app/scss/**/*.scss', ['sass']);

Хотя чаще нам необходимо следить за несколькими типами файлов. Все это можно объединить в методе watch:

gulp.task('watch', function(){
  gulp.watch('app/scss/**/*.scss', ['sass']);
  // другие ресурсы
})
1
2
3
4

gulp.task('watch', function(){
  gulp.watch('app/scss/**/*.scss', ['sass']);
  // другие ресурсы
})

Если запустить gulp watch прямо сейчас, вы заметите, что Gulp уже начал проверять все файлы.
http://s9.uploads.ru/RjCGv.png

А также он будет автоматически запускать задачу sass при любых изменениях в файлах .scss.
http://s3.uploads.ru/PMF1U.gif

Давайте заставим Gulp обновлять страницу браузера при любом изменении .scss с помощью Browser Sync.
Живая перезагрузка с помощью Browser Sync

Browser Sync облегчает жизнь веб-разработчикам, с его помощью можно поднять сервер. Также у него есть и другие функции, как синхронизация действий на множестве устройств. Сначала потребуется установить Browser Sync:

$ npm install browser-sync --save-dev
1

$ npm install browser-sync --save-dev

Вы могли заметить, что при установки Browser Sync мы не использовали префикс gulp-. Все дело в том, что Browser Sync уже работает с Gulp, и нет нужды в этом префиксе. Далее необходимо его подключить.

var browserSync = require('browser-sync');
1

var browserSync = require('browser-sync');

Чтобы поднять сервер в Gulp, необходимо создать задачу browserSync. После запуска сервера нужно задать корневую папку. В нашем случае это папка ‘app’:

gulp.task('browserSync', function() {
  browserSync({
server: {
baseDir: 'app'
},
  })
})
1
2
3
4
5
6
7

gulp.task('browserSync', function() {
  browserSync({
    server: {
      baseDir: 'app'
    },
  })
})

Чтобы наш Browser Sync мог вставлять новые стили в страницу браузера (обновлять CSS), нам потребуется слегка изменить задачу sass.

gulp.task('sass', function() {
  return gulp.src('app/scss/**/*.scss')
.pipe(sass())
.pipe(gulp.dest('app/css'))
.pipe(browserSync.reload({
stream: true
}))
});
1
2
3
4
5
6
7
8

gulp.task('sass', function() {
  return gulp.src('app/scss/**/*.scss')
    .pipe(sass())
    .pipe(gulp.dest('app/css'))
    .pipe(browserSync.reload({
      stream: true
    }))
});

Browser Sync настроен. Для живой перезагрузки нужно одновременно запустить две задачи, watch и browserSync. Но ни в коем случае не запускайте две командные строки, чтобы запустить в них две задачи, это глупо. Необходимо сказать Gulp, чтобы перед запуском watch задача browserSync уже была выполнена. Сделать это можно, добавив второй аргумент в watch. Синтаксис:

gulp.task('watch', ['array', 'of', 'tasks', 'to', 'complete','before', 'watch'], function (){
  // ...
})
1
2
3

gulp.task('watch', ['array', 'of', 'tasks', 'to', 'complete','before', 'watch'], function (){
  // ...
})

И в нашем случае мы добавим задачу browserSync.

gulp.task('watch', ['browserSync'], function (){
  gulp.watch('app/scss/**/*.scss', ['sass']);
  // другие ресурсы
})
1
2
3
4

gulp.task('watch', ['browserSync'], function (){
  gulp.watch('app/scss/**/*.scss', ['sass']);
  // другие ресурсы
})

И чтобы наш CSS был самой новой версии, необходимо, чтобы sass запускался перед watch.
1
2
3
4

gulp.task('watch', ['browserSync', 'sass'], function (){
  gulp.watch('app/scss/**/*.scss', ['sass']);
  // другие ресурсы
});

Если теперь запустить gulp watch, то sass и browserSync запустятся одновременно. После выполнения обеих задач запустится watch.
http://s9.uploads.ru/BwXTt.png

Одновременно с этим откроется окно браузера, а именно страничка app/index.html. Если изменить styles.scss, то браузера автоматически обновится.
http://sd.uploads.ru/iEglo.gif

Есть еще кое-что, о чем стоит упомянуть. Если мы уже обновляем страницу браузера при любых изменениях в .scss, почему бы не делать это при изменениях во всех HTML или JavaScript файлах? Сделать это можно, добавив дополнительные процессы и вызывая функцию browserSync.reload при сохранении файла:

gulp.task('watch', ['browserSync', 'sass'], function (){
  gulp.watch('app/scss/**/*.scss', ['sass']);
  // Обновляем браузер при любых изменениях в HTML или JS
  gulp.watch('app/*.html', browserSync.reload);
  gulp.watch('app/js/**/*.js', browserSync.reload);
});
1
2
3
4
5
6

gulp.task('watch', ['browserSync', 'sass'], function (){
  gulp.watch('app/scss/**/*.scss', ['sass']);
  // Обновляем браузер при любых изменениях в HTML или JS
  gulp.watch('app/*.html', browserSync.reload);
  gulp.watch('app/js/**/*.js', browserSync.reload);
});

На данный момент мы уже умеем три вещи:

Поднимать сервер

Пользоваться препроцессором Sass

Обновлять браузер при любых изменениях в файлах

В следующей главе разберем оптимизацию файлов. Начнем с оптимизации CSS и JavaScript.
Оптимизация CSS и JavaScript файлов

Для оптимизации CSS и JavaScript файлов разработчику требуется выполнить две задачи: минификация и конкатенация. Одна из проблем в том, что сложно конкатенировать скрипт в правильном порядке. К примеру, у нас в index.html подключены три скрипта.

<body>
  <!—- другие ресурсы -->
  <script src="js/lib/a-library.js"></script>
  <script src="js/lib/another-library.js"></script>
  <script src="js/main.js"></script>
</body>
1
2
3
4
5
6

<body>
  <!—- другие ресурсы -->
  <script src="js/lib/a-library.js"></script>
  <script src="js/lib/another-library.js"></script>
  <script src="js/main.js"></script>
</body>

Файлы расположены в разных директориях, поэтому стандартный плагин gulp-concatenate не подойдет. К счастью есть другой плагин gulp-useref, он решает эту проблему. Gulp-useref объединяет любое количество CSS и JavaScript файлов в один с помощью комментариев: начальный «<!—build:» и конечный «<!—endbuild—>». Синтаксис:

<!-- build:<type> <path> -->
... HTML разметка, скрипты/ ссылки.
<!-- endbuild -->
1
2
3

<!-- build:<type> <path> -->
... HTML разметка, скрипты/ ссылки.
<!-- endbuild -->

<type> может принимать значения js, css или remove. Лучше всего устанавливать типы в соответствии с файлами, которые хотите объединить. Если установить тип remove, то Gulp удалит весь блок между комментариев.

<path> — путь к выходному файлу. Нам надо, чтобы финальный файл JavaScript лежал в папке js с именем main.min.js. Следовательно код будет следующий:

<!--build:js js/main.min.js -->
<script src="js/lib/a-library.js"></script>
<script src="js/lib/another-library.js"></script>
<script src="js/main.js"></script>
<!-- endbuild -->
1
2
3
4
5

<!--build:js js/main.min.js -->
<script src="js/lib/a-library.js"></script>
<script src="js/lib/another-library.js"></script>
<script src="js/main.js"></script>
<!-- endbuild -->

Давайте настроим плагин gulp-useref в gulp-файле. Необходимо его установить и подключить.

$ npm install gulp-useref --save-dev
var useref = require('gulp-useref');
1
2

$ npm install gulp-useref --save-dev
var useref = require('gulp-useref');

Создание задачи useref похоже на предыдущие наши задачи. Различие в том, что функция useref.assets() должна вызываться перед gulp.src. Ниже код:

gulp.task('useref', function(){
  var assets = useref.assets();

  return gulp.src('app/*.html')
.pipe(assets)
.pipe(assets.restore())
.pipe(useref())
.pipe(gulp.dest('dist'))
});
1
2
3
4
5
6
7
8
9

gulp.task('useref', function(){
  var assets = useref.assets();

  return gulp.src('app/*.html')
    .pipe(assets)
    .pipe(assets.restore())
    .pipe(useref())
    .pipe(gulp.dest('dist'))
});

Если сейчас запустить useref, Gulp пробежится по трем скриптам и соединит их в один dist/js/main.min.js.
http://sd.uploads.ru/91cd5.png

Однако сам файл еще не минифицирован. С этим нам поможет плагин gulp-uglify, используется для минификации JS файлов.

$ npm install gulp-uglify --save-dev

// другие подключения...
var uglify = require('gulp-uglify');

gulp.task('useref', function(){
  var assets = useref.assets();

  return gulp.src('app/*.html')
.pipe(assets)
.pipe(uglify())
.pipe(assets.restore())
.pipe(useref())
.pipe(gulp.dest('dist'))
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

$ npm install gulp-uglify --save-dev

// другие подключения...
var uglify = require('gulp-uglify');

gulp.task('useref', function(){
  var assets = useref.assets();

  return gulp.src('app/*.html')
    .pipe(assets)
    .pipe(uglify())
    .pipe(assets.restore())
    .pipe(useref())
    .pipe(gulp.dest('dist'))
});

Теперь при запуске задачи useref , Gulp будет автоматически минифицировать файл main.min.js. Наш плагин gulp-useref автоматически объединяет скрипты между комментариев «<!—build:» и «<!—endbuild—>» в один файл и помещает весь код в js/main.min.js.
http://sh.uploads.ru/0ofMh.png

Круто, не правда ли? Таким же способом мы можем соединить CSS файлы (конечно, если их у вас будет больше одного). Шаги все те же самые, добавляем комментарий.

<!--build:css css/styles.min.css-->
<link rel="stylesheet" href="css/styles.css">
<link rel="stylesheet" href="css/another-stylesheet.css">
<!--endbuild-->
1
2
3
4

<!--build:css css/styles.min.css-->
<link rel="stylesheet" href="css/styles.css">
<link rel="stylesheet" href="css/another-stylesheet.css">
<!--endbuild-->

Так как мы используем CSS, то задача useref слегка изменится. Нам не нужно запускать функцию uglify() для CSS файлов, она все испортит. Нужно удостовериться, что uglify() запускается только для JS файлов, в этом нам поможет gulp-if.

$ npm install gulp-if --save-dev
1

$ npm install gulp-if --save-dev

// другие подключения...
var gulpIf = require('gulp-if');

gulp.task('useref', function(){
  var assets = useref.assets();

  return gulp.src('app/*.html')
.pipe(assets)
// Если JS то запускаем uglify()
.pipe(gulpIf('*.js', uglify()))
.pipe(assets.restore())
.pipe(useref())
.pipe(gulp.dest('dist'))
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14

// другие подключения...
var gulpIf = require('gulp-if');

gulp.task('useref', function(){
  var assets = useref.assets();

  return gulp.src('app/*.html')
    .pipe(assets)
    // Если JS то запускаем uglify()
    .pipe(gulpIf('*.js', uglify()))
    .pipe(assets.restore())
    .pipe(useref())
    .pipe(gulp.dest('dist'))
});

Чтобы минифицировать CSS файлы нам потребуется плагин gulp-minify-css.

$ npm install gulp-minify-css
1

$ npm install gulp-minify-css

var minifyCSS = require('gulp-minify-css');

gulp.task('useref', function(){
  var assets = useref.assets();

  return gulp.src('app/*.html')
.pipe(assets)
// Минифицируем только CSS файлы
.pipe(gulpIf('*.css', minifyCSS()))
// Uglifies only if it's a Javascript file
.pipe(gulpIf('*.js', uglify()))
.pipe(assets.restore())
.pipe(useref())
.pipe(gulp.dest('dist'))
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

var minifyCSS = require('gulp-minify-css');

gulp.task('useref', function(){
  var assets = useref.assets();

  return gulp.src('app/*.html')
    .pipe(assets)
    // Минифицируем только CSS файлы
    .pipe(gulpIf('*.css', minifyCSS()))
    // Uglifies only if it's a Javascript file
    .pipe(gulpIf('*.js', uglify()))
    .pipe(assets.restore())
    .pipe(useref())
    .pipe(gulp.dest('dist'))
});

Теперь на выходе мы получаем по одному оптимизированному CSS и JavaScript файлу при любом запуске задачи useref. Идем дальше, оптимизируем изображения.
Оптимизация изображений

Должно быть вы уже догадались; для оптимизации изображений нам нужен плагин gulp-imagemin.

$ npm install gulp-imagemin --save-dev
1

$ npm install gulp-imagemin --save-dev

var imagemin = require('gulp-imagemin');
1

var imagemin = require('gulp-imagemin');

С помощью этого плагина мы можем оптимизировать png, jpg, gif и даже svg. Создадим задачу images.

gulp.task('images', function(){
  return gulp.src('app/images/**/*.+(png|jpg|gif|svg)')
  .pipe(imagemin())
  .pipe(gulp.dest('dist/images'))
});
1
2
3
4
5

gulp.task('images', function(){
  return gulp.src('app/images/**/*.+(png|jpg|gif|svg)')
  .pipe(imagemin())
  .pipe(gulp.dest('dist/images'))
});

К примеру, можно создать чересстрочное гиф-изображение, установив опцию interlaced в true.

gulp.task('images', function(){
  return gulp.src('app/images/**/*.+(png|jpg|jpeg|gif|svg)')
  .pipe(imagemin({

interlaced: true
}))
  .pipe(gulp.dest('dist/images'))
});
1
2
3
4
5
6
7
8

gulp.task('images', function(){
  return gulp.src('app/images/**/*.+(png|jpg|jpeg|gif|svg)')
  .pipe(imagemin({
     
      interlaced: true
    }))
  .pipe(gulp.dest('dist/images'))
});

Можно поиграться и с другими опциями. Однако, процесс оптимизации изображений это очень медленный процесс, так что не стоит его запускать, если он особо не требуется. Для оптимизации нам пригодится плагин gulp-cache.

$ npm install gulp-cache --save-dev
1

$ npm install gulp-cache --save-dev

var cache = require('gulp-cache');

gulp.task('images', function(){
  return gulp.src('app/images/**/*.+(png|jpg|jpeg|gif|svg)')
  // кэширование изображений, прошедших через imagemin
  .pipe(cache(imagemin({
interlaced: true
})))
  .pipe(gulp.dest('dist/images'))
});
1
2
3
4
5
6
7
8
9
10

var cache = require('gulp-cache');

gulp.task('images', function(){
  return gulp.src('app/images/**/*.+(png|jpg|jpeg|gif|svg)')
  // кэширование изображений, прошедших через imagemin
  .pipe(cache(imagemin({
      interlaced: true
    })))
  .pipe(gulp.dest('dist/images'))
});

Мы почти закончили с оптимизацией. Осталась всего одна папка, которую нужно переместить из ‘app’ в ‘dist’, это папка шрифтов. Этим и займемся.
Копируем шрифты в Dist

Так как файлы шрифтов уже оптимизированы, на больше ничего не остается, как просто скопировать их в папку dist. Скопировать файлы через Gulp можно, указав gulp.src и gulp.dist без плагинов.

gulp.task('fonts', function() {
  return gulp.src('app/fonts/**/*')
  .pipe(gulp.dest('dist/fonts'))
})
1
2
3
4

gulp.task('fonts', function() {
  return gulp.src('app/fonts/**/*')
  .pipe(gulp.dest('dist/fonts'))
})

Gulp скопирует шрифты из fonts в папке app в директорию dist при любом запуске задачи gulp fonts.
http://s3.uploads.ru/gh6cz.png

Теперь в нашем gulp-файле 6 различных задач, которые необходимо вызывать вручную, что слегка глупо. Сделаем так, чтобы все задачи запускались одной командой. Но перед этим посмотрим, как удалять автоматически удалять сгенерированные файлы.
Автоматическое удаление сгенерированных файлов

Так как мы генерируем наши файлы автоматически, то нам необходимо быть уверенными, что те файлы, которые нам больше не нужны нигде не завалялись. Этот процесс называется очистка (или проще удаление). Для очистки воспользуемся del.

npm install del --save-dev
1

npm install del --save-dev

var del = require('del');
1

var del = require('del');

Функция del принимает массив подстановок Node, в котором содержатся папки на удаление. Настройка del почти такая же, как и настройка первой задачей, которую мы создавали:

gulp.task('clean', function() {
  del('dist');
})
1
2
3

gulp.task('clean', function() {
  del('dist');
})

Теперь Gulp удалит папку dist при любом запуске задачи gulp clean. Однако, как мы уже упоминали выше, нам нужно избегать лишних запусков задачи images, так как она занимает много времени. Следовательно легче создать отдельную задачу для удаления всех файлов в папке dist кроме изображений.

gulp.task('clean:dist', function(callback){
  del(['dist/**/*', '!dist/images', '!dist/images/**/*'], callback)
});
1
2
3

gulp.task('clean:dist', function(callback){
  del(['dist/**/*', '!dist/images', '!dist/images/**/*'], callback)
});

Прежде всего, мы удаляем все файлы в папке dist/**/*. Так как мы не хотим удалять dist/images, то нужно применить символ «!». Также нам нельзя удалять любые файлы внутри папки dist/images, так что нам нужна третья подстановка. И наконец, нам нужно знать, когда задача clean:dist выполнилась, для этого необходимо добавить аргумент в функцию. По умолчанию при использовании задачи clean удаляется кэш изображений, значит, задаче images придется обрабатывать их заново.

gulp.task('clean', function(callback) {
  del('dist');
  return cache.clearAll(callback);
})
1
2
3
4

gulp.task('clean', function(callback) {
  del('dist');
  return cache.clearAll(callback);
})

Давайте теперь объединим все наши задачи в одну!
Комбинирование задач в Gulp

Давайте обобщим все, что мы проделали. Мы создали два разных набора задач Gulp. Первый набор для разработки: компиляция Sass в CSS, отслеживание изменений и обновление браузера. Второй набор для оптимизации: CSS, JS, изображения и копирование шрифтов из папки app в dist. Первый набор мы уже объединили под общей задачей watch:

gulp.task('watch', ['browserSync', 'sass'], function (){
  // ...
})
1
2
3

gulp.task('watch', ['browserSync', 'sass'], function (){
  // ...
})

Второй набор в себя включает задачи clean:dist, sass, useref, images и fonts. Если следовать в том же ключе, можно создать задачу build, под которой объединить все остальные.

gulp.task('build', [`clean`, `sass`, `useref`, `images`, `fonts`], function (){
  console.log('Building files');
})
1
2
3

gulp.task('build', [`clean`, `sass`, `useref`, `images`, `fonts`], function (){
  console.log('Building files');
})

К несчастью мы не можем написать нашу задачу build так же, как и watch, так как Gulp запустит все задачи во втором аргументе одновременно. Есть вероятность, что useref, images или даже fonts выполнится раньше clean, в таком случае будет удалена вся папка dist. Для того, чтобы очистка выполнялась точно перед остальными задачами, нам потребуется плагин Run Sequence.

$ npm install run-sequence --save-dev
1

$ npm install run-sequence --save-dev

Синтаксис последовательности задач с помощью плагина:

var runSequence = require('run-sequence');

gulp.task('task-name', function(callback) {
  runSequence('task-one', 'task-two', 'task-three', callback);
});
1
2
3
4
5

var runSequence = require('run-sequence');

gulp.task('task-name', function(callback) {
  runSequence('task-one', 'task-two', 'task-three', callback);
});

При вызове task-name задача task-first выполняется первой. После ее выполнения Gulp автоматически запускает task-two. И после task-two запускается task-three. Если поместить задачи в массив, то они могут быть запущены одновременно.

gulp.task('task-name', function(callback) {
  runSequence('task-one', ['tasks','two','run','in','parallel'], 'task-three', callback);
});
1
2
3

gulp.task('task-name', function(callback) {
  runSequence('task-one', ['tasks','two','run','in','parallel'], 'task-three', callback);
});

В этом случае первой запускается task-one, после нее запускаются одновременно все из второго аргумента. Перед запуском task-three все задачи второго аргумента должны завершиться. Теперь мы можем быть уверены, что clean:dist запустится точно перед остальными задачами.

gulp.task('build', function (callback) {
  runSequence('clean:dist',
['sass', 'useref', 'images', 'fonts'],
callback
  )
})
1
2
3
4
5
6

gulp.task('build', function (callback) {
  runSequence('clean:dist',
    ['sass', 'useref', 'images', 'fonts'],
    callback
  )
})

Для красоты мы можем сделать то же самое и с первой группой задач. Назовем задачу default.

gulp.task('default', function (callback) {
  runSequence(['sass','browserSync', 'watch'],
callback
  )
})
1
2
3
4
5

gulp.task('default', function (callback) {
  runSequence(['sass','browserSync', 'watch'],
    callback
  )
})

Почему default? А потому, что с таким именем для запуска задачи вам потребуется набрать gulp. Все, что мы проделали можно посмотреть в репозитории на GitHub.
Заключение

Мы прошли основы по Gulp и настроили рабочий процесс, мы научились компилировать Sass в CSS, следить за изменениями в GTML и JS файлах. Все наши задачи мы можем запустить с помощью одной команды gulp в командной строке.

Также мы создали еще одну задачу Build, которая создает папку dist. В эту папку стекаются все оптимизированные и скомпилированные файлы. Для запуска этой задачи нужно вбить в командную строку gulp build.

И последнее, мы создали задачу clean, которая очищает папку dist от всех сгенерированных файлов, а также чистит кэш изображений. Она нужна нам для удаления любых устаревших и ненужных файлов в папке dist.

Мы настроили Gulp так хорошо, что, в принципе, этого хватит большинству разработчиков. Но всеже есть еще множество настроек и задач, которые можно создать с помощью Gulp.

Источник: https://css-tricks.com/