Запобігайте помилкам зриву / збою годин із глоткою


178

Я запускаю 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.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)

3
дивіться офіційні рецепти gulp на веб- сайті github.com/gulpjs/gulp/tree/master/docs/recipes, у яких є рецепт ... поєднання помилок-потоків для обробки помилок за допомогою stream-combiner2 - це офіційна відповідь!
понеділок74

Відповіді:


257

Ваша swallowErrorфункція повинна виглядати так:

function swallowError (error) {

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

  this.emit('end')
}

Я думаю, що ви повинні зв’язати цю функцію у errorвипадку падіння завдання, а не на watchзавдання, тому що тут не виникає проблема, ви повинні встановити цей зворотний виклик помилок для кожної задачі, яка може вийти з ладу, як плагіни, які ламаються, коли у вас є пропустив ;або щось інше, щоб запобігти 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'))
})

З іншого боку , якщо ви не заперечуєте , щоб включити ще один модуль, ви можете використовувати журнал функцію Ковток-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
Ви можете відредагувати свою відповідь, щоб відобразити остаточну правильну річ, щоб зробити це тим, хто знайде це в майбутньому, не повинен читати ланцюжок коментарів.
Джордж Мауер

1
Це все добре і добре, але чому мені доведеться писати власні обробники помилок? Вся причина, по якій я використовую gulp або grunt або будь-який інший інструмент попередньої обробки, полягає в тому, що це робить брудну роботу для мене. Помилка синтаксису десь у моєму коді (що, мабуть, станеться) не повинна зупиняти всю систему. Порівняйте це з графічним інтерфейсом Prepros (іншого препроцесора) - цей інструмент точно повідомляє, де ваша помилка, і не зависає та не закривається, коли щось не так.
Кокодоко

1
дивно, що ніхто в цілому навіть не згадував паровий комбайн2, хоча це офіційний рецепт ковтну! сантехнік також хороший, хоча я завжди вважаю за краще керуватися рецептами, котрий рецепти gulp постійно оновлюються за допомогою gulp, і їх можна переглянути на github.com/gulpjs/gulp/tree/master/docs/recipes
понеділок74

1
Зіткнувшись із тією ж головою, я вирішив використовувати обгортку навколо, gulp.watch()яка додає .on('error', function() { this.emit('end') })результату функції годинника, оскільки саме завдання годинника я хочу зробити стійким до повішення. Працює дуже добре, а окремі завдання, які не вдається, ще надрукують власні повідомлення про помилки. Дивіться код: github.com/specious/specious.github.io/commit/f8571d28
tknomad

20

Наведені вище приклади не працювали для мене. Однак зробили наступне:

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']);
});

Це чудово, але також було б добре повідомити, якщо виникла помилка (наразі ця помилка записується в термінал)
raison

4

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

(наприклад: * .coffee)

Якщо ви хочете працювати лише з одним форматом файлів, то gulp-plumberце ваше рішення.

Наприклад, помилкові помилки та попередження про кофескрипт:

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/isissue/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;

});

PS:

Тут використовуються модулі та функції вузлів:

// 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');
};

Я все ще бачу вдосконалення для цього коментаря. Як порівняння швидкості та посилання лише на .js файли (за винятком мінімізованих або 3d-партійних бібліотек, або libs з bower_components). Але в основному легко налаштувати та вирішити це нюхання Google.com
Роман М. Косс

3

Мені подобається використовувати сантехніка з глотком, оскільки це може додати глобального слухача до завдання та відобразити змістовне повідомлення.

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

gulp.task('compile-scss', function () {
    gulp.src('scss/main.scss')
        .pipe(plumber())
        .pipe(sass())
        .pipe(autoprefixer())
        .pipe(cssnano())
        .pipe(gulp.dest('css/'));
});

Довідка: https://scotch.io/tutorials/prevent-errors-from-crashing-gulp-watch


2

Я реалізував такий хак як вирішення для https://github.com/gulpjs/gulp/isissue/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.


2

Просте рішення цього - поставити gulp watchнескінченну петлю в оболонці Bash (або sh).

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

Під час редагування JavaScript зберігайте висновок цієї команди на видимій частині екрана. Коли ваші зміни призведуть до помилки, Gulp завершиться збоєм, надрукує свій слід стека, зачекає секунду та відновить перегляд вихідних файлів. Потім ви можете виправити синтаксичну помилку, і Gulp вкаже, чи вдалось змінити редагування, або роздрукувавши це нормальний вихід, або перервавшись (потім відновившись) знову.

Це буде працювати в Linux або Mac терміналі. Якщо ви використовуєте Windows, використовуйте Cygwin або Ubuntu Bash (Windows 10).


Яка мова це? Також чи є користь від цього щодо запропонованих рішень?
Джордж Мауер

Це написано на Bash / sh. Він вимагає менше коду, ніж інші рішення, і його легше запам'ятати та реалізувати.
Джессі Хоган

Чи можете ви відредагувати той факт, що його бажання та інші ваші думки щодо цього, у свою відповідь? Я не погоджуюся, що його простіше, ніж сантехнік, але його дійсний (якщо не міжплановий) підхід. Спочатку я проголосував, бо не було зрозуміло навіть на якій мові мова йде, і я не можу змінити свій голос, якщо ви не редагуєте відповідь.
Джордж Мауер

1
Отже, ви віддаєте перевагу руйнуванню потоку та перезапуску всього процесу, який може зайняти певну кількість залежно від того, що ви робите з нескінченним циклом, а не просто вловлювати помилку? Здається, це мене трохи заважає. А якщо говорити про менший код, то для цього потрібно 16 символів, щоб додати завдання сантехніку, тоді як ваше рішення займає 36, не рахуючи gulp watch.
Бальтазар

Дякую за відгук, @GeorgeMauer, я вносив зміни та писав про середовища / платформи, в яких працює.
Джессі Хоган

1

Машинопис

Це те, що працювало для мене. Я працюю з 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');повністю працює.

Сподіваюся, що це допоможе. Щасти.


1

Це працювало для мене ->

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 (console)), але мені довелося запустити команду gulp як root. Я запускаю вузол gulp в додатку php, тому у мене є кілька облікових записів на одному сервері, тому я зіткнувся з проблемою розриву gulp при помилках синтаксису, тому що я не запускав gulp як root ... Можливо, сантехнік і деякі з інші відповіді тут працювали б для мене, якби я працював як root. Заслуга Кодексу Accio https://www.youtube.com/watch?v=iMR7hq4ABНа відповідь. Він сказав, що, обробляючи помилку, це допомагає вам визначити, на якій лінії знаходиться помилка і яка вона знаходиться в консолі, а також зупиняє, коли глотка не порушується на синтаксичній помилці. Він сказав, що це щось на зразок легкої ваги, тож не впевнений, чи спрацює це те, що ви шукаєте. Хоча швидке виправлення, варто зняти. Сподіваюся, це комусь допоможе!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.