Quantcast
Channel: DQuinn.net
Viewing all articles
Browse latest Browse all 148

Gulp Error Reporting with JShint, Gulp-Notify, and Livereload

$
0
0

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:

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.

Just click New and add FORCE_COLOR with a value of true, in Windows 10.

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.


Viewing all articles
Browse latest Browse all 148

Trending Articles