Skip to content

Javascript frontend build tooling

Javascript is an essential tool for building great user interfaces these days, and has some really mature tools for getting a great development environment. One problem I’ve had is there are many different ways to hooks these tools together.

After a lot of trial and error, I found a set that seems to work pretty well for me across different javascript frameworks.

Goals

  • write my app with multiple files, but deploy as one js file
  • have a machine handle mechanical boilerplate like IIFEs, strict mode, etc
  • automated tests (with code coverage), that run whenever I change a file
  • static analysis of my code to catch problems
  • local webserver to use with my app, that automatically reloads the page whenever I change a file
  • use ecmascript 6 (ES6) or other “compiles down to js” systems (e.g. typescript, react)
  • use other open source javascript libraries
  • use a small number of tools so it’s easier to understand
  • cross-platform development (sometimes I’m on windows, sometimes on linux)

This feels like a pretty high bar, but javascript has some crazy capabilities, and it’d be a shame not to use them.

Solution

npm for tasks and dependencies

I use npm as a task runner and for dependencies. It also seems like everything published to bower is also published to npm, so I’m happy to skip other package managers. Just don’t look too closely in the node_modules folder, it’s madness in there.

The npm scripts are effective for defining tasks without needing to install things globally nor edit my $PATH. Any node-based CLI tools installed to the local node_modules folder via npm install are automatically on the $PATH when using npm scripts. I’d rather spend a little disk space than manage the unintended consequences of shared global state. It also helps reduce setup time for other developers. We can get away with just git clone && npm install && npm start.

I generally make a few custom tasks:

  • npm start – start a local webserver and spin up a bunch of filesystem watchers to run tests and refresh my browser
  • npm run build – create a final bundle for distribution
  • npm run ci – run tests and static analysis for continous integration bots

I also tend to make subtasks, and chain them together using the limited syntax that is shared between sh and cmd.exe.

exorcist + browserify + plugins for compilation

I use browserify for an awful lot of things. It’s my compiler, translator, minifier, and bundler. I tend to think of it all as compilation, but that’s a simplification.

The most basic feature is using nodejs modules to write my code in many files and specify the dependencies between them using require statements at the top of each file. This nicely mirrors imports in every other programming environment (e.g. using in C#, import in python, require, require_once, include in php, etc).

exorcist creates a separate source map file from the browserify output. This is really useful for testing, since most browsers will load up the source map automatically and show you you’re actual source code in the debugger instead of whatever unreadable garbage that actually gets executed.

Most of the browserify functionality comes through plugins:

eslint + karma + jasmine + phantomjs + plugins for testing

This is probably the first bit of javascript build tooling I ever figured out, and I’ve been using it every since. karma has a “watch” option where it will keep re-running tests as code changes.

watchify + live-server + npm-run-all for active development

The “reload-as-you-edit” features are part of what make javascript such a productive environment for user interfaces, especially when you have multiple monitors. I love having a browser / terminal on one monitor showing the UI and test output, and then my editor on another monitor. It’s really great to be able to simply save a file and glance over and see if my tests pass or the UI looks alright.

Conclusion

All in all that’s 29 direct dependencies, and probably hundreds or thousands of indirect dependencies. That still feels crazy to me, but I think that’s mostly because I have to hook it all up myself. Something like eclipse or visual studio has a ton of moving parts, but it’s one installer so I tend not to think about it. You can see some examples on some of my hobby projects: c4-lab, chore-cat, and kpi-me.

There’s room for improvement (e.g. debugging tests, speed), but this setup has worked out pretty well for me. In my last post I decided against it, but then found some more tools that really brought it all together.

Most of these kinds of setups include grunt or gulp, but I haven’t really needed them. Between npm scripts, browserify, endless plugins, and shell redirection I can accomplish the same results with one less dependency and config file. I feel like if I did adopt grunt or gulp, I’d basically have the same setup, but with their plugins instead of browserify plugins.