Grunt watch turns save-and-refresh into one step

Compass compiles the stylesheets and JSHint checks the scripts, and both are run by hand until somebody forgets. grunt-contrib-watch is the piece that makes a task runner worth installing: it holds the file globs and runs the right task when the right file changes.

module.exports = function (grunt) {
    grunt.initConfig({
        compass: { dev: { options: { sassDir: 'src/scss', cssDir: 'public/css' } } },
        jshint:  { all: ['src/js/**/*.js'] },

        watch: {
            css: { files: 'src/scss/**/*.scss', tasks: ['compass:dev'] },
            js:  { files: 'src/js/**/*.js',     tasks: ['jshint'] },
            options: { livereload: true }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.registerTask('default', ['compass:dev', 'jshint']);
};

Two details decide whether it stays installed. Separate watch targets, so editing a stylesheet does not also lint the whole script tree — one catch-all target turns a 200ms compile into a four-second pause on every save, and people stop saving. And livereload: true with the browser extension removes the refresh, which sounds trivial until the page being styled takes six clicks to get back into. The cost is that Grunt spawns a new process per run by default, which is where most of the delay is; spawn: false is noticeably faster and means a task that throws takes the watcher down with it, so the terminal has to be visible.