We ramble about code, technology and life. Sometimes we actually code...


Simple and awesome gulp setup

by Cornelius Weidmann on 21 June 2014

For quite some time now I have been using gulp. Gulp is truly amazing and saves me a bunch of time.

Here is my basic setup. This is intended for app or website development. This is a bare bones structure and assumes we're building a vanilla project without any frameworks. Including frameworks will probably change your gulp setup, but you will definitely be able to use this setup as a starting block. This gulp setup will do the following:

  1. Combine and minify your javascript into a single app.js file.
  2. Compile your stylesheets to a single minified app.css file (using sass).
  3. It will watch all your javascript and sass files, as well as your HTML for changes and live reload your browser on save.
  4. It will manage errors by notifying us with system beeps while making sure our gulp process doesn't break.

I'll explain each step below. If you want to check out the code here's the link to the full gulp setup demo.

0. Some pre-requisites:

  1. I'm assuming you know node, gulp, bower and sass.
  2. You have node, npm and ruby (with sass gem) installed globally.
  3. You have a dev environment setup (I'm using wamp).
  4. You have a LiveReload plugin installed for your browser (firefox extension, chrome extension).
  5. You know how to use the command line, install node and bower packages and can run a gulp task from it.

1. Includes:

var gulp       = require('gulp');
var beep       = require('beepbeep')
var gutil      = require('gulp-util');
var plumber    = require('gulp-plumber');
var uglify     = require('gulp-uglifyjs');
var sass       = require('gulp-ruby-sass');
var livereload = require('gulp-livereload');

Here we include all our dependencies for use in our gulp file.

2. Error handling:

var onError = function (err) {
    beep([0, 0, 0]);
    gutil.log(gutil.colors.green(err));
};

Here we declare a simple error handling function. This function will create three system beeps on error and also log the error message with some basic text highlighting for easier reading.

3. Our JS task:

// JS
gulp.task('uglifyjs', function() {
    return gulp.src([
        './bower_components/jquery/dist/jquery.min.js',
        './js/main.js'
    ])
    .pipe(plumber({
        errorHandler: onError
    }))
    .pipe(uglify('app.js', {
        compress: false
    }))
    .pipe(gulp.dest('./js/'))
    .pipe(livereload());
});

We are using uglifyjs (instead of concat and uglify) because it is simpler to use. Note that plumber needs to be the first pipe. We attached our error handler so in case we make a JS error ;) we will hear three beeps and our gulp process doesn't just break. After our plumber pipe we do the minification and at very last we attach a livereload pipe so that we don't have to manually refresh our browser.

4. Our Sass task:

// Sass
gulp.task('sass', function() {
    return gulp.src([
        './scss/app.scss'
    ])
    .pipe(plumber({
        errorHandler: onError
    }))
    .pipe(sass({
        style: 'compressed',
        cacheLocation: './cache/.sass-cache'
    }))
    .pipe(gulp.dest('./css/'))
    .pipe(livereload());
});

Pretty much the same procedure as with the JS task. To note here is that we are using ruby-sass so that we can pass in the compressed argument and also a custom cache path (just keeps things cleaner). As with JS also attach plumber and livereload.

5. Our HTML task:

// HTML
gulp.task('html', function() {
    return gulp.src([
        './index.html'
    ])
    .pipe(livereload());
});

We don't minify our HTML, that is quite unnecessary unless you're building a static site. However, we definitely want to attach a livereload pipe as this markup is most probably the one piece of code we'll touch on very often (definitely don't want to refresh our browser manually for this).

6. Watch tasks:

// Primary task to watch other tasks
gulp.task('yo', function() {
    // LiveReload
    livereload.listen();
    // Watch JS
    gulp.watch('./js/main.js', ['uglifyjs']);
    // Watch Sass
    gulp.watch(['./scss/_mixins.scss', './scss/_styles.scss', './scss/app.scss'], ['sass']);
    // Watch HTML and livereload
    gulp.watch('./index.html', ['html']);
});

This is our primary (default) task. I called it "yo" because we're hip that way. Note that the very first thing needs to be the livereload.listen() command. For all the tasks we're watching we want to have livereload capabilities. The rest should be straight forward. Just watching certain files for changes and then running the tasks we specified above.

7. Build task:

// Manually build all
gulp.task('build', function() {
    gulp.start('uglifyjs', 'sass');
});

Last but not least, a build task. Why? Sometimes we just want to build without watching…

8. Putting it all together (gulpfile.js):

var gulp       = require('gulp');
var beep       = require('beepbeep')
var gutil      = require('gulp-util');
var plumber    = require('gulp-plumber');
var uglify     = require('gulp-uglifyjs');
var sass       = require('gulp-ruby-sass');
var livereload = require('gulp-livereload');
var onError = function (err) {
    beep([0, 0, 0]);
    gutil.log(gutil.colors.green(err));
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////
//////////     WEBSITE TASKS
//////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// JS
gulp.task('uglifyjs', function() {
    return gulp.src([
        './bower_components/jquery/dist/jquery.min.js',
        './js/main.js'
    ])
    .pipe(plumber({
        errorHandler: onError
    }))
    .pipe(uglify('app.js', {
        compress: false
    }))
    .pipe(gulp.dest('./js/'))
    .pipe(livereload());
});
// Sass
gulp.task('sass', function() {
    return gulp.src([
        './scss/app.scss'
    ])
    .pipe(plumber({
        errorHandler: onError
    }))
    .pipe(sass({
        style: 'compressed',
        cacheLocation: './cache/.sass-cache'
    }))
    .pipe(gulp.dest('./css/'))
    .pipe(livereload());
});
// HTML
gulp.task('html', function() {
    return gulp.src([
        './index.html'
    ])
    .pipe(livereload());
});
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////
//////////     WATCH AND BUILD TASKS
//////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Primary task to watch other tasks
gulp.task('yo', function() {
    // LiveReload
    livereload.listen();
    // Watch JS
    gulp.watch('./js/main.js', ['uglifyjs']);
    // Watch Sass
    gulp.watch(['./scss/_mixins.scss', './scss/_styles.scss', './scss/app.scss'], ['sass']);
    // Watch HTML and livereload
    gulp.watch('./index.html', ['html']);
});
// Manually build all
gulp.task('build', function() {
    gulp.start('uglifyjs', 'sass');
});

To run our setup all we need to do is run:

cd /path/to/project/ gulp yo

After that we open Chrome or Firefox and hit the LiveReload button so that our LiveReload server does its job. Happy coding! :) That's it, hope it helps! It surely makes my life a whole bunch easier. For more info check out the project or go to github.