Get Up And Running With Grunt

Advertisement

In this article, we’ll explore how to use Grunt1 in a project to speed up and change the way you develop websites. We’ll look briefly at what Grunt can do, before jumping into how to set up and use its various plugins to do all of the heavy lifting in a project.

We’ll then look at how to build a simple input validator, using Sass2 as a preprocessor, how to use grunt-cssc and CssMin to combine and minify our CSS, how to use HTMLHint3 to make sure our HTML is written correctly, and how to build our compressed assets on the fly. Lastly, we’ll look at using UglifyJS4 to reduce the size of our JavaScript and ensure that our website uses as little bandwidth as possible.

Grunt.js5
Grunt.js6 is a JavaScript task runner that helps you perform repetitive tasks such as minification, compilation, unit testing or linting.

Getting Started With Grunt

Most developers would agree that the speed and pace of JavaScript development over the last few years has been pretty astounding. Whether with frameworks such as Backbone.js7 and Ember.js8 or with communities such as JS Bin9, the development of this language is changing not only the way we experience websites as users but also the way we build them.

When you are working with JavaScript, you will likely need to execute multiple tasks regularly. While this is pretty much a given in most projects, it’s a time-consuming and repetitive way to work. Being in such an active community, you would assume that tools are available to automate and speed up this process. This is where Grunt comes in.

What Is Grunt?

Built on top of Node.js, Grunt is a task-based command-line tool that speeds up workflows by reducing the effort required to prepare assets for production. It does this by wrapping up jobs into tasks that are compiled automatically as you go along. Basically, you can use Grunt on most tasks that you consider to be grunt work and would normally have to manually configure and run yourself.

While earlier versions came bundled with plugins like JSHint and Uglyify, the most recent release (version 0.4) relies on plugins for everything.

What kind of tasks? Well, the list is exhaustive. Suffice it to say, Grunt can handle most things you throw at it, from minifying10 to concatenating11 JavaScript. It can also be used for a range of tasks unrelated to JavaScript, such as compiling CSS from LESS and Sass. We’ve even used it with blink(1)12 to notify us when a build fails.

Why Use Grunt?

One of the best things about Grunt is the consistency it brings to teams. If you work collaboratively, you’ll know how frustrating inconsistency in the code can be. Grunt enables teams to work with a unified set of commands, thus ensuring that everyone on the team is writing code to the same standard. After all, nothing is more frustrating than a build that fails because of little inconsistencies in how a team of developers writes code.

Grunt also has an incredibly active community of developers, with new plugins being released regularly. The barrier to entry is relatively low because a vast range of tools and automated tasks are already available to use.

Setting Up

The first thing to do in order to use Grunt is to set up Node.js. (If you know nothing about Node.js, don’t worry — it merely needs to be installed in order for Grunt to be able to run.)

Once Node.js is installed, run this command:

$ npm install -g grunt-cli

To make sure Grunt has been properly installed, you can run the following command:

$ grunt --version

The next step is to create a package.json and a gruntfile.js file in the root directory of your project.

Creating the package.json File

The JSON file enables us to track and install all of our development dependencies. Then, anyone who works on the project will have the most current dependencies, which ultimately helps to keep the development environments in sync.

Create a file in the root of your project that contains the following:

{
    "name" : "SampleGrunt",
    "version" : "0.1.0",
    "author" : "Brandon Random",
    "private" : true,

    "devDependencies" : {
        "grunt" :                   "~0.4.0"
    }
}

Once you have done this, run the following command:

$ npm install

This tells npm which dependencies to install and places them in a node_modules folder.

Creating the gruntfile.js File

Gruntfile.js is essentially made up of a wrapper function that takes grunt as an argument.

module.exports = function(grunt){

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json')
    });

    grunt.registerTask('default', []);

};

You are now set up to run Grunt from the command line at the root of your project. But if you do so at this stage, you will get the following warning:

$ grunt

> Task "default" not found. Use --force to continue.

We’d get this because we haven’t specified any tasks or dependencies yet other than Grunt. So, let’s do that. But first, let’s look at how to extend the package.json file.

Extending the package.json File

The best thing about working with Node.js is that it can find packages and install them in one go, simply based on the contents of the package file. To install all of the new dependencies, just add this to the file:

{
    "name" : "SampleGrunt",
    "version" : "0.1.0",
    "author" : "Mike Cunsolo",
    "private" : true,

    "devDependencies" : {
        "grunt" :                       "~0.4.0",
        "grunt-contrib-cssmin":         "*",
        "grunt-contrib-sass":           "*",
        "grunt-contrib-uglify":         "*",
        "grunt-contrib-watch":          "*",
        "grunt-cssc":                   "*",
        "grunt-htmlhint":               "*",
        "matchdep":                     "*"
    }
}

And to complete the process? You guessed it:

$ npm install

Loading npm Tasks In Grunt

Now that the packages have been installed, they have to be loaded in Grunt before we can do anything with them. We can load all of the tasks automatically with a single line of code, using the matchdep dependency. This is a boon for development because now the dependency list will be included only in the package file.

At the top of gruntfile.js, above grunt.initConfig, paste this:

require("matchdep").filterDev("grunt-*").forEach(grunt.loadNpmTasks);

Without matchdep, we would have to write grunt.loadNpmTasks("grunt-task-name"); for each dependency, which would quickly add up as we find and install other plugins.

Because the plugins are loaded into Grunt, we may start specifying options. First off is the HTML file (index.html), which contains the following:

<!DOCTYPE html>
<html lang="en">

    <head>

        <meta charset="utf-8">
        <meta name="viewport"   content="width=device-width; initial-scale=1.0; maximum-scale=1.0;">

        <title>Enter your first name</title>

        <link rel="stylesheet"  href="build/css/master.css">

    </head>

    <body>

        <label for="firstname">Enter your first name</label>
        <input id="firstname" name="firstname" type="text">
        <p id="namevalidation" class="validation"></p>

        <script type="text/javascript" src="build/js/base.min.js"></script>

    </body>

</html>

Validating With HTMLHint

Add this configuration to grunt.initConfig:

htmlhint: {
    build: {
        options: {
            'tag-pair': true,
            'tagname-lowercase': true,
            'attr-lowercase': true,
            'attr-value-double-quotes': true,
            'doctype-first': true,
            'spec-char-escape': true,
            'id-unique': true,
            'head-script-disabled': true,
            'style-disabled': true
        },
        src: ['index.html']
    }
}

A plugin is typically configured like this: the plugin’s name (without the grunt-contrib-/grunt- prefix), then one or more targets of your choosing (which can be used to create custom options for the plugin for different files), an options object, and the files it affects. Now, when we run grunt htmlhint from the terminal, it will check through the source file and make sure that our HTML has no errors! However, manually typing this command several times an hour would get tedious pretty quickly.

Automate Tasks That Run Every Time A File Is Saved

The watch task can run a unique set of tasks according to the file being saved, using targets. Add this configuration to grunt.initConfig:

watch: {
    html: {
        files: ['index.html'],
        tasks: ['htmlhint']
    }
}

Then, run grunt watch in the terminal. Now, try adding a comment to index.html. You’ll notice that when the file is saved, validation is automatic! This is a boon for development because it means that watch will silently validate as you write code, and it will fail if the code hasn’t passed the relevant tests (and it will tell you what the problem is).

Note that grunt watch will keep running until the terminal is closed or until it is stopped (Control + C on a Mac).

Keeping The JavaScript As Lean As Possible

Let’s set up a JavaScript file to validate a user’s name. To keep this as simple as possible, we’ll check only for non-alphabetical characters. We’ll also use the strict mode of JavaScript, which prevents us from writing valid but poor-quality JavaScript. Paste the following into assets/js/base.js:

function Validator()
{
    "use strict";
}

Validator.prototype.checkName = function(name)
{
    "use strict";
    return (/[^a-z]/i.test(name) === false);
};

window.addEventListener('load', function(){
    "use strict";
    document.getElementById('firstname').addEventListener('blur', function(){
        var _this = this;
        var validator = new Validator();
        var validation = document.getElementById('namevalidation');
        if (validator.checkName(_this.value) === true) {
            validation.innerHTML = 'Looks good! :)';
            validation.className = "validation yep";
            _this.className = "yep";
        }
        else {
            validation.innerHTML = 'Looks bad! :(';
            validation.className = "validation nope";
            _this.className = "nope";
        }

    });
});

Let’s use UglifyJS to minify this source file. Add this to grunt.initConfig:

uglify: {
    build: {
        files: {
            'build/js/base.min.js': ['assets/js/base.js']
        }
    }
}

UglifyJS compresses all of the variable and function names in our source file to take up as little space as possible, and then trims out white space and comments — extremely useful for production JavaScript. Again, we have to set up a watch task to build our Uglify’ed JavaScript. Add this to the watch configuration:

watch: {
    js: {
        files: ['assets/js/base.js'],
        tasks: ['uglify']
    }
}

Building CSS From Sass Source Files

Sass is incredibly useful for working with CSS, especially on a team. Less code is usually written in the source file because Sass can generate large CSS code blocks with such things as functions and variables. Walking through Sass itself is a little beyond the scope of this article; so, if you are not comfortable with learning a preprocessor at this stage, you can skip this section. But we will cover a very simple use case, using variables, one mixin and the Sassy CSS (SCSS) syntax, which is very similar to CSS!

Grunt’s Sass plugin requires the Sass gem. You will need to install Ruby on your system (it comes preloaded in OS X). You can check whether Ruby is installed with this terminal command:

ruby -v

Install Sass by running the following:

gem install sass

Depending on your configuration, you might need to run this command via sudo — i.e. sudo gem install sass: — at which point you will be asked for your password. When Sass is installed, create a new directory named assets and, inside that, another named sass. Create a new file named master.scss in this directory, and paste the following in it:

@mixin prefix($property, $value, $prefixes: webkit moz ms o spec) {
    @each $p in $prefixes {
        @if $p == spec {
            #{$property}: $value;
        }
        @else {
            -#{$p}-#{$property}: $value;
        }
    }
}
$input_field:            #999;
$input_focus:           #559ab9;
$validation_passed:     #8aba56;
$validation_failed:     #ba5656;
$bg_colour:             #f4f4f4;
$box_colour:            #fff;
$border_style:          1px solid;
$border_radius:         4px;

html {
    background:         $bg_colour;
}

body {
    width:              720px;
    padding:            40px;
    margin:             80px auto;
    background:         $box_colour;
    box-shadow:         0 1px 3px rgba(0, 0, 0, .1);
    border-radius:      $border_radius;
    font-family:        sans-serif;
}

input[type="text"] {
    @include            prefix(appearance, none, webkit moz);
    @include            prefix(transition, border .3s ease);
    border-radius:      $border_radius;
    border:             $border_style $input_field;
    width:              220px;
}

input[type="text"]:focus {
    border-color:       $input_focus;
    outline:            0;
}

label,
input[type="text"],
.validation {
    line-height:        1;
    font-size:          1em;
    padding:            10px;
    display:            inline;
    margin-right:       20px;
}

input.yep {
    border-color:       $validation_passed;
}

input.nope {
    border-color:       $validation_failed;
}

p.yep {
    color:              $validation_passed;
}

p.nope {
    color:              $validation_failed;
}

You will notice that the SCSS extension looks a lot more like CSS than conventional Sass. This style sheet makes use of two Sass features: mixins and variables. A mixin constructs a block of CSS based on some parameters passed to it, much like a function would, and variables allow common fragments of CSS to be defined once and then reused.

Variables are especially useful for hex colours; we can build a palette that can be changed in one place, which makes tweaking aspects of a design very fast. The mixin is used to prefix rules such as for appearance and transitions, and it reduces bulk in the file itself.

When working with a large style sheet, anything that can be done to reduce the number of lines will make the file easier to read when a team member other than you wants to update a style.

In addition to Sass, grunt-cssc combines CSS rules together, ensuring that the generated CSS has minimal repetition. This can be very useful in medium- to large-scale projects in which a lot of styles are repeated. However, the outputted file is not always the smallest possible. This is where the cssmin task comes in. It not only trims out white space, but transforms colors to their shortest possible values (so, white would become #fff). Add these tasks to gruntfile.js:

cssc: {
    build: {
        options: {
            consolidateViaDeclarations: true,
            consolidateViaSelectors:    true,
            consolidateMediaQueries:    true
        },
        files: {
            'build/css/master.css': 'build/css/master.css'
        }
    }
},

cssmin: {
    build: {
        src: 'build/css/master.css',
        dest: 'build/css/master.css'
    }
},

sass: {
    build: {
        files: {
            'build/css/master.css': 'assets/sass/master.scss'
        }
    }
}

Now that we have something in place to handle style sheets, these tasks should also be run automatically. The build directory is created automatically by Grunt to house all of the production scripts, CSS and (if this were a full website) compressed images. This means that the contents of the assets directory may be heavily commented and may contain more documentation files for development purposes; then, the build directory would strip all of that out, leaving the assets as optimized as possible.

We’re going to define a new set of tasks for working with CSS. Add this line to gruntfile.js, below the default task:

grunt.registerTask('buildcss',  ['sass', 'cssc', 'cssmin']);

Now, when grunt buildcss is run, all of the CSS-related tasks will be executed one after another. This is much tidier than running grunt sass, then grunt cssc, then grunt cssmin. All we have to do now is update the watch configuration so that this gets run automatically.

watch: {
    css: {
        files: ['assets/sass/**/*.scss'],
        tasks: ['buildcss']
    }
}

This path might look a little strange to you. Basically, it recursively checks any directory in our assets/sass directory for .scss files, which allows us to create as many Sass source files as we want, without having to add the paths to gruntfile.js. After adding this, gruntfile.js should look like this:

module.exports = function(grunt){

    "use strict";
   require("matchdep").filterDev("grunt-*").forEach(grunt.loadNpmTasks);

    grunt.initConfig({

        pkg: grunt.file.readJSON('package.json'),

        cssc: {
            build: {
                options: {
                    consolidateViaDeclarations: true,
                    consolidateViaSelectors:    true,
                    consolidateMediaQueries:    true
                },
                files: {
                    'build/css/master.css': 'build/css/master.css'
                }
            }
        },

        cssmin: {
            build: {
                src: 'build/css/master.css',
                dest: 'build/css/master.css'
            }
        },

        sass: {
            build: {
                files: {
                    'build/css/master.css': 'assets/sass/master.scss'
                }
            }
        },

        watch: {
            html: {
                files: ['index.html'],
                tasks: ['htmlhint']
            },
            js: {
                files: ['assets/js/base.js'],
                tasks: ['uglify']
            },
            css: {
                files: ['assets/sass/**/*.scss'],
                tasks: ['buildcss']
            }
        },

        htmlhint: {
            build: {
                options: {
                    'tag-pair': true,
// Force tags to have a closing pair
                    'tagname-lowercase': true,
// Force tags to be lowercase
                    'attr-lowercase': true,
// Force attribute names to be lowercase e.g. <div id="header"> is invalid
                    'attr-value-double-quotes': true,
// Force attributes to have double quotes rather than single
                    'doctype-first': true,
// Force the DOCTYPE declaration to come first in the document
                    'spec-char-escape': true,
// Force special characters to be escaped
                    'id-unique': true,
// Prevent using the same ID multiple times in a document
                    'head-script-disabled': true,
// Prevent script tags being loaded in the  for performance reasons
                    'style-disabled': true
// Prevent style tags. CSS should be loaded through 
                },
                src: ['index.html']
            }
        },

        uglify: {
            build: {
                files: {
                    'build/js/base.min.js': ['assets/js/base.js']
                }
            }
        }

    });

    grunt.registerTask('default',   []);
    grunt.registerTask('buildcss',  ['sass', 'cssc', 'cssmin']);

};

We should now have a static HTML page, along with an assets directory with the Sass and JavaScript source, and a build directory with the optimized CSS and JavaScript inside, along with the package.json and gruntfile.js files.

By now, you should have a pretty solid foundation for exploring Grunt further. As mentioned, an incredibly active community of developers is building front-end plugins. My advice is to head on over to the plugin library13 and explore the more than 300 plugins.

(al)

Footnotes

  1. 1 http://gruntjs.com/
  2. 2 http://sass-lang.com/
  3. 3 http://htmlhint.com/
  4. 4 https://github.com/mishoo/UglifyJS
  5. 5 http://gruntjs.com/
  6. 6 http://gruntjs.com/
  7. 7 http://backbonejs.org/
  8. 8 http://emberjs.com/
  9. 9 http://jsbin.com/welcome/1/edit
  10. 10 https://npmjs.org/package/grunt-minified
  11. 11 https://github.com/gruntjs/grunt-contrib-concat
  12. 12 http://thingm.com/products/blink-1.html
  13. 13 http://gruntjs.com/plugins

↑ Back to topShare on Twitter

Mike Cunsolo is Growth Marketing Manager at CDNify, a content delivery network for Developers and Start Ups.

Advertising
  1. 1

    I’ve been using grunt.js for a while to do exactly these things but didn’t know about dynamically loading tasks, was worth reading for that alone, thanks.

    2
  2. 2

    I don’t really see the point of using grunt when something like prepros exists?! I don’t need to install ruby, node or sass to compile all my pre-processed code, minify, concatenate and live refresh everything by just configuring 1 or 2 options in the gui and then simply saving in Sublime Text.

    Maybe there are more advanced features to grunt I’m missing (?) but in the mean time seems like an awful waste of time.

    0
    • 3

      Obviously you choose the tool that you prefer using (CodeKit is another alternative for some of these tasks), but a couple of advantages to using grunt are the fact that it’s a project with a thriving community and it’s very plugin-based, which means that there are tons of plugins for basically anything you could want to do – and if it doesn’t exist, you can make it. A couple of things we do that I can’t see being possible in Prepos (at the moment, I may be wrong) include using grunt to run QUnit tests on the code (there are also plugins for other test frameworks, like Jasmine), precompile Handlebars templates, run JSHint on the code and a couple of other minor things.

      Basically, grunt gives us greater possibilities for customization and more features, but with the added drawback of having to set things up initially. There’s also the benefit of having it all there in your code, so it’s easy to share between team members. Once you’ve got things set up in grunt, the workflow is pretty much the same. Change a file, save, watch and livereload does its job.

      2
    • 4

      While the Preprocess (or CodeKit, Less’s GUI, etc) is good for lone ranger or local machine, the grunt is perfect for team power on server side (or local machine with “grunt watch” task running in console or IDE).
      Not only it does same as GUI, it also can do file manipulations, do all kinds of twisted routines – for example – generate and concatenate a multiple source files all over 5 times and only then take the rendered source and convert to 3 different CSS files simultaneously – normal, minified and uglified. With dynamic comment banners.
      Grunt also does file management (copy, move, rename, delete files in temporary folders), compression with zip, building snapshots, on different build environments, and the biggest fun – JS testing with Karma Test Runner. On such remote build server, as Jenkins.
      You should definitely _not_ change your favourite working environment if it suits you. But at least you know that there is something more of you want to do more.

      0
  3. 6

    What if I already have package.json file? I am using php framework laravel

    0
    • 7

      As long as the package.json files are in different directories, this shouldn’t really cause a problem. One directory can be the root of laravel, the other can be the root of grunt. Say somewhere in the “public” folder of laravel can be your grunt root, perhaps. This also makes sense to separate where server side code is based and where front-end code is based.

      0
  4. 8

    Another way to get the more-or-less automatic loading is to use the package `load-grunt-tasks`, at which point you replace `require(“matchdep”).filterDev(“grunt-*”).forEach(grunt.loadNpmTasks);` with `require(‘load-grunt-tasks’)(grunt);`

    I say “more or less” because for instance Assemble doesn’t use the required “grunt” as a prefix.

    0
  5. 9

    Why include another task for css minification when the sass task can do that already?

    sass: {
    dev: { options: { style: ‘expanded’ }, files: [{ 'style.css': 'style.scss' }] },
    dist: { options: { style: ‘compressed’ }, files: [{ 'style.css': 'style.scss'}] }
    }

    0
    • 10

      That’s true, but this is a tutorial trying to show what grunt is capable of, and if you are not using a css preprocessor, you can still use the cssmin task.

      Excellent read.

      0
  6. 12

    Champions take failure as a learning opportunity, so take in all you can, and run with it.

    0
  7. 13

    Also remember to add node_modules to your gitignore. No need for those to be in your version control!

    I haven’t gotten the built-in Livereload functionality of grunt-watch to work correctly, though. It works fine as long as it only watches the css file, but as soon as I tell it to livereload js or html files, it starts to fall apart. The problem is that it fires a hard reload on ALL the files it’s watching, so live css injection fails. Not sure how to fix it.

    0
    • 14

      Hey Dan, I had the same problem a while ago and after a bit of hacking came up with this. It’s the gruntfile I’m using at the moment for a WordPress theme (I’ve set pkg.themeName in package.json). Livereload does a hard refresh on page files and injects style changes separately. It’s not perfect, but it does its job. I think after this site’s finished I can start to have a look at improving/completely redoing it.

      Not sure if these have been mentioned in any other comments but Todd Motto's got a great screencast looking at grunt and he’s also released FireShell, where he uses grunt for “Compiling Sass/SCSS, concatenating JavaScript files, connecting to a localhost server and live file reloads and injection. Auto-minification for production.”

      0
  8. 15

    I’ve tried this tutorial and copy-pasted some parts while writing some by myself and I must say it is pretty much straight forward.
    As I wanted to learn how to use grunt anyways this was a nice article to get me started.

    0
  9. 16

    > and explore the more than 300 plugins.

    Not even close ;)
    It’s currently 1643 grunt plugins on npm.

    0
    • 17

      Thanks Sindre, I meant to update the number but its a great example of how quickly the Grunt community is growing!

      0
  10. 18

    Top-notch…as always from Smashing. Thanks for putting this together!

    0
  11. 19

    Julien M. (Discover Grunt)

    October 29, 2013 1:30 pm

    Regarding the SCSS (CSS-like syntax based on SASS) compilation: another Grunt plugin makes it possible to bypass completely Ruby and the gem installation, which I find painful (and slow): https://github.com/sindresorhus/grunt-sass

    It is maintained by Sindre, from Grunt’s core-team, and is evolving rather quickly.
    It is based on the nodejs module https://github.com/andrew/node-sass, which means there is *nothing else* to do apart the usual “npm install –save-dev grunt-sass” (yay!), and is *far faster*.

    Once installed, you simply use it like this:

    grunt.initConfig({
    sass: {
    dist: {
    files: {
    ‘main.css’: ‘main.scss’
    }
    }
    }
    });

    The main limitation is it handles only SCSS syntax for now.
    However, if you only need classic SCSS compilation, it can replace grunt-contrib-sass or grunt-contrib-compass, which both require fiddling with Ruby gems.

    PS: This particular case, as well as step-by-step guides on most common Grunt issues (command-line, Windows, etc.), will be covered in the upcoming book “Discover Grunt”: http://discovergrunt.com. Yay!

    0
  12. 20

    There’s a mistake in your SCSS example. You’re missing a comma after “border”, so it outputs “border 0.3s ease”

    0
  13. 22

    Just wrote about Grunt a week ago http://goo.gl/1wWkHF

    0
  14. 23

    Recently started using grunt to create phonegap applications. It makes everything so easy from running tests, minifying code to wrapping my web app in Phonegap. Powerful stuff and so easy to start. Yeoman is worth a mention too for the easiest way to start your project http://yeoman.io/

    0
    • 24

      Yeoman is a great way to scaffold projects and automatically setup Grunt!

      We’re experimenting with it four our Drupal theme development as well as looking at it for other potential quick setup applications.

      0
  15. 25

    Checkout FireShell, it does all this – automated + tonnes more! :D

    http://getfireshell.com

    0
  16. 26

    Excellent post. Grunt is awesome.

    0
  17. 27

    Perfect introduction to Grunt workflow!

    0
  18. 28

    Filip Bruun Bech-Larsen

    October 30, 2013 10:57 pm

    I wrote a blog-post a couple of days ago about adding compass to your existing grunt scss-setup… might be worth a read for many, since thats the reason many people choose sass over less og stylus..
    http://www.frontendfrontline.com/2013/10/add-compass-to-your-grunt-setup.html

    0
  19. 30

    Hi, thanks a lot for this tutorial!
    After doing everything here, there’s no /build/js folder and no base.min.js-file in it after build/watch. Am I missing something?

    Thanks!

    0
  20. 32

    Oh yeah! The only thing I would add is show people how to load the project locally and watch changes by adding grunt-contrib-connect to devDependencies and then registering a task for [ 'connect', 'watch' ]

    0
  21. 33

    I should also be noted that you don’t need to make your package.json manually. As long as you have node installed on your machine you can just run “npm init” and that will generate your package.json file for you.

    0
  22. 34

    For some reason, I can’t get the “matchdep” part to work; I’m using Node version 10.21. The version of grunt I’m using is 0.4.1, and the version of the CLI is 0.1.9.

    I continuously get the error message “grunt is not defined”. Without the statement, things run fine without of course the custom tasks.

    Any ideas?

    1
  23. 35

    Thank you Mike for the awesome post!! It’s a highly recommended post for beginners who want to explore Grunt.

    0
  24. 36

    Great article. I wasn’t aware of using require(“matchdep”) to load Grunt modules.

    I wrote a quickstart style post about Grunt recently that might be useful to Grunt beginners: http://fcfeibel.com/blog/2013/07/28/grunt-quickstart-set-up-grunt-with-jshint/

    Also, a previous commentor suggested not commiting the node_modules folder, but I kind of disagree. It doesn’t hurt to commit them and it’s safer. The npm faq suggests it in some cases too: https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git

    0
  25. 37

    Really thorough stuff! Thank you! Oddly enough, I wrote a quick tutorial on GruntJS usage the other day as well. It’s definitely a more condensed article, but does include some notes about using LiveReload with Grunt’s Watch task for automatically loading changes into your browser. Cheers!

    http://justinklemm.com/grunt-watch-livereload-javascript-less-sass-compilation/

    0
  26. 38

    What about an example of how to use LESS with grunt?

    0
  27. 39

    Or use Rails

    0
  28. 40

    Nikhil Vilasrao Madhamshettiwar

    November 6, 2013 9:53 am

    A BIG THANK YOU for the step by step guide. I just created my sample project and can’t believe it was so easy.

    I have been trying to learn grunt from long time , but did not find any good articles , I always used to get stuck at some point.

    Thanks again !

    0
  29. 41

    Great intro, thanks a lot!

    I am trying to force htmhint to log some type of error – like deleting the top line (doctype) from the index.html. ‘watch’ fires and I get ‘Done, witout errors.’ in the command prompt – but I expected the doctype-first:true to cause an error if I deleted that line? Am I correct or did I do something wrong? I also tried deleting the last line – but same response – no errors reported – at least in the console?

    0
    • 42

      You can ignore my previous comment – I had changed

      grunt.registerTask(‘default’, []); to grunt.registerTask(‘htmlhint’, []); and so watch worked but htmlhint didn’t.

      Changed to grunt.registerTask(‘default’, ['htmlhint']); and it’s working great!

      0
  30. 43

    Hi awesome article. Thanks a lot for your efforts :)

    I’d suggest using grunt-newer to run tasks only on the latest modified file(s) (really helpful) and also grunt-concurrent which lets you parallelize tasks to speed up the building process.

    0
  31. 44

    Great article, thank you very much, It was really what I was looking for.

    0
  32. 45

    Check out the Grunt Survival Pack

    https://github.com/redaxmedia/gsp

    0
  33. 46

    When I run “grunt” with just the default task (no dependencies) in grunt-cli v0.1.10 and grunt v0.4.2, the console reads “Done, without errors.”

    2
  34. 47

    Great post! I love the mention of dynamic task loading in the gruntfile.

    I’m a bit surprised that you don’t mention that new plugins can be installed and automatically added to your package.json dependencies list with the command

    npm install –save-dev

    so you don’t have to manually edit the package.json file each time you need to install a new plugin for a task.

    0
  35. 48

    Love grunt and after using it some months I realized, that it’s not just automating my workflow, but restructuring and improving it. That’s because grunt makes me think about my workflow like a coding project, by literally letting me code it.
    Even blogged about it: http://www.danielauener.com/coding-workflows-grunt-changes-way-working/

    0
  36. 49

    Thanks for this step-by-step intro to grunt.

    I really appreciate that you took the time to give an example of the most frequent use cases and built off previous steps.

    0
  37. 50

    Thanks for this tutorial.

    0
  38. 51

    SASS (the ruby command-line tool) already minifies the compiled CSS if you use the appropriate option (–style compressed), so there is no need to run a separate grunt task for this. However, I haven’t tested if this works when using the grunt task to run SCSS.

    (Side note: the gruntfile contains “” and maybe some other html tags in the comments for the html hint config, which is being filtered out in the code examples of your article.)

    (Side note, 2: previewing comments doesn’t work.)

    0
  39. 52

    In my “side note” above, I meant to say that the gruntfile’s comments contain html, which is invisible because it got filtered out. Obviously, it was filtered out in my comment , too, so only the quotes were left. :D

    0
  40. 53

    Super awesome thanks for this. Finally got to understanding how to use Grunt.

    0
  41. 54

    Great Tutorial !!!

    0

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top