Blog & News

Articles, insights and thinking from software development vendor

Build tools review: gulp, grunt or else?

Build tools for frontend-developers saves time by automating such routine tasks as compilation, testing, etc. There are dozens of such tools, while competition between them is really strong. Before 2014, Grunt was leading. Later, Grunt's team split to create another task runner. This new tool was Gulp, aimed to automate the project building process.

Which task runner is better? To help you with your decision, let’s look at the most popular task managers out there:

Gulp
Grunt
(We’ll review other tools and methods as well.)

Task runners vs. build tools: what’s the difference?

Task runner or task manager is the task automation tool. In task manager’s configuration you can write task names, functions, and plugins for task automation. However, these tasks can vary. For example:

Deploy tasks (zip of the project, upload of the project, etc)
Build tasks (minification, optimization, validation of the code)
Data migration tasks, etc.
The most well-known task managers out there right now are grunt and gulp. Every frontend task like that can be also automated my other means: for example, by npm run.

Build automation system is a tool aimed only for javascript project build processes, for tasks like:

concatenation,
validation,
minification, etc.
They are the tools like Webpack, Broccoli, Brunch, Browserify, etc.

Example

This is a gulpfile for project build:

const gulp = require (‘gulp’);
const coffee = require (‘gulp-coffee’);
const concat = require (‘gulp-concat’);
const uglify = require (‘gulp-uglify’);
const imagemin = require (‘gulp-imagemin’);
const sourcemaps = require (‘gulp-sourcemaps’);
const del = require (‘del’);
}
However, the build is a particular case of some bigger task. You can create gulpfile for other tasks, for example, the deploy config:

var gulp = require('gulp');
var zip = require('gulp-zip');
var del = require('del');
var install = require('gulp-install');
var runSequence = require('run-sequence');
var awsLambda = require("node-aws-lambda");

gulp.task('clean', function(cb) {
del(['./dist', './dist.zip'], cb);
});

gulp.task('copy', function() {
return gulp.src('index.js')
.pipe(gulp.dest('dist/'));
});

gulp.task('node-mods', function() {
return gulp.src('./package.json')
.pipe(gulp.dest('dist/'))
.pipe(install({production: true}));
});

// Clean up all aws-sdk directories from node_modules. We don't
// need to upload them since the Lambda instance will already
// have it available globally.
gulp.task('clean-aws-sdk', function(callback) {
del(['dist/node_modules/**/aws-sdk'], callback);
});

gulp.task('zip', function() {
return gulp.src(['dist/**/*', '!dist/package.json'])
.pipe(zip('dist.zip'))
.pipe(gulp.dest('./'));
});

gulp.task('upload', function(callback) {
awsLambda.deploy('./dist.zip', require("./lambda-config.js"), callback);
});

gulp.task('deploy', function(callback) {
return runSequence(
['clean'],
['copy'],
['node-mods'],
['clean-aws-sdk'],
['zip'],
['upload'],
callback
);
});
You can also describe the new tasks like the combination of previously created tasks:

gulp.task(‘deploy’,
gulp.series (‘clean’, ‘copy’, ‘node-mods’, ‘clean-aws-sdk’, ‘zip’, ‘upload’)
);
This is the main difference.

gulp vs. grunt

Let’s now review the most popular task runners. They both use node.js and npm, and you need javascript to create tasks for them.

grunt
This is a task-runner developed in 2012. Today it offers more than 11 thousands of plugins.

gulp
This is a streaming build system developed after grunt. Offers about 4 thousands plugins.


They seem to be overlapping each other’s aims, however, gulp can offer something that makes this tool especially comfortable for the building of a project. It’s configuration is more compact, it can stream files, and it’s API consists of only 5 methods. Let’s compare a gulpfile with a gruntfile.

Streaming

Here’s gruntfile. It processes CSS-files:

Gruntfile

You can see from the gruntfile that grunt:

Opens a file;
Starts a process;
Writes files in a temp folder;
Closes a processed file to prevent the next process from changing it;
Saves the file into the output folder.
So the chain includes creating several temporary folders:

Blog Img 6

Why does this happen? Plugins are developed by different authors. To enable every plugin to work with the files without writing them into temporary folders, the files should be represented as objects. In gulp, this is performed by using special virtual filing system - Vynyl-FS. So, gulp instantly passes a file to the next process without writing it into a temp directory.

That’s why the same configuration for gulp is more consice.

Gulpfile

It streams files without writing them, directly into the file system:

Blog Img 7

The sequence of tasks

There is another difference: gulp runs all tasks asynchronously by default. It can be seen both as an advantage, and disadvantage.

This is a streaming what makes gulp so fast and powerful for build tasks, however, sometimes you need running tasks synchronously like grunt does. The problem is solved by callback:

gulp.task('sync', function (cb) {
// setTimeout может быть асинхронной задачей
setTimeout(function () {
cb();
}, 1000);
});
There are other solutions, for example, at NPMjs.

API

Gulp API is short and easy to handle, with only five methods:

.stream() – Typically, Gulp will pass (but never cross) a “stream” of files through plugins, which transforms the files in some way. Streams are handled by Node.
.pipe() – If you’re familiar with the command line, you may already know about the vertical bar | (aka “pipe”). This doohickey is used to pass the output of one command to the input of another. The same thing is accomplished via the .pipe() method. This occurs in the stream.
.task() – Defines a task which executes either an anonymous or callback function.
.src() – Creates a stream of files.
.dest() – Writes the stream to a file on a hard disk.
It’s good to have the .watch() in the project’s native API, because it’s very important to notice how the files change while building a project. Shortness of the API helps gulp to focus on its main aim of build automation.

Gulp/grunt. What else?

Despite the popularity of gulp and grunt, some developers find several disadvantages in these tools. For example, the dependency on plugins, fragment documentation, or frustrating debugging. They offer several alternatives: build systems, (Broccoli, Webpack) or npm-scripts.

Project build systems

Let’s review some Node.js-based solutions that can be as useful as gulp/grunt for project building.

Brunch

This system, like gulp, itself was designed to compete with grunt, however, the developers wanted to create not a task-runner, but just a build tool, with all its advantages and disadvantages. Brunch will recognize that *.js file contains scripts, and that *.coffee is CoffeScript, it’s configuration file is shorter. However, it’s not designed for any free tasks other than building of a project.

Here’s Brunch config. It is written on CoffeeScript (JS is also allowed):

exports.config =
files:
javascripts:
joinTo:
'javascripts/app.js': /^app/
'javascripts/vendor.js': /^(bower_components|vendor)/
stylesheets:
joinTo: 'stylesheets/app.css'
order:
after: ['vendor/styles/helpers.css']
templates:
joinTo: 'javascripts/app.js'
Look at joinTo and order operators. Brunch recognizes them on a config level, and will build them in a needed sequence. The config will be no more than 20-30 lines long.

Broccoli

This indi-tool is still being developed. Their developers wanted to compete with gulp. Compared to gulp, Broccoli.io is based on other principles:

Build acceleration. Each plug-in implements intermediate caching of assembly results instead of partial rebuilding.
Dependence trees. Gulp is better at transforming a file in a single output. Broccolli uses file trees by default instead of files, and transforms them.
Today the tool is being developed actively, new plugins are being implemented, however, it’s too early to say that it is ready to be used in big projects due to a lack of important plugins.

Webpack

Webpack is a flexible modular build system. It has an unusual syntax, but it recognizes any syntaxes of modules. In an attempt to compete with such big players like gulp/grunt, the developers added in Webpack several features to ease the pain of building big projects:

The ability to automatically build a dependency tree
Convenient means for implementing dynamic loading.
Compatibility with almost any modules (AMD, UMD, ES 2015, Common JS, third-party modules based on them).
Compatibility with preprocessors (SASS, Babel, Coffee Script, Type Script, etc.).
Live Reload (the technology of asynchronous download, in which the browser does not update the entire page, but individual applications).
The ability to share code and generate many bundle files, avoiding the creation of a single heavy bundle.js.
The ability to optimize the code.
Note a flexible approach to dependencies. Any file can become a module, including JS, CSS, HTML, JPEG, PNG. You can use require(“myJSfile.js”) and require(“myCSSfile.css”) divide and use artifact’s part again.

npm scripts

Npm scripts can also help you in project building. You even can leave task runners for npm scripts with almost no loss in performance.

Are npm-scripts powerfull?

Npm scripts can run several tasks. For example, any script that can be executed as a set of pre- and post- hooks:

{
"name": "npm-scripts-example",
"version": "1.0.0",
"description": "npm scripts example",
"scripts": {
"prebuild": "echo I run before the build script",
"build": "cross-env NODE_ENV=production webpack"
"postbuild": "echo I run after the build script"
}
}
Scripts will be run according their prefixes: prebuild, will be run before build, while postbuild script will be run the last..

You can also decompose complex tasks:

{
"name": "npm-scripts-example",
"version": "1.0.0",
"description": "npm scripts example",
"scripts": {
"clean": "rimraf ./dist && mkdir dist",
"prebuild": "npm run clean",
"build": "cross-env NODE_ENV=production webpack"
}
}
If the task becomes too complex, just run a single file:

{
"name": "npm-scripts-example",
"version": "1.0.0",
"description": "npm scripts example",
"scripts": {
"build": "node build.js"
}
}
Gulp became more popular because of streaming. However, streaming is default both in Windows and Unix. In Unix, you can grep file’s content and redirect it into a new file:

grep ‘My Name’ bigFile.txt > linesThatHaveMyName.txt
Redirect(>)will send the result into an output file without saving temporary files, like in gulp.

However, there are some disadvantages: you can’t comment in package.json. You can resolve this problem by creating small scripts with clear names, aimed to perform single tasks. If you are interested in using nmp scripts in your automation process, read more: Why I Left Gulp and Grunt for npm Scripts.

Summary

There’s significant competition between different ways to automate your routine frontend tasks. They are both task managers that give your tasks more freedom (like gulp/grunt), and the tools that just automate a single task (Webpack, Browserify, etc).

In the terms of task automation tools, gulp is simpler and more powerful than grunt, it is also faster. Grunt however offers more plugins (for example, the unique plugin for running tests). Gulp beats grunt when you need to build your frontend project

The streaming provided by the Vynyl-FS module.
Asynchronous tasks performance.
Clear API with only 5 methods.
In the terms of build automation tools, Webpack is no less powerful than grunt. It also offers Live Reload technology, however, it doesn’t allow to automate any free tasks.

WeveAccess specialists prefer gulp. It is very simple to integrate it into every project: we use JetBrains products(IDEA, WebStorm, ReSharper) which offer well-done plugins for gulp/grunt and npm/nodejs integration.

Order a phone call

Convenient time to call:

Cancel

Get in touch

Attach
Your file up to 30 mb
Cancel