February 15, 2017
Grunt JS is a task runner, and what that means is that using a command-line interface you can perform predefined tasks that you can configure in a JSON file (Gruntfile.json). These tasks can used for many things such as compiling, minify, testing, watch for file changes and others.
The different types of functionalities are implemented via plugins. Grunt itself, the cli (the command line interface) and the plugins can be installed using NPM(which I'll briefly cover if you never used it).
I always go for version managers instead of just installing things such as Ruby or Node from packages or download binaries. (obviously skip this step if you already have NPM)
# First, if you are using a Debian-based distro you are going to need to have these:
$ sudo apt-get install build-essential libssl-dev
# Next step is install NVM
$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash
# And finally we install NPM, this is how you specify the version
$ nvm install 5.0.0
We do this by creating or editing our package.json:
{
"name": "Test Project",
"version": "0.0.1",
"devDependencies": {
"grunt": "~0.4.5",
"grunt-contrib-uglify": "~0.5.0",
"grunt-contrib-concat": "~1.0.1",
"grunt-contrib-copy": "~1.0.0",
"grunt-contrib-cssmin": "~2.0.0"
}
}
All plugins are named like grunt-contrib-*. And You can view a complete list of available plugins here.
Before we continue lets install ALL THE THINGS:
# Insall all packages from your package.json
$ npm install
# And finally we install the grunt cli so we can use it from the command line
$ npm install -g grunt-cli
Next step is to configure Grunt and the plugins we included before.
Now we need to create our config file: Gruntfile.js, "where" depends on your project but probably along side your package.json.
Bellow is the basic structure of a Gruntfile, it can be split in 3 main sections:
// Gruntfile.js
/* NOTE: In the code where i wrote stuff like {plugin_name1} is where
* you need to put the plugins names like: Example: uglify, cssmin, etc ...
*/
module.exports = function(grunt) {
/* (1) Project configuration. */
grunt.initConfig({
// Doing this we pick up the name from our package.json file
pkg: grunt.file.readJSON('package.json'),
/* Plugin configuration goes here.... */
"plugin_name1": {
// Plugin config here....
},
"plugin_name2": {
// Another plugin config here....
}
});
/* (2) Load the plugins that provides the tasks. */
grunt.loadNpmTasks('grunt-contrib-{plugin_name1}');
grunt.loadNpmTasks('grunt-contrib-{plugin_name2}');
/* (3) Tasks */
grunt.registerTask('{task_name}', ['{plugin_name1}', '{plugin_name1}']);
grunt.registerTask('default', ['{plugin_name1}', '{plugin_name1}']);
/* Task Examples */
/*
This registers a task named 'buildAssets' (you can use any string here)
The second parameter is an array of which plugins you wanna to run.
*/
grunt.registerTask('buildAssets', ['uglify', 'cssmin']);
/*
If we register a task 'default', it will run when you invoke grunt it without any parameters
*/
grunt.registerTask('default', ['watch']);
};
The example provides the buildAssets task which runs the uglify and cssmin plugins.
$ grunt buildAssets
Simple way to join/obfuscate/minify your code. Check the config section of the example bellow, the build section in particular.
I've included 3 possible cases in the build/files section:
// Gruntfile.js
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
build: {
files: [{
src: 'src/frontend/*.js',
dest: 'public/js/frontend.min.js'
},{
src: ['src/backend/script1.js', 'src/backend/script2.js'],
dest: 'public/js/backend.min.js'
},{
expand: true,
cwd: 'src/modules/',
src: '**/*.js',
dest: 'public/js/modules/',
}]
}
}
});
// Load the plugin that provides the "uglify" task.
grunt.loadNpmTasks('grunt-contrib-uglify');
// Default task.
grunt.registerTask('default', ['uglify']);
};
Very easy plugin to concatenate/merge files into one.
// Gruntfile.js
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
frontendJS: {
src: ['node_modules/prismjs/components/prism-ruby.min.js',
'node_modules/prismjs/components/prism-php.min.js',
'node_modules/prismjs/components/prism-javascript.min.js',
'node_modules/prismjs/components/prism-c.min.js',
'node_modules/prismjs/components/prism-css.min.js',
'node_modules/prismjs/components/prism-bash.min.js',
'node_modules/prismjs/components/prism-json.min.js'
],
dest: 'public/js/prism.min.js'
},
frontendCSS: {
// Another and/or more files here...
}
}
});
// Load the plugin that provides the "concat" task.
grunt.loadNpmTasks('grunt-contrib-concat');
// Default task.
grunt.registerTask('default', ['concat']);
};
Another simple one to copy files from one location to another one.
// Gruntfile.js
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
copy: {
main: {
files: [
{
expand: true,
cwd: 'node_modules/font-awesome/fonts/',
src: '*.*',
dest: 'public/assets/fonts/'
}
]
}
}
});
// Load the plugin that provides the "copy" task.
grunt.loadNpmTasks('grunt-contrib-copy');
// Default task.
grunt.registerTask('default', ['copy']);
};
Very simple way to minify one or more CSS files.
// Gruntfile.js
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
cssmin: {
target: {
files: {
'public/css/styles.min.css': ['src/css/*.css']
}
}
}
});
// Load the plugin that provides the "cssmin" task.
grunt.loadNpmTasks('grunt-contrib-cssmin');
// Default task.
grunt.registerTask('default', ['cssmin']);
};
With this plugin you can tell Grunt to execute certain tasks when files changes are detected. After the configuration is set, we can run "grunt watch", this will leave grunt in a "waiting" status and will automatically run any task you want when you modify the source files.
// Gruntfile.js
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
cssmin: {
target: {
files: {
'public/css/styles.min.css': ['src/css/*.css']
}
}
},
watch: {
css: {
files: ['src/css/*.css'],
tasks: ['cssmin'],
options: {
spawn: false,
}
}
}
});
// Load the plugin that provides the "cssmin" task.
grunt.loadNpmTasks('grunt-contrib-cssmin');
// Load the plugin that provides the "watch" task.
grunt.loadNpmTasks('grunt-contrib-watch');
// Default task.
grunt.registerTask('default', ['watch']);
};
Plugin to compile your less files. Config is super easy, so i also included the watch plugin to make things easier during development. The only "new" thing here is the options/path configuration var that we use to specify where less scans for @import directives files.
// Gruntfile.js
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
less: {
development: {
options: {
paths: ['src/less/inc/']
},
files: {
'public/css/site.css': 'src/less/*.less'
}
}
},
watch: {
css: {
files: ['src/less/*.less'],
tasks: ['less'],
options: {
spawn: false,
}
}
}
});
// Load the plugin that provides the "less" task.
grunt.loadNpmTasks('grunt-contrib-less');
// Load the plugin that provides the "watch" task.
grunt.loadNpmTasks('grunt-contrib-watch');
// Default task.
grunt.registerTask('default', ['watch']);
};
All plugins have many options, this post covers just the most basic ones.
I'm a 32-years old programmer and web developer currently living in Montevideo, Uruguay. I been programming since I was about 15 y.o, and for the past 12 actively working in the area.