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.