Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to catch errors without stopping gulp.watch? #71

Closed
dashed opened this issue Dec 26, 2013 · 30 comments
Closed

How to catch errors without stopping gulp.watch? #71

dashed opened this issue Dec 26, 2013 · 30 comments
Labels

Comments

@dashed
Copy link
Contributor

dashed commented Dec 26, 2013

I'm exploring gulp as a replacement for gruntjs.

Here is my gulpfile.js.

I'm using gulp to watch and compile coffeescript files (with gulp-coffee). In addition, I'm using gulp.watch to only compile individual files instead of entire targeted globbed paths.

My issue is that if I purposely put incorrect coffeescript syntax, gulp exits:

events.js:72
        throw er; // Unhandled 'error' event
< gulp-coffee error here >
< rest of stack trace >

How should I catch the error without having it stop gulp.watch? And perhaps re-initiate the default task?

I'm not familiar with streaming in node. I tried try-catch and checked if any callbacks are catching the error to no avail. Appreciate if someone point me in the right direction.

@yocontra
Copy link
Member

You have to catch the error event on the stream emitting it. In node if something emits an error event and nobody listening it turns it into a throw. By adding a .on('error') listener to the coffee plugin you can handle it gracefully

@yocontra
Copy link
Member

This should probably be documented more in the wiki

@dashed
Copy link
Contributor Author

dashed commented Dec 26, 2013

Exactly what I needed. Thanks!

Previously, I was trying to listen to the 'error' by doing this:

var stream = gulp.src(...)...;

stream.on('error', function() {});

@yocontra
Copy link
Member

Just a quick update: I was waiting until the new task system in gulp 4.0 for this to be fixed but it seems to be a large enough issue that I put a hotfix in place in 3.6. Watch will no longer stop and the process will no longer exit just because an error was thrown.

@dashed
Copy link
Contributor Author

dashed commented Apr 4, 2014

I assume this is the hotfix: 623bb18#diff-06552d6d19e21d54f6696352aefc7f12R99?

Will there be a better solution than this in 4.0?

@yocontra
Copy link
Member

yocontra commented Apr 4, 2014

@dashed yes, an entirely new task system that doesn't have this issue. this is an orchestrator issue

@dashed
Copy link
Contributor Author

dashed commented Apr 4, 2014

Awesome.

@rocketraman
Copy link

On Gulp 3.6.1, this is still not working for me. I have added the on('error', cb) function to my less processor, and it is called and the process does not exit like before. However, the watch never triggers again.

Task definition:

gulp.task('less', function() {
  return gulp.src('app/css/*.less')
    .pipe(less().on('error', gutil.log))
    .pipe(gulpif(isDebug, debug({verbose: true})))
    .pipe(gulp.dest('app/css'));
});

and watch:

gulp.watch('app/css/*.less', ['less', 'usemin']);

@robertjd
Copy link

@rocketraman i had this problem too, i solved it by manually ending the less stream when an error happens:

gulp.task('less', function () {
  var l = less({});
  l.on('error',function(e){
    gutil.log(e);
    l.end();
  });
  return gulp.src('main.less')
    .pipe(l)
    .pipe(gulp.dest('.tmp/'));
});

@laurelnaiad
Copy link
Contributor

That + gulp-plumber for those plugins that want to completely crash the party seems like the state of the art today.

@rocketraman
Copy link

@robertjd Thanks, that worked perfectly!

@andrewmartin
Copy link

@robertjd thank you! 👍 for that solution, best I've seen so far.

@ELLIOTTCABLE
Copy link

Just to make it a little prettier (especially if you're using CoffeeScript, as I am):

handle = (stream)->
   stream.on 'error', ->
      util.log.apply this, arguments
      stream.end()

Then, whenever you call a plugin, prefix it with handle.

plugin('watch') glob: paths.js.synch, (_)->
   _  .pipe plugin('debug') title: 'synch'
      .pipe plugin('if') /[.]coffee$/, handle plugin('coffee') bare: yes, header: no
      .pipe plugin('concat') 'synch.concat.js'
      # ...

Far from perfect, but actually a manageable solution. (=

@yocontra
Copy link
Member

I love coffee-script, but it looks like shit when you use fluent APIs without parenthesis IMO

@benweet
Copy link

benweet commented Jun 29, 2014

👍 @robertjd

@koistya
Copy link
Contributor

koistya commented Jul 1, 2014

@robertjd 👍

@dallonf
Copy link

dallonf commented Jul 24, 2014

This seems like a major design flaw in Gulp... I love the idea of it, but from a practical standpoint, the fact that, by default, a watch crashes at the first sign of trouble is almost a showstopper for me.

And philosophically... seriously, in an environment that pipes streams, I have to manually handle errors on every single one (not counting gulp-plumber, which is so hackish that I could never take it seriously as a long-term solution)? Shouldn't the error bubble up and get handled by the watch expression itself? Is this a design flaw in Node itself?

I'm at a loss for why this is so clunky. Is this something that can be fixed?

(update) After a little bit of search, it looks like I'm beating a dead horse. Sorry about that, but I just can't find enough information to make the decision to keep using Gulp and await fixes, or go back to Grunt. I keep hearing a lot about this magical new task system (bach?), but I have no idea if that would actually fix this issue, or when I could expect to see that in the core... information is spread out all over the place and I can't find any solid answers.

@yocontra
Copy link
Member

@dallonf If you look at the roadmap, this will all be fixed in gulp 4. All of us on the team are busy people though and haven't had a lot of time to put towards this, but it's getting there.

@dallonf
Copy link

dallonf commented Jul 24, 2014

@contra I've seen a lot of mentions to gulp 4.0 in related tickets, but I can't find that roadmap you mentioned anywhere... now, that's probably because I lost my glasses this morning, but could you provide a link? Maybe it should go on the main README, as well... if it isn't already? squints

Gosh, I need to find my glasses...

@yocontra
Copy link
Member

@rbalicki2
Copy link

Hi everyone, FWIW, I published a package to NPM (see npmjs.org/package/pipe-error-stop) that might make your lives easier. You can wrap a stream that might emit an error in pipeErrorStop, and if it does, no data will be emitted onward. pipeErrorStop also handles the errors.
-Robert

@mietek
Copy link

mietek commented Aug 30, 2014

Initially, @robertjd's solution did not work for me. What worked for me was doing this.emit('end') instead of this.end(), which was rather puzzling. Eventually, I figured out the reason for this was that my gulp plugin was not emitting errors properly!

When using a through2.obj stream to define a gulp plugin, within the transformFunction(chunk, encoding, callback), on error, it is not enough to:

return callback(new gutil.PluginError('gulp-foo', 'bar'));

It is necessary to:

this.emit('error', new gutil.PluginError('gulp-foo', 'bar'));
return callback();

@codeofsumit
Copy link

+1
Not sure why this is closed as it's still a problem. I started using GULP last week and this really bugs our team. If this will be fixed in 4.0 - great. Doesn't fix the problem now though so this issue should still be open.
We won't do any of the workarounds mentioned here though because in the end we just want to update GULP and don't make everyone on our team get a new gulpfile.

@yocontra
Copy link
Member

@codeofsumit It isn't being fixed in 3.0 so the issue was closed. Look at the 4.0 branch

@honi
Copy link

honi commented Oct 17, 2014

@ELLIOTTCABLE's solution works great for me. In practice I only needed to handle 2 streams, less compiler and coffeescript compiler. All other plugins won't normally error with valid input, so no need to catch errors there.

@conatus
Copy link

conatus commented Nov 6, 2014

+1 for this.

@StreetStrider
Copy link

Have the same issue.

@rex
Copy link

rex commented Dec 4, 2014

Gulp looks like such an amazing tool, and the multiple times I've used it have proved that gulp is far simpler to configure and use than Grunt. But the stream-killing error situation is a catch I can't sell to my boss :(

I can't wait for 4.0 to come out so that I can bring Gulp back up as a viable long-term solution! In the meantime, major shouts out to @contra and the Gulp team for working their asses off creating such a kick ass product.

@ghost
Copy link

ghost commented Dec 24, 2014

I run into this issue and came up with the following workaround. Welcome to the land of JavaScript!

// 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 nextStreams = dest._nextStreams;
            if (nextStreams) {
                nextStreams.forEach(function (nextStream) {
                    nextStream.emit('error', error);
                });
            } else if (dest.listeners('error').length === 1) {
                throw error;
            }
        });
        var nextStream = fixPipe(origPipe.apply(this, arguments));
        (this._nextStreams || (this._nextStreams = [])).push(nextStream);
        return nextStream;
    };
    return stream;
}

Add it to your gulpfile.js and use it like that:

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

@yocontra
Copy link
Member

@joelrich This is going to be added in 4 (see #358)

All future discussion should go either #359 or #358

@gulpjs gulpjs locked and limited conversation to collaborators Dec 24, 2014
wincent added a commit to wincent/corpus that referenced this issue May 29, 2015
I am not sure how this works seeing as it doesn't seem to be documented,
but it does work...

According to this, everything will suck until gulp 4:

  gulpjs/gulp#71

This is the page where I found the reference to `fatalLevel`:

  http://www.artandlogic.com/blog/2014/05/error-handling-in-gulp/
wincent added a commit to wincent/corpus that referenced this issue May 29, 2015
Tried this before and thought it was working but evidently
I was either mistesting or there are cases for which it
does not work. This, however, does. Apparently, this will
all become a lot easier once gulp 4 is out:

  gulpjs/gulp#71
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests