floatdrop / gulp-plumber

Fixing Node pipes
MIT License
806 stars 32 forks source link

Not working with gulp-less #30

Closed dyf19118 closed 8 years ago

dyf19118 commented 9 years ago

I used plumber to prevent exiting on any error thrown while compiling my less files.I purposely made an error in my less file and of course an error occurred while compiling it.I expected that plumber can prevent it but it actually didn't work at all. Or Is there anything wrong in my gulpfile ? Here's following the critical code of my gulpfile.js and i run "gulp watch" to watch my less files and auto-compiling on modifications.

/* gulpfile.js */
var changedFile;
gulp.task("single-less", function() {
    return gulp.src(changedFile)
            .pipe(plumber())
            .pipe(less())
            .pipe(gulp.dest(config.cssdist))
            .pipe(livereload());
});
var lessWatcher;
gulp.task("watch", function() {
    livereload.listen();
    lessWatcher = gulp.watch(config.less(), ["single-less"]);
    lessWatcher.on("change", function(file) {
        if (file.type === "changed") {
            changedFile = file.path;
            gulp.start("single-less");
        }
    });
});
floatdrop commented 9 years ago

Can you reduce code to only gulp-plumber and gulp-less usages? It could be, that gulp.watch is reacting on error from single-less task.

dyf19118 commented 9 years ago

okay, i got it. I wrote a simple demo only with gulp-plumber and gulp-less, it works. Umm...Maybe i should have a try to use gulp-watch instead of gulp.watch. Thanks a lot!

mgol commented 8 years ago

I have a similar issue. The test case is as follows:

gulp.task('css-failing', () =>
    gulp.src('./css/floating_layout.less', {base: './css'})
        .pipe(plumber())
        .pipe(less())
        .pipe(gulp.dest('./css'))
);

Now when I remove a semi-colon inside floating_layout.less and run the task, it displays an error, finishes the task & exits with code 0:

$ gulp css-failing; echo $?
[10:43:59] Requiring external module babel-register
Node.js version: v5.7.1
[10:43:59] Using gulpfile ~/Documents/projects/yougov/opi_front/php/opigram/gulpfile.babel.js
[10:43:59] Starting 'css-failing'...
[10:43:59] Plumber found unhandled error:
 Error in plugin 'gulp-less'
Message:
    missing semi-colon or unrecognised media features on import in file /Users/mgol/Documents/projects/yougov/opi_front/php/opigram/css/floating_layout.less line no. 37
Details:
    type: Syntax
    filename: /Users/mgol/Documents/projects/yougov/opi_front/php/opigram/css/floating_layout.less
    index: 924
    line: 37
    callLine: NaN
    callExtract: undefined
    column: 0
    extract: @import '@{opigram-path}/components/common/follow-member';,@import "@{opigram-path}/components/common/report-to-yougov",@import '@{opigram-path}/components/common/widget-container';
    lineNumber: 37
    fileName: /Users/mgol/Documents/projects/yougov/opi_front/php/opigram/css/floating_layout.less
[10:43:59] Finished 'css-failing' after 34 ms
0

When I restore the semicolon but remove one in another less file that is imported from the previous one, it also displays an error and finishes with code 0 but the task doesn't seem to finish at all:

$ gulp css-failing; echo $?
[10:44:09] Requiring external module babel-register
Node.js version: v5.7.1
[10:44:10] Using gulpfile ~/Documents/projects/yougov/opi_front/php/opigram/gulpfile.babel.js
[10:44:10] Starting 'css-failing'...
[10:44:10] Plumber found unhandled error:
 Error in plugin 'gulp-less'
Message:
    Unrecognised input in file /Users/mgol/Documents/projects/yougov/opi_front/php/opigram/css/src/less/components/notifications/notification.less line no. 53
Details:
    type: Parse
    filename: /Users/mgol/Documents/projects/yougov/opi_front/php/opigram/css/src/less/components/notifications/notification.less
    index: 1773
    line: 53
    callLine: NaN
    callExtract: undefined
    column: 27
    extract:             background-position: 20px 22px,            background-size: 23px 15px;,        }
    lineNumber: 53
    fileName: /Users/mgol/Documents/projects/yougov/opi_front/php/opigram/css/src/less/components/notifications/notification.less
0

I believe that's the reason why, when combined with gulp-watch, after first such error the task is never run again.

gulpm-plumber 1.1.0, gulp-less 3.0.5, gulp-watch 4.3.5.

webxl commented 8 years ago

This is what worked for me:

function plumber_config(done) {
  return {
    errorHandler: function (err) {
      done(err);
    }
  }
}

gulp.task('less', function (done) {
  return gulp.src(lessFileGlob)
    .pipe(plumber(plumber_config(done)))
    .pipe(sourcemaps.init())
    .pipe(less())
...

The plumber config doesn't have to be reusable, but I think what trips gulp.watch() up is that gulp-less doesn't break the pipeline like all the other plugins do. Add gulp-postcss to that, apparently.

iby commented 8 years ago

@webxl makes a good point, but that very often fails with callback called twice, especially when using multiple sources, for example when compiling Foo.less and Bar.less, Bar.less has an error, and Foo.less imports Bar.less.

Instead, simply emit the end event on the stream, all kudos are to Kate Hudson.

gulp.src('…')  
    .pipe(plumber(function (error) {
        console.log(error);
        this.emit('end');
    }))
    .pipe(less)
    .dest(gulp.dest('…'));
josecabana commented 8 years ago

Thanks @ianbytchek , your solution works with my jade task

iby commented 8 years ago

@josecabana after trial and error I ended up using the following, emit('end') wasn't enough sometimes.

plumber(function (error) {

    // Must emit end event for any dependent streams to pick up on this. Destroying the stream
    // ensures nothing else in that stream gets done, for example, if we're dealing with five
    // files, after an error in one of them, any other won't carry on. Doing destroy without 
    // ending it first will not notify depending streams, tasks like `watch` will hang up.

    this.emit('end');
    this.destroy();
}