Documenting build commands with NPM scripts

In the past, running JavaScript followed a simple model. You wrote some code in file.js and then used a <script> tag to load the file on a page.

However, complex JavaScript projects today require some kind of build process. Languages like TypeScript or ES 2015 may need to be compiled into JavaScript that can run in the browser. Projects can consists of hundreds of JavaScript files, and you need a bundler so you don't have to include a hundred <script> tags in your HTML.

So, before being able to work on a project you may need to run Babel, Webpack and various other tools.

These build steps have made it easier for developers to write large maintainable JavaScript apps. But they also increased the setup required before a developer can start working on a project.

Hopefully, the project you're working on has a readme file that explains the setup process.

Alongside a readme, NPM scripts can be used document the different build commands that are available for a particular project. This post will explain how.

What are NPM scripts?

NPM (Node Package manager) is a tool used to install JavaScript libraries. Even though the name contains "Node" it's used on both the frontend and the backend.

Every project that uses NPM contains a package.json file that lists all dependencies that need to be installed.

The first thing to do when setting up a project that uses NPM is to run npm install. This will download all the necessary packages that are needed for the build process.

The package.json file contains not only a list of dependencies but also other information like the author's name and the version of Node required to run the project.

NPM scripts are another thing that's stored in the package.json. They are a set of terminal commands that can be run using npm run [scriptName].

For example, this is the scripts property of ImmutableJS's package.json file:

"scripts": {
    "build": "grunt default && gulp default",
    "lint": "eslint src/ && grunt lint && gulp lint",
    "testonly": "./resources/",
    "test": "npm run lint && npm run testonly && npm run type-check",
    "type-check": "cd type-definitions/tests && flow check",
    "perf": "node ./resources/bench.js",
    "start": "npm run build && node ./pages/resources/start.js",
    "deploy": "(cd ./pages/out && git init && git config \"Travis CI\" && ..."

To compile the project into a single JavaScript file that could be included with a <script> tag you can use npm run build.

In addition to the build script, test is the most common script name you'll encounter (to run automated tests on the code).

Being able to find all available scripts in one place makes it easy to discover the commands you'll need when working on a project.

For example, Immutable has an npm run perf script that runs performance benchmarks.

Immutable JS performance benchmarks in Terminal

There's also a lint command to run linters that point out code quality issues.

Looking at the available NPM scripts gives you an idea of the tools that a project uses.

Advantages of using NPM Scripts

As we saw, NPM scripts provide a consistent place for JavaScript developers to find what commands are required to build and test a project.

Of course, a readme file can do the same thing. However, a distinct advantage of NPM scripts is that you don't need to memorize long commands. A short script name is enough.

In the ImmutableJS example above this is the lint command:

eslint src/ && grunt lint && gulp lint

You could put that in your Readme, but most likely any developer would have to regularly look up the command, as it's not straightforward to memorize.

With NPM scripts you can simply run npm run lint and NPM will look up the exact command.

Using local modules instead of requiring global installation

To run eslint src/ && grunt lint && gulp lint in the terminal you'll need to have eslint, grunt, and gulp installed globally on your computer.

This means that, in addition to running npm install, you need to separately install all global dependencies of the project.

NPM scripts have access to packages installed locally in your project. That means no global dependencies will need to be installed and a single npm install is enough to be able to run the scripts in package.json and start development.

Downsides of using NPM Scripts

While NPM scripts are very useful there are two limitations that are worth pointing out.

First of all, it's not always clear what each script actually does. You can try to make the script name as descriptive as possible, but in a JSON file it's a lot harder to provide a detailed explanation than it would be in a readme.

However, there are some workarounds that allow you to include comments in the package.json file.

Also, keep in mind that not everyone is aware of NPM scripts. Make sure to mention the most important NPM commands in the readme (e.g. npm run build). Then point to the scripts property of package.json for more info.