Five Good Reasons to Use Grunt for Front End CQ Development

Grunt.js is a JavaScript task runner that automates repetitive tasks like minification, compilation, unit testing, linting, and others. By using Grunt, you’ll streamline your workflow, write more robust code, and produce better quality assets. The time you’ll save will then be available for use on more challenging development tasks than those that lend themselves to automation.

Grunt is simple to configure and easy to use, which will ensure that other team members can quickly get up to speed to contribute to your project. Given the size of the community and ecosystem, all the most common needs are met by a wealth of available plugins. At CITYTECH, we’ve found Grunt to be absolutely invaluable to our development efforts.

What follows are five good reasons to use Grunt, as well as an example Gruntfile to help you get started with Grunt and Adobe CQ.

1. Lint, Compile, Prefix, and Minify your CSS

These days, it’s standard practice to use a CSS preprocessor, such as SassLESS, or Stylus. With Grunt you can easily compile your preprocessor of choice, as well as lint your CSS, prefix it with Autoprefixer (or another postprocessor like Myth or Pleease), and then minify it for production.

More recent versions of Adobe CQ come with support for LESS, but the included version is never up-to-date and has limited functionality as a result. Using Grunt to compile your LESS is preferable, especially when one factors in the flexibility that the Grunt plugin ecosystem provides.

An Example:

less: {
  build: {
    files:{
      '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>clientlibs/css/dist/application.css':
      '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>clientlibs/css/source/application.less'
    }
  }
},
// add vendor prefixes to CSS
autoprefixer: {
  options: {
    browsers: [
      'last 2 versions',
      'safari 6',
      'ie 8',
      'ie 9',
      'opera 12.1',
      'ios 6',
      'android 4'
    ]
  },
  build: {
    files:{
      '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>clientlibs/css/dist/application.css':
      '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>clientlibs/css/dist/application.css'
    }
  },
},
// minify CSS
cssmin: {
  build: {
    files:{
      '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>clientlibs/css/dist/application.min.css':
      '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>clientlibs/css/dist/application.css'
    }
  }
}

2. Lint, Test, Concatenate, and Compress your JavaScript

With Grunt you can lint your JavaScript (with JSHintJSLint, or ESLint) and run unit tests (with JasmineMocha, or Qunit), too. If your code passes, you can then concatenate it and even compress it, if desired. This sounds awfully similar to our first reason to use Grunt, right? That’s the point. We’re automating these repetitive tasks so we can focus our efforts on more difficult development matters.

Regarding JavaScript compression, Adobe CQ comes with an old version of YUI Compressor, which has been deprecated for years. The project has since been maintained by open source contributors, but better alternatives now exist, such as UglifyJS. As such, it may be preferable to use those alternatives as part of your Grunt (or Maven) build, although unfortunately extra work is required to maintain separate builds for development and production.

An Example:

// lint our JS
jshint: {
  options: {
    jshintrc: '.jshintrc',
    reporter: require('jshint-stylish')
  },
  all: ['<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>clientlibs/js/source/**/*.js']
}
concat: {
  options: {
    separator: ';'
  },
  build: {
    src: ['<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>clientlibs/js/source/**/*.js'],
    dest: '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>clientlibs/js/dist/application.js'
  }
},
// uglify our JS to reduce file size
uglify: {
  build: {
    files: {
      '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>clientlibs/js/dist/application.min.js': ['<%= concat.build.dest %>']
    }
  }
}

3. Build Image Sprites and Optimize Images

For your image assets, you can use Grunt to build an image sprite with Spritesmith. No longer will you be monotonously building a sprite by hand in Photoshop. Just drop your images in a directory and let Grunt convert them into a sprite sheet with corresponding CSS variables. You can then optimize your images with grunt-contrib-imagemin to reduce their file sizes, which is an easy performance win.

An Example:

// spritesmith
sprite: {
  build: {
    src: '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>static/sprites/source/*.png',
    destImg: '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>static/sprites/dist/spritesheet.png',
    destCSS: '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>clientlibs/css/dist/sprites.css'
  }
}
// optimize images
imagemin: {
  build: {
    files: [{
      expand: true,
      cwd: '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>static/img/source',
      src: ['**/*.{png,jpg,gif}'],
      dest: '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>static/img/dist'
    }]
  }
}

4. Build SVG Icons with PNG Fallbacks and Optimize Both

Again, say goodbye to a monotonous workflow between Illustrator and Photoshop. Use Grunticon to build SVG icons (with PNG fallbacks), minify those very same icons, and optimize those fallback images too. See how easy this is?

An Example:

// clean the generated icons directory
clean: {
  icons: ['<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>static/icons/dist/']
},
grunticon: {
  build: {
    files: [{
      expand: true,
      cwd: '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>static/icons/source/compressed/',
      src: ['*.svg'],
      dest: '<%= pathTo.jcrRoot %><%= pathTo.projectDesigns %>static/icons/dist/'
    }]
  }
}

5. Use the Watch Task with Grunt Slang

The preceding reasons to use Grunt are mostly focused on building production-ready assets, but it doesn’t need to be that way. You can run these tasks as you develop with help from a few Grunt tasks: watchconcurrent, and Grunt Slang, the former being an open source project by our very own Mike Nelson.

The combination of these tasks will allow you to “sling files to Sling” in near real time. What does this mean for your development workflow? You can now write your CSS and see the change in the time it takes you to reload your browser. A small change to a front-end asset will no longer require a full build of the project.

An Example:

watch: {
  author: {
    files: ['<%= pathTo.jcrRoot %>**/*.{css,xml,html,js,jsp,txt}'],
    tasks: ['slang:author'],
    options: {
      spawn: false
    }
  },
  publish: {
    files: ['<%= pathTo.jcrRoot %>**/*.{css,xml,html,js,jsp,txt}'],
    tasks: ['slang:publish'],
    options: {
      spawn: false
    },
  },
  less: {
    files: ['<%= pathTo.jcrRoot %>**/*.less'],
    tasks: ['less','autoprefixer']
  },
  js: {
    files: ['<%= jshint.all %>'],
    tasks: ['jshint']
  }
},
concurrent: {
  options: {
    logConcurrentOutput: true
  },
  author: [
    'watch:less',
    'watch:js',
    'watch:author'
  ],
  publish: [
    'watch:less',
    'watch:js',
    'watch:publish'
  ]
},
slang: {
  author: {
    options: {
      port: '4502'
    }
  },
  publish: {
    options: {
      port: '4503'
    }
  }
}

Get Started

Setup

Install Node.js.

Install the command line interface for Grunt (via NPM, which comes with Node.js).

Example Files

To help you get started, here are two example files that should be put in the root of your project’s working directory and committed into version control:

Please Note:

  1. These example files cover only a sample of the features discussed above
  2. You will need to customize and configure these files to meet your needs.

Install Dependencies

Run the following commands to install the dependencies in package.json:

  • npm cache clean
  • npm install
  • npm update

Grunt Workflow

Here are the Grunt commands that are available for use:

  • grunt check: Checks for outdated dependencies (with grunt-dev-update) and JavaScript code quality with JSHint
  • grunt css: Compiles LESS, adds in vendor prefixes with Autoprefixer, and minifies the resulting CSS
  • grunt icons: Wipes clean the generated icons directory, minifies the SVGs, runs Grunticon, and then optimizes the fallback PNGs
  • grunt images: Optimizes the images for file size, but only the images that have been modified since the last time the command was run, courtesy of grunt-newer
  • grunt js: Checks JavaScript code quality with JSHint (again only newer files), concatenates the files, and then uglifies them.
  • grunt assets: Runs the css, icons, images, and js commands in that order
  • grunt author: Concurrently runs watch tasks for changes in the LESS and JavaScript files in the author instance of Adobe CQ. If files are changed they’re then slung to Sling.
  • grunt publish: Concurrently runs watch tasks for changes in the LESS and JavaScript files in the publish instance of Adobe CQ. If files are changed they’re then slung to Sling.