Skip to content

Instantly share code, notes, and snippets.

@floatdrop
Last active January 18, 2021 03:54
Show Gist options
  • Select an option

  • Save floatdrop/8269868 to your computer and use it in GitHub Desktop.

Select an option

Save floatdrop/8269868 to your computer and use it in GitHub Desktop.
Error management in gulp

#Error management in gulp

Sucking at something is the first step to becoming sorta good at something

No one can assure you, that plugins will run smooth in any circumstances (except for tests - they could), so neither should you convince anyone, that your plugin will never break. Only thing, that you could possibly do (if something gone wrong) - is gracefully inform your plugin user, that something went wrong and die.

We are will use this plugin from beginning to demonstrate error management. Suppose you have a task in gulpfile.js that contains this code (we modified it a little bit to be closer to real-usage):

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

gulp.src('coffee/**/*.coffee')
  .pipe(gulpPrefixer('// Copyright 2014 (C) Aswesome company'))
  .pipe(coffee())
  .pipe(gulp.dest('js/'));

What could possibly go wrong? Well gulpPrefixer could emit errors event, as any of Stream gulp-plugins, for example gulp-sass. If you don't do anything with it inside task, Node will throw errors and whole task will be stopped.

You can easily avoid it by catch them and show by appending .on('error', gutil.log) handlers:

gulp.src('coffee/**/*.coffee')
  .pipe(gulpPrefixer('// Copyright 2014 (C) Aswesome company'))
  .on('error', gutil.log)
  .pipe(coffee())
  .on('error', gutil.log)
  .pipe(gulp.dest('js/'));

But this will not solve "stopping" problem of the task. By design, Node stream will stop accepting incoming data, if error event was raised. You can see it in stream.js:103 - cleanup function will deattach ondata handler from source (which in our case is gulp.src) and coffee plugin will stop receiving files although, the rest of the files can be compiled.

For now, we have no other solution besides patching pipe function behaviour. So the gulp-plumber may fix this problem:

gulp.src('coffee/**/*.coffee')
  .pipe(plumber())
  .pipe(gulpPrefixer('// Copyright 2014 (C) Aswesome company'))
  .pipe(coffee())
  .pipe(gulp.dest('js/'));

Note: This will work only if Stream class used in gulp-plugin will not panic on error event and stop being writable/readable.

@felixrabe

Copy link
Copy Markdown

Non-master permalink for stream.js: stream.js:103

@barneycarroll

Copy link
Copy Markdown

Once you've decided to adopt plumber, you pretty much want it invoked whenever you open a gulp pipe chain. Why not have a DRY convenience wrapper, e.g.:

gulp.plumbedSrc = function( src ){
  return gulp.src.call( gulp, Array.prototype.slice( arguments, 0 ) )
    .pipe( plumber() );
}

@timnew

timnew commented Jul 14, 2014

Copy link
Copy Markdown

@barneycarroll

I assume you mean this:

gulp.plumbedSrc = function( ){
  return gulp.src.apply( gulp, Array.prototype.slice( arguments, 0 ) )
    .pipe( plumber() );
}

@hontas

hontas commented Oct 16, 2014

Copy link
Copy Markdown

@barneycarroll
@timnew

And I assume you mean this:

gulp.plumbedSrc = function( ){
  return gulp.src.apply( gulp, Array.prototype.slice.call( arguments ))
    .pipe( plumber() );
}

@radekn

radekn commented Nov 27, 2014

Copy link
Copy Markdown

@barneycarroll
@timnew
@hontas

I assume you mean this:

gulp.plumbedSrc = function( ){
  return gulp.src.apply( gulp, arguments )
    .pipe( plumber() );
}

@vmadman

vmadman commented Dec 22, 2014

Copy link
Copy Markdown

@barneycarroll
@timnew
@hontas
@radekn

I assume you mean this:

gulp.plumbedSrc = function( ){
  return gulp.src.raawwwrrrrrrr();  // todo: define raawwwrrrrrrr()
}

@scharf

scharf commented Jan 9, 2015

Copy link
Copy Markdown

What about the solution proposed Joel Rich here and here? The idea is to patch gulp.src.

@sandro-pasquali

Copy link
Copy Markdown

I found overriding #src and binding to gulp-notify to be pretty simple and useful

var _gulpsrc = gulp.src;
gulp.src = function() {
    return _gulpsrc.apply(gulp, arguments)
    .pipe(plumber({
        errorHandler: function(err) {
            notify.onError({
                title:    "Gulp Error",
                message:  "Error: <%= error.message %>",
                sound:    "Bottle"
            })(err);
            this.emit('end');
        }
    }));
};

@MiguelCastillo

Copy link
Copy Markdown

Alright, I had to add a useless comment... But the whole assumption/correction segment was pretty funny :D

@brendanfalkowski

Copy link
Copy Markdown

I've been trying to wrap my head around error reporting. Anyone smarter than me have a better approach than this: mikaelbr/gulp-notify#81

Tried everything I could read up, but still not smooth. Feels like I'm missing something obvious nobody talks about anymore.

@ckapilla

Copy link
Copy Markdown

@brendanfalkowski

Feels like I'm missing something obvious nobody talks about anymore.

story of my life

@jiuxiaosheng

Copy link
Copy Markdown

i just want to say, it's funny to watch you guys talk;

@JonCatmull

Copy link
Copy Markdown

Haha great comment stream! and the article wasn't to bad either. 👍

@man-oi

man-oi commented Mar 16, 2016

Copy link
Copy Markdown

great idea @sandro-pasquali

@demonkoryu

Copy link
Copy Markdown

Good article, but the comments... I can't even

@blackcater

Copy link
Copy Markdown

Thanks a lot!

@kilianc

kilianc commented Apr 13, 2016

Copy link
Copy Markdown

This is very helpful for development but how do you handle CI and deploy? I need a hard exit > 0 if anything goes wrong.

@robianmcd

robianmcd commented Jun 14, 2016

Copy link
Copy Markdown

@kilianc I'm setting a boolean to determine weather a task should exit the process or not and running something like this

var exitOnError = true; //set to false when running a watch task

//...
.pipe(somethingThatThrowsAnError())
.on("error", function (err) {
  gutil.log(err);
  if(exitOnError) {
    process.exit(1);
  } else {
    this.emit('end');
  }
});

...seems kind of crazy there is no standard way to do this in gulp

@bool3max

Copy link
Copy Markdown

@robianmcd I hate just logging the entire error object, so I always just log err.message. It's way easier to read.

@kwojcik-blockether

Copy link
Copy Markdown

Do we really need gulp-plumber in 2016? It seems that the watch do not stops when the error is occurred. Tried several times and everything is working fine.

gulp.task('styles', function() {   
 return gulp.src('public/sass/*.scss')
   .pipe(sass(SassOptions).on('error', sass.logError))
   .pipe(gulp.dest('public/stylesheets'));
});

@normbr

normbr commented Sep 7, 2016

Copy link
Copy Markdown

I think FieryCod has a good question...any thoughts...is plumber still needed?

@Gwenouille

Copy link
Copy Markdown

Hi guys,
Did someone here manage to have gulp work nicely with stylus ? I have set a small watch task with a pipe through stylus, autoprefixer and others, and it crashes altogether if stylus encounters a problem on compiling (like a bad indent).

@toby-howell

Copy link
Copy Markdown

@barneycarroll
@timnew
@hontas
@radekn

I assume you mean this:

gulp.plumbedSrc = (...args) => gulp.src(...args).pipe(plumber());

@absolux

absolux commented Mar 14, 2017

Copy link
Copy Markdown

😆 😃

gulp.plumbed = () => gulp.src(...arguments).pipe(plumber())

@VinnyFonseca

Copy link
Copy Markdown

¯_(ツ)_/¯

@absolux

gulp.plmbd = () => gulp.src(...args).pipe(plumber())

@paraofheaven

Copy link
Copy Markdown

plumber can solve the pro,that's just what i need

@Joelsz

Joelsz commented Jun 15, 2018

Copy link
Copy Markdown

Thanks @sassy-ankit that cleared my way to use plumber for gulp-sass

@craigphicks

Copy link
Copy Markdown

I wish you explain in more detail the circumstances under which

But this will not solve "stopping" problem of the task. By design, Node stream will stop accepting incoming data, if error event was raised.

is a problem. Unhandled exceptions are certainly a problem - but isn't "stopping on error" the a reasonable default behavior?

@DLiblik

DLiblik commented Jul 26, 2020

Copy link
Copy Markdown

@craigphicks old comment, but in case anyone ends up here... an error in one file in the task doesn't always mean the desire is to have the whole process grind to a halt - depends on the task. This whole conversation covers creating the option to choose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment