by Flo Preynat

Right so I’ve made the leap.

After quite a ride, and some cool adventures with Codekit, I’ve decided to switch to Grunt. I had made the plan way before it became the hot topic of the month, before being relegated to second best to Gulp… lol, you’ve got to love this ever-changing technology and probably laugh at it sometimes too.

Anyway, don’t even start with Gulp, I’ve just made it to the grunt deck for less that a month or so and since I’m still taking baby grunting steps, I thought I’d share the reason of my decision and maybe my minimalistic grunt boilerplate in case you’d be interested.

Valid reasons

Codekit has been a good companion all this time and will remain one for smaller projects (Mixture is also a cool one too when it comes down to prototyping), … but those tools have been magic as long as it was me, myself and I working on a project.

The thing is… it’s getting more complicated now. I’ve started working with other people, we do some responsive web design (just html/css/js) that we later move and adapt to the salesforce.com platform. We use some new tools, we’re working remotely and not everybody is using Macs.

I know Prepros is a good option for windows users, I wrote about it at the time it went out. And I know you can export your Codekit settings and share them among mac users and all. But with version control driving the lot, it has become clear we needed a common ground as far as all this preprocessing-minification-optimisation business is concerned.

Cut a long story short: Gruntjs is next logical step.

I’ve been playing with grunt for a wee while – I was saying- and since a boilerplate was on the cards all this time, let’s take a look at the one I’ve made… for myself first and obviously for the small team I’m working with.

My grunt wish list

  • javascript error detecting tool.
  • javascript minification
  • some preprocessing with sass
  • auto-prefixing
  • image optimisation
  • automatic browser refreshing when html/css/js changes occur
  • work in html only (fed up php)
  • yet a templating system
  • and an automatic building process of the (optimised) lot

I’m restricting this list to something small to start off. Obviously more shall come, Autoprefixer (UPDATE January 27th 2014: now added), deployement to only name a couple.

Set up

You need node and npm and you need to read this getting started guide.

Install grunt with:

npm install -g grunt-cli

Create a package.json file at the root of your project like this one:

{
  "name": "my-project-name",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.2"
  }
}

Modules install

Install stuff by using:

npm install <module> --save-dev

Create a Gruntfile.js at the root of your folder too, and update it as many times as you add modules like so:

module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),   
    task1: {
    	options: {
    	}
    },
    task2: {
    }
  });
  
// Load the plugin that provides the tasks.
  grunt.loadNpmTasks('grunt-task1');
  grunt.loadNpmTasks('grunt-task2');
  
// Default task(s).
  grunt.registerTask('default', ['task1','task2']);

};

This is how I do it. Some people prefer using load-grunt-tasks and only include require(‘load-grunt-tasks’)(grunt); at the top of their Gruntfile.js (check the documentation).
I personally don’t as I always leave rubbish in my node modules folder and I’d rather write and control what I use instead of taking the lot for granted.

My current folder and files setup is as follows (make it your own obviously):

gruntjs-boilerplate1

Picking Modules

Javascript error detecting tool : grunt-contrib-jshint

jshint: {
      all: 'js/*.js'
}

Explanation: Let’s check out all javascript files in the js folder (all but libraries really, as in the ones you’re likely to fuck up by hand).

Javascript minification: grunt-contrib-uglify

uglify: {
    options: {
        mangle: false
    },
    dist: {
    	files: {
      	'build/js/myscript.js': ['js/libs/jquery.js','js/libs/*.js','js/*.js']
    	}	
    }
}

Explanation: You need mangle:false in there for some reason I don’t know (lol), and for the rest, let’s get (in that sequence order) jquery, the rest of the library .js files, then your own custom js files minified into build/js/myscript.js.

Sass pre-processing: grunt-contrib-sass

sass: {
     dist: {
    	  options: {
      		  style: 'compressed'
    	  },
    	  files: {
      		'build/css/global.min.css': 'scss/global.scss'
    	  }
     }
}

Explanation: Easy peasy with Sass. Note that I import all my _.scss files in a global.scss and have only this one compressed into build/css/global.min.css

Autoprefixing: grunt-autoprefixer

autoprefixer: {
   dist: {
     files: {
       'build/css/global.min.auto.css': 'build/css/global.min.css'
     }
   }
},

Explanation: Here, I’m asking autoprefixer to check my css and add the relevant browser prefixes. global.min.css is changed to global.min.auto.css.

Image optimisation: grunt-contrib-imagemin

imagemin: {
    dist: {
        options: {
          cache: false
        },
        files: [{
          expand: true,
          cwd: 'images',
          src: ['*.{png,jpg,gif}'],
          dest: 'build/images/'
        }]
    }
}

Explanation: Working on raw image samples (from the images folder) and outputting the optimised versions of png/jpg/gif files in build/images

Note: I have added the cache:false options to the module after noticing I was often getting empty files during optimisation.

HTML includes: grunt-includes

includes: {
	files: {
		src: ['pages/*.html'],
		dest: 'build',
		flatten: true,
		cwd: '.',
		options: {
		  	silent: true,
		}
	}
}

Explanation: Just follow the spec to be able to add include your includes/file.html in any of your pages. And send it all to the build folder.

Note: simply add the below line within your page when adding a component (or include):

include "../include/footer.html"

Watch (and Livereload): grunt-contrib-watch

watch: {
  	js: {
	    files: 'js/*.js',
	    tasks: ['jshint','uglify'],
	    options: {
	      	spawn: false,
	      	livereload: true
	    }
	 },
  	css: {
    	files: '**/*.scss',
    	tasks: ['sass','autoprefixer'],
    	options: {
      		spawn: false,
      		livereload: true
    	}
  	},
  	files: '**/*.html',
  	tasks: ['includes'],
  	options: {
    	spawn: false,
    	livereload: true
  	}
}

Explanation: Here in the settings, I’m separating the various tasks so the watch task doesn’t do the full reprocessing every time something is changed. I’m running jshint and uglify for javascript files, sass for scss changes, and includes for html changes.

Note: You’ll need the Livereload chrome extension installed in your favourite browser for this one.

Build: all the above + grunt-contrib-copy

Explanation: Most of the things i’m running above builds up my final folder, but I wanted to be able to put that entire folder in the trash whenever I wanted to start the building process from scratch. So I simply ran an additional task in order to duplicate my fonts folder into build/fonts.

Wrapping up

This is it.

Running grunt in the terminal (our default task) would build the lot from scratch and we would get an optimised and working build directory.

gruntjs-boilerplate2

Meanwhile, grunt watch (and the livereload extension turned on) will pick on any changes made to any of the html/css/js. Simply browse to your build folder while working on your project.

You will notice that No MAMP nor php includes are needed here while we have a full and customisable website templating system.

This may not be the way you work. After all, I’m far from a conventional developer (never really learned the stuff as I’m very much autodidact), but this process and folder structure suits me. It’s simple enough and since I won’t be industrializing it, it does exactly what I need it to do.

So long.

Note: Github repo now available.

My name is Flo Preynat and I am the freelance webdesigner and developer behind shoogle designs. I live in France and specialize in responsive web design. Give me a shoogle or get in touch with me on twitter.

Most Recent Posts

Special Recent Posts

Sip: a color picker refreshingly simple indeed

Sip: a color picker refreshingly simple indeed

July 10th, 2014

I've just discovered Sip, a color picker app for Mac users. "Just discovered" since it's been around[...]

Perch – the CMS that does not pollute your web design workflow

Perch - the CMS that does not pollute your web design workflow

July 7th, 2014

I have recently finished a project based on Perch, the clever 'little' CMS created by edgeofmyseat.c[...]

Responsive video code snippet

Responsive video code snippet

June 29th, 2014

More of a reminder than a pure detailed blogpost, this code snippet will be my go-to resource when I[...]

Project Naphta: a nifty extension to play with text embedded in images

Project Naphta: a nifty extension to play with text embedded in images

June 9th, 2014

We've all been there. You want to select a good chunk of text on a website, only to realise you can'[...]

Free photos for your web design projects

Free photos for your web design projects

June 4th, 2014

Nothing beats using a real professional photographer when working on a cool project. You can be the[...]

Comments

  1. Neil says:

    Nice post. Will have to look into the plugins.

    Autoprefixer on paper seems really good, I will have to test it and let you know.

  2. If you have used the first version of this boilerplate, note that I have since added the cache:false options to the imagemin module to solve the empty file issue I was having while running the grunt task.

  3. Ronan says:

    Hi Flo,

    Nice read. I’m a huge fan of Grunt (I’ve built my whole boilerplate with it). It’s quite amazing to setup your workflow exactly like you want to instead of relying on tools which may not offer all the options one is looking for.

    That being said, I have to admit that Gulp is quite amazing too. I suggest you take a look at it as a next logical step :)