Showing posts with label Gulp. Show all posts
Showing posts with label Gulp. Show all posts

Saturday, 7 November 2015

A Few Tips on Gulp

I have been using Gulp a lot these days and have encountered a few cases that are a bit tricky to solve if you are new to Gulp. These scenarios get even trickier if you used Grunt before and just started using Gulp later, like myself. This is because, Grunt is synchronous and the execution of a Grunt task that combines a set of tasks is predictable. On the other hand, Gulp is asynchronous and we need to carefully examine the way a combined task runs in order to get maximum benefits out of it.

The asynchronous behavior of Gulp tasks makes it a bit difficult to perform things like chaining multiple tasks, handling tasks not returning a stream work seamlessly and performing multiple operations in a single task. In this post, we will see how to handle these tasks.

Chaining Multiple Tasks
It is common to define multiple tasks and combining them to create a master task. The master task alone is called whenever there is a need to perform the set of tasks together. Some of these tasks may be dependent on each other and others may be independent. In general, a set of Gulp tasks are combined using the following syntax:

gulp.task('build', ['copy-files', 'concat-files', 'run-tests', 'copy-coverage-results']);
Out of these tasks, the task concat-files is dependent on the task copy-files. The above setup starts executing these tasks at the same time. Execution of the task concat-files is not paused until execution of the task copy-files is completed. It can be solved in two ways. One way is to declare the task copy-files as a dependent task on the task concat-files and have the concat-files task alone as dependency on the build task.

gulp.task('concat-files', ['copy-files'], function(){
  //definition of the task
});


The second way is to run these tasks in sequence using the run-sequence package. It is shown below:

var runSequence = require('run-sequence');
gulp.task('copy-and-concat', function(){
  return runSequence('copy-files','concat-files');
});


We have to use one of these ways to solve this case based on the scenario in hand.

Task not returning a Stream
Sometimes we have to deal with tasks that don’t return streams. Such tasks are difficult to chain, as gulp doesn’t understand about their completion. One of such tasks is gulp-requirejs. We need to wrap execution of such tasks inside gulp pipes to make them return streams. Following snippet wraps the gulp-requirejs task inside a pipe:


gulp.src('undefined.js')
  .pipe(requires(/*configuration of the task goes here*/))
  .pipe(gulp.dest('path-of-destiation'));


Task handling Multiple Operations
A task may handle multiple asynchronous operations. In such case, the task has to return a stream representing the combined execution. Sometimes, we can return the stream returned by the last operation alone, but this approach doesn’t guarantee that all tasks are completed by the time the stream is completed. So, it is a good practice to combine such tasks using the event-stream package. Following snippet combines a number of copy operations into a single task using this package:

gulp.task('copy-files', function () {
  return es.merge(
    gulp.src('app/index.html')
      .pipe(gulp.dest('build')),
    gulp.src('app/JSON/*.json')
      .pipe(gulp.dest('build/JSON')),
    gulp.src('app/requirejs-config.js')
      .pipe(gulp.dest('build/temp'))
    );
});


I have encountered these cases quite a few times and the solutions discussed here worked well for me. These may not be the only possible ways to tackle these cases, but these are just my views. If you got any other ways to solve these problems, feel free to add a comment.

Happy coding!

Friday, 25 September 2015

Writing Gulpfile using TypeScript

Lately, I have been using Gulp a lot at my work and also in the demos of my articles. I also use TypeScript quite often these days while playing with Angular 2. While using Gulp to transpile TypeScript to JavaScript using Gulp, I got thought to use TypeScript itself to write the gulpfile as well. It might sound a bit weird as we use Gulp to transpile the files to JavaScript and the gulpfile itself has to be converted by someone into JavaScript before any other task runs. Thanks to npm scripts, we have a way to achieve this.

The scripts section of the package.json file can be used to register commands and these commands can be executed from command prompt of any OS using the “npm run” command. For instance, if we have the following configuration saved in scripts section of package.json file:

"scripts": {
  "setup" : "npm install && bower install"
}

We can run the command “npm run setup” from the command prompt. This command would install all Node.js dependencies and the bower dependencies. We can transpile the gulpfile using this section and then combine this command with a command to run a task. For this, we need to have TypeScript installed globally. This can be done using the following command:

> npm install –g typescript

To write the gulpfile using TypeScript and take advantage of the type checking system, we need to get the type definition files. Type definitions for the gulpfile are available on tsd. Following command gets the type definitions for the gulpfile:

> tsd install gulp --save

These files are saved inside typings folder of the project. To make our lives easier, the tsd command creates a type definition file that refers to all of the installed type definitions. This file is tsd.d.ts inside the typings folder.

Now, we need to refer the tsd.d.ts file in the gulpfile.ts file and start writing Gulp tasks. Following snippet shows a task that concatenates all JavaScript files:

/// <reference path="typings/tsd.d.ts" />

var gulp = require('gulp'),
    concat = require('gulp-concat');

gulp.task('default', function(){
  return gulp.src(["scripts/*.js"])
    .pipe(concat("combined.js"))
    .pipe(gulp.dest("dist"));
});

This example is a simple one. In more advanced scenarios, we can use types as well.

To run this gulp task, we need to define a command in the scripts section to transpile the file and then run the task. Following is the command:

"scripts": {
  "concat": "tsc gulpfile.ts && gulp"
}

All is done. We can now run this command as follows:

> npm run concat

Happy coding!

Thursday, 25 December 2014

Automating Tasks in Front-end Web Apps Using Gulp

As we started writing a lot of JavaScript and CSS these days, front-end development has matured like anything. We create hundreds of JavaScript source files to make our code organized; but finally we need to ship just one JavaScript file and one CSS file while deploying the application. This conversion is not easy; as it involves several steps like running tests, validating against jshint, concatenating, minifying, uglifying and many other tasks. Thankfully, we have a number of automated task runners and a handful of plugins on each of these task runners to make these tasks easier.

Out of the existing task runners, Grunt and Gulp are most widely used. I use Grunt a lot these days. Though I haven’t blogged about it, I used it in some of my SitePoint articles. Lately, Gulp is becoming more famous. Gulp uses a different approach to address the same problem that Grunt addresses. Let’s see how we can leverage Gulp to automate our tasks.

Gulp is a task runner based on Node.js. It uses streams to carry its tasks. The way Gulp works is, it accepts a source (can be a file, or a set of files), processes them based on a task and passes it to the next task in the pipe for further processing. The pipes continues processing till the last task. Following is the syntax of a typical Gulp task:

gulp.task('task-name', function () {
  return gulp.src([source paths])
    .pipe(task1(parameters))
    .pipe(task2())
    ...
    ...
    ...
    .pipe(taskn())
    .pipe(gulp.dest('destination-path'));
});

Tasks piped in the above Gulp task are tasks loaded using Gulp plugins. Gulp has a huge number of plugins contributed and actively developed by community, which makes it a very good ecosystem. To be able to use Gulp in your project, you need to have it installed globally and locally. Run the following commands in a command prompt to get Gulp installed:

  • npm installed –g gulp
  • npm installed gulp --save-dev (To be ran in your project folder)


Let’s write a Gulp task for cleaning distribution files and regenerating them after concatenating and minifying. For this, we need the following Gulp plugins:

  • gulp-clean
  • gulp-concat
  • gulp-uglify


These can be installed using the following nom commands:
  • npm install gulp-clean --save-dev
  • npm install gulp-concat --save-dev
  • npm install gulp-uglify --save-dev


Add a file to the project and rename it to Gulpfile.js. Load the Gulp tasks in this file:


var gulp = require('gulp'),
    concat = require('gulp-concat'),
    uglify = require('gulp-uglify'),
    clean = require('gulp-clean');


Before generating the files to be deployed, let’s clean the folder. Following task does this:

gulp.task('clean', function () {
    return gulp.src(['dist'])
        .pipe(clean());
});


Now, let’s create a bundle task that concatenates all JS files, uglifies them and copies inside a folder to be distributed. Following is the task:

gulp.task('bundle', function () {
  return gulp.src(['public/src/*.js'])
    .pipe(concat('dist/combined.js'))
    .pipe(uglify())
    .pipe(gulp.dest('.'));
});


The folder public/src contains all JS files of the application. They are concatenated into one file and the contents are then uglified and finally we call the dest task to copy the resultant file to destination, which is the dist folder.

These two tasks can be combined into one task as follows:


gulp.task('createDist', ['clean', 'bundle']);


Now, if you run the following command, you will have the combined.js file created inside dist folder.

gulp createDist

To make a task default, name of the task has to be default.


gulp.task('default', ['clean', 'bundle']);


To run this task, you can run gulp command without passing names of any tasks to it.

We will see explore more features of Gulp in future posts.

Happy coding!