Предотвращение ошибок при сбоях/сбоях gulp

Я запускаю gulp 3.6.2 и имею следующую задачу, которая была создана из примера онлайн

gulp.task('watch', ['default'], function () {
  gulp.watch([
    'views/**/*.html',        
    'public/**/*.js',
    'public/**/*.css'        
  ], function (event) {
    return gulp.src(event.path)
      .pipe(refresh(lrserver));
  });

  gulp.watch(['./app/**/*.coffee'],['scripts']);
  gulp.watch('./app/**/*.scss',['scss']);
});

Всякий раз, когда в моей программе CoffeeScript gulp появляется ошибка, - очевидно, не то, что я хочу.

Как рекомендовано в других местах, я пробовал это

gulp.watch(['./app/**/*.coffee'],['scripts']).on('error', swallowError);
gulp.watch('./app/**/*.scss',['scss']).on('error', swallowError);
function swallowError (error) { error.end(); }

но он не работает.

Что я делаю неправильно?


В ответ на ответ @Aperçu я изменил свой метод swallowError и попробовал следующее:

gulp.task('scripts', function () {
  gulp.src('./app/script/*.coffee')
    .pipe(coffee({ bare: true }))
    .pipe(gulp.dest('./public/js'))
    .on('error', swallowError);
});

Перезагрузился, а затем создал синтаксическую ошибку в файле кофе. Тот же вопрос:

[gulp] Finished 'scripts' after 306 μs

stream.js:94
      throw er; // Unhandled stream error in pipe.
            ^
Error: W:\bariokart\app\script\trishell.coffee:5:1: error: unexpected *
*
^
  at Stream.modifyFile (W:\bariokart\node_modules\gulp-coffee\index.js:37:33)
  at Stream.stream.write (W:\bariokart\node_modules\gulp-coffee\node_modules\event-stream\node_modules\through\index.js:26:11)
  at Stream.ondata (stream.js:51:26)
  at Stream.EventEmitter.emit (events.js:95:17)
  at queueData (W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\node_modules\map-stream\index.js:43:21)
  at next (W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\node_modules\map-stream\index.js:71:7)
  at W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\node_modules\map-stream\index.js:85:7
  at W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\lib\src\bufferFile.js:8:5
  at fs.js:266:14
  at W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\node_modules\graceful-fs\graceful-fs.js:104:5
  at Object.oncomplete (fs.js:107:15)

Ответ 1

Ваша функция swallowError должна выглядеть так:

function swallowError (error) {

  // If you want details of the error in the console
  console.log(error.toString())

  this.emit('end')
}

Я думаю, вам нужно привязать эту функцию к событию error для задачи, которая была падающей, а не к задаче watch, потому что в этом случае не возникает проблема, вы должны установить этот обратный вызов ошибки для каждой задачи, которая может fail, как плагины, которые ломаются, когда вы пропустили ; или что-то еще, чтобы предотвратить остановку задачи watch.

Примеры:

gulp.task('all', function () {
  gulp.src('./app/script/*.coffee')
    .pipe(coffee({ bare: true }))
    .on('error', swallowError)
    .pipe(gulp.dest('./public/js'))

  gulp.src('css/*.scss')
    .pipe(sass({ compass: true }))
    .on('error', swallowError)
    .pipe(cssmin())
    .pipe(gulp.dest('dist'))
})

В качестве альтернативы, если вы не хотите включать другой модуль, вы можете использовать функцию log gulp-util, чтобы вы не объявили дополнительную функцию в gulpfile:

.on('error', gutil.log)

Но я могу порекомендовать взглянуть на удивительный плагин gulp-plumber, который используется для удаления onerror обработчика события error, вызывающего разрывы потоков. Он очень прост в использовании и не позволяет вам уловить все задачи, которые могут потерпеть неудачу.

gulp.src('./app/script/*.coffee')
  .pipe(plumber())
  .pipe(coffee({ bare: true }))
  .pipe(gulp.dest('./public/js'))

Подробнее об этом на в этой статье создатель соответствующего плагина.

Ответ 2

Вышеприведенные примеры не помогли мне. Однако следующее:

var plumber = require('gulp-plumber');
var liveReload = require('gulp-livereload');
var gutil = require('gulp-util');
var plumber = require('gulp-plumber');
var compass = require('gulp-compass');
var rename = require('gulp-rename');
var minifycss = require('gulp-minify-css');
var notify = require('gulp-notify');

gulp.task('styles', function () {
    //only process main.scss which imports all other required styles - including vendor files.
    return gulp.src('./assets/scss/main.scss')
            .pipe(plumber(function (error) {
                gutil.log(error.message);
                this.emit('end');
            }))
            .pipe(compass({
                config_file: './config.rb',
                css: './css'
                , sass: './assets/scss'
            }))
            //minify files
            .pipe(rename({suffix: '.min'}))
            .pipe(minifycss())

            //output
            .pipe(gulp.dest('./css'))
            .pipe(notify({message: 'Styles task complete'}));
});

gulp.task('watch', function () {
    liveReload.listen();
    gulp.watch('assets/scss/**/*.scss', ['styles']);
});

Ответ 3

С одним форматом файлов

(только: *. coffee)

Если вы хотите работать только с одним форматом файлов, тогда gulp-plumber - ваше решение.

Например, обработанные ошибки и предупреждения для coffeescripting:

gulp.task('scripts', function() {
  return gulp.src(['assets/scripts/**/*.coffee'])
    .pipe(plumber())
    .pipe(coffeelint())
    .pipe(coffeelint.reporter())
    .pipe(lintThreshold(10, 0, lintThresholdHandler))
    .pipe(coffee({
      bare: true
    }))
    .on('error', swallowError)
    .pipe(concat('application.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

С несколькими типами форматов файлов

(например: *. coffee и *.js в то же время)

Но если вы не будете работать с несколькими типами форматов файлов (например: *.js и *.coffee), то я опубликую свое решение.

Я просто опубликую сам объяснительный код здесь, с некоторым описанием раньше.

gulp.task('scripts', function() {
  // plumber don't fetch errors inside gulpif(.., coffee(...)) while in watch process
  return gulp.src(['assets/scripts/**/*.js', 'assets/scripts/**/*.coffee'])
    .pipe(plumber())
    .pipe(gulpif(/[.]coffee$/, coffeelint()))
    .pipe(coffeelint.reporter())
    .pipe(lintThreshold(10, 0, lintThresholdHandler))
    .pipe(gulpif(/[.]coffee$/, coffee({ // if some error occurs on this step, plumber won't catch it
      bare: true
    })))
    .on('error', swallowError)
    .pipe(concat('application.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

Я столкнулся с проблемой gulp-plumber и gulp-if с помощью gulp.watch(...

См. соответствующую проблему здесь: https://github.com/floatdrop/gulp-plumber/issues/23

Итак, лучший вариант для меня:

  • Каждая часть как файл, и конкатенация после. Создайте несколько задач, которые могут обрабатывать каждую часть в отдельном файле (например, grunt) и объединяют их
  • Каждая часть как поток и объединяет потоки после. Объедините два потока, используя merge-stream (который был сделан из event-stream) в один и продолжите задание (я попробовал это во-первых, и он отлично работает для меня, поэтому он быстрее, чем предыдущий)

Каждая часть как поток и объединять потоки после

Она является основной частью моего кода:

gulp.task('scripts', function() {
  coffeed = gulp.src(['assets/scripts/**/*.coffee'])
    .pipe(plumber())
    .pipe(coffeelint())
    .pipe(coffeelint.reporter())
    .pipe(lintThreshold(10, 0, lintThresholdHandler))
    .pipe(coffee({
      bare: true
    }))
    .on('error', swallowError);

  jsfiles = gulp.src(['assets/scripts/**/*.js']);

  return merge([jsfiles, coffeed])
    .pipe(concat('application.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

Каждая часть в виде файла и конкатенация после

Если разделить это на части, то в каждой части должен быть создан файл результата. Например:

gulp.task('scripts-coffee', function() {

  return gulp.src(['assets/scripts/**/*.coffee'])
    .pipe(plumber())
    .pipe(coffeelint())
    .pipe(coffeelint.reporter())
    .pipe(lintThreshold(10, 0, lintThresholdHandler))
    .pipe(coffee({
      bare: true
    }))
    .on('error', swallowError)
    .pipe(concat('application-coffee.js'))
    .pipe(gulp.dest('dist/scripts'));

});

gulp.task('scripts-js', function() {

  return gulp.src(['assets/scripts/**/*.js'])
    .pipe(concat('application-coffee.js'))
    .pipe(gulp.dest('dist/scripts'));

});

gulp.task('scripts', ['scripts-js', 'scripts-coffee'], function() {

  var re = gulp.src([
    'dist/scripts/application-js.js', 'dist/scripts/application-coffee.js'
  ])
    .pipe(concat('application.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe(notify({ message: 'Scripts task complete' }));

  del(['dist/scripts/application-js.js', 'dist/scripts/application-coffee.js']);

  return re;

});

P.S:.

Здесь node модули и функции, которые были использованы:

// Load plugins
var gulp = require('gulp'),
    uglify = require('gulp-uglify'),
    rename = require('gulp-rename'),
    concat = require('gulp-concat'),
    notify = require('gulp-notify'),
    plumber = require('gulp-plumber'),
    merge = require('ordered-merge-stream'),
    replace = require('gulp-replace'),
    del = require('del'),
    gulpif = require('gulp-if'),
    gulputil = require('gulp-util'),
    coffee = require('gulp-coffee'),
    coffeelint = require('gulp-coffeelint),
    lintThreshold = require('gulp-coffeelint-threshold');

var lintThresholdHandler = function(numberOfWarnings, numberOfErrors) {
  var msg;
  gulputil.beep();
  msg = 'CoffeeLint failure; see above. Warning count: ';
  msg += numberOfWarnings;
  msg += '. Error count: ' + numberOfErrors + '.';
  gulputil.log(msg);
};
var swallowError = function(err) {
  gulputil.log(err.toString());
  this.emit('end');
};

Ответ 4

Я применил следующий хак в качестве обходного пути для https://github.com/gulpjs/gulp/issues/71:

// Workaround for https://github.com/gulpjs/gulp/issues/71
var origSrc = gulp.src;
gulp.src = function () {
    return fixPipe(origSrc.apply(this, arguments));
};
function fixPipe(stream) {
    var origPipe = stream.pipe;
    stream.pipe = function (dest) {
        arguments[0] = dest.on('error', function (error) {
            var state = dest._readableState,
                pipesCount = state.pipesCount,
                pipes = state.pipes;
            if (pipesCount === 1) {
                pipes.emit('error', error);
            } else if (pipesCount > 1) {
                pipes.forEach(function (pipe) {
                    pipe.emit('error', error);
                });
            } else if (dest.listeners('error').length === 1) {
                throw error;
            }
        });
        return fixPipe(origPipe.apply(this, arguments));
    };
    return stream;
}

Добавьте его в свой gulpfile.js и используйте его так:

gulp.src(src)
    // ...
    .pipe(uglify({compress: {}}))
    .pipe(gulp.dest('./dist'))
    .on('error', function (error) {
        console.error('' + error);
    });

Это похоже на самую естественную обработку ошибок. Если обработчик ошибок вообще отсутствует, он выдаст ошибку. Протестировано с помощью Node v0.11.13.

Ответ 5

Typescript

Это то, что сработало для меня. Я работаю с Typescript и отделяю функцию (от аовидной путаницы с ключевым словом this) для обработки less. Это также работает с Javascript.

var gulp = require('gulp');
var less = require('gulp-less');

gulp.task('less', function() {
    // writing a function to avoid confusion of 'this'
    var l = less({});
    l.on('error', function(err) {
        // *****
        // Handle the error as you like
        // *****
        l.emit('end');
    });

    return gulp
        .src('path/to/.less')
        .pipe(l)
        .pipe(gulp.dest('path/to/css/output/dir'))
})

Теперь, когда вы watch .less файлы и error, watch не останавливается, и новые изменения будут обрабатываться в соответствии с вашим less task.

ПРИМЕЧАНИЕ: я пробовал с l.end();; однако это не сработало. Однако l.emit('end'); полностью работает.

Надеюсь на эту помощь. Удачи.

Ответ 6

Простым решением для этого является положить gulp watch в бесконечный цикл внутри оболочки Bash (или sh).

while true; do gulp; gulp watch; sleep 1; done

Сохраняйте вывод этой команды в видимой области на экране при изменении JavaScript. Когда ваши изменения приводят к ошибке, Gulp выйдет из строя, распечатает трассировку стека, подождет секунду и возобновит просмотр ваших исходных файлов. Затем вы можете исправить ошибку синтаксиса, а Gulp укажет, удавалось ли редактирование, либо распечатывая его нормальный вывод, либо снова сбой (затем возобновление).

Это будет работать на терминале Linux или Mac. Если вы используете Windows, используйте Cygwin или Ubuntu Bash (Windows 10).

Ответ 7

Это сработало для меня →

var gulp = require('gulp');
var sass = require('gulp-sass');

gulp.task('sass', function(){
    setTimeout(function(){
        return gulp.src('sass/*.sass')
        .pipe(sass({indentedSyntax: true}))
        .on('error', console.error.bind(console))
        .pipe(gulp.dest('sass'));
    }, 300);
});



gulp.task('watch', function(){
    gulp.watch('sass/*.sass', ['sass']);
});

gulp.task('default', ['sass', 'watch'])

Я только что добавил   .on('error', console.error.bind(консоль)) но я должен был запустить   gulp команда как root. Я запускаю node gulp в php-приложении, поэтому у меня есть несколько учетных записей на одном сервере, поэтому я столкнулся с проблемой gulp нарушения синтаксических ошибок, поскольку я не выполнял gulp как root... Может быть, сантехник и некоторые другие ответы здесь могли бы работать для меня, если бы я бежал как корень. Примите к сведению код Accio https://www.youtube.com/watch?v=iMR7hq4ABOw для ответа. Он сказал, что, обрабатывая ошибку, вы можете определить, в какой строке находится ошибка, и что находится в консоли, но также останавливает gulp от взлома синтаксической ошибки. Он сказал, что это было небольшое облегчение, поэтому не уверен, что он будет работать на то, что вы ищете. Быстрое исправление, хотя и стоит того. Надеюсь, это поможет кому-то!

Ответ 8

Самый простой способ while [ 1 ]; do gulp watch; sleep 0; done.