Getting Started with Javascript Gulp Task Runner

Javascripts Gulp Task Runner helps you be productive by automating build tasks like SCSS, image processing and minificaion.

By Tim Trott | (Java|Type)Script / jQuery | June 19, 2015
1,827 words, estimated reading time 7 minutes.

Gulp is a Javascript Task Runner which automates most, if not all, the tedious tasks web developers traditionally do. Gulp lets you automate tasks such as bundling and minifying libraries and stylesheets, Less/Sass to CSS compilation, compressing and optimising images, copying modified files to an output directory and it can even reload the browser window when files are changed.

The Gulp Task Runner Workflow

Gulp works using tasks. Each task takes in a set of files which are loaded into the Gulp stream to be processed. Each file is then processed and sent to the destination file. A simple input, process, output workflow.

Tasks can also be chained together so that a file can be processed, then another action can be performed before it is written to the output.

Installing Gulp Task Runner via NPM and Grunt

Grunt can easily be installed using the Node.js Package Manager. If you do not have it installed already, head over to the npm website  where you can download and install it.

Gulp is installed globally, and also into your project. Global installation is only required once.

npm install gulp -g

Next, we need to change the directory to your project folder and install gulp on the project. This will install the modules and packages we will be using as well as create the default project settings.

If you are creating a new project you will first need to run the node init command to create files and folder structures.

cd webproject1
npm init

Then you can install gulp into the project.

npm install gulp --save-dev

Installing Gulp Task Runner Plugins

Next, we need to install a few plugins which we will be using in our tasks. Here I will just install some of the basic and most frequently used plugins. You can find a list of all the available plugins for Gulp  here.

These can all be installed on the command line using npm.

npm install gulp-ruby-sass gulp-autoprefixer gulp-cssnano jshint gulp-jshint gulp-concat gulp-uglify gulp-imagemin gulp-notify gulp-rename gulp-livereload gulp-cache gulp-htmlmin del --save-dev

Creating a gulpfile to Manage Tasks

Next, we need to create a gulpfile.js and load in the plugins. The gulpfile is a plain javascript file.

javascript
var gulp = require('gulp'),
    sass = require('gulp-ruby-sass'),
    autoprefixer = require('gulp-autoprefixer'),
    cssnano = require('gulp-cssnano'),
    jshint = require('gulp-jshint'),
    uglify = require('gulp-uglify'),
    imagemin = require('gulp-imagemin'),
    rename = require('gulp-rename'),
    concat = require('gulp-concat'),
    notify = require('gulp-notify'),
    cache = require('gulp-cache'),
    livereload = require('gulp-livereload'),
    htmlmin = require('gulp-htmlmin'),
    del = require('del');

This is a pretty standard header for the file, as you can see it simply loads in the plugin files. Feel free to change this accordingly. If you don't intend on using a plugin you can comment it out or delete the line.

Windows users will also need to install Ruby  as well as the sass gem.

Creating Tasks in Gulp Task Runner

Next, we need to create a few tasks, since that is the whole point of the exercise. A Task takes in a source file, runs an action on the contents of the file then outputs the result, either to another plugin or to a file.

We must first create a default task in which gulp runs automatically. This task will launch all the other tasks we define.

In this example, we will transform a source SCSS stylesheet into a CSS file for distribution.

This code goes into the gulpfile.js after the plugins.

javascript
gulp.task('default', function() {
    gulp.start('styles');
});

I'm going to create a very basic SCSS file in src/styles/main.scss with the following contents.

scss
$font-stack:    Helvetica, sans-serif;
$primary-color: #333;

body {
  font: 100% $font-stack;
  color: $primary-color;
}

Next, I'm going to create the task to transform this into CSS so we can upload it to our web server.

This goes in after the default task.

javascript
gulp.task('styles', function() {
  return sass('src/styles/main.scss', { style: 'expanded' })
    .pipe(gulp.dest('dist/assets/css'));
});

All this is going to do is transform the SCSS into CSS.

We can run gulp by simply running the command gulp in the command line in the project folder.

Once it has been completed, the folder dist/assets/css should contain a file called main.css. This will have pure CSS.

css
body {
  font: 100% Helvetica, sans-serif;
  color: #333;
}

Now we will leverage some of the power of gulp and chain some plugins together to further transform this file. We will automatically add vendor prefixes to CSS properties, minify the output, rename the output file and show a message in the console when the command is complete. This is useful when lots of tasks are to be run so you know what is being run.

We can modify our styles task to include the following:

javascript
gulp.task('styles', function() {
  return sass('src/styles/main.scss', { style: 'expanded' })
    .pipe(autoprefixer('last 2 version'))
    .pipe(gulp.dest('dist/assets/css'))
    .pipe(rename({suffix: '.min'}))
    .pipe(cssnano())
    .pipe(gulp.dest('dist/assets/css'))
    .pipe(notify({ message: 'Styles task complete' }));
});

Now when we run gulp, we will see a main.min.css has been generated, with the minified CSS contents.

css
body{font:100% Helvetica,sans-serif;color:#333}

Now you may have noticed that we have a main.css and a main.min.css in the dist folder. It would be great if we could clear out old files each time gulp is run, so let's create a task for that.

javascript
gulp.task('clean', function() {
    return del(['dist/assets/css', 'dist/assets/js', 'dist/assets/img']);
});

Next, we need to modify the default task to include a clean task. We will add clean as a dependency since we want it to always run before anything else. This is done by adding an array as the second argument.

javascript
gulp.task('default', ['clean'], function() {
    gulp.start('styles');
});

Now we can add a task to do the same thing for some Javascript. This will take all the javascript files in all subfolders, combine them into one file, minify, run jshint to validate the javascript code and finally write out main.js (unminifed) and main.min.js (minified) to the dest folder.

javascript
gulp.task('scripts', function() {
  return gulp.src('src/scripts/**/*.js')
    .pipe(jshint('.jshintrc'))
    .pipe(jshint.reporter('default'))
    .pipe(concat('main.js'))
    .pipe(gulp.dest('dist/assets/js'))
    .pipe(rename({suffix: '.min'}))
    .pipe(uglify())
    .pipe(gulp.dest('dist/assets/js'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

Again this task is added to the default task runner.

javascript
gulp.task('default', ['clean'], function() {
    gulp.start('styles', 'scripts');
});

The next task to add will be to optimise and copy images from our source folder to the assets folder.

javascript
gulp.task('images', function() {
  return gulp.src('src/images/**/*')
    .pipe(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true }))
    .pipe(gulp.dest('dist/assets/img'))
    .pipe(notify({ message: 'Images task complete' }));
});

This is OK if there are only a small number of images, but if your site has many images it is better to cache the results so that only modified images get reprocessed. This saves a lot of time during the build process. Again this task will take all images in all subfolders and output them to the dist/assets/img folder.

javascript
gulp.task('images', function() {
  return gulp.src('src/images/**/*')
    .pipe(cache(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true })))
    .pipe(gulp.dest('dist/assets/img'))
    .pipe(notify({ message: 'Images task complete' }));
});

Finally, no website would be complete without HTML, so we're going to take our HTML pages, minify them and copy them to the dist folder.

javascript
gulp.task('minify', function() {
  return gulp.src('src/*.html')
    .pipe(htmlmin({collapseWhitespace: true}))
    .pipe(gulp.dest('dist'));
});

Gulp Task Runner and Live Reload Plugin

One of the most powerful features of Gulp Task Runner is the ability to add file watchers. These will trigger when files are changed and automatically rebuild the output files and also refresh the browser window, meaning you change the code, save the file and automatically the browser refreshes with the new code.

To configure this we need to add a new task for a watch and install the browser plugin from LiveReload .

Download for Firefox  Download for Chrome 

javascript
gulp.task('watch', function() {
    gulp.watch('src/styles/**/*.scss', ['styles']);
    gulp.watch('src/scripts/**/*.js', ['scripts']);
    gulp.watch('src/images/**/*', ['images']);
    gulp.watch('src/*.html', ['minify']);
    
    livereload.listen();
    gulp.watch(['dist/**']).on('change', livereload.changed);
});

This will watch for any changes to styles, scripts, images and HTML and fire off the relevant task. If a file changes in the dist folder then it will fire off the browser reload.

To run the gulp watcher, just enter this command in the project folder.

gulp watch

Full Practical Example of Gulp Javascript Task Runner

Below is the full gulpfile.js which I use for most of my web templates. It should be more than enough to get you started.

javascript
var gulp = require('gulp'),
    sass = require('gulp-ruby-sass'),
    autoprefixer = require('gulp-autoprefixer'),
    cssnano = require('gulp-cssnano'),
    jshint = require('gulp-jshint'),
    uglify = require('gulp-uglify'),
    imagemin = require('gulp-imagemin'),
    rename = require('gulp-rename'),
    concat = require('gulp-concat'),
    notify = require('gulp-notify'),
    cache = require('gulp-cache'),
    htmlmin = require('gulp-htmlmin'),
    livereload = require('gulp-livereload'),
    del = require('del');

gulp.task('default', ['clean'], function() {
    gulp.start('styles', 'scripts', 'images', 'minify');
});

gulp.task('watch', function() {
    gulp.watch('src/styles/**/*.scss', ['styles']);
    gulp.watch('src/scripts/**/*.js', ['scripts']);
    gulp.watch('src/images/**/*', ['images']);
    gulp.watch('src/*.html', ['minify']);
    
    livereload.listen();
    gulp.watch(['dist/**']).on('change', livereload.changed);
});

gulp.task('clean', function() {
    return del(['dist/assets/css', 'dist/assets/js', 'dist/assets/img']);
});

gulp.task('styles', function() {
  return sass('src/styles/main.scss', { style: 'expanded' })
    .pipe(autoprefixer('last 2 version'))
    .pipe(gulp.dest('dist/assets/css'))
    .pipe(rename({suffix: '.min'}))
    .pipe(cssnano())
    .pipe(gulp.dest('dist/assets/css'))
    .pipe(notify({ message: 'Styles task complete' }));
});

gulp.task('scripts', function() {
  return gulp.src('src/scripts/**/*.js')
    .pipe(jshint('.jshintrc'))
    .pipe(jshint.reporter('default'))
    .pipe(concat('main.js'))
    .pipe(gulp.dest('dist/assets/js'))
    .pipe(rename({suffix: '.min'}))
    .pipe(uglify())
    .pipe(gulp.dest('dist/assets/js'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

gulp.task('images', function() {
  return gulp.src('src/images/**/*')
    .pipe(cache(imagemin({ optimizationLevel: 5, progressive: true, interlaced: true })))
    .pipe(gulp.dest('dist/assets/img'))
    .pipe(notify({ message: 'Images task complete' }));
});

gulp.task('minify', function() {
  return gulp.src('src/*.html')
    .pipe(htmlmin({collapseWhitespace: true}))
    .pipe(gulp.dest('dist'))
    .pipe(notify({ message: 'Minify task complete' }));
});

Do you use Gulp? Have you any helpful tasks we can add to the collection? Do you use another task runner? Let us know in the comments below!

Was this article helpful to you?
 

Related ArticlesThese articles may also be of interest to you

CommentsShare your thoughts in the comments below

If you enjoyed reading this article, or it helped you in some way, all I ask in return is you leave a comment below or share this page with your friends. Thank you.

There are no comments yet. Why not get the discussion started?

We respect your privacy, and will not make your email public. Learn how your comment data is processed.