Skip to main content
Sheelah Brennan

From Guard to Grunt

I recently got to attend the Open Web Camp V in San Jose, CA. I made a last-minute switch on my session choice in the afternoon and opted to attend Dirk Ginader’s “Let Grunt Do the Work, Focus on the Fun!” talk, and I am so glad that I did.

I have been hearing about Grunt for awhile and have been tempted to try it out for Javascript file concatenation and minification and even had heard you could configure other tasks like JS hinting upon file save. At Dirk’s talk I found out you can have grunt compile your SASS as well upon file save and even set up live browser reload. At that point I was sold and decided to try Grunt out in place of Guard on my linux system, which had been working just fine for SASS compilation and live reload upon file save.

I installed Grunt and configured it for an existing project without much trouble.

Installation

Note that node.js is a prerequisite for using Grunt. I had to update my Fedora installation in order to be able to install node (how quickly things get out of date!). I followed the steps at the GruntJS site to install Grunt via npm install. It was there that I found out I needed two files for each project that I want to use with Grunt — a package.json file and a Gruntfile.js file.

I installed a basic Gruntfile from Github, installing grunt-init first as the instructions detailed. I used the npm init command to create a basic package.json file.

Plugins

Next the customization fun began. There are a huge number of Grunt plugins that can be installed to add additional functionality. I am using:

There are tons of other plugins I am still finding out about, like a CSS linter. Good stuff! I like that the installation of plugins is very easy too. Since Grunt plugins are packaged as node modules, they can be installed via npm.

So far, so good with Grunt. For SASS compilation, I simply run grunt and leave it running. Any time I save a SASS file, the compilation takes place. The other tasks, like livereload, work the same way (as long as I have the livereload browser extension running, my browser refreshes immediately).

Sample Configuration Files

My Gruntfile:

module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    // Metadata.
    pkg: grunt.file.readJSON('package.json'),
     banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
      '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
      '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
      '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
      ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
    // Task configuration.
    concat: {
      options: {
        banner: '<%= banner %>',
        stripBanners: true
      },
      dist: {
        src: ['lib/<%= pkg.name %>.js'],
        dest: 'dist/<%= pkg.name %>.js'
      }
    },
    compass: {
      dist: {
        options: {
          config: 'config.rb',
          force: true
        }
      }
    },
    uglify: {
      options: {
        banner: '<%= banner %>'
      },
      dist: {
        src: '<%= concat.dist.dest %>',
        dest: 'dist/<%= pkg.name %>.min.js'
      }
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        unused: true,
        boss: true,
        eqnull: true,
        browser: true,
        globals: {}
      },
      gruntfile: {
        src: 'Gruntfile.js'
      },
      lib_test: {
        src: ['lib/**/*.js', 'test/**/*.js']
      }
    },
    watch: {
      gruntfile: {
        files: '<%= jshint.gruntfile.src %>',
        tasks: ['jshint:gruntfile']
      },
      sass: {
       files: ['sass/*.scss'],
        tasks: ['compass'],
        options: {
          livereload: true,
        }
      },
      js: {
        files: ['js/*.js'],
        tasks: ['uglify', 'jshint']
      }
    }
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');

  // Default task.
  grunt.registerTask('default', ['jshint', 'concat', 'watch']);

};

My package.json file:

{
  "name": "sheelahb",
  "description": "Portfolio site",
  "version": "0.0.0",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-concat": "~0.1.2",
    "grunt-contrib-jshint": "~0.6.0",
    "grunt-contrib-uglify": "~0.2.2",
    "grunt-contrib-watch": "~0.5.1",
    "grunt-contrib-sass": "~0.4.1",
    "grunt-contrib-compass": "~0.5.0"
  }
}

Follow Me

Built with ♥ and Gatsby, hosted on Netlify

My new Skillshare course: Make Your Website Stand Out