Monday 21 July 2014

Grunt & Gulp – an overview

Furthering my journey into JavaScript up to now I have not had much interaction with JS task/build systems so to remedy that I recently attended a DoLess workshop on Grunt & Gulp to discover what they were all about.

Most often people associate both Grunt & Gulp with building systems but they are not restrict to that and both can form part of the of a front end dev’s day to day development process being able to run tests & reload html when altered, etc

Similarities

Grunt & Gulp are actually very similar:

  • Both use Node.js to provide their functionality
  • Installed via NPM & need both a global and project specific install
  • Have a plugin eco-system
  • Their configuration files are valid JavaScript
  • Configuration consists of “Tasks”

One other gotcha that I ran into with both Grunt & Gulp is that for them to work with a project you must have a package.json file, if you don’t have that file then when you install plugins (via NPM) even though the plugin is on disk and included in your config neither system will actually use it as it won’t be listed in the package.json.

Tasks

Both systems revolve around tasks, they are the building blocks used to allow you to create complex transformations by combining the simple tasks and chaining the results together.

Most tasks will use a plugin and the plugin eco-systems for both systems are growing all the time, providing functionality for you out of the box like minification, linting, testng, etc and if there isn’t a plugin for what you need you are able to create your own custom tasks by writing JavaScript to do whatever you need.

As part of development flow

Both systems are not restricted to simply being used for building they can be used as part of the development work flow.

One of the simplest “flows” is using a task to host the “site”, such as connect, and a watch task to look for changes which uses livereload to refresh the browser so you can see your changes as you make them.

Differences

 

Grunt

Grunt stores its instructions in a GruntFile.js and although it is a valid JavaScript file for the most part it reads more like configuration rather than code:

   1:  module.exports = function(grunt) {
   2:   
   3:    grunt.initConfig({
   4:          uglify: {
   5:              build: {
   6:                  files: {
   7:                      'js/app.js': ['js/lib/jquery.min.js', 'js/accordion.js']
   8:                  }
   9:              }
  10:          }
  11:    });
  12:   
  13:    grunt.loadNpmTasks('grunt-contrib-uglify');
  14:   
  15:    grunt.registerTask('default', ['uglify']);
  16:   
  17:  };

Grunt processes its tasks in a sequential manner and executes them in the order that you have specified. In the sample above the there is only one task, uglify, but you’ll notice a default task is defined this is used when you execute grunt without specifying a task.

You may want to run multiple tasks and can do this easily by registering a task which then executes multiple other tasks by passing a string array of task names as the second parameter to the registerTask function e.g.

grunt.registerTask(‘default’,[‘qunit’,‘sass’,‘uglify’]); 

Grunt works with files which can cause a bottleneck since if a task transforms a file e.g. uglify, then the next task will not start until the resulting file has been written to disk.

Due to the fact that Grunt processes each task sequentially (although there is a plugin that will allow you to run tasks concurrently with some caveats) you can build up complex flows with each item working with the output of the previous one.

One thing Grunt also supports is the ability to have tasks in there own separate files which can be combined together. This allows you isolate the tasks and keep the overall file size down making it easier to manage and maintain the tasks as your scripts grow and become more complex.

You can find more information and a larger example of a gruntfile here.

Gulp

Gulp stores its instructions in a GulpFile.js and it reads more like code than configuration:

   1:  var gulp = require('gulp');
   2:   
   3:  var uglify = require('gulp-uglify');
   4:  var concat = require('gulp-concat');
   5:   
   6:  gulp.task('build', function() {
   7:      return gulp
   8:      .src(['js/lib/jquery.min.js','js/*.js'])
   9:      .pipe(concat('app.js'))
  10:      .pipe(uglify())
  11:      .pipe(gulp.dest('.'));
  12:  });
  13:   
  14:  gulp.task('default',['build']);

Gulps main difference from Grunt, as far as I can tell, is that it works with streams which means that the contents of a file are worked on in memory and then streamed to the next task.

One big advantage of this is speed since nothing is written to disk until all the tasks have been completed, and if you forget to pipe to gulp.dest then it won’t even make it to disk!

Gulp processes its tasks asynchronously which means that if you specify multiple tasks to be run it will not guarantee the order that the tasks run in, there is a library you can download called run-sequence which will execute task in a specific sequence allowing you to wrap the tasks

Gulps tasks look nothing like most Grunt tasks since they are JavaScript functions and the plugins themselves are simply called as a function, in the example above you can see that the input to a pipe method takes the return from the concat method which we get via require.

One additional thing you are able to do with Gulp is to pass other tasks as parameters, so if you need another specific task to run before the current task you pass the name in the task definition e.g.

gulp.task('build',['clean'], function(cb) {…}

In this example the clean task has to complete before the build task will run, a note of caution as currently if you pass multiple tasks you cannot guarantee the order they will execute it.

You can more information about Gulp and a larger gulpfile example here.

Summary

Both of these systems will provide you a multitude of functionality ranging from simple minification through to use in day to day development.

Currently Grunt feels to me slightly more mature with a bigger range of plugins available but due to its architecture it will always execute more slowly than Gulp.

There is a Visual Studio extension called Grunt Launcher, the name is slightly misleading as it also works with Gulp & Bower, which will allow you to launch tasks from inside Visual Studio simply by right clicking the file.

Hopefully this overview has given you an insight into the two tools whether you simply wanted to know what all the fuss was about or you have some understanding if you intend to pick them up and use them.

No comments:

Post a Comment