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.