Gulp 目前的錯誤處理方式有點操蛋,一旦發生錯誤進程就掛了,得手動去重啟。雖然開發者預期在 gulp 4 中解決此問題 ,但 gulp 4 什么時候發布並沒有明確時間表,在此之前,還是很有必要了解一下更優雅的錯誤處理方式,除非你鍾情於反復在命令行里輸入 gulp
然后回車。
使用 Stream 事件 API 處理錯誤
Stream 發生錯誤時,會觸發 error
事件,監聽 error
事件進行錯誤處理可以避免 gulp 進程崩潰。
基本錯誤處理
下面的例子中,添加了 Less 編譯的錯誤處理,Less 發生編譯錯誤時,會在命令行輸出錯誤信息,gulp 進程不會掛掉,修正錯誤后,watch 任務將繼續執行。
注意:使用 gulp-util 只是使錯誤日志格式與 gulp 的日志保持一致,如果不想多一個依賴,可以直接使用 console
。
var gulp = require('gulp'); var less = require('gulp-less'); var csso = require('gulp-csso'); var gutil = require('gulp-util'); gulp.task('less', function() { return gulp.src('less/app.less') .pipe(less()) .on('error', function(err) { gutil.log('Less Error!', err.message); this.end(); }) .pipe(csso()) .pipe(gulp.dest('./dist')) }); gulp.task('watch', function() { gulp.watch('less/**/*.less', ['less']); });
gulp.watch 與 Browserify 中的錯誤處理
Browserify 中的常規流與 gulp 中的 vinyl 對象流有點不同,browserify 的錯誤處理中需要手動觸發 end
事件 ,以停止流在管道中傳送。如果不添加 this.emit('end');
,進程仍然會掛掉。
var gulp = require('gulp'); var browserify = require('browserify'); var source = require("vinyl-source-stream"); gulp.task('browserify', function(){ return browserify('./main.js').bundle() .on('error', function(err){ console.log(err.message); this.emit('end'); }) .pipe(source('main.out.js')) .pipe(gulp.dest('./dist')); });
使用插件
使用 Stream 的事件 API 雖然可以處理錯誤,但是在每個插件后面都需要添加錯誤監聽函數,有點惡心,還好有專門的插件處理這個問題。
gulp-plumber
gulp-plumber 可以阻止 gulp 插件發生錯誤導致進程退出並輸出錯誤日志。
var gulp = require('gulp'); var less = require('gulp-less'); var csso = require('gulp-csso'); var plumber = require('gulp-plumber'); gulp.task('less', function() { return gulp.src('less/app.less') .pipe(plumber()) .pipe(less()) .pipe(csso()) .pipe(gulp.dest('./dist')) });
這比添加錯誤監聽事件省事多了。
stream-combiner2
stream-combiner2 把多個 stream 合並為一個,也就是說只需要添加一個錯誤監聽,相比之下,還是 gulp-plumber 方便。
var combiner = require('stream-combiner2'); var uglify = require('gulp-uglify'); var gulp = require('gulp'); gulp.task('test', function() { var combined = combiner.obj([ gulp.src('bootstrap/js/*.js'), uglify(), gulp.dest('public/bootstrap') ]); // any errors in the above streams will get caught // by this listener, instead of being thrown: combined.on('error', console.error.bind(console)); return combined; });