Web Design that taps into the haromny and vision of your dreams.

Getting started with Gulp

By on in HTML/CSS

1,776 words, estimated reading time 9 minutes.

Gulp is a tool which most web developers have heard of, but few know what it actually does. In this article, we will discover how we can be more productive by automating repetitive tasks.

Gulp is a task runner written in Javascript which automates most, if not all, the tedious tasks web developers traditionally. 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 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 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 directory to your project folder and install gulp to the project. This will install the modules and packages we will be using as well as creating 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 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

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

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

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 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.

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.

$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 we can upload to our web server.

This goes in after the default task.

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 completed, the folder dist/assets/css should contain a file called main.css. This will have the pure 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:

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.

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.

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 the 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.

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 to 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.

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.

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

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

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.

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.

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

Gulp Live Reload

One of the most powerful features of Gulp 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 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.

[storeicons mozilla="https://addons.mozilla.org/en-US/firefox/addon/livereload-web-extension/" chrome="https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei/related"]

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

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.

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!

Last updated on: Thursday 21st December 2017

 

Comments

Have a question or suggestion? Please leave a comment to start the discussion.

 

Leave a Reply

Please keep in mind that all comments are moderated according to our privacy policy, and all links are nofollow. Do NOT use keywords in the name field. Let's have a personal and meaningful conversation.

Your email address will not be published.