If you find yourself squinting at a dull console, this quick write-up on adding color-coding, OS notifications, and error reporting to gulp will be a sight for sore eyes.
Posted on December 31, 2016 in Web Design
Damn you kids, I was using Gulp before Gulp was cool! When was that, 2013? I know—I’m a dinosaur. Anyway, back then, Gulp wasn’t as mature as Grunt, but I recently switched back, because now it certainly is. I thought I might share some useful bits from my configuration, to save you time.
Setting up Gulp with functioning error reporting and Livereload was a bit of a hassle. I wanted Gulp to output color-coded error messaging in the console, as well as send a notification to my desktop, for both SASS and jshint, while watching and/or when I run the task manually.
The end result I wanted is this:
And in the console:
First, here’s the package.json:
"devDependencies": { "chalk": "^1.1.3", "events": "^1.1.1", "gulp": "latest", "gulp-jshint": "^2.0.4", "gulp-livereload": "^3.8.1", "gulp-load-plugins": "^1.4.0", "gulp-notify": "^2.2.0", "gulp-plumber": "^1.1.0", "gulp-sass": "latest", "gulp-sourcemaps": "^1.9.1", "gulp-util": "^3.0.7", "gulp-watch": "^4.3.11", "jshint": "^2.9.4", "jshint-stylish": "^2.2.1", "map-stream": "0.0.6", "path": "^0.12.7" },
We need a whole bunch of crap for this to work. You’ll want to npm install all of these first:
- events, path, map-stream for our error reporting function
- chalk, for color coding out console output
- plumber to catch errors
- notify to send notifications to our OS
- jshint and jshint-stylish to scan our JS for problems
- gulp-watch and livereload in our browser
- gulp-load-plugins to autoload everything
Gulp Sass Notifications
Then, load everything up:
/** * init gulp plugins */ var gulp = require('gulp'); var plugins = require('gulp-load-plugins')(); var map = require('map-stream'); var events = require('events'); var emitter = new events.EventEmitter(); var path = require('path'); var gutil = require('gulp-util'); var currentTask = '';
Okay, let’s do the SASS error reporting first. Here is a simplified SASS task:
/** * sass to css */ gulp.task('sass', function () { currentTask = 'sass'; return gulp.src('styles/sass/screen.scss') .pipe(plugins.plumber({ errorHandler: reportError })) .pipe(plugins.sass()) .pipe(gulp.dest('styles')) .pipe(plugins.livereload()); });
So in this task, we’re compiling all the SASS partials listed out in /styles/sass/screen.scss, and compiling them into the /styles/ folder as screen.css. Notice we start by calling plugins.plumber, and pass errors off to the reportError function.
That function will do the following magic:
/** * error reporter object (for plugins) */ var reportError = function (error) { var lineNumber = (error.lineNumber) ? 'LINE ' + error.lineNumber + ' -- ' : ''; var pluginName = (error.plugin) ? ': ['+error.plugin+']' : '['+currentTask+']'; plugins.notify({ title: 'Task Failed '+ pluginName, message: lineNumber + 'See console.' }).write(error); gutil.beep(); var report = ''; var chalk = gutil.colors.white.bgRed; report += chalk('TASK:') + pluginName+'\n'; report += chalk('ERROR:') + ' ' + error.message + '\n'; if (error.lineNumber) { report += chalk('LINE:') + ' ' + error.lineNumber + '\n'; } if (error.fileName) { report += chalk('FILE:') + ' ' + error.fileName + '\n'; } console.error(report); this.emit('end'); }
I cannot claim credit for this function, but I combed the depths of gulp-notify’s github issues to find the solution. Kudos to @brendanfalkowski. It is basically taking the error and breaking it up into sensible bits to display in the OS notifier. I use Windows 10, so this is the little popup generated by the Notifications tray. I had to add a system environment variable FORCE_COLOR = true to get my console to accept chalk colors, so your mileage may vary.
What’s great about this function is that you can use it in other tasks, and it will handle the popup. For example, in my cssmin task, I use plumber to pass the error to the same error reporting function:
/** * minifies css */ gulp.task('cssmin', function () { currentTask = 'cssmin'; return gulp.src('styles/screen.css') .pipe(plugins.plumber({ errorHandler: reportError })) .pipe(plugins.cleanCss()) .pipe(plugins.rename({suffix: '.min'})) .pipe(gulp.dest('styles')) });
Notice the currentTask variable. In @brendanfalkowski‘s original function, error.plugin isn’t always available in a task’s error output, so if you specify the name of the task inside each task, this guarantees the notify popup will always specify which task is failing.
OK! Now we just need to hook this up with our watch task.
/** * gulp watch */ gulp.task('watch', function() { plugins.livereload.listen(); gulp.watch('styles/sass/**/**/*.scss', ['sass']); });
Make sure to install the Chrome Livereload extension and turn it on by clicking the below icon (after running gulp watch) when you’re ready to watch a page in your browser:
JSHint Notifications
For jshint we’ll need a slightly different error function. Let’s start with our task:
/** * jshints js/modules/*.js */ gulp.task('jshint', function() { return gulp.src(['js/modules/**/*.js']) .pipe(plugins.jshint('.jshintrc')) .pipe(plugins.jshint.reporter('jshint-stylish')) .pipe(jsHintErrorReporter) .on('error', plugins.notify.onError(function (error) { return error.message; } )) .pipe(plugins.livereload()); });
We set up jshint and jshint stylish first, then pipe the error to notify, which in turn uses our error function. This function I cribbed and modified from the following gist:
/** * custom reporter for jshint-stylish */ var jsHintErrorReporter = map(function (file, cb) { if (!file.jshint.success) { file.jshint.results.forEach(function (err) { if (err) { var msg = [ path.basename(file.path), 'LINE: ' + err.error.line, 'ERROR: ' + err.error.reason ]; // Emit this error event emitter.emit('error', new Error(msg.join(" - "))); } }); } cb(null, file); });
Now we just need to add this to our watch task:
/** * gulp watch */ gulp.task('watch', function() { plugins.livereload.listen(); gulp.watch('styles/sass/**/**/*.scss', ['sass']); gulp.watch(['js/modules/*.js'], ['jshint']); });
Ta da! Now you have sass and jshint notifications. Congrats. Go make lots of errors.