Skip to content

Instantly share code, notes, and snippets.

@zachrose
Last active January 11, 2016 16:26
Show Gist options
  • Save zachrose/36e87435c6364b52cc51 to your computer and use it in GitHub Desktop.
Save zachrose/36e87435c6364b52cc51 to your computer and use it in GitHub Desktop.
Front-end JavaScript Tooling Preferences

Front-end JavaScript Tooling Preferences

At the end of the day these are personal preferences that have worked for me in the past, but I'll try to sell them here with concrete benefits.

These preferences are dated early 2016, but have been stable for about a year and a half now.

Package Manager

Use NPM. Its the CPAN of JavaScript.

Why not Bower? Bower tries to do "web stuff" including CSS and fonts. I'm not opposed to that, but I also see JavaScript dependencies and CSS dependencies as completely different things. Let's say we were looking for a library to do financial calculations in JavaScript. NPM has exactly what we want, whereas Bower has a grab bag of tangentially related libraries and view-specific widgets.

Why not just downloading JS files and putting them in /vendor? Not a bad idea, but I prefer to keep third-party libraries out of my repo.

Module System

Use CommonJS modules.

  1. It's really easy to look at a file of code and know where all the dependencies come from.
  2. Just the right amount of syntax. (var foo = require('foo'); module.exports = "bar").
  3. You get to easily use anything in NPM.

Why not AMD/Require.js? AMD modules are verbose, and I've yet to see a need for asynchronously loading dependencies.

Why not ECMAScript 6 modules? Because that requires ES6, which affects way more than modules and is a whole 'nother discussion.

Why not global dependencies on a page, with the traditional (function(jQuery){ ... })($) pattern? This still assumes that modules export their stuff into a global namespace, which means they're available globally, which is less constraint than I prefer.

JS Concatenator/Linker/Compiler

I like Browserify, although from what I understand Webpack does the same thing and might be faster. Browserify is meant to bring common.js modules to the browser, that's just about the only thing it does. It also allows for "transforms" to be plugged in so that your code can require .jsx files and the like, but to me this is a minor benefit.

Task runners

Grunt? Gulp? Broccoli? Brunch? Task runners don't do it for me.

  1. They usually require "shim" libraries that adapt the task runner to the dependency that you really wanted to use. All to often these shims have subtle incompatibilites with the version of the dependency you want to use or with the version of the task runner itself.
  2. They encourage an ever-growing task file that doesn't really have any clear responsibility. It's too easy to add stuff to the task runner when it doesn't necessarily belong there, which makes it ever-easier to couple tasks that shouldn't be coupled.

What do I do instead? Short, custom NPM scripts defined in the package.json. You're already using that file for NPM dependencies. Anything longer or more specific (e.g. watcher tasks) I might break out into an independent script in /bin, but still use through an npm script for consistency (e.g. npm run watch).

Testing

I like Mocha.

Why not Jasmine? Jasmine was designed to run in a browser, and requires adapters to run on the command line. That just seems backwards to me, and also doesn't play nice with CommonJS modules.

What about assertions? Mocha is just for organizing and running tests, and doesn't include utilities for mocks/stubs or for assertions. I see that as a good thing, if only because it makes it a little more clear which piece is doing what, and because I want to opt-in to using mocks and stubs rather than just having them by default. I like sinon for mocks, stubs, and time travel, and either should for assertions or the plain-jane Node.js assert module.

Also, having a test runner that's designed to work with CommonJS modules makes it easy and most-importantly fast to just require a single module and test it without involving your entire JS build.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment