A Beginner’s Guide to Using Grunt With Magento

Posted by Matt Bailey on 10 January 2014

My guess is that if you’ve stumbled across this article you’ve probably already heard of Grunt, but maybe you’ve not used it much before or are a complete beginner, or maybe you’re wondering how you can use it as part of your Magento front-end workflow. This article will take you through that process, step by step.

In short, Grunt is a task runner - with it one can automate front-end tasks. For example, you could validate (lint) your Javascript and minify it, precompile your CSS and optimise your images, all with one command. Pretty cool huh?

I’ve written this article in the context of using Grunt with Magento, but to be honest the principles are the same regardless of the type of project you’re working on - you could easily just ignore the Magento stuff.

Magento isn’t the easiest of ‘beasts’ to work with, but with a bit of forethought and prep you can quite easily implement an automated front-end workflow. If that interests you then read on...

What we’re going to cover

All the files in this tutorial can be found on Github. If you spot any issues, or have any questions/suggestions please also post them on Github.

 

1. Initial Magento setup

Create project directory

 

From now on, unless specified otherwise, it will be assumed that all directory references and terminal commands are relative to magento-grunt-proj/.

Create shop root directory

 

Install Magento in shop root

If you’re reading this article I’m going to assume that you’re already familiar with installing and setting up Magento. However, here’s a handy tip - check out magerun. It provides developers with a number of useful Magento command line tools, including a brilliantly simple automated install script.

Set up local virtual host

As with installing Magento, I’m also going to assume that you know how to set up a local virtual host for your site.

Once you’re set up Magento, your project directory should look something like this:

 

2. Creating a (symlinked) theme

One thing you’ll notice straight away about this process that’s a bit different is that we’re going to put our theme files outside of our Magento shop root. The reason for this is that we basically want to treat our theme as a separate, contained project that we can commit to our Git repo without all the other Magento files. It also makes creating and maintaining our Gruntfile much easier.

It’s worth pointing out though, that you should only symlink your theme in a development environment and not in a live environment as it’s considered insecure - your deployment process would include steps that clone the theme’s repo, runs Grunt and then rsyncs the files/folders into the relevant places.

Create theme folder

Back in the root of your main project directory create the layout and skin folder structure for your theme:

 

Allow and create symlinks

In order to locate our theme files/folders in this non-standard location outside of our shop root we have to tell Magento to allow symlinks, and then create them.

Log in to Magento admin, go into System > Configuration > Developer > Template Settings and set Allow Symlinks to Yes.

Then on the command line:

 

What’s happening here is that we’re going into the standard Magento layout and skin folders and creating symlinks back to our external theme folders.

If you now show the contents of the two frontend directories above (ls -al) you’ll see the created symlinks:

Activate your theme

Once you’ve done the above you’re ready to activate your theme. In System > Configuration > General > Design and enter the following details:

Package

Current Package Name: my-theme

Themes

Templates: default
Skin (Images / CSS): default
Layout: default

TIP: At this point it’s probably a good idea to delete and turn off the Magento cache while you’re developing your theme. If you’re using magerun you can do this really easily from the command line:

 

All being well, if you now visit your site’s homepage you should see an unstyled page (because we haven’t added any kind of styling to our theme yet). If you get an error saying something about your package not being found it’s probably because you have a typo in one of your folder names (I’ve made this mistake many times), or created one of the symlinks incorrectly.

 

3. Setting up version control (Git)

If you’re just interested in getting to the good stuff and don’t really care about version control yet, you can skip forward to 4. Adding some theme files

Now is probably a good time to set up some version control. Here’s how to do it if you use Github.

For the sake of this tutorial we don’t want Git to track every file as we’re only interested in our theme files. Each person’s development environment is different anyway, so you’d want to tailor things to your specific requirements. So, create a .gitignore file in your project root directory:

 

Then in your code editor add the code below to the new .gitignore file - this basically tells Git to exclude pretty much everything but our project and theme specific files/folders:

 

Next create a README.md file. You can do this simply on the command line:

 

On a private repo you may wonder what is the point of creating a README.md file? Here at GPMD we use it on our own projects as a central reference point for all our developers - if there’s something specific they need to know about the setup of a site for example.

Now create your remote repo on Github(log into your Github account, click the Create new repo button and follow the instructions).

Once you’ve done that you’re ready to initialise your repo locally and push it to the remote Github repo (NOTE: you’ll need to enter your own Git username and repo where indicated):

 

You’ll also find the above instructions on your (currently) empty Github repo page - They’re very helpful like that.

Once Git has done its thing and pushed to Github try refreshing your Github repo page - you should see that it now contains some files/folders. However, if you’ve been paying attention you’ll also notice that our theme/ folder isn’t there. That’s because we haven’t added any files to our theme yet - Git doesn’t track empty folders.

 

4. Adding some theme files

At this point we can actually start setting up our theme, finally! There are, of course, many options open to you - You could use a boilerplate, such as this one based on Bootstrap 3 (we often use PolarCore based on Foundation, although it’s not free). Or you could, if you’re feeling particularly adventurous, start completely from scratch. However, for the sake of this tutorial I’m just going to use the existing Magento ‘modern’ theme as the starting point for my own theme.

We can quickly duplicate all the files/folders we need using the command line:

 

Now if you refresh the homepage of your site you should see if styled using the lovely *cough* Magento ‘modern’ theme, albeit with some missing assets (which, for the purposes of this article, we can ignore).

As above, you can ignore the next Git bit if you want and just move on to 5. Setting up a Grunt environment

Let’s add all our new files to Git.

 

If you refresh your Github repo page you should now see the theme/ folder.

 

5. Setting up a Grunt environment

Fantastic, this is where it starts to get fun! But before we can create some actual Grunt tasks we need to make sure our dev environment has everything it needs.

Install Node.js

In order to use Grunt you’ll need to install Node.js first - Simply download the package and install it like you would any other app. Node is basically the ‘engine’ that makes everything we want to do, work.

Install the Grunt Command Line Interface (grunt-cli)

Then you’ll need to install the Grunt Command Line Interface (grunt-cli), so we can, er, interface with Grunt using the command line:

 

This command uses Node package manager to install node modules, in this case, grunt-cli. We’re installing it globally (-g) so that we can run it from anywhere.

Install Compass

A bit later on we’re going to set up a CSS pre-processing Grunt task. In my example I’m going to use Compass (A CSS framework that uses Sass/SCSS), so you’ll need to make sure you have Compass installed. If you just want to use vanilla Sass without Compass then you’ll need to make sure you have Sass installed instead.

Create package.json for Node.js

As a bare minimum you need a package.json file for Node.js in the root directory of your project. Create package.json and enter the following:

 

This defines the name of your project, the project version number, and the fact that you want to install Grunt as a Node module (version 0.4.2 or whichever is the latest version if higher than 0.4.2).

Now go to the command line and run:

 

You should see a load of output (ignore warnings about ‘no description’, ‘no repository field’ and so on) and if you now look in your project folder you should see a new folder called node_modules/, which contains a folder called grunt/. Success, you’ve installed the Grunt Node module for your project!

 

6. Adding Grunt tasks

We’ve done a lot of cool stuff so far already, but now it’s going to get really interesting as we add our first Grunt tasks!

Add CSS pre-processing task

First of all we need to install the Grunt Node module that we want to use to do our pre-processing. As I mentioned before, I’m going to use Compass (the module is called grunt-contrib-compass), but if you want to just use vanilla Sass there’s a module for that too, called grunt-contrib-sass. Here’s how to install the Compass module in our project:

 

Once you’ve run this command, open package.json and you’ll see a new line has been added to the devDependencies section: "grunt-contrib-compass": "~0.7.0"

You should also see a new folder in node_modules/, called grunt-contrib-compass/.

But wait a minute, at the moment we don’t have any Sass/SCSS files to do any pre-processing on. Let’s create some - The Magento ‘modern’ theme contains a few CSS files, which we can convert into SCSS files and then have Grunt compile them into CSS for us.

First of all create a new folder for your SCSS files:

 

Then duplicate the CSS files into this directory:

 

Then rename the suffix on each of these files to .scss:

 
 

NOTE: Be careful with the second command above - make sure you’re in the right directory or you could end up renaming a lot more files than you mean to.

If you look in the scss/ folder now you should see that all (four) CSS files have .scss suffixes.

Now we can set up the actual Grunt task. In order for Grunt to work we need to tell it what we want it to do each time it’s run, and we put that information in a file called Gruntfile.js. Go ahead and create this file in the root directory of your project, then open it and enter the following:

 

First of all I’ve defined the skin/ and app/ directories (to avoid a lot of re-typing later). Then I’ve told it where the package.json file is.

Next, I’ve set up some simple config for Compass, by telling it where my SCSS files are and where it should put the compiled CSS files (NOTE: see how I’ve used my skinDir variable), what my working environment should be (development or production), and what I’d like my output style to be. There are a lot more config options available, which you can read more about here, but these are really the only ones we need to get started. If you’re using grunt-contrib-sass then the syntax is slightly different - refer to the Github page for some examples, but it’s very similar and quite straightforward.

If you look a bit further down the code you’ll see I’ve told it to load the task grunt-contrib-compass:

grunt.loadNpmTasks('grunt-contrib-compass');

 

And finally I’ve registered the compass task to run when the default grunt task is run:

 

Now go to your command line and run:

 

You should see some output in your terminal that looks like this:

“Done, without errors.” Nice! In fact you’ll probably notice that Compass hasn’t actually done anything because nothing has changed between the SCSS and CSS files (they’re basically the same files at the moment as we simply copied them). In order to see Compass in action open up styles.scss and make a simple change - maybe change the background-color on the body tag to red? Run grunt again and this time the styles.scss line in your terminal output should say something like this:

Awesome, we can now see that styles.css has been overwritten! If you now open styles.css you should see that the layout has changed a bit - it’ll look a bit more bunched up (that’s the nested option) and there will now be comments telling you where the source of that particular definition group comes from (that’s the development option, which is really useful for debugging). If you set environment to production and the outputStyle to compressed all the comments will disappear and the CSS will be on one line - pretty cool!

Add some automation with grunt-contrib-watch

All this is well and good, but we can go one better - how about we create a task that will automatically run the Compass task if it detects a change to any of the .scss files?

For this we’ll need the grunt-contrib-watch module. Install it in the same way that you installed the grunt-contrib-compass module:

 

You can check this has worked by looking in package.json and the node_modules/ folder.

Then add the following config to Gruntfile.js after your compass task config:

 

This is basically telling the watch task to keep an eye on the scss/ folder, and if it detects any changes to any of the .scss files to run the compass task.

Finally, tell it to load the grunt-contrib-watch module or it won’t work:

grunt.loadNpmTasks('grunt-contrib-watch');

 

To use the watch task you need to run the following on your command line:

 

All being well you should see this:

This means it’s waiting for you to do something. Try making another change to styles.scss, save it, and see what happens - suddenly you’ll see the terminal spring to life and it will say something like this:

TIP: To stop the watch task from running (on a Mac at least) type Control + C.

Add a live browser-refresh task (LiveReload)

But wait, we can go even better! You may have heard of a browser plugin called LiveReload (go ahead and install the plugin if you haven’t already)? We can use LiveReload to refresh the web page and see our changes happen as we make them, and the best part is that this functionality is already built into the grunt-contrib-watch module - I’m going to change the watch task config a bit, so copy and paste it again:

 

So we’ve enabled livereload, Then we’ve told it to watch for changes in our scss/ folder and if it detects any, to run the compass task.

Now run the grunt watch task on the command line, go to a page on your site, make sure LiveReload is enabled (you’ll probably get a LiveReload error if you try enabling it before you run grunt watch), and then make a change to the styles.scss file. You should see the terminal spit out a load of stuff and the browser window refresh to show your changes (I’m not sure why it shows styles.scss being reloaded twice - one for the Grunt pros out there, but it works?) - it’s like magic or something!

Add image optimisation using grunt-contrib-imagemin

Another thing worth adding is an image optimisation task. The brilliant thing about Grunt is that if you can think of something you want to do there’s probably a module for it already, and in this case it’s called grunt-contrib-imagemin.

However, before we install the module, we need to duplicate the existing image folder/files. This is because we don’t want the location of our optimised files to be somewhere different - you’d then have to go through all the css and templates and change all the image path references to the new optimised image path - boring (and time-consuming)! Instead, we’ll create a new folder for our original (source) image files and then save the optimised versions back into the existing images/ folder. Makes sense? It’ll become clearer as you following along with me...

We’ve already used the command line to duplicate some folders, so let’s do the same again:

 

Now you should have two identical image folders, one called images/ and the other called images-src/.

Then, as before, let’s install the necessary Grunt module:

 

Check it’s there in the Node modules folder and package.json, and then register it in our Gruntfile:

grunt.loadNpmTasks('grunt-contrib-imagemin');

 

Add the task configuration below:

 

This is telling the task where our original (source) images are, what type of files to optimise, and where to save them when they’ve been optimised.

And finally add the task to our default set (Let’s start putting them on individual lines as it will become easier to follow as we add more tasks):

 

Now run grunt on the command line and watch it squish all those images (it might take a couple of seconds as there are quite a few)! Here’s a snippet from my terminal output.

If you’ve been following along you can probably already guess what I’m going to suggest we do next? That’s right, we’re going to add the imagemin task to our watch task. Here’s our watch config now:

 

All I’ve done here is to tell livereload to watch the images-src/ directory for changes, and to run the imagemin task if it does.

Try dropping a new image into images-src/ and you should see your terminal do it’s thing and the browser window reload.

Add clean task (grunt-contrib-clean)

Another useful task we could add at this stage is grunt-contrib-clean. The reason I’m introducing it at this point is because what I actually want to do is delete the images/ folder before I optimise images-src/. If you don’t do this your images/ folder could become full of files you’re no longer using - grunt-contrib-imagemin doesn’t remove files from the destination directory if/when you remove them from the source directory.

Let’s go through the usual process. First install the module:

 

Now add the task loader to your Gruntfile:

 

Then add the following config:

 

This basically creates a subtask of clean called images that simply removes the images/ directory. You need to be a little careful with the clean task because you could accidentally delete files/folders you don’t mean to - it won’t give you any warning, it’ll just do it, so maybe do a test first?

Add the task to our default set:

 

And finally to our watch tasks:

 

Go ahead and run grunt or grunt watch again whilst keeping an eye on the images/ directory. It might happen very quickly, but you should see it disappear and then reappear again when the tasks are run. If you don’t see anything happen (it’s probably too fast for your computer to register anything has changed) check your terminal output and you should see a line saying the clean:images task ran OK.

A bit more Git

And again, you can ignore the next Git bit if you want and move on to Add a Javascript validation task

Now we’ve added our theme directory and some Grunt tasks let’s commit them to Git.

If you run git status on the command line you’ll probably see something like this:

 

There are actually a few things here we don’t want to commit to Git. We don’t want to track changes to .sass-cache/ and there’s no need to track node_modules/ either - the beauty of Node and npm is that everything we need to know is in package.json. If we want to set this project up on another computer we have only to clone the repo, run npm install and all the modules we’ve specified will be installed automagically!

So, open your .gitignore file and add the following rules:

 

Run git status again and you see the above directories have disappeared and that the .gitignore file is now showing as modified. Add the changes:

 

You’ll notice I’ve specified each item in the git add command. If you know a bit about Git you’ll know that you can simply say git add . (the dot means ‘everything’) and all modified or new files will be added to the commit. However, this is kind of considered bad practice as you can’t be sure that you’re not going to add something you didn’t want to. Either way, it’s up to you how you do it (I’m lazy sometimes too).

Now you can commit your changes with a message and push them to the remote repo:

 

TIP: In reality you would probably want to do your commits on a much more granular level, after you’ve added each Grunt task for example. That way if you mess things up you can just roll-back to the last task/commit. You should probably also follow a branching model such as gitflow, rather than working directly on the master branch.

Add a Javascript validation task (grunt-contrib-jshint)

I’d be surprised if in this day and age your site didn’t have some kind of Javascript functionality, so let’s add a linting (validation) task to check your code for you.

First, install the grunt-contrib-jshint module:

 

Then in your Gruntfile make sure the task is loaded:

 

Add the following task config (TIP: We might as well lint our Gruntfile too):

 

Add the task to our default set:

 

And finally update the watch task so jshint is run automatically when you make a change to any of your Javascript files:

 

All that remains is to actually create a theme/skin/frontend/my-theme/default/js/ folder and a theme/skin/frontend/my-theme/default/js/scripts.js file to test our new jshint task... Done that, I’ll wait while you do?

So in scripts.js let’s add some Javascript:

 

Now go ahead and run grunt. Providing you’ve typed everything in correctly you should get the following message in your terminal:

Let’s see what happens if we purposely put an error in our Javascript. Open scripts.js, mess up your code (maybe remove the first opening curly bracket) and run grunt again. Your terminal should now go crazy and spit out a load of errors:

You can use this message to help bug-fix your code. I know the errors aren’t necessarily that clear (when are they ever?), but they’re a start…

Add a javascript minification task (grunt-contrib-uglify)

I showed you earlier how you can use grunt-contrib-compass to precompile and minify your CSS. Why don’t we now do the same with our Javascript? For that we can use grunt-contrib-uglify.

So, following the usual process, install the module:

 

Load the task in your Gruntfile:

 

Add the following task config (TIP: setting mangle to false will preserve our variable and function names so they are less likely to inadvertently clash with any other Magento Javascripts):

 

Note: You can’t use skinDir in the first part of the files config - that’s because we’re actually declaring a property name here, not just a string, so we can’t concatenate our skinDir variable to it.

And finally add the task to the default set:

 

Now run grunt and see what happens. Once all the tasks have run check your js/ folder and you should find a new file called scripts.min.js. Open it, and you’ll see a minified version of your javascript.

Your terminal output should also look like this:

However, there’s one more thing you need to do - run grunt again and see what happens. You should now see an error in your terminal:

This is because the jshint task is trying to lint the .min.js file. I’m not a Javascript expert by any means, but my understanding is that certain syntax conventions aren’t actually required by browsers, such as some occurrences of semi-colons - we just put them in our code for completeness. To get round this we can tell jshint to ignore any minified files. Change your jshint task config to the following:

 

All we’ve done here is add a negation, by telling it to lint all the .js files in the js/ directory, but not (note the ‘!’) any that end in .min.js. Run grunt again and you should no longer see the error.

Now we’ve got that working we can also add uglify to our watch task:

 

As with the jshint task we need to add some negation here by telling it not to watch for changes in the .min files. If you don’t do this your watch task will just go round in an endless loop as it spots a change in scripts.min.js, re-lints and minifies scripts.js again, which triggers a change in scripts.min.js, and so on... Note that the syntax for negating .min files is slightly different here, but it’s doing the same thing as we had in our jshint task config.

Run grunt watch, make a change to scripts.js again and watch the magic unfold before your eyes!

 

7. Watching for changes in XML and PHTML files

Of course our Javascript tasks above are kind of pointless because we’ve not actually told Magento to load our new scripts.min.js file, so let’s do that now by adding it to a local.xml file (this is generally considered the best way to modify your Magento layout). We can then watch that file for future changes and use LiveReload to refresh the web page.

Start by creating the local.xml file:

 

Then in that file add the following code:

 

What we’re doing here is telling Magento to add an item to the head section of our page, specifically our scripts.min.js file in our skin’s js/ folder.

If you now refresh your web page and view the source you should see the scripts.min.js file being loaded. And if you view your web inspector’s Javascript console you should see our little message “Hello world!” (ignore all the 404s, they’re just the missing home page banners).

Now we’ve done that let’s tell our watch task to look out for changes to our theme’s XML files. Update the watch task config as follows:

 

All we’ve simply done is to tell it to watch for changes in any of the .xml files.

Now run grunt watch and make a change to local.xml (just change scripts.min.js to scripts.js for example, that way you won’t actually ‘break’ the file) - you should see all the tasks run and the web page refresh. If you look closer at the terminal output you should this a line that looks like this:

And at the end of the output:

We can take this a step further though - let’s also tell the watch task to keep an eye on our .phtml files. Change the line you just added to the watch config so it now reads:

 

To test that it’s working let’s edit a file. Run grunt watch and then open theme/app/design/frontend/my-theme/default/template/page/html/header.phtml and make a change in it - do something obvious, such as adding <h1>Test</h1> somewhere.

When you save the file you should see all the Grunt tasks run as normal and your ‘Test’ heading appear on the web page as it refreshes.

And so we’ve reached the end of my ‘little’ tutorial. Don’t forget to keep committing your changes to Git.

And one last tip - let grunt --verbose be your friend! If you’re having trouble getting anything to work, using the verbose flag will give you a lot more information about what’s happening, or not happening beneath the hood.

All the files in this tutorial can be found on Github. If you spot any issues, or have any questions/suggestions please also post them on Github.

Here are the sections again in case you want to jump back up to any of them:

So to sum it all up

What we’ve done here really only scratches the surface of what’s capable with Grunt. Lot’s of people are discovering the power of front-end automation and writing about it - A quick google and you’ll find loads of other resources to help you on your way.

Here are a few links you might find interesting if you want to take things further:

I hope, if you got this far, that you enjoyed the article and found it useful - Good luck!


You can follow Matt on Twitter, Dribbble and Google Plus. He also has his own blog.

Comments (4)

  • Paul Rogers Paul Rogers on January 11th, 2014

    Quality content as always Matthew!

  • Oğuz Çelikdemir Oğuz Çelikdemir on January 17th, 2014

    Dear Matt,

    I can't view the pictures that you are hosted on Dropbox. Could you please check?

  • Paul Paul on January 17th, 2014

    Hi Matt,

    excellent article, love it! Keep the good work going.

    Paul

  • Magento Training in Lucknow Magento Training in Lucknow on January 21st, 2014

    Thanks for sharing this guide.

Post your comment