In this post, I’ll show you how to get Grunt up and running with regards to your front-end web development. I’ll take you through the whole process and make your development a hell of a lot easier. What’s more, I’ll show you how to manage the files that Grunt outputs with Git in mind so that you don’t “git” those nasty merge conflicts. Grab a coffee, sit back and let’s do this.
Installing Grunt
First things first, you need to install Grunt, Grunt runs off of NPM so if you don’t have Node or NPM installed, here’s how:
Node.js
Visit: https://nodejs.org/en/download/ – select your operating system and download the installer. If you’re on Mac OS X it will be a .pkg file. Once done, simply double-click and let the installer do the hard work. It may take a bit of time, but it’s usually pretty quick. To verify that Node is installed, fire up your Terminal and hit:
node -v
If its successful, the Terminal will return the version of node you have installed.
P.s if you have trouble installing the next part, prefix the commands with sudo – this allows the terminal to run as administrator, and will ask you for your password if necessary.
Fantastic. Next up is NPM.
NPM
NPM is a package manager for Node. Much like Bower for Front-end dependencies like jQuery or Bootstrap or Composer for PHP. Moving on! Let’s get NPM running, we’ll install it globally so you can use it from within any folder on your system, if you still have the command line open, type:
sudo npm install npm -g
This will install NPM on your system. Plenty of libraries require NPM, so its a great tool to have installed on your system even if you don’t think you’ll use it all that much.
Grunt
So what exactly is Grunt? In its most basic form, Grunt is a Javascript Task Manager, it lets you automate and run a bunch of redundant tasks that front and back-end developers really don’t want to do every 5 minutes. It runs off of NPM and its core files are written in Javascript and JSON.
We’ll want to install Grunt globally much like we did NPM, so go back to Terminal and type:
sudo npm install -g grunt-cli
This installs Grunt globally and allows you to run it from the command line.
Alrighty, we now have all our dependencies (Node, NPM) as well as Grunt installed and we can get into the nitty gritty work. Before we move on, it’s important to understand how Grunt works, so we’ll cover that next.
How Grunt Works
Grunt uses two files right from the get go. Namely package.json and Gruntfile.js. The package.json contains meta-data about the project such as name, version, npm dependancies, authors and more. We’re going to write our own one in a bit. The Gruntfile.js is where we call the package.json and initiate settings and what are called “Grunt plugins” to make sure they do what we need them to do. Once we have set this all up, all we need to do is cd (change directory if you’re a noob at the command line) into the folder we’re going to create and type:
grunt
…into the command line and Grunt will start working its magic.
Before all this can happen we need to make sure our package.json is filled out as well as our Gruntfile.js. We’ll start with a simple empty directory.
- Fire up Terminal if you haven’t already got it running.
- Make sure you’re in the Home folder of your computer, it will most likely be named after you. If you’re unsure, type pwd (present working directory) and it will give you a file path as to where you are. Mine currently says /Users/Daine
- Next, we’ll change directory into the desktop, so type: cd Desktop
- Next, lets create a folder to store our files, type: mkdir yourfoldername
- Finally cd into your new folder, type: cd yourfoldername
P.s yourfoldername here is obviously whatever name you choose.
Cool. Lets do some grunt work.
Package.json
Im going to show you how to create a package.json using the command line, it provides a nice walkthrough for you. Once you’ve done this process once or twice, just duplicate your package.json for future projects, making sure you change the values of particular properties.
If you’re in your project folder on the command line type in:
npm init
This will initialise a wizard for you that will take you through the steps of creating the file.
Fill in the following:
name:
version:
description:
author:
Leave the rest blank by just hitting Enter on your keyboard. Terminal will ask you if you are happy with what you have so far and just hit Enter again. If you go look back at your folder, you’ll see a brand spanking new package.json file is present. Well done! Next, we will have to tell package.json what dependencies / plugins we wish to use, here’s how we do it!
Heres how our final gruntfile.js will look:
{ "name": "my-projects", "version": "1.0.0", "description": "A project to teach people how to grunt" "author":"Daine Mawer" "devDependencies": { "grunt": "~0.4.5", "grunt-contrib-watch": "~0.6.1", "grunt-contrib-sass": "~0.8.1", "grunt-contrib-concat": "~0.5.0", "grunt-contrib-cssmin": "~0.10.0", "grunt-contrib-uglify": "~0.6.0" } }
So what are we doing here? Where we see “devDependencies” is an indication of what plugins we’re using. There are hundreds in the Grunt Plugin repository, the ones here are some of the nifty ones for your most typical development environments. “grunt” is the actual grunt frameowrk that allows us to use the task manager. “grunt-contrib-watch” automatically refreshes the browser when we save a certain file or files. “grunt-contrib-sass” allows us to use the CSS preprocessor: SASS in our workflow, if you don’t know a lot about SASS or why you should be using it, you can view more about it here. “grunt-contrib-concat” takes a group of files of the same type, say .css or .js and merges them into one file. Its really useful, and lessens server load. “grunt-contrib-cssmin” minifies CSS files and “grunt-contrib-uglify” minifies Javascript files.
Alright, now that we have that setup, we need to jump back to the command line and type:
npm install
NPM will now install these dependencies from the Grunt repository for you and store them in a file called node_modules, it can take sometime. All grunt plugins are curated by the Grunt community and they all have plenty of documentation as to how they work and what they can do.
Great, we’re nearly there. Next up is the Gruntfile.js
Gruntfile.js
This file can be a little intimidating, generally people break it because they forget their {} or comma’s, so lets go through it step by step.
Our first line is this:
module.exports = function(grunt) { };
This function contains all the logic that Grunt uses to run your plugins. Everything we do from here on out must be with in this function otherwise your Grunt won’t work.
Next we’re just going to keep things simple and reference our package.json:
module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), }) };
The part we just added essentially imports the JSON data in our package.json and uses it as a reference for our project and dependencies. Great, now we’re going to work a little back wards, we’re going to use a couple methods called .loadNpmTask and .registerTask to get our Grunt plugins initiated before we set their options.
module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), }); grunt.loadNpmTasks('grunt-contrib-sass'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-cssmin'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.registerTask('default', ['watch']); };
What this does is references the plugins we specified in our package.json – essentially loading them once the options have been defined. The .registerTask() which uses ‘default’ (needed) runs the “watch” task every time we save a file (we’ll set the options now). Don’t worry too much about this, it will all make sense in a minute.
Grunt still won’t work until we have set up each plugins options. Each plugin option forms a JSON object that lives within the initConfig() function. Make sure when following along with this next section that all your code lives with inside the initConfig(), otherwise your Grunt will give an error.
sass: { dist: { files: [{ expand: true, cwd: 'build/sass', src: ['*.scss'], dest: 'css', ext: '.css' }] } },
To explain: dist stands for distribution, we want the way SASS is compiled to be in expanded format, not nested for instance. In other words, this will just look like regular CSS formatting. The working directory (cwd) should be located in a folder called build, in a folder called sass. We want the sass to be compiled from any (*) .scss file we use in the build/sass folder, the destination (dest) once compiled to a certain file is a folder called “css” and the extention of that file will be a .css. Easy?
Next up is the concatenation plugin
concat: { basic: { src: ['css/styles.css', 'css/normalize.css', 'css/bootstrap.css'], dest: 'css/production.css', }, extras: { src: ['js/scripts.js', 'js/bootstrap.js'], dest: 'js/production.js', }, },
With this plugin we can set and array of files that we wish to concatenate into one single file and specify its destination at the same time. You’ll notice that src (where the files are located) and dest (where they must be sent to) are the same for basic and extra’s. Its important to note that the order in which your CSS and its cascade works is still the same when you concatenate the file.
Next we’ll tackle CSSmin and Uglify:
cssmin: { options: { keepSpecialComments: 0 }, combine: { files: { 'css/production.min.css': ['css/production.css'] } } }, // UGLIFY uglify: { my_target: { files: { 'js/production.min.js': ['js/production.js'] } } },
Cssmin creates a .min version of our production.css file. While uglify does the same for our javascript file. This helps web developers a lot. As we write CSS and JS, our minified version is always kept up to date and we can push it to the production server.
Finally, we have watch
watch: { scripts: { files: ['**/build/sass/*.scss', '**/js/*.js', '**/*.html', '**/*.php'], tasks: ['sass', 'concat', 'cssmin', 'uglify'], options: { spawn: false, livereload: true }, }, }
The watch task is probably the most important. What we’ll do is tell Grunt to run all of the above plugins on file save, which will compile the SASS, concatenate the CSS and JS files, minify them and reload the browser all at the same time! You’ll notice that in the files property we have an array in which we tell Grunt the files we want to constantly watch for changes. When grunt picks up that we’re using a specific file, we tell it to run the sass, concat, cssmin and uglify tasks, and state that livereload in the browser is true.
Your gruntfile.js therefore should look like this:
module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), // SASS TO CSS COMPILING sass: { dist: { files: [{ expand: true, cwd: 'build/sass', src: ['*.scss'], dest: 'css', ext: '.css' }] } }, // CONCAT JS AND CSS concat: { basic : { src: ['css/style.css', 'css/normalize.css'], dest: 'css/production.css', }, extras : { src: ['js/scripts.js', 'js/boostrap.js'], dest: 'js/production.js', }, }, // CSS MIN cssmin: { options: { keepSpecialComments: 0 }, combine: { files: { 'css/production.min.css': ['css/production.css'] } } }, // UGLIFY uglify: { my_target: { files: { 'js/production.min.js': ['js/production.js'] } } }, watch: { scripts: { files: ['**/build/sass/*.scss', '**/js/*.js', '**/*.html', '**/*.php'], tasks: ['sass', 'concat', 'cssmin', 'uglify'], options: { spawn: false, livereload: true }, }, } }); // Load the plugin that provides the "sass" task. grunt.loadNpmTasks('grunt-contrib-sass'); // Load the plugin that provides the "watch" task. grunt.loadNpmTasks('grunt-contrib-watch'); // Load the plugin that provides the "concat" task. grunt.loadNpmTasks('grunt-contrib-concat'); // Load the plugin that provides the "cssmin" task. grunt.loadNpmTasks('grunt-contrib-cssmin'); // Load the plugin that provides the "uglify" task. grunt.loadNpmTasks('grunt-contrib-uglify'); // Default task(s). grunt.registerTask('default', ['watch']); };
Well done, your final step, jump back to the command line and in the folder that we have been working in, type in
grunt
—
For those of you that use Git, I’d like to point your attention to a few things, if you are working collaboratively, then you will want to be specific in your .gitignore about which files to push and pull. I have found that committing the production.min.css / production.css and production.min.js / production.js files cause problems. Ideally, you only want to commit your source files. In your .gitignore type the following:
js/production.js js/production.min.js css/production.css css/production.min.css node_modules/*
Your team mate should run npm install and grunt on their own development environment to install the plugins and compile CSS and JS. When you pull, you will only pull updates made on their SASS and CSS files, not their final production files.
That’s it! You have setup Grunt! I’ve created a Github repository for you, with HTML5 Boilerplate and Bootstrap as a template that you can use for beginning any project from scratch with Grunt integrated and setup. Please do let me know your thoughts on Twitter at @dainemawer