Выявление ошибок на Gulp.js

Режим просмотра важен для современных систем сборки, особенно для интерфейсной части. Gulp также имеет эту функцию, но с некоторыми оговорками, которые усложняют работу. Это потоковая система сборки, поэтому вам придется иметь дело с Steam API, где вы должны перехватывать каждую ошибку, иначе будет выброшено неперехваченное исключение, которое остановит процесс сборки.

Это особенно важно для наблюдателя, потому что демон watch живет долгое время, и это нехорошо, когда неперехваченная ошибка убивает его.

В чем дело?

Прежде всего, нам нужно выяснить, почему это происходит, почему наблюдатель иногда дает сбой и умирает. Рекомендуемый способ уведомления о произошедших ошибках в плагинах gulp - это выдача события error. Но потоки node.js, которые фактически используются в gulp, не позволяют оставлять ошибки незамеченными. Если в каком-либо потоке нет слушателей на событие `error`, в случае ошибки будет сгенерировано необработанное исключение. Это должно было быть уверенным, что сообщение об ошибке из потока дошло до пользователей. В результате при работе с gulp разработчики часто видят в консоли следующую ошибку:

events.js:72 
    throw er; // Unhandled ‘error’ event

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

Что делать?

По этому поводу ведется много дискуссий, например, о stackoverflow. Также есть проблема на Github в репозитории gulp. Предлагаются некоторые решения.

Во-первых, подпишитесь на событие ошибки и не позволяйте генерировать необработанное исключение:

gulp.task('less', function() { 
  return gulp.src('less/*.less') 
    .pipe(less().on('error', gutil.log))
    .pipe(gulp.dest('app/css'));
});

Затем вы можете использовать плагин gulp-plumber, который подавляет обработчик ошибок по умолчанию для всех последующих плагинов в цепочке pipe ().

gulp.task('less', function() {
  return gulp.src('less/*.less')
    .pipe(plumber())
    .pipe(less())
    .pipe(gulp.dest('app/css'));
});

Зачем понадобилось другое решение?

Несмотря на то, что проблема выглядит решенной, это не так. Теперь вы не будете получать никаких сообщений об ошибках при сборке на CI-сервере. Все ошибки теперь где-то фиксируются, поэтому gulp думает, что все задачи были выполнены правильно, даже если возникли некоторые ошибки. Компьютеры не могут читать и понимать вывод консоли, они используют коды выхода, чтобы сообщить результат процесса, и в этом случае код выхода равен нулю, что означает «успех». И теперь у нас есть вопрос, как вернуть наши обработчики ошибок.

Правильное получение ошибок

Фактически, gulp может получать ошибки из конвейера. Но только от последнего в цепочке, потому что потоки предназначены для того, чтобы не распространять ошибки по каналам. В репозитории Node.js есть пул-реквест с соответствующим предложением, но он еще не объединен. Итак, теперь gulp может получить только ошибку из последнего потока, и обычно это вызов gulp.dest () для записи результата задачи в файл. Но обычно ошибки возникают в других подключаемых модулях между gulp.src и dest. Глоток их не видит, но мы можем ему помочь.

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

gulp.task('less', function(done) {
  gulp.src('less/*.less')
    .pipe(less()).on('error', function(error) {
      // we have an error
      done(error); 
    })
    .pipe(gulp.dest(‘app/css’))
    .on(‘end’, function() {
      // in case of success
      done();
    });
});

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

gulp.task(‘less’, wrapPipe(function(success, error) {
  return gulp.src(‘less/*.less’)
    .pipe(less().on(‘error’, error))
    .pipe(gulp.dest(‘app/css’));
}));

Теперь мы можем спокойно относиться к нашей сборке на CI-сервере, а также наслаждаться локальной разработкой.