Quick, clean commits with partial linting

by Rouan Wilsenach

Tired of your commits taking >10 seconds? Give this a bash.

Linting is great, but no one likes slow commits!

At Tes, we use husky to run code when the git precommit hook triggers. Most often, we run npm run lint so that we can catch linting errors before they’re even committed. (We use ESLint for linting.)

The problem is that, even when you’re developing microservices, it could take quite a while to lint all the files in your repository. On one particular repository, committing was taking 12 seconds, so I decided to do something about it.

Speed up commits with partial linting

I found a library called lint-staged which only runs your linter on the files that are staged for commit. Using this approach can really speed up your commits. I recently updated a particularly large service:

Before:

real    0m16.476s
user    0m16.462s
sys     0m1.402s

After:

real    0m3.676s
user    0m2.847s
sys     0m0.826s

Steps

Here’s how.

Install

npm install --save-dev lint-staged

Or, if you’re not using husky yet:

npm install --save-dev lint-staged husky

Configure

Create a .lintstagedrc file at the root of your project. It configures the linters you want to use for each file extension. Here’s what ours looks like:

{
  "*.js": "eslint",
  "*.jsx": "eslint"
}

Set up the hook

In the scripts section of your package.json file, add:

  "scripts": {
    // ... other scripts
    "precommit": "lint-staged"
  },

That’s (almost) it!

Now when you run git commit, your commit will fail if there are any linting errors, and it will only check files you’ve actually changed.

Lint everything on CI

There are times when partial linting isn’t enough. For example, if you remove a dependency from your package.json and don’t remove a corresponding import in another file, then the import/no-extraneous-dependencies linting rule will not fail your commit, because you didn’t actually change the file it would complain about.

The solution is to make sure you lint your full codebase on your CI server, so that anything that slips through the cracks will be caught on CI, rather than by the next developer to commit.

Just add a lint script to your package.json:

  "scripts": {
    // ... other scripts
    "precommit": "lint-staged",
    "lint": "eslint"
  },

and be sure to run npm run lint somewhere in your build script.