Grunt, Gulp and Other "G" Tools (2018)

Estimated reading time: 2 minutes.

Complexity is the enemy of good software, but as I've complained about before, modern development seems to be all about adding complexity wherever possible to make life a little bit easier. Fair warning: more grumpy old man incoming.

Even that outlook doesn't fully explain the situation with tools like Grunt and Gulp. Purporting to create less work, they offer the ability to accomplish approximately the same thing as a tiny shell script and only require the installation of hundreds of dependencies npm install grunt resulted in 92 packages being installed. npm install gulp resulted in 274 packages being installed. in order to provide... well, very little functionality—all the functionality comes from plugins. Plugins which come with their own dependencies, maintainers, lack of documentation, and other issues. And for the most part just end up running the same command line tools that you could be calling from your shell script.

The vast majority of projects that web developers are working on barely require package management, never mind complex build tools and processes that poorly reimplement make. Even if your project may require a complex build process one day that justifies the complexity it probably doesn't today, and chances are YAGNI.

“Well, we're not going to minify our JavaScript by hand,” you might say, “so what exactly do you propose we do?”

The solution has been staring you in the face all along. You want a way to repeatedly run a set of commands, maybe pipe output from one script to another, maybe even chain a few of those together? npm's scripts directive will do all that and more! Let me introduce you to the package.json from a project I was working on the other day that involved digitizing pictures taken via webcam, converting them into a collection of convex polygons, importing those into a physics engine, then rendering the eventual result in an interactive game on a 46" touchscreen coffee table:

{
  "name": "@adampippin/sample-project",
  "homepage": "http://adampippin.ca/",
  "license": { "license": "UNLICENSED" },
  "author": "Adam Pippin <hello@adampippin.ca> (http://adampippin.ca/)",
  "version": "0.1.0",
  "devDependencies": {
    "node-sass": "^4.7.2",
    "nodemon": "^1.14.3",
    "uglify-js": "^3.3.2"
  },
  "optionalDependencies":{
    "matter-js": "^0.14.1",
    "pixi.js": "^4.7.0",
    "poly-decomp": "^0.2.1"
  },
  "scripts": {
    "build": "npm run-script scss:build && npm run-script js:build",

    "scss:build": "node-sass --style compressed assets/css/sampleproject.scss assets/css/sampleproject.css",
    "scss:watch": "nodemon -e scss --watch assets/css/ -x \"npm run-script scss:build\"",

    "js:build": "uglifyjs assets/js/vend/*.js assets/js/sampleproject.js assets/js/module/*.js --compress --mangle -o assets/js/sampleproject.min.js",
    "js:watch": "nodemon -e js --watch assets/js/ --ignore assets/js/sampleproject.min.js -x \"npm run-script js:build\"",
    "js:import": "cp node_modules/pixi.js/dist/pixi.js assets/js/vend/pixi.js && cp node_modules/poly-decomp/build/decomp.js assets/js/vend/decomp.js && cp node_modules/matter-js/build/matter.js assets/js/vend/matter.js"
  },
  "repository":{
    "type": "git",
    "url": "fakettp://adampippin.ca/sample-project.git"
  }
}

Wait what's this import thing? We'll talk about that later.

Once I made the switch, it wasn't hard to find some people much smarter than myself making the same case. Keith Cirkel, Senior Application Engineer at GitHub, had written an article years ago (2014) about using npm as a build tool, and certainly made the case much better than I did. Turns out he'd also made the case against using grunt or gulp. Hey Keith, we should probably be best friends.

Good developer tooling gets out of your way and lets you focus on doing what you need to do, not on the tooling.

Further Reading

If you use a build tool (Grunt, Gulp, Webpack etc.) for long enough you’ll begin to find that you start fighting with the tool rather than focusing on writing the code for your application.