Gulp: как я проект для production собирал, livereload запускал и перехват ошибок делал

от автора

Хочу поделиться историей моего знакомства с gulp и как я решал некоторые проблемы при разработке. Материал ориентирован на тех, кто знаком с nodejs и только начинает знакомиться с gulp, а также ищущих решение схожей проблемы. Как следует из названия, статья состоит из трех глав.

В самом начале

Мое знакомство с gulp началось два месяца назад, когда, будучи безработным, я начал подумывать устроиться в офис. Помониторив вакансии, я решил переквалифицироваться из php девелопера в frontend — благо опыт и знания позволяли это сделать быстро. И вот, спустя некоторое время, не без усилий, меня взяли на испытательный срок. Я смутно представляю как мне удалось это сделать, но, придя в первый день на работу, я исписал страницу блокнота с двух сторон терминами, которые я слышал впервые… В тот день я понял, что затерялся в веке веб-разработчиков 🙁

Вступление

Я расскажу про три мои проблемы в процессе знакомства с gulp:

  1. Как собирать compressed (production) и uncompressed версии проекта без особых усилий?
  2. Как заставить браузер автоматически перезагружать проект при внесении изменений?
  3. Как перехватывать ошибки в коде, чтобы 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 и важными для себя выводами. Все документации доступны по указанным в статье ссылкам.

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

Посмотреть пример.
Скачать пример архивом.

ссылка на оригинал статьи http://habrahabr.ru/post/269673/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *