I\'m running gulp 3.6.2 and have the following task that was set up from a sample online
gulp.task(\'watch\', [\'default\'], function () {
gulp.watch([
Typescript
This is what worked for me. I work with Typescript
and separated the function (to aovid confusion with this
keyword) to handle less
. This works with Javascript
as well.
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'))
})
Now, when you watch
.less
files, and an error
occurs, the watch
will not stop and new changes will processed as per your less task
.
NOTE : I tried with l.end();
; however, it did not work. However, l.emit('end');
totally works.
Hope this help. Good Luck.
Your swallowError
function should look like this:
function swallowError (error) {
// If you want details of the error in the console
console.log(error.toString())
this.emit('end')
}
I think you have to bind this function on the error
event of the task that was falling, not the watch
task, because that's not where comes the problem, you should set this error callback on each task that may fail, like plugins that breaks when you have missed a ;
or something else, to prevent watch
task to stop.
Examples :
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'))
})
Alternately, if you don't mind to include another module, you can use the log function of gulp-util to keep you from declare an extra function in your gulpfile
:
.on('error', gutil.log)
But I may recommend having a look at the awesome gulp-plumber plugin, which is used to remove the onerror
handler of the error
event, causing the break of the streams. It's very simple to use and it stops you from catch all the tasks that may fail.
gulp.src('./app/script/*.coffee')
.pipe(plumber())
.pipe(coffee({ bare: true }))
.pipe(gulp.dest('./public/js'))
More info about this on this article by the creator of the concerned plugin.
(ex: *.coffee only)
If you want to work only with one format of files, then gulp-plumber
is your solution.
For example rich handled errors and warning for coffeescripting:
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' }));
});
(ex: *.coffee and *.js at same time)
But if you won't to work with multiple types of file formats (for example: *.js
and *.coffee
), than i will post my solution.
I will just post a self explanatory code over here, with some description before.
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' }));
});
I faced the issue with gulp-plumber
and gulp-if
using gulp.watch(...
See related issue here: https://github.com/floatdrop/gulp-plumber/issues/23
So the best option for me was:
merge-stream
(that was made from event-stream
) into one and continue the job (i tried that first, and it work fine for me, so it is faster solution than previous one)Her is the main part of my code:
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' }));
});
If to separate this into parts, then in each part there should be a result file created. For ex.:
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;
});
Here node modules and functions that were used:
// 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');
};
I like to use gulp plumber because it can add a global listener to a task and have a meaningful message displayed.
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/'));
});
Reference : https://scotch.io/tutorials/prevent-errors-from-crashing-gulp-watch
This worked for me ->
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'])
I just added the .on('error', console.error.bind(console)) line, but I had to run the gulp command as root. I'm running node gulp on a php application so I have multiple accounts on one server, which is why I ran into the issue of gulp breaking on syntax errors because I was not running gulp as root... Maybe plumber and some of the other answers here would have worked for me if I ran as root. Credit to Accio Code https://www.youtube.com/watch?v=iMR7hq4ABOw for the answer. He said that by handling the error it helps you to determine what line the error is on and what it is in the console, but also stops gulp from breaking on syntax error. He said it was kind of a light weight fix, so not sure if it will work for what you are looking for. Quick fix though, worth a shot. Hope this helps someone!
I have implemented the following hack as a workaround for 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;
}
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);
});
This feels like the most natural error handling to me. If there is no error handler at all, it will throw an error. Tested with Node v0.11.13.