Posted on January 20, 2015 by Chris Harrington

Concurrent watches with Grunt

I’ve been using Grunt with Browserify recently to build the theme for this blog (https://github.com/chrisharrington/dapper-developer-theme) and I’ve noticed that using grunt-contrib-watch in conjunction with Browserify is pretty slow: on the order of 1500ms on a JavaScript code change, which I felt was unacceptable. Watchify is a tool used to bundle Browserify modules on change that works much faster because it only rebundles files that have changed. This is great, but I run into a problem if I’m watching my LESS files at the same time, as each watcher will block. I’ve put together a quick Gruntfile that’ll allow you to run multiple watchers using grunt-concurrent, a Grunt task that’ll let us to run multiple blocking tasks at the same time.

grunt.initConfig({
	browserify: {
		watch: {
			src: ["script/vendor/**/*.js", "script/app/**/*.js""],
			dest: "script/app.js",
			options: {
				watch: true,
				keepAlive: true
			}
		}
	},

	watch: {
		styles: {
			files: ["style/**/*.less", "style/**/*.css"],
			tasks: ["less"],
			options: {
				spawn: false
			}
		}
	},

	concurrent: {
		watch: {
			tasks: ["watch", "browserify:watch"],
			options: {
				logConcurrentOutput: true	
			}
		}
	}
});

Browserify

The grunt-browserify package allows us to hook into Browserify for our Grunt builds. The configuration above is used specifically for watching, although removing the options section will run your Browserify code just the once. The watch option indicates that we want to watch our code for changes, while the keepAlive option says that the watcher should remain running indefinitely.

LESS

We’re using grunt-contrib-watch to watch for LESS file changes. There’s nothing really of note here that should be unfamiliar to anyone who’s used the Grunt watcher in the past. The spawn option indicates that we’re not spawning a child process for our watcher, which increases performance, but decreases reliability. That said, I’ve never run into a problem with missed watches.

Concurrent Tasks

The final task in our Gruntfile is concurrent, which specifies that we want watch and browserify:watch to run at the same time via the tasks section. The logConcurrentOutput option indicates that we want to see any console.logs from both of our concurrent tasks on the command line.

Conclusion

That’s it! Nothing to it, right? Run your double-watcher from the command line with grunt concurrent:watch. Thanks for reading!