24 Feb 2015

My Gulp Workflow

Meeting Gulp for the first time.

Around a year ago I started my new job as a front-end developer and I was introduced to Gulp by a colleague, I had a basic understanding of Gulp (I knew what it was and what it did) and I was keen to try it but never really got round to actually sitting down and looking at it. The first front-end project I worked on, I was given basic instructions on how to setup the project:

npm install && bower install && gulp watch

This was a new world for me, I usually just dragged my project folder in to Prepros and wrote some Scss or LESS. Instantly I felt like Gulp was complicated and over the top just to compile some Scss but I stuck it out. I was aware that it did other things but I didn’t really notice it until later on in the project when I began to realise it did some other pretty cool shit like minifying the JS, compressing images and some other stuff and I was pretty impressed by that. I started using Gulp out of the office and experimenting with different things and I’m at a point now where I couldn’t start a project without it (this may change in the future) and I really mean that.

What is Gulp?

I’ll give you a short intro to Gulp as there is thousands of articles over the web that can explain this 10x better than I can. Gulp is a build system that runs from the command line. You can create multiple tasks by adding Javascript to a gulpfile.js file, you can create tasks like: compiling Sass/Stylus/Scss/LESS to CSS, minifying JS, compressing images, livereload and literally anything else.

The packages I use.

I have a pretty simple workflow when it comes to Gulp as I feel many front-end developers do too and even though I started off thinking that this process was complicated and overwhelming it’s really not. So below is my package.json file, the file that you include your packages in for Gulp to use when you create your tasks. I’ll run you through it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "name": "lifes-good",
  "version": "0.0.0",
  "description": "my jekyll",
  "main": "gulpfile.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Joe Richardson",
  "devDependencies": {
    "browser-sync": "^2.0",
    "gulp": "^3.8.8",
    "gulp-autoprefixer": "^1.0.1",
    "gulp-imagemin": "^2.2.0",
    "gulp-less": "~2.0.1",
    "gulp-minify-css": "^0.4.5",
    "gulp-notify": "^2.2.0",
    "gulp-rename": "^1.2.0",
    "gulp-uglify": "^1.1.0",
  }
}

We include gulp, browser-sync, gulp-less, gulp-autoprefixer, gulp-minify-css, gulp-rename, gulp-notify, gulp-uglify and gulp imagemin — The names are pretty self explanatory.

If you’re new to this then I doubt that makes much sense but I’ve basically just told you individually what the package does and if you want to learn more on how to create tasks then check out the Gulp documentation.

Gulp setup

Now I’m going to run you through my gulpfile.js — see below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
var gulp         = require('gulp');
var browserSync  = require('browser-sync');
var less         = require('gulp-less');
var autoprefixer = require('gulp-autoprefixer');
var minifyCSS    = require('gulp-minify-css');
var notify       = require('gulp-notify');
var gutil        = require('gulp-util');
var cp           = require('child_process');
var path         = require('path');
var uglify       = require('gulp-uglify');
var imagemin     = require('gulp-imagemin');
var pngquant     = require('imagemin-pngquant');


var messages = {
    jekyllBuild: '<span style="color: grey">Running:</span> $ jekyll build'
};

/**
 * Build the Jekyll Site
 */
gulp.task('jekyll-build', function (done) {
    browserSync.notify(messages.jekyllBuild);
    return cp.spawn('jekyll', ['build'], {stdio: 'inherit'})
        .on('close', done);
});

// minifiy js
gulp.task('compress', function() {
  gulp.src('js/*.js')
    .pipe(uglify())
    .pipe(gulp.dest('js/min'))
});

// minifiy images
gulp.task('images', function () {
    return gulp.src('images/*')
        .pipe(imagemin({
            progressive: true,
            svgoPlugins: [{removeViewBox: false}],
            use: [pngquant()]
        }))
        .pipe(gulp.dest('images'));
});

// compile LESS
gulp.task('less', function () {
  gulp.src('_less/main.less')
    .pipe(less({
      paths: [ path.join(__dirname, '_less', 'includes') ]
    }))
    .pipe(less({compress: true}).on('error', gutil.log))
    .pipe(autoprefixer('last 10 versions', 'ie 9'))
    .pipe(minifyCSS({keepBreaks: false}))
    .pipe(gulp.dest('css'))
    .pipe(notify('Less Compiled, Prefixed and Minified'));
});

// Watch files
gulp.task('watch', function () {
    gulp.watch('_less/**/*.less', ['less']);
    gulp.watch(['index.html', '_layouts/*.html', '_posts/*', '**/*.html', '_less/**/*.less', 'js/**/*', 'images/*'], ['jekyll-rebuild']);
});

gulp.task('default', ['browser-sync', 'images', 'watch', 'compress']);

I run my portfolio on Jekyll and use Gulp to build the static pages whilst running other tasks too. So above I have a pretty big gulpfile.js that runs 6 tasks which are:

  1. Building the Jekyll files
  2. Minifying the Javascript
  3. Compressing the Images
  4. Compiling LESS and running a few ‘sub tasks’ like autoprefix and to notify me when its compiled.
  5. Watch any files that are changed (eg. _posts/*)
  6. The last task is your default task that runs the 5 tasks above. We can achieve this by writing ‘Gulp’ in our terminal.

Gulp

As you can see that runs my tasks, build my sites and gives me a link to view my site from.

Fin.

Feel free to take these two code snippets and play around with them. I'd reccomend experimenting with different packages and even looking in to Grunt too and see which you prefer. I hope this article helps and please feedback if something doesn't make sense or I've got something wrong.

Thanks <3.

EDIT: I made a Gulp Starter Kit for anybody who is interested. Also some good discussions about this post here & here.