Kat’s Short Guide To JS Devops Ecosystem

So as it turns out, the front-end JS ecosystem is fairly complicated. So many libraries to do basically everything, 100 times over. For a lot of folks, one of the biggest and most controversial bits of this is what to do at the development environment level, which I call devops. This is the stuff that isn’t your front-end framework or whatever, but the tools that help you put everything together and smooth the actual process of coding out.

I’ve tried to collapse them into a set of choices that you can make between fairly-equivalent tools, and you can figure out the details based on your specific project needs.

Note that depending on your other tools (servers, front-end frameworks, etc), a lot of these choices will be made for you. This post is for clarification, and doesn’t cover those cases, which you’ll have to suss out on your own.

1. pick a task runner

These are for abstracting away common development tasks, like running tests or a dev server. tool <commandname> to do each thing, i.e. gulp test.

Choices: Grunt, gulp, make, and npm scripts.

They are all the same thing — ops tools for composing together large, complicated build tasks. The first 2 (grunt, gulp) are nice because they have big ecosystems of common tasks, so you simply import them, and add some configuration, and they take care of the details. The others require no extra dependencies, but don’t scale very well as things get more complex (if that’s where you’re headed).

Edit: A previous version of this referred to broccoli as a task runner — this is not quite right. It works more like a bundler in practice (see below).

2. pick a bundler

(front-end only)

If you’re doing front-end, you usually want a tool that can get all your javascript files, collect them, minify them, and spit them out as a single app.js that you then put in a <script> tag.

Choices: Webpack, browserify, broccoli.

They only differ in some details in their approach. Pick whichever you find yourself more confident with after looking at their docs. Most of the time, there will be no real difference in the end. npm cannot do this very easily at all, unless you write a manual concatenation bash script. Please don’t do that, and ignore the jerks who try and convince you that’ll ever be maintainable.

3. pick a compiler tool

(optional)

Compilers let you write javascript in one style (such as ES6/ES2015 or CoffeeScript), and convert them to es3 or es5 so it works with most platforms, or even minify or otherwise transform it.

Choices: babel, UglifyJS or plugins to your bundler (babel can also be, and often is, a plugin)

If you’re just gonna write and output straight-up es5 or es3 (“regular” javascript), you do not need this.

That said, the functionality in compiler tools is almost always absorbed into the build pipeline for bundlers, so most of the time these will just be plugins you add to those.

4. pick a test runner

There’s a bunch of test runners, they all work somewhat differently, but they all basically do the same thing: run your project’s tests.

Choices: karma, testee, tap, mocha, jasmine, etc.

Your choice here should depend on what you want your tests to look like, and what just happens to be more convenient for you. Running tests on a browser can be tricky, but the first two items on the list above specialize in running your test code in actual browsers, automatically.

Some clarification: You might see karma or testee talking about being able to run tests with mocha and jasmine. That just means they can use a subset of those tools (which are actually larger frameworks) to run your tests, but they essentially wrap them, and act as their own, separate tools.

5. pick a linter

(optional)

Linters are like a simplified mini-test-suite that usually runs before your actual tests, or in your browser. Linters just read through your javascript to find common errors, like misspelled variables, syntax errors, or formatting problems. They’re often used to make sure everyone on your project is coding in the same general style, and catch simple programmer errors.

Choices: standard, eslint

standard is nice because you’ll never have arguments about how to configure your linter. eslint is nice because you get to spend weeks arguing about every single little detail about your team’s coding style. :trollface:

Edit: my snark above should tell you everything you need to know about how I feel about the details of this one in particular. Linters are handy. Don’t waste more time on them than they save you.

6. use npm scripts to wrap all of the above

Invoke all the above tools through npm scripts, so you have a single, straightforward command into all this stuff that works across the ecosystem.

npm scripts add binary dependencies to $PATH, so you can do:

“scripts”: { “build”: “grunt build” }

And then npm run build to run that task.

Since you know npm will basically always be installed, these days, getting your devs used to just doing npm test or npm start will be more future-safe. And really, you can let complexity happen over time this way, without complicating the interface, and most importantly: You don’t need to tell devs to npm i -g grunt-cli, which is a really annoying setup step for new dev, imo.

Choices: npm ;)

7. pick a front-end-specific package manager

(optional, discouraged)

These tools are not really that necessary these days, but the fact is, npm’s front-end module support isn’t gonna do as good a job in some cases. npm@3 usually flattens, but there’s no way to guarantee this, so you may run into issues where things you were pathing into node_modules/ for unexpectedly moved deeper in the tree, or suddenly you have two copies of jQuery trumping each other, etc. Bundlers usually fix this, but it can still be a problem.

Choices: bower, jspm, etc

idk. I don’t use any of these anymore. They’re just more dependencies I don’t need <:) (disclaimer: Some of you may not be aware, but I’m a dev for the npm CLI. This last bit is clearly biased. I’ve used bower plenty in the past. Do whatever makes sense for you in the end.)

putting everything together

Curious about what this might all look like? You can check out https://github.com/zkat/mona/blob/develop/package.json for an example of a setup for a front-end-compatible library that:

  1. publishes to npm
  2. only uses npm scripts as the task runner
  3. uses webpack for bundling
  4. uses babel for converting ES2015 to ES5 (without bundling) to make it available to Node.js
  5. Runs a linter (standard), builds, and uses mocha to run the test suite.
  6. Does all of the above as devDependencies, requiring no global or external installations besides npm itself.