(Comments)
Grunt is a javascript task runner used to automate the building and packaging of all front-end components. Grunt has numerous plugins for all repetitive tasks like minification, linting, compilation etc.
Javascript being extremely popular language for sometime now, there are good alternatives to grunt such as gulp and webpack. We will limit this post to just grunt and how to perform some basic tasks with it.
grunt is a node package. So we need node and npm installed in our system. If you don't have them installed already, follow our guide managing front-end javascript dependencies using Node Package Manager and bower.
Install grunt-cli
globally with
npm install -g grunt-cli
Since we are installing it globally, we need superuser credentials (on linux) or administrator rights (on windows). Once the grunt-cli is installed, we can access it from any directory.
Initiate node project and then install grunt with
npm install --save-dev grunt
Now we can run grunt in our project directory with the command grunt
. But that will only raise an error like this
A valid Gruntfile could not be found. Please see the getting started guide for more information on how to configure grunt: http://gruntjs.com/getting-started Fatal error: Unable to find Gruntfile.
This is because grunt looks for a file named gruntfile.js
that describes the tasks and the configuration of individual tasks. The above error is caused when it fails to find gruntfile.js
.
Let us create the file gruntfile.js
. The grunt file is basically of the form
module.exports = function(grunt) { // List the grunt tasks here. };
All the tasks and configurations are defined within this function.
To understand how grunt works, let us install a grunt plugin called grunt-contrib-uglify
which is used to minify javascript files. Install it with
npm install --save-dev grunt-contrib-uglify
We need to load the plugin in the grunt function to import the tasks from it. Load it with
grunt.loadNpmTasks('grunt-contrib-uglify');
Though this loads all the tasks, uglify still needs some configuration. All the configuration to grunt is passed as an object to the methd initConfig
as follows.
grunt.initConfig({ // Configuration in this object });
We provide configuration for uglify
plugin with this object as the value to the key 'uglify'. The configuration looks something like this.
grunt.initConfig({ uglify: { target: { files: { 'dist/output.min.js': ['src/file1.js', 'src/file2.js'] } } } });
To be clear the complete file look like this.
module.exports = function(grunt) { grunt.initConfig({ uglify: { target: { files: { 'dist/output.min.js': ['src/file1.js', 'src/file2.js'] } } } }); grunt.loadNpmTasks('grunt-contrib-uglify'); };
Before we try to understand the configuration completely, create a directory named src
with two files file1.js
and file2.js
. Let us put the following contents in those files.
function greeting_one() { console.log('Hello world! This is the first file.'); } greeting_one();
in the first file and
function greeting_two() { console.log('Hello world! This is the second file.'); } greeting_two();
in the second file. Now let us look at the configuration. The object with key files
is of interest here. The key in the object is 'dist/output.min.js'
and its value is the list ['src/file1.js', 'src/file2.js']
. Uglify takes the files specified in the list and minifies them and saves the result as the given key 'dist/output.min.js'
. Now run uglify task with
grunt uglify
Grunt will run the uglify task, which will concatinate the 'src/file1.js' and 'src/file2.js' files and remove uncessary white spaces and save the result as 'dist/output.min.js'. The content of the dist/output.min.js
file will be like this.
function greeting_one(){console.log("Hello world! This is the first file.")}function greeting_two(){console.log("Hello world! This is the second file.")}greeting_one(),greeting_two();
Yes, it is ugly. You can run this file with node with command
node dist/output.min.js
The output will be
ravi$ node dist/output.min.js Hello world! This is the first file. Hello world! This is the second file.
It is difficult to specify each and every file that needs to be minified. Grunt allows wildcards to specify source files. To include all the .js files from the src
directory, the configuration would be
files: { 'dist/output.min.js': ['src/*.js'] }
We can specify to include all the .js files from all the sub-directories with
files: { 'dist/output.min.js': ['src/**/*.js'] }
This will combine all the js files from all the sub-directories in src
, minify and save as dist/output.min.js
. Other options provided by uglify are listed and explained on uglify's gihub page.
uglify
plugin will have defined the task named uglify
which we ran with grunt uglify
. How do we create our own custom task? We create a task with the registerTask()
method
grunt.registerTask('<custom_taskname>', ['<task 1>', '<task 2>', ...]);
The task registered with above method is aggregation of the list of tasks passed and second argument. For example, we can define the 'default' task that executes 'uglify' with
grunt.registerTask('default', ['uglify']);
We can execute the default task with grunt default
. Grunt by default looks for a task named 'default' and execute it when we do not specify any task.
grunt
is equivalent to
grunt default
We can add multiple tasks to single task and execute all of them as if it is a single task. The tasks are run in the specified order.
For more information on how tasks work and are created, visit grunt's official tutorial creating tasks and the grunt's API documentation.
Let us also configure our gruntfile to compile Sass files into CSS files. This can be done with the grunt plugin grunt-sass. Install grunt-sass with
npm install --save-dev grunt-sass
Load the grunt sass tasks with
grunt.loadNpmTasks('grunt-sass');
Then configure sass with the
grunt.initConfig({ sass: { dist: { files: { 'dist/css/app.css': ['src/styles/*.scss'] } } } });
Also add the sass task to the 'default' task with the line
grunt.registerTask('default', ['sass']);
My gruntfile at this point (along with uglify tasks) looks like this.
module.exports = function(grunt) { grunt.initConfig({ uglify: { target: { files: { 'dist/output.min.js': ['src/file1.js', 'src/file2.js'] } } }, sass: { dist: { files: { 'dist/css/app.css': ['src/styles/*.scss'] } } } }); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-sass'); grunt.registerTask('default', ['uglify', 'sass']); };
This configuration will compile all the .scss files in src/styles/
directory and save the output as the file dist/css/app.css
. To test this create a file in src/styles/
named main.scss
with the following contents.
.container { .right { text-align: right; } }
Save the file and then run grunt with
grunt
The .scss sass file will be compiled and the resulting file will be placed in dist/css
as app.css
with the contents
.container .right { text-align: right; }
grunt-sass
works with node-sass
. The options will be same as that of node-sass
which can be found at https://github.com/sass/node-sass#options.
We develop web applications to our customers using python/django/angular.
Contact us at hello@cowhite.com
Comments