Gulp — сборщик проекта, который на первый вгляд может показаться усложненным. Но как только Вы немного погрузитесь в него, то поразитесь, насколько он удобен и гибок для подстройки именно под Вашу структуру.

В этой статье мы разберем простой пример настройки Gulp и его плагинов, делается это через gulpfile.js в корне проекта. Установка самого сборщика и его плагинов осуществляется через пакетный менеджер npm.

Что мы используем в обычном проекте?

В простом проекте по верстке, в котором у нас будет папка исходников (src) и рабочего проекта (dist), мы работаем с:

  • HTML — в нашем случае все будет в различных .html файлах двух типов: страницы и темплейты компонентов (здесь мы будем использовать плагин gulp-file-include, что очень сильно облегчает разработку и соответствует DRY);
  • SASS/SCSS — будем использовать препроцессоры для удобства, те собирать будем все .scss файлы в один оптимизированный стилевой файл style.css;
  • JS — те или иные скрипты, все .js файлы, хотелось бы тоже собрать по всему проекту в один оптимизированный script.js;
  • Images — разные статические картинки, которые учавствуют в оформлении. Их будем собирать по всему проекту в одну папку без сохранения изначальной стркутуры папок, а так же оптимизировать размер;
  • Live Dev Server — хотелось бы как-то налету применять все изменения при разработке, за это будет отвечать локальный сервер.

Сначала мы рассмотрим отдельные части кода, потом соберем весь пазл.

Необходимые плагины

Плагины мы устанавливаем, как dev зависимости с помощью npm например.

npm i -D gulp browser-sync gulp-flatten del...

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

// COMMON
import gulp from 'gulp';
const { src, dest, watch, series } = gulp;

import { deleteAsync } from 'del';
import syncServer from 'browser-sync';
const sync = syncServer.create();

import flatten from 'gulp-flatten';

// STYLE
import * as dartSass from 'sass';
import gulpSass from 'gulp-sass';
const sass = gulpSass(dartSass);
import autoprefixer from 'gulp-autoprefixer';
import minify from 'gulp-clean-css';
import sourcemaps from 'gulp-sourcemaps';
import concat from 'gulp-concat';

// HTML
import include from 'gulp-file-include';

// IMAGES
import imagemin from 'gulp-imagemin';

HTML

В HTML нас ждет один из самых приятных сюрпризов, это возможность разделять код на файлы и подключать и в любом месте других файлов, например так:

  <head>
    @@include('src/components/meta/index.html')
    <title>Title</title>
  </head>

За работу с html будет отвечать одноименная функция, заметьте, что мы не берем все .html из проекта, а только те, что считаем страницами, при этом шаблоны подключаются из папки компонентов:

function html() {
  return src('src/pages/**/**.html') // берем все файлы по шаблону
    .pipe( 
      include({
        prefix: '@@',
        basepath: '@root',
      }),// запускаем плагин, который подставит все темплейты
    )
    .pipe(dest('dist')); // кладем файлы с сохранением структуры и проект
} 

SASS/SCSS

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

function scss() {
  return src('src/**/**.scss') // берем все файлы с расширением .scss
    .pipe(sourcemaps.init()) // начинаем собирать sourcemap информацию
    .pipe(autoprefixer()) // добавляем браузерные префиксы
    .pipe(sass().on('error', sass.logError)) // препроцессор sass
    .pipe(concat('style.min.css')) // собираем все в 1 файл
    .pipe(minify()) // минифицируем
    .pipe(sourcemaps.write('.')) // указываем sourcemap  туже директорию
    .pipe(dest('dist/assets/css')); // сохраняем конечный фалй
}

JS

C JS все достаточно просто, собираем в один файл всё с расширением .js. Но Вы можете подключить дополнительные плагины для манификации кода например.

function js() {
  return src('src/**/**.js') // выбираем файлы по маске
    .pipe(concat('script.js')) // сиединяем в один файл script.js
    .pipe(dest('dist/assets/js')); // сохраняем в необходимую директорию
}

Images

Собираем все картинки в папке, и обрабатываем необходимым образом.

function images() {
  return src('src/assets/images/*') // выбираем файлы по маске
    .pipe(imagemin()) // оптимизируем картинки
    .pipe(flatten()) // избавляемся от вложенности, можно убрать
    .pipe(dest('dist/assets/images/')); // сохраняем в проект
}

Вспомогательные функции

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

function clear() {
  return deleteAsync('dist'); // удаляем все файлы из итогового проекта
}

function serve() {
  // инициализируем сервер, который хостит нашу папку итогового проекта
  sync.init({ server: './dist' }); 

  // следим за файлами по маске и запускаем функции при их изменении
  // далее перезагружаем сервер
  watch(['src/**/**.html'], series(html)).on('change', sync.reload);
  watch(['src/**/**.scss'], series(scss)).on('change', sync.reload);
  watch(['src/assets/images/*'], series(images)).on('change', sync.reload);
  watch('src/**/**.js', series(js)).on('change', sync.reload);
}

Функции сборки проекта

В итоге для удобства нам хотелось бы иметь короткие функции сборки всего проекта и запуска их из консоли. Нам понадобятся dev и build сборки. Запускать их будем так:

gulp dev
gulp build

Для сборок будем использовать наборы функций, которые запускаются последовательно, для этого используем метод gulp — series. Он возвращает функцию, которую мы экспортируем и сможем использовать для запуска из коммандной строки.

// series последовательно запускает указанные функции
const build = series([clear, scss, html, js, images]);
const dev = series([clear, scss, html, js, images, serve]);

export { build, dev };

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

Итоговый файл настройки

// COMMON
import gulp from 'gulp';
const { src, dest, watch, series } = gulp;

import { deleteAsync } from 'del';
import syncServer from 'browser-sync';
const sync = syncServer.create();
import flatten from 'gulp-flatten';

// STYLE
import * as dartSass from 'sass';
import gulpSass from 'gulp-sass';
const sass = gulpSass(dartSass);
import autoprefixer from 'gulp-autoprefixer';
import minify from 'gulp-clean-css';
import sourcemaps from 'gulp-sourcemaps';
import concat from 'gulp-concat';

// HTML
import include from 'gulp-file-include';

// IMAGES
import imagemin from 'gulp-imagemin';

function html() {
  return src('src/pages/**/**.html')
    .pipe(
      include({
        prefix: '@@',
        basepath: '@root',
      }),
    )
    .pipe(dest('dist'));
}

function images() {
  return src('src/assets/images/*')
    .pipe(imagemin())
    .pipe(flatten())
    .pipe(dest('dist/assets/images/'));
}

function scss() {
  return src('src/**/**.scss')
    .pipe(sourcemaps.init())
    .pipe(autoprefixer())
    .pipe(sass().on('error', sass.logError))
    .pipe(concat('style.min.css'))
    .pipe(minify())
    .pipe(sourcemaps.write('.'))
    .pipe(dest('dist/assets/css'));
}

function js() {
  return src('src/**/**.js').pipe(concat('script.js')).pipe(dest('dist/assets/js'));
}

function clear() {
  return deleteAsync('dist');
}

function serve() {
  sync.init({ server: './dist' });

  watch(['src/**/**.html'], series(html)).on('change', sync.reload);
  watch(['src/**/**.scss'], series(scss)).on('change', sync.reload);
  watch(['src/assets/images/*'], series(images)).on('change', sync.reload);
  watch(['src/**/**.js'], series(js)).on('change', sync.reload);
}

const build = series([clear, scss, html, js, images]);
const dev = series([clear, scss, html, js, images, serve]);

export { build, dev };

Заключение

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

Если остались вопросы, напишите нам на почту, мы постараемся помочь!