Introduction to Gulp.js with practical examples

What is Gulp.js?

Gulp.js is what we call a JavaScript Task Runner, it is Open Source and available on GitHub. It helps you automate repetitive tasks such as minification, compilation, unit testing, linting, etc. Gulp.js does not revolutionize automation but simplifies it tremendously.

Today the Web automation ecosystem is dominated by Grunt.js (which is a great tool BTW) but lately Gulp.js is getting more trending and soon will be overtaking Grunt.js (according to the GitHub popularity, aka “stars”: 7900 for Grunt.js and 6250 for Gulp.js).

How is it better than Grunt or Cakefile?

I would say it is no better nor worse than Grunt or Cakefile, it is different. While Cakefile or Grunt use files to execute tasks, Gulp.js uses streams. It means that a typical Cakefile or Grunt workflow would be to execute a task that dumps a temporary file, than based on this file to execute another task that dumps another temporary file an so on…

With Gulp.js everything happens on the fly using Node’s stream, temporary files are not needed anymore which make it easy to learn, use and enjoy.

Installation

Use the -g options to install Gulp globally on your machine.

sudo npm install -g gulp

Practical examples

Now let’s use Gulp a little bit. Throughout those examples we will discover how to use plugins to create specific tasks such as minifying, concatenate or even linting your code.

Source available on Github

HTML Minification

Using gulp-minify-html

npm install --save-dev gulp-minify-html

gulpfile.js:

// including plugins
var gulp = require('gulp')
, minifyHtml = require("gulp-minify-html");

// task
gulp.task('minify-html', function () {
	gulp.src('./Html/*.html') // path to your files
	.pipe(minifyHtml())
	.pipe(gulp.dest('path/to/destination'));
});

Run:

gulp minify-html

CSS Minification

Using gulp-minify-css

npm install --save-dev gulp-minify-css

gulpfile.js:

// including plugins
var gulp = require('gulp')
, minifyCss = require("gulp-minify-css");

// task
gulp.task('minify-css', function () {
	gulp.src('./Css/one.css') // path to your file
	.pipe(minifyCss())
	.pipe(gulp.dest('path/to/destination'));
});

Run:

gulp minify-css

JS Minification

Using gulp-uglify

npm install --save-dev gulp-uglify

gulpfile.js:

// including plugins
var gulp = require('gulp')
, uglify = require("gulp-uglify");

// task
gulp.task('minify-js', function () {
	gulp.src('./JavaScript/*.js') // path to your files
	.pipe(uglify())
	.pipe(gulp.dest('path/to/destination'));
});

Run:

gulp minify-js

CoffeeScript Compilation

Using gulp-coffee

npm install --save-dev gulp-coffee

gulpfile.js:

// including plugins
var gulp = require('gulp')
, coffee = require("gulp-coffee");

// task
gulp.task('compile-coffee', function () {
	gulp.src('./CoffeeScript/one.coffee') // path to your file
	.pipe(coffee())
	.pipe(gulp.dest('path/to/destination'));
});

Run:

gulp compile-coffee

Less Compilation

Using gulp-less

npm install --save-dev gulp-less

gulpfile.js:

// including plugins
var gulp = require('gulp')
, less = require("gulp-less");

// task
gulp.task('compile-less', function () {
	gulp.src('./Less/one.less') // path to your file
	.pipe(less())
	.pipe(gulp.dest('path/to/destination'));
});

Run:

gulp compile-less

Sass Compilation

Using gulp-sass

npm install --save-dev gulp-sass

gulpfile.js:

// including plugins
var gulp = require('gulp')
, sass = require("gulp-sass");

// task
gulp.task('compile-sass', function () {
	gulp.src('./Sass/one.sass') // path to your file
	.pipe(sass())
	.pipe(gulp.dest('path/to/destination'));
});

Run:

gulp compile-sass

ECMAScript 6 Compilation

Using gulp-babel

npm install --save-dev gulp-babel

gulpfile.js:

// including plugins
var gulp = require('gulp')
, babel = require("gulp-babel");

// task
gulp.task('compile-es6', function () {
	gulp.src('./ES6/one.es6.js')
        .pipe(babel())
	.pipe(gulp.dest('path/to/destination'));
});

Run:

gulp compile-es6

JavaScript Linting

Using gulp-jshint

npm install --save-dev gulp-jshint

gulpfile.js:

// including plugins
var gulp = require('gulp')
, jshint = require("gulp-jshint");

// task
gulp.task('jsLint', function () {
	gulp.src('./JavaScript/*.js') // path to your files
	.pipe(jshint())
	.pipe(jshint.reporter()); // Dump results
});

In case of success:

[gulp] Starting 'jsLint'...
[gulp] Finished 'jsLint' after 6.47 ms

In case of failure:

[gulp] Starting 'jsLint'...
[gulp] Finished 'jsLint' after 5.86 ms
/var/www/gulp-examples/JavaScript/two.js: line 3, col 15, Expected '}' to match '{' from line 3 and instead saw '['.
/var/www/gulp-examples/JavaScript/two.js: line 3, col 16, Missing semicolon.
/var/www/gulp-examples/JavaScript/two.js: line 3, col 154, Expected an assignment or function call and instead saw an expression.

3 errors

Run:

gulp jsLint

CoffeeScript Linting

Using gulp-coffeelint

npm install --save-dev gulp-coffeelint

gulpfile.js:

// including plugins
var gulp = require('gulp')
, coffeelint = require("gulp-coffeelint");

// task
gulp.task('coffeeLint', function () {
	gulp.src('./CoffeeScript/*.coffee') // path to your files
	.pipe(coffeelint())
	.pipe(coffeelint.reporter());
});

In case of success:

[gulp] Starting 'coffeeLint'...
[gulp] Finished 'coffeeLint' after 7.37 ms

In case of failure:

[gulp] Starting 'coffeeLint'...
[gulp] Finished 'coffeeLint' after 6.25 ms

one.coffee
?  line 3  Line contains a trailing semicolon

? 1 error

Run:

gulp coffeeLint

Rename a file

Using gulp-rename

npm install --save-dev gulp-rename

gulpfile.js:

// including plugins
var gulp = require('gulp')
, rename = require('gulp-rename')
, coffee = require("gulp-coffee");

// task
gulp.task('rename', function () {
	gulp.src('./CoffeeScript/one.coffee') // path to your file
	.pipe(coffee())  // compile coffeeScript
	.pipe(rename('renamed.js')) // rename into "renamed.js" (original name "one.js")
	.pipe(gulp.dest('path/to/destination'));
});

Run:

gulp rename

Concatenate files

Using gulp-concat

npm install --save-dev gulp-concat

gulpfile.js:

// including plugins
var gulp = require('gulp')
, concat = require("gulp-concat");

// task
gulp.task('concat', function () {
	gulp.src('./JavaScript/*.js') // path to your files
	.pipe(concat('concat.js'))  // concat and name it "concat.js"
	.pipe(gulp.dest('path/to/destination'));
});

Run:

gulp concat

Add copyright

Using gulp-header

npm install --save-dev gulp-header

Copyright

/*
Gulp Examples by @julienrenaux:

* https://github.com/shprink
* https://twitter.com/julienrenaux
* https://www.facebook.com/julienrenauxblog

Full source at https://github.com/shprink/gulp-examples

MIT License, https://github.com/shprink/gulp-examples/blob/master/LICENSE
*/

gulpfile.js:

// including plugins
var gulp = require('gulp')
, fs = require('fs')
, concat = require("gulp-concat")
, header = require("gulp-header");

// functions

// Get copyright using NodeJs file system
var getCopyright = function () {
	return fs.readFileSync('Copyright');
};

// task
gulp.task('concat-copyright', function () {
	gulp.src('./JavaScript/*.js') // path to your files
	.pipe(concat('concat-copyright.js')) // concat and name it "concat-copyright.js"
	.pipe(header(getCopyright()))
	.pipe(gulp.dest('path/to/destination'));
});

Run:

gulp concat-copyright

Add copyright with version

Using gulp-header and Node’s file system

npm install --save-dev gulp-header

Copyright

/*
Gulp Examples by @julienrenaux:

* https://github.com/shprink
* https://twitter.com/julienrenaux
* https://www.facebook.com/julienrenauxblog

Version: <%= version %>
Full source at https://github.com/shprink/gulp-examples

MIT License, https://github.com/shprink/gulp-examples/blob/master/LICENSE
*/

Version

1.0.0

gulpfile.js:

// including plugins
var gulp = require('gulp')
, fs = require('fs')
, concat = require("gulp-concat")
, header = require("gulp-header");

// functions

// Get version using NodeJs file system
var getVersion = function () {
	return fs.readFileSync('Version');
};

// Get copyright using NodeJs file system
var getCopyright = function () {
	return fs.readFileSync('Copyright');
};

// task
gulp.task('concat-copyright-version', function () {
	gulp.src('./JavaScript/*.js')
	.pipe(concat('concat-copyright-version.js')) // concat and name it "concat-copyright-version.js"
	.pipe(header(getCopyrightVersion(), {version: getVersion()}))
	.pipe(gulp.dest('path/to/destination'));
});

Run:

gulp concat-copyright-version

Mix them up (Lint, Concat, Compile, Minify etc.)

The purpose of this task is to mix the previous tasks into just one.

Copyright

/*
Gulp Examples by @julienrenaux:

* https://github.com/shprink
* https://twitter.com/julienrenaux
* https://www.facebook.com/julienrenauxblog

Version: <%= version %>
Full source at https://github.com/shprink/gulp-examples

MIT License, https://github.com/shprink/gulp-examples/blob/master/LICENSE
*/

Version

1.0.0

gulpfile.js:

// including plugins
var gulp = require('gulp')
, fs = require('fs')
, coffeelint = require("gulp-coffeelint")
, coffee = require("gulp-coffee")
, uglify = require("gulp-uglify")
, concat = require("gulp-concat")
, header = require("gulp-header");

// functions

// Get version using NodeJs file system
var getVersion = function () {
	return fs.readFileSync('Version');
};

// Get copyright using NodeJs file system
var getCopyright = function () {
	return fs.readFileSync('Copyright');
};

// task
gulp.task('bundle-one', function () {
	gulp.src('./CoffeeScript/*.coffee') // path to your files
	.pipe(coffeelint()) // lint files
	.pipe(coffeelint.reporter('fail')) // make sure the task fails if not compliant
	.pipe(concat('bundleOne.js')) // concat files
	.pipe(coffee()) // compile coffee
	.pipe(uglify()) // minify files
	.pipe(header(getCopyrightVersion(), {version: getVersion()})) // Add the copyright
	.pipe(gulp.dest('path/to/destination'));
});

Run:

gulp bundle-one

Tasks automation

Using gulp.watch you can easily automate any tasks when files are modified. It is really convenient because you do not have to run single tasks by hand every time a file is modified, and therefore your code is always up to date.

// including plugins
var gulp = require('gulp');

// task
gulp.task('watch-coffeescript', function () {
    gulp.watch(['./CoffeeScript/*.coffee'], ['compile-coffee']);
});

Run:

Now run the task:

gulp watch-coffeescript

and see what happens when you modify one of the source file.

Ionic Framework features you may have missed

Ionic Framework is one of the best framework for developing hybrid mobile apps with HTML5. Based on AngularJS the set of available features is tremendous. This post presents, with examples, some of the best hidden features provided.

Scroll

Scroll documentation

Infinite Scroll

The ionInfiniteScroll directive allows you to call a function whenever the user gets to the bottom of the page or near the bottom of the page.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”jukJh” default_tab=”result” user=”shprink”]See the Pen Infinite Scroll: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

List

List documentation

Collection repeat

The collection-repeat directive is a directive that allows you to render lists with thousands of items in them, and experience little to no performance penalty.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”HoIDJ” default_tab=”result” user=”shprink”]See the Pen collection-repeat: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

Gesture

$ionicGesture documentation

Events

The gesture service has only two methods, on adds an event listener for an DOM element and off removes it. While AngularJS ngTouch provides only three touch events (ngClick, ngSwipeLeft and ngSwipeRight) $ionicGesture provides dozens (hold, tap, doubletap, drag, dragstart etc.).

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”txliu” default_tab=”result” user=”shprink”]See the Pen Ionic $ionicGesture example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

Dom manipulation

DomUtil documentation

If you are accustomed to AngularJS I am sure that you experienced some difficulties when manipulating the DOM. JQlite helps but is itself very limited. Ionic provides some methods to help you deal with it.

ionic.DomUtil.ready

Call a function when the DOM is ready, or if it is already ready call the function immediately.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”BxufK” default_tab=”result” user=”shprink”]See the Pen ionic.DomUtil.ready Example by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

ionic.DomUtil.getParentWithClass

Returns the closest parent of element matching the className, or null.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”lDrpb” default_tab=”result” user=”shprink”]See the Pen ionic.DomUtil.getParentWithClass Example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

Utilities

ionic.throttle

Only call a function once in the given interval. In this example the function should be called half as many as we tried.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”iefAE” default_tab=”result” user=”shprink”]See the Pen Ionic Throttle example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

ionic.debounce

Only call a function once in the given interval, the timer is reset on every call. In this example the function should never be called.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”yzrsD” default_tab=”result” user=”shprink”]See the Pen Ionic Debounce example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

ionic.Utils.arrayMove

Really useful function that manipulates array items position.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”HghBw” default_tab=”result” user=”shprink”]See the Pen Ionic arrayMove example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

Tabs

Starting from ionic beta.14 we can select the position of the tabs through configuration.

Tabs top

.config(function($ionicConfigProvider){
    $ionicConfigProvider.tabs.position('top');
})

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”qlECF” default_tab=”result” user=”shprink”]See the Pen Tabs Top: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

Tabs bottom

.config(function($ionicConfigProvider){
    $ionicConfigProvider.tabs.position('bottom');
})

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”emXyjV” default_tab=”result” user=”shprink”]See the Pen Tabs bottom: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]

Delegation

Delegation allow you to have several instances of the same component within the same view. You have this capability on ion-side-menus, ion-tabs,ion-scroll ion-content, ion-list and ion-slide-box using the delegate-handle directive attribute.

[codepen_embed height=”268″ theme_id=”5820″ slug_hash=”CsBhf” default_tab=”result” user=”shprink”]See the Pen Ionic Side Menu delegation: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]