
Grunt 101: Automating the Boring (but Useful) Stuff
I was looking through the screencasts on CSS-Tricks the other day, and I noticed a couple of recent videos on how to use Grunt to automate various development tasks. Now, as a developer who does tasks every now and then, this seemed likes something that could be helpful. In this post I'll talk briefly about how to get started with Grunt and show you how I'm starting to use it to build this site.
So what is Grunt exactly? Grunt is a task runner module that runs on Node.js that allows developers to write a simple script to automate a large number of common development tasks. These tasks are likely to be repetive tasks like compilaton, minification or css pre-processing that are certainly valuable, but can be tedious and time consuming. With Grunt you can run them all with a single command, or even set up grunt trigger tasks when certain files are updated. Automating these tasks will save time and allow you to focus on the fun parts of developing your applications.
Getting started is a fairly painless endeavor. Grunt has an easy-to-follow guide on their site, but if you really want a clear walkthrough I would recommend watching Screencast #130 on CSS-Tricks. Here's a quick recap of the steps I took to get things set up for my project:
- I had never used Node.js before so my first step was to download and install it.
Next I used npm to install the Grunt Command Line Interface.
Tys-MacBook-Pro:workspace thorsenty$ npm install -g grunt-cli
Then I added the
package.json
andGruntfile.js
files to the root directory of my application. Proceeded to tinker with different plugins and set up a few different tasks.Tys-MacBook-Pro:thorsenty.github.io thorsenty$ grunt
Profit.
Seems simple right? It really is. Let's walk through those two files I added.
1 /* package.json */
2 {
3 "name": "thorsent",
4 "version": "0.1.0",
5 "devDependencies": {
6 "grunt": "~0.4.5",
7 "grunt-autoprefixer": "^1.0.1",
8 "grunt-contrib-jshint": "~0.10.0",
9 "grunt-contrib-sass": "^0.8.1",
10 "grunt-contrib-uglify": "~0.5.0",
11 "grunt-contrib-watch": "^0.6.1",
12 "grunt-shell": "^1.1.1"
13 }
14 }
Above is my current version of package.json
. This file is used by npm to install and mange all of the modules that Grunt uses to run the tasks I want. You see here that I'm including a number of different modules, primarily related to optimizing my client-side code. Autoprefixer and SASS are for CSS related tasks, jshint and uglify help clean and optimize my Javascript files, and watch and shell are used to coordinate and execute various sets of tasks.
Below is my Gruntfile.js
. At the bottom you can see the three tasks I'm currently using. The one I want to highlight is the 'default' task. I run this task once when I start developing. It runs through each of the pre-processing tasks and the build task, then calls watch. Watch continues to run, and watches for files changes within my project. When an SCSS file changes, it runs the CSS pre-processors and rebuilds automatically. When a Javascript file is changed, Grunt knows to run jshint and uglify on the changed files. Any changes to site pages or blog posts are automatically rebuilt as well.
1 /* Gruntfile.js */
2 module.exports = function(grunt) {
3
4 grunt.initConfig({
5
6 pkg: grunt.file.readJSON('package.json'),
7
8 autoprefixer: {
9 all: {
10 expand: true,
11 flatten: true,
12 src: "styles/*.css",
13 dest: "styles/dist/"
14 }
15 },
16
17 jshint: {
18 options: {
19 curly: true,
20 eqeqeq: true,
21 eqnull: true,
22 browser: true,
23 globals: {
24 jQuery: true
25 },
26 },
27 all: ['scripts/*.js']
28 },
29
30 sass: {
31 dist: {
32 files: [{
33 expand: true,
34 cwd: "styles",
35 src: "*.scss",
36 dest: "styles",
37 ext: ".css"
38 }],
39 options: {
40 style: "compressed"
41 }
42 }
43 },
44
45 shell: {
46 jekyllBuild: {
47 command: "jekyll build --drafts"
48 },
49 jekyllBuildProd: {
50 command: "jekyll build"
51 },
52 jekyllServe: {
53 command: "jekyll serve"
54 }
55 },
56
57 uglify: {
58 dist: {
59 files: [{
60 expand: true,
61 cwd: "scripts",
62 src: "*.js",
63 dest: "scripts/dist",
64 ext: ".min.js"
65 }]
66 }
67 },
68
69 watch: {
70 css: {
71 files: ['styles/*.scss'],
72 tasks: ['sass', 'autoprefixer', 'shell:jekyllBuild']
73 },
74 js: {
75 files: ['scripts/*.js'],
76 tasks: ['uglify', 'jshint', 'shell:jekyllBuild']
77 },
78 site: {
79 files: ['**/*.html', '!_site/**/*.html', '_posts/**/*.md', '_drafts/**/*.md'],
80 tasks: ['shell:jekyllBuild']
81 }
82 }
83 });
84
85 grunt.loadNpmTasks('grunt-autoprefixer');
86 grunt.loadNpmTasks('grunt-contrib-jshint');
87 grunt.loadNpmTasks('grunt-contrib-sass');
88 grunt.loadNpmTasks('grunt-contrib-uglify');
89 grunt.loadNpmTasks('grunt-contrib-watch');
90 grunt.loadNpmTasks('grunt-shell');
91
92 grunt.registerTask('default', ['uglify', 'jshint', 'sass', 'autoprefixer', 'shell:jekyllBuild', 'watch']);
93 grunt.registerTask('prod', ['uglify', 'jshint', 'sass', 'autoprefixer', 'shell:jekyllBuildProd']);
94 grunt.registerTask('serve', ['shell:jekyllServe']);
95 };
96
97 grunt.loadNpmTasks('grunt-contrib-uglify');
98
99 grunt.registerTask('default', ['uglify']);
100 };
With Grunt watching for file changes in my project and running these tasks automatically, I'm free to focus on the fun parts of developing my site. I highly recommend adding Grunt to your projects. I plan to continue to investigate new plugins and more prowerful ways to utilize this awesome tool.
comments powered by Disqus