Что такое gulp и зачем он нужен
Gulp — это инструмент, который помогает разработчикам автоматизировать рутинные задачи. Чаще всего gulp используется в frontend разработке для таких задач:
- Автоматическая перезагрузка браузера при сохранении файла
- Использование препроцессоров
- Оптимизация ресурсов таких как javascript, css, изображения
- Использование автопрефиксера
- Создание карт проекта
- Объединение нескольких файлов в один
Если вы внедрите в свою практику эту систему, вы значительно увеличите скорость вашей работы. Так же gulp откроет вам путь к новым возможностям, который значительно повысит ваш уровень знаний в веб-разработки.
Установка Gulp
Установка Gulp 4 довольно простая. Так как Gulp написан на языке javascript, изначально необходимо установить Node.js на вашу систему. Просто заходите на сайт https://nodejs.org, скачиваете инсталятор последний версии и устанавливаете.
Далее создаем папку для проекта в любом удобном месте компьютера и вызываем окно терминала в этом каталоге. В командной строке запускаем инициализацию проекта:
npm init
Отвечаем на вопросы на каждом шаге. После каждого ввода нажимаем Enter и переходим к следующему шагу. В результате получим файл package.json, который содержит информацию о проекте и установленных плагинах. Далее установим gulp в наш проект:
npm i gulp --save-dev
После установке Gulp 4 название пакета и его версия сохранятся в файле package.json. Флаг —save-dev используется для сохранения пакета в package.json в раздел devDependencies, то есть в целях разработки. Если установить пакет с флагом —save, то пакет попадает в раздел dependencies (для запуска приложения).
Такой подход дает возможность сохранять все пакеты в файле package.json со всеми зависимостями, а при разворачивании нового проекта достаточно скопировать файл package.json и запустить команду:
npm install
Таким образом все пакеты и зависимости установятся автоматически. После установки gulp в каталоге проекта создалась папка node_modules. Все новые установленные пакеты и зависимости сохраняются в данную папку. Поэтому изменять содержимое этого каталога нельзя.
Далее в каталоге проекта создаем файл gulpfile.js. Это самый основной файл, без которого Gulp работать не может. По сути в него можно писать любой javascript код, но gulp — это менеджер управления задачами, и эти задачи описываются в этом файле в виде обычных функций. Что бы запускать эти задачи, функцию нужно экспортировать через оператор exports. Пример:
function testTask(done){
console.log('test');
done();
}
exports.test = testTask;
На примере выше мы создали задачу под название testTask, в которой выводим строчку test. После этого мы экспортируем эту задачу. Что бы Gulp знал, что задача выполнена, мы вызываем функцию обратного вызова done.
Что бы запустить Gulp, можно установить отдельную утилиту глобально на вашу систему:
npm install --global gulp-cli
После этого в консоли вводим команду gulp и через пробел название задачи:
gulp test
Но есть и альтернативный вариант. Можно передать дополнительные параметры командам запуска в файле package.json для раздела scripts:
...
"scripts": {
"gulp": "gulp"
},
...
В этом случае запускается задача так:
npm run gulp test
gulp — это значение с раздела scripts файла package.json, а test — название задачи. В итоге в консоле выведется слово test:
Задача по умолчанию (gulp default task)
Создадим в файле gulpfile.js задачу по умолчанию. Этот такс лучше всего представить, как точку входа в наш проект. Цель этой задачи — собрать и запустить таски в определенной последовательности, которые gulp должен выполнить по умолчанию. В нашем случае мы заменим таск test на default в функции экспорта:
exports.default = testTask;
Теперь для запуска проекта нам необходимо ввести:
npm run gulp
Таким образом мы получим такой же результат, как и раньше, но при этом мы не указываем конкретный таск, а запускаем задачу по умолчанию.
Gulp parallel, gulp series
В Gulp существуют методы parallel и series для объединения задач в цепочки. Метод parallel запускает задачи одновременно в любой последовательности. Метод series — выполняет задачи одна за одной в указанном порядке:
exports.default = gulp.series( gulp.parallel(a, b), gulp.parallel(c, d) )
На примере выше, задачи a и b запускаются параллельно. Только после завершения этих задач, запускаются таски c и d в паралельном режиме.
Gulp src, gulp dist, gulp pipe
Прежде чем приступать к практике, определимся еще с некоторыми базовыми понятиями. Ранее мы создали тестовый таск, который просто выводит значение в консоль. Но смысл gulp в том, чтобы выполнять рутинные задачи в процессе разработки. Другими словами — взять какой-то файл нашего проекта, выполнить определенные манипуляции с ним, и на выходе получить обновленный файл. Для того, чтобы указать входной файл, используется выражение gulp.src(‘source-file’), а исходящий — gulp.dest(‘dest-folder’). Давайте рассмотрим на примере:
const gulp = require('gulp');
function testTask(){
return gulp.src('./test.js')
.pipe(gulp.dest('./output'));
}
exports.default = testTask;
Первой строчкой подключаем сам gulp в наш проект. Далее создаем таск, как мы делали это ранее. Указываем gulp что мы работаем с файлом test.js. После этого через метод pipe говорим gulp, что исходная папка называется output. Таким образом мы просто скопировали файл test.js в папку output.
Метод pipe — это основное API для gulp. Этот метод как бы объединяет все операции внутри таска. Через pipe можно выстроить неограниченную цепочку из операций для создания определенных сценариев.
Шаблоны путей к файлам
Очень часто необходимо на вход gulp передать не конкретный файл, а группу файлов. Для этого используют так называемые шаблоны. Рассмотрим на примере какие они бывают:
./input/*.js — выберет все файлы с расширением js в корне папки input
./input/**/*.js — выберет все файлы с расширением js в корне папки input и дочерних каталогах
!./input/test.js — исключает файл test.js из выборки
./input/*.+(js, css) — выберет файлы js и css
Так же, в качестве входных данных в gulp можно передавать массив с несколькими файлами или шаблонами:
gulp.src(["./input/**/*.css", "!./input/test.css"])
На примере мы выбираем все файлы с расширением css, но исключаем файл test.css.
Gulp плагины
Стандартный функционал gulp достаточно примитивен. Для того, чтобы реализовать более сложные операции, необходимо использовать так называемые плагины. Другими словами, это расширение, которое мы подключаем к себе в проект для решения той или иной задачи. Существует огромное количество плагинов для gulp. Найти и посмотреть их описание можно на официальном сайте.
Ранее мы написали скрипт, который просто копирует файл в другую папку. Давайте усложним задачу: при копировании имя файла должно переименовывается. Для этого как раз и воспользуемся плагином, который называется gulp-rename. Для начала, установим этот плагин:
npm i gulp-rename --save-dev
Любой плагин, как и npm модуль, устанавливается в папку node_modules, и попадает в файл package.json. Далее его нужно подключить в gulpfile.js, и через метод pipe вызвать необходимую операцию:
const gulp = require('gulp');
const rename = require("gulp-rename");
function testTask(){
return gulp.src('./test.js')
.pipe(rename('testNew.js'))
.pipe(gulp.dest('./output'));
}
exports.default = testTask
Таким образом, мы берем файл test.js, переименовываем его в testNew.js, и копируем в папку output.
Gulp сборка для верстки сайта. Стартовый шаблон
И так, мы установили Gulp, настроили окружение и можем переходить к созданию своей сборки для верстки сайта.
Для начала поставим себе задачу: мы хотим создать стартовый шаблон для начала работы с любым проектом. Сборка будет выполнять ряд задач: работа с препроцессорами, минификация кода, сжатия и преобразования изображений, конвертация шрифтов, сборка спрайтов, подключение отдельный частей html в единый шаблон и многое другое.
Режимы работы
Gulp сборка должна запускаться в двух режимах: сборка проекта для разработки и сборка для продакшин. В режиме разработки важна скорость работы, поэтому мы не будем минифицировать код, сжимать изображение и выполнять другие трудоемкие операции. В режиме продакшин мы подготавливаем наш проект к дальнейшему использованию или выгрузке на хостинг, очищаем от всего лишнего, сжимаем код и выполняем другие действия. Давайте это реализуем.
В файле package.json в раздел scripts вносим некоторые изменения:
...
"scripts": {
"dev": "gulp",
"prod": "gulp --prod"
},
...
Для запуска сборки в режиме разработки необходимо ввести команду:
npm run dev
Для запуска в режиме продакшин:
npm run prod
Как видим выше, в режиме прод мы добавляем переменную окружения prod. Далее, чтобы определить в каком режиме мы работаем, необходимо установить плагин yargs:
npm i yargs --save-dev
Подключаем этот плагин в gulpfile.js:
const argv = require('yargs').argv;
Если запустить сборку в режиме дев, то значение переменной argv.prod будет равно undefined, а если в прод режиме, то true. Таким образом, если переменная argv.prod равна true, то мы работаем в прод режиме. Если не true, то дев режим.
Для удобства, создадим две функции, которые проверяют режим работы:
/**
* Dev check
*/
const isDev = function(){
return !argv.prod;
}
/**
* Prod check
*/
const isProd = function(){
return !!argv.prod;
}
Файловая структура gulp сборки
Создадим базовую структуру файлов и папок. Это стандартная структура любого web проекта, которую можно поменять под свой вкус и потребности.gulpProject: . | gulpfile.js | package-lock.json | package.json +—dist +—src | index.html +—assets | +—css | +—fonts | +—img | +—js +—_components
Рассмотрим предназначение каждой папки и файла:
- gulpfile.js — главный файл для настройки Gulp4
- package-lock.json — файл создается автоматически при изменении в node_modules
- package.json — файла-манифеста для проекта
- dist — в эту папку автоматически сохраняются все готовые файлы. Другими словами в этой папке содержится готовый проект
- src — в этом каталоге хранятся исходники проекта
- index.html — шаблон главной страницы
- assets — папка для активов, таких, как стили, скрипты, шрифты и др
- css — файлы для препроцессора CSS
- fonts — каталог для шрифтов
- img — папка для исходных изображений
- js — каталог для исходных скриптов
Это основная файловая структура сборки, но она будет меняться в ходе работы.
Давайте сразу добавим файл .gitignore в корень проекта со следующим содержимым:
/node_modules/*
/dist/*
Здесь мы скрываем каталоги dist и node_modules от систем контроль версий, так как они создаются автоматически.
Настройка путей
Создадим в корне проекта файл projectConfig.json. Это простой json файл, в него мы будем записывать различные настройки для нашей сборки. Для начала определим переменные для путей:
{
"path": {
"src": {
"srcPath": "./src",
},
"dist": {
"distPath": "./dist"
}
}
}
Мы определили переменную path, которая в свою очередь содержит два значения: настройки путей для исходников проекта и для готового результата. В конечном итоге мы можем изменять эти значения, что дает гибкость нашей gulp сборки. В процессе работы мы будем добавлять необходимые нам настройки.
Далее в gulpfile.js подключим файл с настройками:
const projectConfig = require('./projectСonfig.json');
const path = projectConfig.path;
Теперь можно обратится к переменной path и получить необходимые значения.
Browser sync gulp. Автоматическое обновление страницы в браузере
Browser sync — это очень полезный плагин. Он позволяет открыть страницы сайта, используя локальный сервер, и настроить автоматическую перезагрузку сайта. Установим плагин browsersync в наш проект:
npm install browser-sync gulp --save-dev
В файле gulpfile.js добавим описание таска для плагина browsersync. На данном этапе файл gulpfile.js выглядит так:
/**
* Подключение плагинов
*/
const gulp = require('gulp');
const argv = require('yargs').argv;
const browserSync = require('browser-sync').create();
/**
* Подключение файла настроек
*/
const projectConfig = require('./projectСonfig.json');
/**
* Значения путей проекта
*/
const path = projectConfig.path;
/**
* Проверка на dev режим
*/
const isDev = function(){
return !argv.prod;
}
/**
* Проверка на prod режим
*/
const isProd = function(){
return !!argv.prod;
}
/**
* Serve
*/
function browsersync() {
browserSync.init({
open: true,
server: path.dist.distPath
});
}
exports.default = browsersync;
Все как обычно: подключаем browserSync через require, описываем задачу для него, и запускаем таск по умолчанию. Теперь при запуске gulp автоматически откроется браузер. На данном этапе нам этого будет достаточно.
Gulp html
Для работы с html, будем использовать шаблонизатор nunjucks (подробнее почитать можно тут). Для начала определим структуру каталога и файлов для штмл файлов:src: . | index.html +— _html +— _base +— _includes | _header.html | _footer.html +— _layouts | _default.html
Рассмотрим подробнее файловую структуру:
- index.html — главная страница сайта
- _includes — каталог с подключаемыми файлами
- _header.html — верхняя часть сайта
- _footer.html — нижняя часть сайта
- _layouts — папка с шаблонами
- _default.html — основной шаблон
Нижний прочерк в названии файлов и папок говорит о том, что они подключаются в основной файл.
Далее зададим настройки путей для html в файле projectСonfig.json. В раздел src добавим массив со значением папки, где находятся штмл файлы, относительно каталога с исходниками проекта. Аналогично добавим значения для исходящего файла в раздел dist.
{
"path": {
"src": {
"srcPath": "./src",
"components": "/_components",
"html": [
"/**/*.html"
]
},
"dist": {
"distPath": "./dist",
"html": "/"
}
}
}
В gulpfile.js создадим массив путей для входных файлов:
path.src.html[0] = path.src.srcPath + path.src.html[0];
path.src.html[1] = "!" + path.src.html[0].slice(0, -6) + "_*.html";
path.src.html[2] = "!" + path.src.srcPath + "/assets";
path.src.html[3] = "!" + path.src.srcPath + "/_html";
В первой строке формируем путь к html файлам, которые нужно скомпилировать. Во второй запрещаем компилировать файлы, которые начинаются с нижнего прочерка. В третей и четвертой запрещаем компиляцию с папки assets и _html. В итоге получим такой массив:
html: [
'./src/**/*.html',
'!./src/**/_*.html',
'!./src/assets',
'!./src/_html'
]
Так же формируем переменную для папки с готовыми html файлами:
path.dist.html = path.dist.distPath + path.dist.html;
В результате получим такое значение:
html: './dist/'
И так, пути мы сформировали, теперь описываем задачу для html файлов:
function njk() {
return gulp.src(path.src.html)
.pipe(nunjucks.compile())
.pipe(gulp.dest(path.dist.html))
.on('end', browserSync.reload);
}
exports.njk = njk;
Как видим, это обычная задача для gulp. В конце этого таска мы автоматически перезагружаем браузер.
Создадим общий каркас для всех страниц сайта в файле _default.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ title }}</title>
<meta name="description" content="{{ meta_description }}">
</head>
<body {% if bodyClass %}class="{{ bodyClass }}"{% endif %}>
<div class="page-wrapper" id="pageWrapper">
{% include "_html/_base/_includes/_header.html" %}
{% block content %}{% endblock %}
{% include "_html/_base/_includes/_footer.html" %}
</div>
</body>
</html>
В файлах _header.html и _footer.html выведем верхнюю и нижнюю части сайта, которые мы подключаем к основному шаблону. _header.html:
<header>Header</header>
_footer.html:
<footer>Footer</footer>
В файле index.html находится основная часть главной страницы сайта:
{% set title = "Home" %}
{% set bodyClass = "is-home" %}
{% extends "_html/_base/_layouts/_default.html" %}
{% block content %}
<h1>Content</h1>
{% endblock %}
На примере выше мы определили переменные title страницы и класса тега body. В процессе работы можно добавлять другие переменные и передавать их в основной шаблон. Далее мы указываем, что наследуем основной шаблон и в блоке content описываем контентную часть страницы.
Таким образом мы можем создавать общие html файлы для нашего проекта, подключать их в шаблон и менять содержимое в одном месте.
Теперь запустим на выполнение таск:
Как видим, все исходники скомпилировались в один файл index.html. Теперь можно создавать сколь угодно html файлов и все они будут собираться в папке dist.
Gulp watch. Отслеживаем изменения в файлах
В Gulp предусмотрен метод watch, с помощью которого можно отслеживать изменения в том или ином файле. Если мы, например, модифицировали наш файл index.html, то с помощью метода watch можно автоматически запустить тот или иной таск. Реализуем это в нашей сборке.
Для начала в переменной path определим свойство watch как пустой объект:
path.watch = {};
В ней укажем файлы, которые нужно отслеживать для сборки html:
path.watch.html = [];
path.watch.html[0] = path.src.html[0];
То есть, мы отслеживаем все файлы в папке src. Создадим gulp tack для отслеживания изменений в файлах:
function watch(){
gulp.watch(path.watch.html, njk);
}
На примере выше мы создали обычный таск, в нем вызываем метод watch, в который передаем два параметра: какие фалы отслеживаем, и какой таск запускаем при модификации в этих файлах.
После этого изменим дефолтный таск:
exports.default = gulp.series(
gulp.parallel(njk),
gulp.parallel(browsersync, watch)
);
Здесь сначала запускается таск njk, после этого в параллельном режиме запускаем локальный сервер и отслеживание в файлах.
Теперь при запуске дефолтного таска откроется главная страница на локальном сервере. При изменении в штмл файлах сайт обновляется автоматически уже с измененными данными.
Gulp scss. Работа со стилями
В качестве препроцессора для стилей будем использовать SASS в синтаксисе SCSS. В папке src/assets/css создадим файл app.scss. Это будет основной файл стилей.
В projectСonfig.json задаем настройки путей к файлам стилей. В разделе src добавляем:
"style": [
"/assets/css/app.scss"
]
В раздел dist:
"style": "/assets/css/"
В gulpfile.js задаем массив путей для файлов стилей:
path.src.style[0] = path.src.srcPath + path.src.style[0];
path.dist.style = path.dist.distPath + path.dist.style;
path.watch.style = [];
path.watch.style[0] = path.src.style[0].replace( path.src.style[0].split('/').pop(), '**/*.scss' );
В итоге получим:
- Входной файл: ./src/assets/css/app.scss
- Исходящая директория: ./dist/assets/css/
- Файлы для отслеживания: ./src/assets/css/**/*.scss
Сразу откроем наш основной шаблон _default.html и в раздел head добавим файл стилей, который будет называется app.min.css:
<link rel="stylesheet" type="text/css" href="assets/css/app.min.css">
Далее добавляем нужные плагины для работы со стилями:
npm i sass gulp-sass gulp-sourcemaps gulp-autoprefixer gulp-csso gulp-rename gulp-group-css-media-queries gulp-if --save-dave
- sass — скрипт компиляции sass файлов
- gulp-sass — gulp плагин для sass
- gulp-sourcemaps — плагин для source maps, который позволяет в DevTools отслеживать стили в исходных файлах
- gulp-autoprefixer — плагин для расстановки префиксов
- gulp-csso — плагин для минификации css
- gulp-rename — плагин для переименования файлов
- gulp-group-css-media-queries — плагин для группировки медиа запросов в стилях
- gulp-if — плагин для создания условий в gulp файле
Подключаем все эти плагины:
const sass = require('gulp-sass')(require('sass'));
const sourcemaps = require('gulp-sourcemaps');
const gulpif = require('gulp-if');
const autoprefixer = require('gulp-autoprefixer');
const csso = require('gulp-csso');
const rename = require("gulp-rename");
const gcmq = require('gulp-group-css-media-queries');
Далее создаем gulp таск для CSS стилей:
function scss(){
return gulp.src(path.src.style)
.pipe(gulpif(isDev(), sourcemaps.init()))
.pipe(sass())
.pipe(gulpif(isProd(), autoprefixer({
grid: true
})))
.pipe(gulpif(isProd(), gcmq()))
.pipe(gulpif(isDev(), sourcemaps.write()))
.pipe(gulpif(isProd(), gulp.dest(path.dist.style)))
.pipe(gulpif(isProd(), csso()))
.pipe(rename({ suffix: '.min' }))
.pipe(gulp.dest(path.dist.style))
.pipe(browserSync.reload({stream: true}))
}
Рассмотрим детально код выше. С помощью плагина gulpif мы проверяем в каком режиме мы работаем. Если в дев режиме, то мы инициализируем sourcemaps, выполняем компиляцию sass, сохраняем sourcemaps в конец файла, добавляем суффикс min к названию файла, сохраняем готовый файл и перезагружаем браузер. Таким образов, в папке dist/css создастся файл app.min.css. Несмотря на то, что мы добавили суффикс min, стили в нем не сжаты и добавлены sourcemaps для удобства разработки.
В прод режиме нам нужно оптимизировать стили и подготовить для боевых условий. После компиляции SASS добавляются префиксы, группируются медиа запросы (gulp group css media queries). Далее мы сохраняем несжатый файл стилей в папку dist/css. Этот файл называется app.css и он не будет подключен к сайту. Сделано это для удобства, что бы рядом со сжатым файлом был оригинальный файл стилей. Далее мы минифицируем стили, добавляем суффикс min, сохраняем и перегружаем браузер. В итоге получим файл app.min.css, который оптимизирован и подключен к проекту.
Теперь нужно немного настроить автопрефиксер, указать какие браузеры нужно поддерживать. Это можно сделать, добавив в файл package.json специальное свойство browserslist в конец файла:
...
"browserslist": [
"last 4 versions"
]
Добавим отслеживание изменения в файлах стиле в таске watch:
function watch(){
gulp.watch(path.watch.html, njk);
gulp.watch(path.watch.style, scss);
}
Так же скорректируем таск по умолчанию:
exports.default = gulp.series(
gulp.parallel(njk, scss),
gulp.parallel(browsersync, watch)
);
Теперь можно запустить сборку. И если мы все правильно сделали, то все стили должны применятся на сайте, и при модификации любого scss файла в пвпке ./src/assets/css/, браузер будет перегружаться автоматически.
Gulp и webpack. Работа со скриптами
Для работы с js скриптами мы будем использовать webpack. Webpack — это популярный и гибкий сборщик модулей для javascript. Он умеет решать великое множество задач, как простых, так и сложных. Это полноценный и самостоятельный инструмент, с большим количеством дополнений. Но в нашей сборке мы попробуем подружить webpack и gulp. Для этого будем использовать gulp плагин webpack-stream.
И так, как обычно, в файле projectСonfig.json зададим настройки путей для скриптов. Раздел src:
"script": [
"/assets/js/app.js"
]
Раздел dist:
"script": "/assets/js/"
Как видим, исходный файл находится по пути src/assets/js/app.js, а компилироваться скрипты будут в папку dist/ assets/js/.
В gulpfile.js задаем массивы с путями:
path.src.script[0] = path.src.srcPath + path.src.script[0];
path.dist.script = path.dist.distPath + path.dist.script;
path.watch.script = [];
path.watch.script[0] = path.src.script[0].replace( path.src.script[0].split('/').pop(), '**/*.js' );
В итоге получаем:
- Входящий файл: ./src/assets/js/app.js
- Исходящая директория: ./dist/assets/js/
- Файлы для отслеживания: ./src/assets/js/**/*.js
После этого устанавливаем нужные плагины:
npm i webpack-stream webpack gulp-plumber gulp-uglify babel-loader @babel/core @babel/preset-env --save-dev
Рассмотрим каждый плагин:
- webpack-stream — gulp плагин для работы с webpack
- webpack — сам бандлер
- gulp-plumber — специальный gulp плагин для отслеживания ошибок
- gulp-uglify — плагин для сжатия скриптов
- babel-loader, @babel/core, @babel/preset-env — набор плагинов для совместимости для старых браузеров
Подключаем плагины:
const webpackStream = require('webpack-stream');
const webpack = require('webpack');
const plumber = require('gulp-plumber');
const uglify = require('gulp-uglify');
Описываем таск для работы со скриптами. Для начала создаем объект для конфигурации webpack:
const webpackConf = {
mode: isDev() ? 'development' : 'production',
devtool: isDev() ? 'eval-source-map' : false,
optimization: {
minimize: false
},
output: {
filename: 'app.js',
},
module: {
rules: []
}
}
Здесь определяем в каком режиме работаем, включаем source maps в dev режиме и задаем исходящий файл app.js.
Далее подключаем babel в прод режиме:
if(isProd()){
webpackConf.module.rules.push({
test: /\.(js)$/,
exclude: /(node_modules)/,
loader: 'babel-loader'
});
}
На этом не будем подробно останавливается, единственное что еще нужно — это создать файл .babelrc с таким содержимым:
{
"presets": [
"@babel/preset-env"
]
}
И наконец, создаем сам таск:
function script(){
return gulp.src(path.src.script)
.pipe(plumber())
.pipe(webpackStream(webpackConf, webpack))
.pipe(gulpif(isProd(), gulp.dest(path.dist.script)))
.pipe(gulpif(isProd(), uglify()))
.pipe(rename({ suffix: '.min' }))
.pipe(gulp.dest(path.dist.script))
.pipe(browserSync.reload({stream: true}))
}
Здесь все подобно, как и с таском со стилями. Включаем отображение ошибок, запускаем webpack, сжимаем файл в прод режиме, добавляем суффикс min и перегружаем браузер.
Добавим файлы для отслеживания в функцию watch:
…
gulp.watch(path.watch.script, script);
…
Далее изменяем таск по умолчанию:
exports.default = gulp.series(
gulp.parallel(njk, scss, script),
gulp.parallel(browsersync, watch)
);
Создаем файл app.js. Подключаем в шаблоне _default.html файл app.min.js перед закрывающимся тегом body:
…
<script src="assets/js/app.min.js"></script>
</body>
</html>
На этом настройка gulp задачи для работы со скриптами закончена.
Gulp imagemin. Сжатие изображений
Далее мы реализуем возможность для работы с изображениями с помощью плагина imagemin. Этот плагин предназначен для сжатия и оптимизации изображений различных форматов.
Зададим настройки для путей к изображениям. В раздел src добавим:
"image": [
"/assets/img/**/*.*"
]
В раздел dist:
"image": "/assets/img/"
Создаем массивы настроек в gulpfile.js:
path.src.image[0] = path.src.srcPath + path.src.image[0];
path.src.image[1] = "!" + path.src.image[0].slice(0, -6) + "svgIcons/*.svg";
path.dist.image = path.dist.distPath + path.dist.image;
path.watch.image = [];
path.watch.image[0] = path.src.image[0];
path.watch.image[1] = "!" + path.src.image[0].slice(0, -6) + "svgIcons/*.svg";
Получаем такой массив:
- Входящие файлы: ./src/assets/img/**/*.*, !./src/assets/img/svgIcons/*.svg
- Исходящая директория: ./dist/assets/img/
- Файлы для отслеживания: ./src/assets/img/**/*.*, !./src/assets/img/svgIcons/*.svg
Здесь мы исключаем папку svgIcons, которая предназначена для генерации svg спрайтов. К этому мы вернемся чуть позже. Устанавливаем необходимые плагины:
npm i gulp-newer gulp-imagemin imagemin-jpeg-recompress imagemin-pngquant --save-dev
Рассмотрим каждый плагин:
- gulp-newer — запускают задачи только для тех файлов, которые изменились
- gulp-imagemin — плагин для сжатия изображений
- imagemin-jpeg-recompress — плагин для оптимизации jpeg изображений
- imagemin-pngquant — плагин для оптимизации png изображений
Подключаем плагины:
const newer = require('gulp-newer');
const imagemin = require('gulp-imagemin');
const imageminJpegRecompress = require('imagemin-jpeg-recompress');
const pngquant = require('imagemin-pngquant');
Создаем таск для сжатия изображений:
function imageMin(){
return gulp.src(path.src.image)
.pipe(newer(path.dist.image))
.pipe(imagemin([
imageminJpegRecompress({
progressive: true,
min: 70, max: 75
}),
pngquant({
speed: 5,
quality: [0.6, 0.8]
}),
imagemin.svgo({
plugins: [
{ removeViewBox: false },
{ removeUnusedNS: false },
{ removeUselessStrokeAndFill: false },
{ cleanupIDs: false },
{ removeComments: true },
{ removeEmptyAttrs: true },
{ removeEmptyText: true },
{ collapseGroups: true }
]
})
]))
.pipe(gulp.dest(path.dist.image))
}
Gulp webp. Конвертация изображений в webp формат
Далее создадим таск, который конвертирует все изображение в webp формат. Это делается с целью оптимизации скорости загрузки сайта. Для этого установим плагин gulp-webp:
npm i gulp-webp --save-dev
Подключим этот плагин:
const webp = require('gulp-webp');
Создаем таск для конвертации изображений в webp:
function webConverter(){
return gulp.src(path.dist.image + '**/*.{png,jpg,jpeg}')
.pipe(webp())
.pipe(gulp.dest(path.dist.image))
}
В этом таске в качестве входных файлов мы берем изображения в папке dist/img, преобразовываем в webp формат и сохраняем в эту же папку.
Теперь мы совместим два таска: сначала выполняем сжатие изображений, потом конвертацию и перезагружаем браузер после выполнения этих двух задач:
const image = gulp.series(imageMin, webConverter, (done) => {browserSync.reload(); done();});
Далее изменяем таск по умолчанию:
exports.default = gulp.series(
gulp.parallel(njk, scss, script, image),
gulp.parallel(browsersync, watch)
);
Также установим отслеживание за изображениями в исходной папке:
function watch(){
gulp.watch(path.watch.html, njk);
gulp.watch(path.watch.style, scss);
gulp.watch(path.watch.script, script);
gulp.watch(path.watch.image, image);
}
Gulp fonts. Работа со шрифтами
Следующая возможность, которую хотелось бы реализовать в нашей сборке — это работа со шрифтами. На сегодняшний день самыми популярными форматами шрифтов являются woff2 и woff. Именно их и нужно подключать в CSS стилях. Для начала определим пути для работы со шрифтами в файле projectСonfig.json. Раздел src:
"font": [
"/assets/fonts/**/*.*"
]
Раздел dist:
"font": "/assets/fonts/"
Определяем массив для настройки путей шрифтов:
path.src.font[0] = path.src.srcPath + path.src.font[0];
path.src.font[1] = "!" + path.src.font[0].slice(0, -6) + "src/*.*";
path.dist.font = path.dist.distPath + path.dist.font;
path.watch.font = [];
path.watch.font[0] = path.src.font[0];
path.watch.font[1] = "!" + path.src.font[0].slice(0, -6) + "src/*.*";
Получаем:
- Входящий файл: ./src/assets/fonts/**/*.*, !./src/assets/fonts/src/*.*
- Исходящая директория: ./dist/assets/fonts/
- Файлы для отслеживания: ./src/assets/fonts/**/*.*, !./src/assets/fonts/src/*.*
Как видим, исходные шрифты будут копироваться с папки ./src/assets/fonts/ в каталог ./dist/assets/fonts/. Так же мы исключили каталог src в папке с исходными шрифтами.
Очень часто возникает задача сконвертировать шрифты устаревших форматов в современные. Эта задача довольно скучная, поэтому мы автоматизируем конвертацию с помощью gulp. Именно в папке src будут сохранятся шрифты старых форматов, а преобразовывать их будем в форматы woff2 и woff и сохранять в папку с исходными шрифтами.
Для начала создадим задачу, которая конвертирует шрифт ttf в woff2 и woff. Нам понадобятся два плагина: gulp-ttf2woff2 и gulp-ttf2woff. Устанавливаем их:
npm i gulp-ttf2woff gulp-ttf2woff2 --save-dev
Подключаем эти плагины:
const ttf2woff = require('gulp-ttf2woff');
const ttf2woff2 = require('gulp-ttf2woff2');
Дале описываем таски для преобразования шрифтов:
function ttf2woff2Converter(){
return gulp.src(path.src.font[0].slice(0, -6) + "src/*.ttf")
.pipe(ttf2woff2())
.pipe(gulp.dest(path.src.font[0].slice(0, -6)));
}
function ttf2woffConverter(){
return gulp.src(path.src.font[0].slice(0, -6) + "src/*.ttf")
.pipe(ttf2woff())
.pipe(gulp.dest(path.src.font[0].slice(0, -6)));
}
Обедняем эти таски, выполнив один за одним:
const fontsConvert = gulp.series(ttf2woff2Converter, ttf2woffConverter);
После этого экспортируем функцию:
exports.fontsConvert = fontsConvert;
И так, чтобы шрифты с расширением ttf конвертировать в woff2 и woff, необходимо ввести команду:
npm run dev fontsConvert
После этой команды все ttf шрифты c каталога src преобразуются в современные форматы и скопируются в папку /src/assets/fonts.
Теперь реализуем конвертацию с формата otf. Для этого мы сначала преобразуем формат otf в ttf, сохраним в папку src, ну а далее, как на примере выше конвертируем в нужные форматы. Для этого понадобится плагин fonter. Устанавливаем его:
npm i gulp-fonter --save-dev
Подключаем:
const fonter = require('gulp-fonter');
Описываем таск для конвертации:
function otf2ttf(){
return gulp.src(path.src.font[0].slice(0, -6) + "src/*")
.pipe(fonter({
formats: ['ttf']
}))
.pipe(gulp.dest(path.src.font[0].slice(0, -6) + "src"));
}
Вносим изменения в значение fontsConvert:
const fontsConvert = gulp.series(otf2ttf, ttf2woff2Converter, ttf2woffConverter);
Таким образом все шрифты в формате otf и ttf преобразуются в нужные форматы. Далее создадим таск, который скопирует эти шрифты в папку dist:
function font() {
return gulp.src(path.src.font)
.pipe(gulp.dest(path.dist.font))
.on('end', browserSync.reload);
};
Отредактируем таск по умолчанию:
exports.default = gulp.series(
gulp.parallel(njk, scss, script, image, font),
gulp.parallel(browsersync, watch)
);
Настроем отслеживание за файлами в папке со шрифтами:
function watch(){
gulp.watch(path.watch.html, njk);
gulp.watch(path.watch.style, scss);
gulp.watch(path.watch.script, script);
gulp.watch(path.watch.image, image);
gulp.watch(path.watch.font, font);
}
Таким образом, при изменении файлов в каталоге src/assets/fonts (либо вручную, либо в результате конвертации), запускается таск font, который скопирует шрифты в папку dist/assets/fonts.
Gulp clean. Очистка папки dist
Создадим простой таск, который очищает папку dist. Запускать мы его будем каждый раз при запуске нашей сборки. Для этого подключим npm плагин del:
npm i del --save-dev
Подключаем его:
const del = require('del');
Создаем таск clean:
function clean(){
return del([path.dist.distPath]);
}
В дефолтном таске вызываем очистку перед всеми остальными задачами:
exports.default = gulp.series(
gulp.parallel(clean),
gulp.parallel(njk, scss, script, image, font),
gulp.parallel(browsersync, watch)
);
Результат
На этом пока все. Мы разобрали основы работы с Gulp 4, рассмотрели примеры использования, создали свою сборку для верстки сайта. В дальнейших статьях мы будем ее дополнять и модифицировать. Посмотреть и скачать исходники сборки можно с репозитория.