For the current moment build systems are the inseparable part of any Front-End project. They allow to automate project’s assembling, compilation, minification, files’ linting, to start Unit-tests and much more. In February 2013 one of the most stable and popular build systems was born - Grunt. Grunt is command-line based instrument for assembling the projects, relying on consecutive tasks execution. Definition of this task should be done in a specific file Gruntfile.js, which should be a valid js file. From the first day of the release quantity of plugins for it increased and now this number is around 2000+. In many articles it is mentioned that to write Grunt’s plugin is easier than to read it and it is so. To be able to make configuration file all you need is to read documentation where you can find templates ready to injection into your project. However, grasping already configured one can be tricky. Just imagine - you start working with a Grunt project that contains 20+ plugins, and all of them are in a mutual dependency and should be executed in some order. One of the simplest configurations is provided below.
module.exports = function(grunt) {
grunt.initConfig({
concat: {
'dist/all.js': ['src/*.js']
},
uglify: {
'dist/all.min.js': ['dist/all.js']
},
jshint: {
files: ['gruntfile.js', 'src/*.js']
},
watch: {
files: ['<%= jshint.files =>'],
tasks: ['jshint', 'concat', 'uglify']
}
});
// Load Our Plugins
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
// Register Default Task
grunt.registerTask('default', ['jshint', 'concat', 'uglify']);
};
Although, when the application grows your configuration file may become more like this. It’s very easy to understand, isn't it? The performance is probably a bottle-neck of Grunt. When the Grunt was released no-one was thinking about multi-threading, caching and other methods for speeding up assembling. However, the biggest problem is in multithreaded data-processing. Usually one actions order is connected to the same database but grunt knows nothing about this and uses separate in/out thread for each task (each time reads files, executes for them some operation, saves results back to the hard-drive). This situation happens for each task, thus we are wasting a lot of resources when we could be using only one thread for all the tasks. At the moment some attempts are made to provide multithreading for Grunt (grunt-concurrent) and to use caching (grunt-newer), but it looks more like crutches than a good coding solution. Recently new build-system was released - gulp.js, that occurs to be a right alternative to Grunt. what is the main difference? Gulp is build on thread-based conception of data-processing. It allows to avoid temporary files/folders and to flush information to hard-drive. All operations are executed in operative memory, thus a process can become 10 times faster. Unlike Grunt you should set src only for tasks that will use concrete files allowing to execut file in/output only once which makes it faster. Gulp uses multi-threading as default mode, so all tasks will be running in separate threads. Configuration should be done according to CommonJs so it is easier to read and understand. Here is an example of the same configuration but for Gulp.
var gulp = require('gulp');
var jshint = require('gulp-jshint');
var concat = require('gulp-concat');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
// Lint & Concat & Minify JS
gulp.task('build_js', function(){
gulp.src('./src/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'));
.pipe(concat('all.js'))
.pipe(gulp.dest('./dist'))
.pipe(rename('all.min.js'))
.pipe(uglify())
.pipe(gulp.dest('./dist'));
});
// Default
gulp.task('default', function(){
gulp.run('build_js');
// Watch JS Files
gulp.watch("./src/*.js", function(event){
gulp.run('build_js');
});
});
As you may have noticed, the configuration file is based on pipeline in the best Unix-traditions. Configuration Gulp file.js is accurate and readable due to a good-structured source code. As to the existing plugins Gulp still looses Grunt in their quantity, but this situation won’t last long. There are 200 plugins for Gulp and this number increases. There is a plugin for porting Grunt plugins to Gulp (gulp-grunt), which allows running the Grunt plugins in the Gulp projects. It’s hard to predict Grunt development in the future. According to the latest gossips developers are going to improve performance of Grunt, but on my opinion it is dying, and problem is not in quality of this product, but in architecture that won’t give it a possibility to compete with other more modern systems. Gulp is a breath of fresh air in modern build systems. I do like direction and development speed of this project, and hope that it will replace Grunt afterwards.