Ngăn chặn lỗi phá vỡ / sụp đổ đồng hồ gulp


178

Tôi đang chạy gulp 3.6.2 và có tác vụ sau được thiết lập từ một mẫu trực tuyến

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

Bất cứ khi nào có lỗi trong đồng hồ gulp CoffeeScript của tôi dừng lại - rõ ràng không phải là điều tôi muốn.

Theo khuyến cáo ở nơi khác, tôi đã thử nó

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

nhưng nó dường như không hoạt động.

Tôi đang làm gì sai?


Để đáp lại câu trả lời của @ Aperçu, tôi đã sửa đổi swallowErrorphương pháp của mình và thay vào đó đã thử cách sau:

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

Khởi động lại, và sau đó tạo ra một lỗi cú pháp trong tệp cà phê của tôi. Cùng một vấn đề:

[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
xem các công thức nấu ăn chính thức tại github.com/gulpjs/gulp/tree/master/docs/recipes có công thức để ... kết hợp các luồng-xử lý-lỗi bằng cách sử dụng stream-combiner2 đây là câu trả lời chính thức!
danday74

Câu trả lời:


257

swallowErrorChức năng của bạn sẽ trông như thế này:

function swallowError (error) {

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

  this.emit('end')
}

Tôi nghĩ rằng bạn phải liên kết chức năng này trong errortrường hợp nhiệm vụ bị rơi chứ không phải watchnhiệm vụ, vì đó không phải là vấn đề xảy ra, bạn nên đặt lại cuộc gọi lại lỗi này cho mỗi tác vụ có thể bị lỗi, như các plugin bị hỏng khi bạn có bỏ lỡ một ;hoặc một cái gì đó khác, để ngăn chặn watchnhiệm vụ dừng lại.

Ví dụ:

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

Cách khác, nếu bạn không bao gồm một mô-đun khác, bạn có thể sử dụng chức năng nhật ký của gulp-produc để ngăn bạn khai báo một chức năng bổ sung trong gulpfile:

.on('error', gutil.log)

Nhưng tôi có thể khuyên bạn nên xem qua plugin gulp-plumber tuyệt vời , được sử dụng để loại bỏ onerrortrình xử lý errorsự kiện, gây ra sự gián đoạn của các luồng. Nó rất đơn giản để sử dụng và nó ngăn bạn bắt tất cả các nhiệm vụ có thể thất bại.

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

Thông tin thêm về điều này trên bài viết này bởi người tạo ra các plugin có liên quan.


Tôi đánh giá cao sự giúp đỡ của bạn. Xem chỉnh sửa của tôi. Tôi nghĩ rằng tôi đang làm những gì bạn đang nói và nó vẫn không hoạt động
George Mauer

2
Bạn có thể muốn chỉnh sửa câu trả lời của mình để phản ánh điều chính xác cuối cùng cần làm để bất kỳ ai tìm thấy điều này trong tương lai không phải đọc chuỗi nhận xét.
George Mauer

1
Đây là tất cả tốt và tốt, nhưng tại sao tôi phải viết trình xử lý lỗi của riêng tôi? Toàn bộ lý do tôi sử dụng gulp hoặc grunt hoặc bất kỳ công cụ tiền xử lý nào, là nó làm công việc bẩn thỉu đối với tôi. Một lỗi cú pháp ở đâu đó trong mã của tôi (điều này chắc chắn sẽ xảy ra) không nên dừng toàn bộ hệ thống. So sánh điều này với GUI của Prepros (một bộ tiền xử lý khác) - công cụ này cho bạn biết chính xác lỗi của bạn ở đâu và không treo hoặc thoát khi có lỗi.
Kokodoko 20/03/2015

1
thật đáng kinh ngạc khi không ai trong suốt thậm chí đã đề cập đến steam-combiner2 mặc dù đây là công thức chính thức! Thợ sửa ống nước cũng tốt nhưng tôi luôn thích làm theo công thức gulp, công thức gulp được cập nhật bởi gulp và có thể được xem tại github.com/gulpjs/gulp/tree/master/docs/recipes
danday74

1
Đối mặt với câu hỏi hóc búa tương tự, tôi quyết định sử dụng một lớp bọc xung quanh gulp.watch()có thêm .on('error', function() { this.emit('end') })kết quả của chức năng đồng hồ, vì đó cụ thể là nhiệm vụ đồng hồ mà tôi muốn làm cho kiên cường để treo lên. Hoạt động thực sự tốt và các tác vụ riêng lẻ không in được thông báo lỗi của riêng chúng. Xem mã: github.com/specious/specious.github.io/commit/f8571d28
tknomad

20

Các ví dụ trên không làm việc cho tôi. Sau đây đã làm:

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

Điều này thật tuyệt, nhưng cũng sẽ rất tốt để thông báo nếu có lỗi (hiện tại đây chỉ là lỗi ghi nhật ký trong thiết bị đầu cuối)
raison

4

Với một định dạng của tập tin

(ví dụ: * .coffee chỉ)

Nếu bạn chỉ muốn làm việc với một định dạng tệp, thì đó gulp-plumberlà giải pháp của bạn.

Ví dụ: các lỗi được xử lý phong phú và cảnh báo cho việc ghi lại:

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

Với nhiều loại định dạng tệp

(ví dụ: * .coffee và * .js cùng một lúc)

Nhưng nếu bạn sẽ không làm việc với nhiều loại định dạng tệp (ví dụ: *.js*.coffee), thì tôi sẽ đăng giải pháp của mình.

Tôi sẽ chỉ đăng một mã tự giải thích ở đây, với một số mô tả trước đây.

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

Tôi đã đối mặt với vấn đề với gulp-plumbergulp-ifsử dụnggulp.watch(...

Xem vấn đề liên quan tại đây: https://github.com/floatdrop/gulp-plumber/issues/23

Vì vậy, lựa chọn tốt nhất cho tôi là:

  • Mỗi phần như tập tin, và nối sau . Tạo nhiều tác vụ có thể xử lý từng phần trong tệp riêng biệt (như grunt không) và ghép chúng lại
  • Mỗi phần như luồng và hợp nhất luồng sau . Hợp nhất hai luồng sử dụng merge-stream(được tạo từ event-stream) thành một và tiếp tục công việc (tôi đã thử nó trước và nó hoạt động tốt với tôi, vì vậy nó là giải pháp nhanh hơn so với trước đó)

Mỗi phần dưới dạng luồng và hợp nhất các luồng sau

Cô ấy là phần chính trong mã của tôi:

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

Mỗi phần dưới dạng tệp và nối sau

Nếu để tách phần này thành các phần, thì trong mỗi phần sẽ có một tệp kết quả được tạo. Ví dụ:

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;

});

Tái bút

Ở đây các mô-đun nút và các chức năng đã được sử dụng:

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

Tôi vẫn thấy những cải tiến cho ý kiến ​​này. Giống như so sánh tốc độ và chỉ liên kết cho các tệp .js (không bao gồm các thư viện bên được thu nhỏ hoặc 3d hoặc lib từ bower_components). Nhưng về cơ bản, thật dễ dàng để điều chỉnh và giải quyết vấn đề đánh hơi này bằng Google.com
Roman M. Koss

3

Tôi thích sử dụng thợ sửa ống nước vì nó có thể thêm một người nghe toàn cầu vào một nhiệm vụ và có một thông điệp có ý nghĩa được hiển thị.

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

Tham khảo: https://scotch.io/tutorials/prevent-errors-from-crashing-gulp-watch


2

Tôi đã triển khai bản hack sau đây như một cách giải quyết cho 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;
}

Thêm nó vào gulpfile.js của bạn và sử dụng nó như thế:

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

Điều này cảm thấy như xử lý lỗi tự nhiên nhất đối với tôi. Nếu không có xử lý lỗi nào cả, nó sẽ đưa ra lỗi. Đã thử nghiệm với Node v0.11.13.


2

Một giải pháp đơn giản cho vấn đề này là đặt gulp watchmột vòng lặp vô hạn trong lớp vỏ Bash (hoặc sh).

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

Giữ đầu ra của lệnh này trong vùng hiển thị trên màn hình của bạn khi bạn chỉnh sửa JavaScript. Khi các chỉnh sửa của bạn dẫn đến lỗi, Gulp sẽ gặp sự cố, in dấu vết ngăn xếp của nó, đợi một giây và tiếp tục xem các tệp nguồn của bạn. Sau đó, bạn có thể sửa lỗi cú pháp và Gulp sẽ cho biết liệu chỉnh sửa có thành công hay không bằng cách in ra đầu ra bình thường hoặc bị lỗi (sau đó tiếp tục lại).

Điều này sẽ làm việc trong một thiết bị đầu cuối Linux hoặc Mac. Nếu bạn đang sử dụng Windows, hãy sử dụng Cygwin hoặc Ubuntu Bash (Windows 10).


Ngôn ngữ này là gì? Ngoài ra, có bất kỳ lợi ích cho điều này trên các giải pháp được đề xuất?
George Mauer

Nó được viết bằng Bash / sh. Nó đòi hỏi ít mã hơn các giải pháp khác và dễ nhớ và dễ thực hiện hơn.
Jesse Hogan

Bạn có thể chỉnh sửa sự thật rằng bash của nó và những suy nghĩ khác của bạn về điều này thành câu trả lời của bạn không? Tôi không đồng ý rằng nó dễ hơn thợ sửa ống nước, nhưng đó là một cách tiếp cận hợp lệ (nếu không phải là đa nền tảng). Tôi đã bỏ phiếu ban đầu vì không rõ ngôn ngữ đó là gì và tôi không thể thay đổi phiếu bầu của mình trừ khi bạn chỉnh sửa câu trả lời.
George Mauer

1
Vì vậy, bạn thích phá vỡ luồng và khởi động lại toàn bộ quá trình có thể mất khá nhiều tùy thuộc vào những gì bạn đang làm với một vòng lặp vô hạn thay vì chỉ đơn giản là bắt lỗi? Có vẻ hơi phiền với tôi. Và nói về ít mã hơn, nó yêu cầu bạn 16 ký tự để thêm thợ sửa ống nước vào nhiệm vụ của bạn trong khi giải pháp của bạn mất 36 mà không tính gulp watch.
Balthazar

Cảm ơn phản hồi, @GeorgeMauer, tôi đã thực hiện các chỉnh sửa và viết về môi trường / nền tảng mà nó hoạt động.
Jesse Hogan

1

Bản đánh máy

Đây là những gì làm việc cho tôi. Tôi làm việc với Typescriptvà tách chức năng (để nhầm lẫn với thistừ khóa) để xử lý less. Điều này làm việc với Javascriptlà tốt.

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

Bây giờ, khi bạn gửi watch .lesstệp và errorxảy ra, watchsẽ không dừng lại và những thay đổi mới sẽ được xử lý theo của bạn less task.

LƯU Ý : Tôi đã thử với l.end();; Tuy nhiên, nó đã không hoạt động. Tuy nhiên, l.emit('end');hoàn toàn hoạt động.

Hy vọng điều này giúp đỡ. Chúc may mắn.


1

Điều này làm việc cho tôi ->

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

Tôi vừa thêm dòng .on ('error', console.error.bind (console)), nhưng tôi phải chạy lệnh gulp với quyền root. Tôi đang chạy nút gulp trên một ứng dụng php vì vậy tôi có nhiều tài khoản trên một máy chủ, đó là lý do tại sao tôi gặp phải vấn đề về lỗi gulp do lỗi cú pháp vì tôi không chạy gulp với quyền root ... Có thể là thợ sửa ống nước và một số câu trả lời khác ở đây sẽ có tác dụng với tôi nếu tôi chạy bằng root. Tín dụng vào mã Accio https://www.youtube.com/watch?v=iMR7hq4ABOw cho câu trả lời. Ông nói rằng bằng cách xử lý lỗi, nó giúp bạn xác định lỗi nào đang xảy ra và lỗi gì trong bảng điều khiển, nhưng cũng ngăn chặn được lỗi do lỗi cú pháp. Ông nói rằng đó là một loại sửa chữa trọng lượng nhẹ, vì vậy không chắc chắn nếu nó sẽ làm việc cho những gì bạn đang tìm kiếm. Sửa chữa nhanh chóng, giá trị một shot. Hy vọng điều này sẽ giúp được ai đó!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.