
Хочу поделиться историей моего знакомства с gulp и как я решал некоторые проблемы при разработке. Материал ориентирован на тех, кто знаком с nodejs и только начинает знакомиться с gulp, а также на тех, кто ищет решение схожей проблемы. Как следует из названия, статья состоит из трех глав.
В самом начале
Мое знакомство с gulp началось два месяца назад, когда, будучи некоторое время безработным, я начал подумывать устроиться в офис. Помониторив вакансии, я решил переквалифицироваться из php девелопера в frontend — благо опыт и знания позволяли это сделать быстро. И вот, спустя некоторое время, не без усилий, меня взяли на испытательный срок. Я смутно представляю, как мне удалось это сделать, но, придя в первый день на работу, я исписал страницу блокнота с двух сторон терминами, которые я слышал впервые… В тот день я понял, что затерялся в веке веб-разработчиков.
Вступление
Я расскажу про три мои проблемы в процессе знакомства с gulp:
- Как собирать compressed (production) и uncompressed версии проекта без особых усилий?
- Как заставить браузер автоматически перезагружать проект при внесении изменений?
- Как перехватывать ошибки в коде, чтобы watch таски не вылетали, если в коде была допущена ошибка?
Для наглядности я сделал небольшой проект. Посмотреть можно по ссылке. Скачать со всеми вариациями gulpfile.js из текущей статьи можно архивом по ссылке.
Структура проекта:
gulpfile.habrahabr.webulla.ru/
- assets/
- - core/
- - - components/
- - - - woman.js
- - - application.js
- web/
- - assets/
- - index.html
- gulpfile.js
- package.json
Работающий gulpfile.js, который я буду дополнять разобранными в статье решениями (в архиве — gulpfile-0-original.js):
'use strict';
// подключаем компоненты gulp
var gulp = require('gulp');
var browserify = require('gulp-browserify');
// настройки путей к файлам
var rootDir = '.';
var sourceDir = rootDir + '/assets'; // здесь хранятся все исходники
var destDir = rootDir + '/web/assets'; // здесь хранится все на выходе
// блок с настройками компонентов
// здесь я храню настройки для задач
// удалил отсюда все кроме scripts для наглядности
var components = {
scripts: {
source: sourceDir + '/core/application.js',
dest: destDir,
watch: sourceDir + '/core/**/*.js',
options: {
paths: ['./node_modules', sourceDir],
debug: false,
fullPaths: true
}
}
};
// задача для компиляции скриптов
gulp.task('scripts', function () {
gulp.src(components.scripts.source)
.pipe(browserify(components.scripts.options))
.pipe(gulp.dest(components.scripts.dest));
});
// задача для слежения за изменениями в скриптах
gulp.task('watch:scripts', ['scripts'], function () {
// если отслеживаемые файлы изменились, запускаем задачу компиляции скриптов
gulp.watch(components.scripts.watch, ['scripts']);
});
gulp.task('default', ['scripts']);
gulp.task('watch', ['watch:scripts']);
Сборка проекта из консоли:
gulp
Запуск задачи для слежения за изменениями в файлах:
gulp watch
Глава 1 — Сборка compressed (production) и uncompressed версии проекта
Проблема
Чтобы уменьшить размер скомпилированного application.js я использую пакет gulp-uglify. Проблема в том, что искать косяки и дебажить код мне удобнее в не сжатом коде (без применения gulp-uglify). В общем, как сделать так, чтобы без правок в gulpfile.js можно было собирать как uncompressed версию проекта для отладки, так и compressed версию для продакшена?
Решение
Я не помню, где подсмотрел это решение, но оно мне понравилось и хочу поделиться с вами. Оно заключается в том, чтобы при запуске gulp из консоли, передавать определенный флаг:
# сборка uncompressed версии
gulp
# сборка compressed версии
gulp --production
Для такой реализации я воспользовался:
- пакетом yargs для доступа к аргументам команды;
- пакетом gulp-uglify для сжатия кода проекта;
- пакетом gulp-if, чтобы запускать gulp-uglify только когда это нужно.
Сначала поставил все необходимые пакеты:
npm install --save-dev yargs gulp-uglify gulp-if
Подключил пакеты в gulpfile.js:
var argv = require('yargs').argv;
var gulpif = require('gulp-if');
var uglify = require('gulp-uglify');
Добавил pipe в задачу scripts:
gulp.src(components.scripts.source)
.pipe(browserify(components.scripts.options))
.pipe(gulpif(argv.production, uglify())) // <- добавляем вот эту строчку
.pipe(gulp.dest(components.scripts.dest));
Добавление этой строчки эквивалентно следующему коду:
var src = gulp.src(components.scripts.source)
.pipe(browserify(components.scripts.options));
// проверяем, передан ли флаг production
if(argv.production) {
src.pipe(uglify());
}
src.pipe(gulp.dest(components.scripts.dest));
Пояснение: в случае, когда argv.production == true, будет применен uglify.
Теперь сборку uncompressed версии проекта выполняю командой:
gulp
А сборку compressed версии:
gulp --production
Условие if(argv.production) {...} я использую и в других местах, например, при сборке стилей для продакшена.
Результат
Дополненный решением из этой главы gulpfile.js лежит в архиве и называется gulpfile-1-production.js.
Глава 2 — Автоматическая перезагрузка вкладки с проектом в браузере после изменений
Проблема
Каждый раз, после внесения изменений в файлы и при запущенном gulp watch проект заново собирается, но страница с проектом не перезагружается. Мне нужно переключиться на chrome и обновить вкладку проекта. Удобно сделать так, когда в файлы вносятся правки, а на другом экране окно браузера с проектом автоматически перезагружается с новым кодом.
Решение
Эту проблему я решил с помощью пакета gulp-livereload и расширения livereload для chrome. Это расширение доступно и для других браузеров: http://livereload.com/.
Установил необходимый пакет:
npm install --save-dev gulp-livereload
Подключил пакет:
var livereload = require('gulp-livereload');
Добавил команду запуска сервера в задачу watch:scripts:
// запускаем сервер
livereload.listen();
Добавил команду перезагрузки сервера в задачу scripts:
gulp.src(components.scripts.source)
.pipe(browserify(components.scripts.options))
.pipe(gulpif(argv.production, uglify()))
.pipe(gulp.dest(components.scripts.dest))
.pipe(livereload()); // <- добавляем вот эту строчку
Запустил gulp watch:
gulp watch
Установил расширение chrome livereload. Скажем, папка web моего проекта доступна по адресу gulpfile.habrahabr.ru.local. Я открываю его в браузере, клацаю на кнопку Enable LiveReload в баре и готово! При каждом сохранении каких-либо файлов, отслеживаемых задачей watch, страница браузера автоматически перезагружается.
Результат
Дополненный gulpfile.js в архиве — gulpfile-2-livereload.js.
Глава 3 — Перехват ошибок допущенных в проекте при разработке
Проблема
Если я допускал ошибку в скриптах проекта, то работающая задача gulp watch останавливалась с ошибкой при компиляции. Хотелось чтобы такого не происходило и gulp watch продолжал работать.
Решение
Для себя я решил пррблему так: создал отдельную функцию для перехвата ошибок с логгированием в консоль.
/**
* Обработчик ошибок.
* @param e
*/
var error = function (e) {
console.error('Error in plugin "' + e.plugin + '"');
console.error(' "' + e.message + '"');
console.error(' In file "' + e.fileName + '", line "' + e.lineNumber + '".');
console.log('--------------------------------------');
console.log(e);
};
Добавил обработку события в задачу gulp scripts:
gulp.src(components.scripts.source)
.pipe(browserify(components.scripts.options).on('error', error)) // <- добавил .on('error', error) на этой строчке
.pipe(gulpif(argv.production, uglify()))
.pipe(gulp.dest(components.scripts.dest))
.pipe(livereload());
Теперь, даже если я допускаю ошибку в коде, то я вижу уведомление в консоли и мне не нужно заново запускать gulp watch.
Результат
Дополненный gulpfile.js в архиве — gulpfile-3-error.js.
Заключение
В этой статье я не хотел пересказывать документацию или рассказать что-то инновационное, а поделился своим опытом работы с gulp и важными для себя выводами. Все документации доступны по указанным в статье ссылкам.
Также хочется услышать мнение опытных и знающих людей как по поводу технической части, так и по поводу текста: понятен ли материал, может где-то стоит по-другому сказать или что-то еще. Я бы хотел научиться доносить свою мысль до людей :) Спасибо за внимание!
Посмотреть пример.
Скачать пример архивом.
Дополнения к статье
Обновление от 06.11.2015 в 12:22
Для обработки ошибок есть gulp-plumberagatische