Why (and how) to use eslint in your project

Npmjs.org has 100s of thousands of packages, but that doesn’t mean they are of equal quality. Its important to check how well managed your direct dependencies are. No single missing management practice should eliminate a package from your consideration if the features are right, but when you have a choice of packages, pick ones that are well managed – or be prepared to maintain the package yourself!

I intend to write about a handful of the practices I use to evaluate projects:

  • presence of a github.com repo,
  • a useful README,
  • use of semver,
  • a test suite that runs with git clone; npm i; npm test,
  • etc.

Today’s topic is linting.

Why lint your javascript?

Well run projects have clear consistent coding conventions, with automated enforcement. When I review a project, and its code looks like a house built by a child using nothing but a hatchet and a picture of a house, it doesn’t inspire confidence that the code is functional.

Not having coding conventions is also a barrier to attracting contributions, and depending on a project that does not welcome (quality!) contributions is itself a risk.

Besides checking style, linters are also excellent tools for finding certain classes of bugs, such as those related to variable scope. Assignment to undeclared variables (these leak into the global scope, contaminating it and possibly causing very difficult to find bugs) and use of undefined variables are examples of errors that are detectable at lint time.

How to configure eslint?

eslint is the dominant tool for linting Node.js packages, and can be configured to enforce multiple coding styles. It is possible to define your own style definitions, but here I will show how to use the StrongLoop style. There are others, but StrongLoop’s style is unremarkable (a good thing, coding style should not attract attention), and is similar to that used in many open-source Node.js projects.

Install and save package dependencies:

npm install --save-dev eslint eslint-config-strongloop

Setup eslint to use the strongloop configuration by running:

echo '{"extends": "strongloop"}' > .eslintrc.json

Ensure you have a .gitignore file (so derived files do not get linted, only original source files). If you don’t have one, a minimal one can be created with:

echo node_modules/ >> .gitignore

Note that is also possible to use an eslint-specific .eslintignore file, that has the same syntax as .gitignore, and likely the same contents. To avoid this maintenance burden, most projects use just a .gitignore.

With this setup, configure eslint to run automatically before your tests by changing your package.json to have a pretest script. It should look similar to this:

{
    ...
    "scripts": {
        "pretest": "eslint --ignore-path .gitignore ."
    }
    ...
}

The exact contents of your package.json depend on your project, it is the pretest script that you have to add to cause eslint to run before your unit tests (when you you use npm to run the test script, it will also run the pretest and posttest scripts if they exist). I prefer this, because eslint usually runs much more quickly than my tests, and lint errors are easy to fix, but some people prefer the entire test suite to run before the linter, in which case, use posttest.

Commit the eslint automation support:

git add package.json .gitignore .eslintrc.json
git commit -m 'Add eslint automation'

Once this is complete, run the linter:

npm run pretest

Do not get discouraged if your console is awash in a sea of errors!

How do we get existing code to lint clean?

One reason some avoid using eslint is that cleaning up never-before-linted code can feel like cleaning the Augean stables. I recommend doing as Hercules did: get help from tools.

eslint can automatically fix many syntactic problems automatically, this should be the first tool you use to clean up your source:

./node_modules/.bin/eslint --fix --ignore-path .gitignore .

If you have an eslint pretest script, you can also do:

npm run pretest -- --fix

There are certain classes of problems that eslint will not fix, however, in which case a one-time cleanup using prettier can help. prettier is more commonly used as an alternative to eslint, and setup to auto-format source before it is committed (an interesting but not often used approach that is beyond the scope of this blog), but it is also quite useful in bootstrapping eslint. Run it like:

npm i prettier
./node_modules/.bin/prettier --single-quote --trailing-comma es5 --print-width 80 --write --no-bracket-spacing **/*.js

After running eslint --fix and prettier, you should have very few remaining warnings to cleanup manually. While prettier isn’t as commonly used a tool as eslint, it can be used as a complement to eslint if you want (prettier for auto-formatting, eslint for format enforcement and error checking). If for some reason you don’t have the time to fix these right now, disable the eslint rules. It is much better to have some subset of style enforced automatically than none at all. You can override some of the StrongLoop style for a specific project, and then come back and cleanup the code when you have time. Here’s an example of relaxing the max-len rule to allow run-on lines up to 120 characters wide:

{
  "extends": "strongloop",
  "rules": {
    "max-len": [2, 120, 8]
  }
}

You may find that your code uses a consistent style, but is not StrongLoop’s style. If it is close, you can customize the StrongLoop style, and publish it as your own. If your style is radically different, it could make sense to just write and publish your own reuseable configuration.

Once your code lints cleanly (check with npm run pretest), commit the result:

git commit -a -m 'Project lints clean'

Automate it

There are two levels of automation, project wide policy, and your own personal setup.

In terms of project wide policy, because eslint is configured to run with your tests, there is nothing more to do. Unless you don’t run your tests automatically for your project, in which case it is time to start!

In terms of my own personal setup, I prefer eslint to be run on every one of my commits, so any problems I introduce are caught on my machine before they are caught by CI. I do this with a git “pre-commit” hook. To set this up, use the example hook as a base:

cp .git/hooks/pre-commit.sample .git/hooks/pre-commit

The last lines of the file will look like this:

# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --

Change it to look like:

set -e
npm run pretest

# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --

Congratulations!

That’s it, you are now another user of eslint.

1 comment on"Why (and how) to use eslint in your project"

  1. […] This story was written by Sam Roberts, a Senior Software Engineer at IBM Canada. It was first published in IBM developerWorks blog. […]

Join The Discussion

Your email address will not be published. Required fields are marked *