January 2018 : Instructor-led Online Course in ASP.NET Core 2.0. Conducted by Bipin Joshi. Read more...
Registration for January 2018 batch of ASP.NET Core 2.0 instructor-led online course has already started. Conducted by Bipin Joshi. Register today ! Click here for more details.

Prepare Yourself for ASP.NET 5 - Part 3 (Grunt, Gulp)

In Part 1 of this series I discussed Less and Sass and in Part 2 I discussed NuGet, Npm and Bower. In this part you will learn the basics of JavaScript task runners. Modern web applications extensively use JavaScript and CSS. While working on a project often you need to perform operations such as:

  • Copying files from Bower_Components and Node_Modules folder to some other location in the project folder structure.
  • Compile Less and Sass files to plain CSS.
  • Minify JavaScript and CSS files
  • Bundle script files by concatenating multiple script files into a single file.

and more. These operations are called tasks and can be automated using tools known as task runners. Currently two task runners are commonly in use - Grunt and Gulp. I won't go into too much details of the pros and cons of each or how one is better than other. My intention is to make you familiar with both of them using simple examples so that you can understand their role in ASP.NET 5.

For the sake of this article I will perform the following four tasks using Grunt as well as Gulp. They are:

  • Compile a Less file into a plain CSS
  • Copy jQuery library from Node_Modules folder to the Scripts folder of a project.
  • Minify two JavaScript files - MyScript1.js and MyScript2.js
  • Concatenate the minified versions of MyScript1.js and MyScript2.js into a single file - Main.js

Ok. So, let's get going.

Create Less and JavaScript sample files

Before you do anything specific Grunt, let's create the Less and JavaScript files needed for this example.

Create a Styles subfolder under the project root and add StyleSheet1.less file to it. Add the following code to the StyleSheet1.less file:

@textSize:20px;
@fontName: Arial;

h1{
    color:blue;
    font-family:@fontName;
    font-size:@textSize;
}

Now create Scripts subfolder under the project root and add two JavaScript files - MyScript1.js and MyScript2.js - to it.

MyScript1.js contains a simple function as shown below:

function HelloWorld(name) {
    alert("Hello World from " + name);
}

Similarly, MyScript2.js contains the following function:

function HelloUniverse(name) {
    alert("Hello Universe from " + name);
}

Also, make sure that you have jQuery Npm package installed in the Node_Modules folder in the local package store. 

Using Grunt

In order to use Grunt task runner you need to first install grunt-cli (Grunt Command Line Interface) package using Npm. You can do that by issuing the following command at the command prompt.

npm install grunt-cli -g

This command will install grunt-cli in the global repository on your machine.

Depending on the tasks you wish to perform you also need to install additional task specific plugins. For our example, you need four plugin packages - grunt-contrib-less, grunt-contrib-copy, grunt-contrib-uglify and grunt-contrib-concat. These packages are intended for Less compilation, file copy, JS minification and file concatenation respectively. You can install these packages by issuing the following commands (make sure to navigate to your VS project folder before issuing them) :

npm install grunt-contrib-less
npm install grunt-contrib-copy
npm install grunt-contrib-uglify
npm install grunt-contrib-concat

Now create a JavaScript file named GruntFile.js in your project root folder. This file contains Grunt configuration that defines various tasks you wish to execute. You can create this file using any text editor or Visual Studio JavaScript editor. Add the following code to this file:

module.exports = function (grunt) {

    grunt.initConfig({

      less: {
        development: {
          options: {
            compress: true,
            yuicompress: true,
            optimization: 2
          },
          files: {
            "Styles/StyleSheet1.css": 
                "Styles/StyleSheet1.less"
          }
        }
      },

     copy: {
       settings: {
         files: [{
                  expand: true,
                  dest: 'Scripts',
                  cwd: 'node_modules/jquery/dist',
                  src: ['*.js'] }]
         }
     },

     uglify: {
       settings: {
         options: {
           mangle: false
         },
         files: {
           'Scripts/MyScript1.min.js': 
             ['Scripts/MyScript1.js'],
           'Scripts/MyScript2.min.js': 
             ['Scripts/MyScript2.js']
         }
       }
     },

     concat: {
       settings: {
         dest: 'Scripts/Main.js',
         src: ['Scripts/MyScript1.min.js', 
               'Scripts/MyScript2.min.js']
       }
     }
    });

    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-concat');

    grunt.registerTask('default', ['less', 'copy', 
                       'uglify', 'concat']);

};

I will not go into the details of each and every aspect of GruntFile.js here. You can read the documentation of individual plugin for all available options and their meaning. I will briefly discuss some of the options used above.

The GruntFile.js contains a function often called a wrapper function. This function is responsible for configuring and loading Grunt tasks. In the above example, you have configured four tasks namely less, copy, uglify and concat. The configuration is stored in a JavaScript object literal form.

Notice the files setting under the less property. It specifies that Styles/StyleSheet1.less should be stored as Styles/StyleSheet1.css after the Less compilation.

The copy property specifies that all the JavaScript files (*.js) from node_modules/jquery/dist should be copied to Scripts folder when the task is run.

The uglify property specifies that Scripts/MyScript1.js should be stored as Scripts/MyScript1.min.js after the minification. Similarly, Scripts/MyScript2.js should be minified to Scripts/MyScript2.min.js.

The concat property specifies that source files Scripts/MyScript1.min.js and Scripts/MyScript2.min.js are to concatenated to Scripts/Main.js when the task is run.

Once the JavaScript object is passed to the initConfig() method of the grunt object, the plugins required to run the tasks you just configured are loaded. This is done using loadNpmTasks() method of the grunt object and passing the name of the plugin to be loaded. In our example we load four plugins - grunt-contrib-less, grunt-contrib-copy, grunt-contrib-uglify and grunt-contrib-concat.

The final line of GruntFile.js calls registerTask() method on the grunt object and passes a list of tasks to run as a default task. Note that the names in this list (less, copy, uglify and concat) are the same as you used in the configuration object.

Now you are ready to run the tasks. Before running the tasks let's observe Solution Explorer.

Observe the location of various files marked in red color. These are the "source" files on which our tasks are going to run.

Now, go back to the command prompt and issue the following command:

grunt

The grunt command reads the GruntFile.js you created earlier and executes the tasks as per the configuration. If you execute the tasks successfully your Solution Explorer will now look like this:

Notice the Scripts and Styles folders carefully. The jquery.js and jquery.min.js files from node_modules/jquery/dist folder have copied to the Scripts folder. MyScript1.js and MyScript2.js files have minified versions namely MyScript.min.js and MyScript2.min.js. Main.js has been created and it contains the concatenated version of the minified files. The StyleSheet1.less from Styles folder has been compiled to StyleSheet1.css.

Open the minified files in Visual Studio or any text editor. You will find that they contain the minified versions of the original source code.

Using Gulp

Now let's perform the same four operations using Gulp.

As in the case of Grunt you need to install Gulp on your machine. So, open command prompt and issue the following commands:

npm install gulp -g
npm install gulp

Note that you are installing gulp globally as well as locally. Although strictly speaking this is not required, it makes your working with Gulp easy (something to do with PATH).

Now let's install Gulp plugins for Less compilation, file copy, minification and concatenation respectively. To do so, issue the following commands:

npm install gulp-less
npm install gulp-copy
npm install gulp-uglify
npm install gulp-concat

As you can see Gulp plugins are quite similar to Grunt plugins.

Now create a JavaScript file named GulpFile.js in your project root folder. This file contains Gulp code that defines various tasks you wish to execute. You can create this file using any text editor or Visual Studio JavaScript editor. You will notice that GulpFile follows code over configuration approach to define the tasks.

Add the following code to this file:

var gulp = require('gulp');
var less = require('gulp-less');
var copy = require('gulp-copy');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');

gulp.task('less', function () {
    gulp.src('Styles/StyleSheet1.less')
      .pipe(less())
      .pipe(gulp.dest('Styles'));
});

gulp.task('copy', function () {
    gulp.src('bower_components/jquery/dist/*.js')
    .pipe(gulp.dest('Scripts'));
});

gulp.task('minify_concat', function () {
    return gulp.src(['Scripts/MyScript1.js', 'Scripts/MyScript2.js'])
        .pipe(uglify())
        .pipe(concat('Main.js'))
        .pipe(gulp.dest('Scripts'));
});

gulp.task('default', ['less','copy', 'minify_concat']);

Again, I won't go into too much details of the above code here. Read the documentation for Gulp and Gulp plugins. Basically what this code is done is this -

It first loads the required plugins using require() method. The code then defines three tasks using task() method of gulp object. Each task has a name and a function that performs the operations of a task.

The less task specifies that source file named Styles/StyleSheet1.less should be Less compiled using less() and stored to Styles folder as StyleSheet1.css.

The copy task specifies that all the JavaScript files (*.js) from bower_components/jquery/dis folder are to be copied to Scripts folder.

The minify_concat task does two operations. First it reads Scripts/MyScript1.js and Scripts/MyScript2.js and minifies them using uglify(). The output of uglify() is fed to concat() and stored as Main.js in the Scripts folder.

Finally, the default task is executed which will call less, copy and minify_concat tasks.

To run the tasks you just specified invoke the following command at the command prompt:

gulp

The gulp command reads GulpFile.js and executes the tasks as mentioned therein. If you successfully execute the tasks your Solution Explorer should look like this:

Notice that, this time no separate min files are created because we fed the output of minification directly to concatenation. The Main.js will have the output that is minified as well as concatenated.

That's it! Will be back with the next installment soon.


Bipin Joshi is a software consultant, an author and a yoga mentor having 22+ years of experience in software development. He also conducts online courses in ASP.NET MVC / Core and Design Patterns. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click here.

Get connected : Twitter  Facebook  Google+  LinkedIn

Posted On : 06 April 2015


Tags : ASP.NET MVC JavaScript Visual Studio