Never Refresh Again
How about an easy to way eliminate thousands of keystrokes? Grunt can do that.
Grunt is an excellent tool that can automate many of the things we do during web development. The result is that you get more time to focus on building while avoiding repetitive minutae.
In this protip, we'll focus on one aspect of Grunt - watching for changes to files and automatically refreshing the browser in response. There are a few steps to get set up, but the end result is worth it.
If you've never used Grunt, it's easy to get started. First, make sure you have node.js and npm installed. You won't have to write (much) node code, but Grunt needs it to run. There are a bunch of ways to install, so pick the one that's easiest for your platform.
Once that's settled, let's get the grunt
command-line interface. Install it by running:
sudo npm install -g grunt-cli
This makes the grunt
command available within a terminal.
Next, navigate to your web project's directory. We'll use npm
to set up the package.json
configuration file. Run the following command and it will guide you through a short initialization sequence.
npm init
Good. Now you've got a package.json
file and are ready to install the two grunt dependencies we'll use. The first is the grunt
module, and the second is the grunt-contrib-watch
plugin. Install both like this:
npm install grunt --save-dev
npm install grunt-contrib-watch --save-dev
Notice that --save-dev
flag. It will add entries to the devDependencies
section of package.json
. Look in that file and you'll see that it keeps a record of which npm packages are required for the project.
It's a good idea to commit package.json
to source control so that new dev environments can be set up quickly. If you're working with a team, they'll only have to run npm install
to get all the necessary dependencies automatically.
Alright. Next we'll set up a file named Gruntfile.js
which will tell Grunt what to do. There are lots of excellent plugins which can do various things like sass compilation, javascript uglification, js linting, and more - but for the sake of this protip's scope we'll limit ourselves to the grunt-contrib-watch
plugin.
Our basic Gruntfile.js
will look something like this:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
watch: {
foobar: {
files: ['**/*.js'],
options: {
livereload: true
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['watch']);
};
Let's break it down.
module.exports
is the wrapper for node modules (like Grunt!)
grunt.initConfig()
tells grunt which plugins and tasks we'd like to make available, and how each one should be configured. Other than feeding in the package.json
file, our only task is watch
.
The foobar
key in the watch
object can be named anything you like. You could call it scripts
, files
, css
, etc. It tells the watch
plugin that you'd like it to look for any changes to the files
within. For this example, it will respond to any files matching **/*.js
(which means any .js
file in any subdirectory).
When a .js
file is changed, Grunt will notice and run everything in the tasks
array of the foobar
object. But... wait. We didn't put any tasks in foobar
. That's OK. In this example we're only going to refresh the browser, which is a feature built into grunt-contrib-watch
and doesn't require additional tasks. However, if you want to add some tasks (like minification or sass compilation) then those would run before the browser refreshes. Pretty handy.
Now, the options
object is what enables livereload
which is where the magic happens. After all tasks have run (if there are any) the LiveReload server will be notified that it's time to refresh. Once our browser is set up to handle this, we won't have to press ⌘⇧R anymore!
Lastly, the default
task is what grunt runs when it's invoked without any command-line arguments. Here we've made the default watch
. So, on the command line, just run grunt
in your project directory (where your Gruntfile is), and grunt will go into watch mode.
If you set it up like the example, run grunt
and you should see:
Running "watch" task
Waiting...
We're so close!
The last step is to activate LiveReload in your browser. The simplest way is to use a browser extension. Once installed, enable it by clicking the icon in the upper right. Now it should refresh when changes are made to .js
files within your project. When this happens you should also see some console messages in the terminal where grunt
is running. Try it out!
Something that's even more fun is to enable LiveReload by adding a <script>
tag to your web app's header. This is really useful if you have a bunch of devices (phone, tablet, etc.) that you'd like to keep nearby and automatically refresh along with your desktop browser. Of course, these devices must be able to connect to your dev site already, and they also need to be able to connect to your local machine's IP (or whichever machine grunt is running on).
If you want to do this, point the script tag at http://your.local.machine.ip:35279/livereload.js?snipver=1
(Mine looks like <script type="text/javascript" src="http://192.168.0.2:35729/livereload.js?snipver=1"></script>
). Again, this IP should point to the machine grunt
is running on. This way, you don't need a browser plugin and you can auto-reload in nearly any environment. (IE excluded, naturally)
One last note to make you giddy with delight. CSS changes are special when using LiveReload - they happen without a refresh. That is, they are applied instantly within your browser. This feels like magic, and it makes responsive development a breeze.
I hope you've found this guide useful. Thank you to everyone who helped build Node.js, npm, grunt, and LiveReload!
More documentation on grunt and grunt-contrib watch can be found at http://gruntjs.com/ and https://github.com/gruntjs/grunt-contrib-watch