Tutorial

Prevent Errors from Crashing Gulp Watch

Draft updated on Invalid Date
    Default avatar

    By Samuel Oloruntoba

    Prevent Errors from Crashing Gulp Watch

    This tutorial is out of date and no longer maintained.

    Introduction

    Developers are a lazy bunch. Or at least I assume we are. Because of this reason we tend to build tools that make our work faster. From highly customizable editors to task runners.

    With gulp, we can build tasks that automatically compile Sass, start a Laravel server, live reload the browser, transpile ES6 to ES5, etc.

    Thankfully, there are a few languages out there like Javascript which is very forgiving. Nonetheless, mistakes can happen.

    Since we have a “gulp watcher” that watches our project and runs defined tasks when we make any change, an error can easily break our pipeline.

    Creating and Watching a Gulp Task

    Watching in Gulp refers to triggering a task when a change is made to a project’s source.

    So, before we watch a task, let’s create a task that we will use as our example throughout this tutorial. The task we will create is a SCSS compilation task.

    We can create a new working directory, name it whatever you want. We can now create our gulpfile.js in our working directory. Then we add our build task. Before we define our task, we need to install our dependencies.

    For this article, here is a list of our dependencies.

    {
      "private": true,
      "devDependencies": {
        "gulp": "^3.9.1",
        "gulp-notify": "^2.2.0",
        "gulp-plumber": "^1.1.0",
        "gulp-sass": "^2.3.2",
        "gulp-util": "^3.0.7"
      }
    }
    

    Now that we have our dependency list, we can run npm install or if you have the new yarn package manager based on npm, you can run yarn install.

    In the gulpfile, we can then define our gulp task.

    const gulp = require('gulp');
    const sass = require('gulp-sass');
    
    gulp.task('compile-scss', function () {
        gulp.src('scss/main.scss')
            .pipe(sass())
            .pipe(gulp.dest('css/'));
    });
    

    So from the command line, we can run gulp compile-scss and our Sass file should be compiled.

    Watching a Task

    Now that we have a task defined, let’s trigger the file whenever we make a change to the project’s source.

    gulp.task('watch', function () {
        gulp.watch('scss/**/*.scss', ['compile-scss']);
    });
    

    From the terminal, we can run gulp watch and whenever a file ending with .scss extension in any folder within the scss directory gets changed, compile-scss task is run.

    Prevent Errors from Breaking Tasks

    We’ve got our task and watcher up and running, but if an error occurs in our SCSS file, the gulp watcher gets terminated. We then have to go back to the terminal and type gulp watch again. This gets very annoying really fast. A silly little ; can break our watcher.

    To avoid breakage like this, we can one of three things:

    1. Swallow the Error.
    2. Gulp Util.
    3. Gulp Plumber.

    Swallow the Error

    One a way to go about dealing with errors is to “swallow the error”. The error(s) will be taken in by the application to prevent the task from breaking. Basically, errors will not be reported and the task will keep running.

    Since gulp sends a lot of events, we can hook into the error event of the task we don’t want to fail.

    gulp.task('compile-scss', function () {
        gulp.src('scss/main.scss')
            .pipe(sass())
            .on('error', function (err) {
                console.log(err.toString());
    
                this.emit('end');
            })
            .pipe(gulp.dest('css/'));
    });
    

    As you can see above, from the on listener on the task. The on event listener takes in two parameters: the event and a function to be triggered when the event gets called. The function that gets called takes in the error object. We then log the stringified version of the error to the terminal.

    It is absolutely important to this.emit('end'), if this event is not triggered, the next pipe in this task pipeline never gets called, and the buffer will be left open.

    Gulp Util

    This method involves using the gulp-util plugin.

    The gulp-util plugin provides a lot of helpful methods, one of them is log. With this method, we can log the error to the terminal. To use this, we attach an error event listener to the pipe.

    var gutil = require('gulp-util');
    
    gulp.task('compile-scss', function () {
        gulp.src('scss/main.scss')
            .pipe(sass())
            .on('error', gutil.log)
            .pipe(gulp.dest('css/'));
    });
    

    But this method also requires us to go through each pipe in the pipeline and attach .on('error', gutil.log) listener to all tasks. Something like this.

    gulp.task('compile-scss', function () {
        gulp.src('scss/main.scss')
            .pipe(sass())
            .on('error', gutil.log)
            .pipe(autoprefixer())
            .on('error', gutil.log)
            .pipe(gulp.dest('css/'));
    });
    

    Gulp Plumber

    Out of all three methods, this is my favorite. With gulp-plumber, we don’t need to go to each pipe and add a listener, we can just add a global listener to the task and have a meaningful error 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/'));
    });
    

    We can have multiple pipes in this task and still only ever need to call plumber once.

    Alerting the User to Errors

    Now that we can see the errors without breaking out of watch, we need to find a way to get some kind of notification when an error occurs. There are several ways to do this, but I will cover only one method.

    The method I will cover in this article: will play a beeping sound when an error occurs, and also show a system notification that looks like this.

    This notification looks different according to your operating system.

    To get this feature to work, we need to extend the gulp-plumber plugin. So in our gulp task, we update our call to plumber.

    gulp.task('scss', function () {
        gulp.src('scss/main.scss')
            .pipe(plumber({ errorHandler: function() {
                // do stuff here
            }}))
            .pipe(sass())
            .pipe(gulp.dest('css'));
    });
    

    Notice, we pass an object that has an errorHandler property that takes a closure to plumber. We can then call our notify plugin in that closure.

    var notify = require('gulp-notify');
    
    gulp.task('scss', function () {
        gulp.src('scss/main.scss')
            .pipe(plumber({ errorHandler: function(err) {
                notify.onError({
                    title: "Gulp error in " + err.plugin,
                    message:  err.toString()
                })(err);
            }}))
            .pipe(sass())
            .pipe(gulp.dest('css'));
    });
    

    We call the notify plugin and pass it an object that has a title and message property. Now, when an error occurs, a notification is triggered. To play a beeping sound, we can use **gulp-util ** for that.

    var notify = require('gulp-notify');
    
    gulp.task('scss', function () {
        gulp.src('scss/main.scss')
            .pipe(plumber({ errorHandler: function(err) {
                notify.onError({
                    title: "Gulp error in " + err.plugin,
                    message:  err.toString()
                })(err);
    
                // play a sound once
                gutil.beep();
            }}))
            .pipe(sass())
            .pipe(gulp.dest('css'));
    });
    

    Now, when an error occurs, we get both sound and system notification, and then you can check your terminal for more information.

    Conclusion

    The configuration in this article should be suitable for most users, but if you have any suggestions/improvements, please let us know in the comments.

    Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

    Learn more about us


    About the authors
    Default avatar
    Samuel Oloruntoba

    author

    Still looking for an answer?

    Ask a questionSearch for more help

    Was this helpful?
     
    Leave a comment
    

    This textbox defaults to using Markdown to format your answer.

    You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

    Try DigitalOcean for free

    Click below to sign up and get $200 of credit to try our products over 60 days!

    Sign up

    Join the Tech Talk
    Success! Thank you! Please check your email for further details.

    Please complete your information!

    Get our biweekly newsletter

    Sign up for Infrastructure as a Newsletter.

    Hollie's Hub for Good

    Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

    Become a contributor

    Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

    Welcome to the developer cloud

    DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

    Learn more
    DigitalOcean Cloud Control Panel