Setting up JSHint with Grunt

JSHint is a popular JavaScript linter that can help detect low-quality code.

It's good to run a linter every time you edit any JavaScript source code. You can automate this with using a tool called Grunt.

This article will take you from installing Grunt to automating the linting process.

Installing Node / NPM

The tools we are going to use are all written in JavaScript. To run them we need to install a JavaScript runtime called Node.

Follow the instructions on the installation page. Installing Node will also automatically install NPM, the Node Package Manager.

Initializing an NPM package.json file

NPM allows us to install Node packages like Grunt or JSHint. There's a video on the NPM website explaining what NPM does.

Like Grunt and JSHint, your own code is also going to be a package. So to get started we need to initialize our package by running this command in the directory that our code is in:

npm init

NPM will then ask you a series of questions. The exact answers you give aren't really important, since you're not going to make your package public.

This seems like a lot of work to lint some code, doesn't it!

The reason we use NPM is that, once it's set up, we can easily add new steps to our development process. In addition to linting we might want to minify our code or check that it follows our style guide.

After running npm init you should have a file called package.json in your directory.

Installing Grunt

To install Grunt run

npm install grunt --save-dev

This will download Grunt into a folder called node_modules.

In your package.json you'll find a new section called devDependencies:

"devDependencies": {
    "grunt": "^0.4.5"
}

By adding --save-dev to our npm install command, we can keep track of the Node packages we've installed. Then, instead of storing the packages in source control like a Git or SVN repository, we can run npm install to download all the dependencies we need.

Grunt also has a command line interface (CLI) that needs to be installed globally (using the -g flag):

npm install grunt-cli -g

You can now run Grunt!

grunt

Since we haven't configured it Grunt will show an error message:

A valid Gruntfile could not be found. Please see the getting started guide for more information on how to configure grunt: http://gruntjs.com/getting-started
Fatal error: Unable to find Gruntfile.

Creating a Gruntfile

Create a new empty JavaScript file called Gruntfile.js in the same directory as your package.json file.

Now running grunt will give you a different error:

Warning: Task "default" not found. Use --force to continue.

Aborted due to warnings.

Instead of default our task will be called jshint. So we'll be using

grunt jshint

to run the task.

Installing and configuring JSHint

Now Grunt still isn't able to find a task called jshint. We first need to install JSHint and configure it.

First we install the JSHint Grunt plugin:

npm install grunt-contrib-jshint --save-dev

Then we can load the JSHint package by putting this code into our Gruntfile.js:

module.exports = function(grunt) {
    grunt.loadNpmTasks('grunt-contrib-jshint');
};

Now running grunt jshint will find the task, but show a different error message:

>> No "jshint" targets found. Warning: Task "jshint" failed. Use --force to continue.

Aborted due to warnings.

We've installed Grunt correctly, but it still doesn't know which JavaScript files we want to lint.

To lint the correct files we need to add a configuration object to the Gruntfile:

module.exports = function(grunt) {
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.initConfig({
        jshint: {
            all: ['Gruntfile.js']
        }
    });
}

We pass the configuration object into the grunt.initConfig function. In the object we specify the task that we want to configure (jshint).

In this case, we want to configure JSHint to lint the Gruntfile.js file.

Now running grunt jshint correctly lints our file:

Running "jshint:all" (jshint) task

Gruntfile.js
  8 |}
      ^ Missing semicolon.

> > 1 error in 1 file
Warning: Task "jshint:all" failed. Use --force to continue.

Aborted due to warnings.

You can see that the module.exports = function(){...} assignment doesn't end on a semicolon. Let's fix that and run grunt jshint again:

Running "jshint:all" (jshint) task >> 1 file lint free.

Done, without errors.

Now JSHint no longer complains about our code.

Running JSHint on multiple files at once

The file paths that we pass into Grunt supports several globbing patterns. ** and * are two of them.

For example, if your application code is inside a folder called app this would be the correct configuration:

jshint: {
    all: ['Gruntfile.js', 'app/**/*.js']
}

** matches any file or directory, including nested directories.

*.js matches all files whose names end on .js.

Together, app/**/*.js will match all JavaScript files inside the app directory or any of its sub-directories.

Running grunt jshint will now lint all of those files and Gruntfile.js.

Automatically linting files when they change

To do this we need to install a Grunt plugin called watch that detects when a file has been updated:

npm install grunt-contrib-watch --save-dev

Then we configure the watch task in Gruntfile.js:

grunt.initConfig({
    jshint: {
        all: ['Gruntfile.js']
    },
    watch: {
        files: ['Gruntfile.js'],
        tasks: ['jshint']
    }
});

If any code in our files changes we want to run the jshint task. That's equivalent to running grunt jshint.

You can use file name globbing in the same way as in the JSHint Grunt task.

Run the watch task and then edit and save your Gruntfile:

grunt watch

Every time you save the file you should now see jshint task running in the console.