Streamline JavaScript Development with ESLint
JavaScript is a dynamic language which, at runtime, executes common programming behaviors that static programming languages perform during compilation. This makes JavaScript a productive language but at the cost of not having a safety net to validate the code.
This problem is easily addressed with a structured approach to writing your code: linting.
What is Linting?
Linting is the process of running a program that will analyze code for potential errors.
The name is derived from a particular program named
lint
that flagged some suspicious and non-portable constructs (likely to be bugs) in C language source. The term is now applied generically to tools that flag suspicious usage in software written in any computer language. -- Lint (software), Wikipedia
Why is Linting Important?
- It defines best practices for projects and teams
- It makes communication easier
- It establishes coding rules that remove troubling bugs and performance regressions
- It provides needed safety nets
A quick example of linting:
var num = parseInt("071"); // 57
var num = parseInt("071", 10); // 71
Linting rules can be established to catch errors, like in the example above where the radix is not explicitly defined.
How Do I Lint My Code?
There are a multitude of projects within the JavaScript community that have attempted to solve linting - JSCS, JSHint, and ESLint are just a few of the all-time major ones.
ESLint has established itself as the clear winner because of the architectural decisions behind it. Nicholas C. Zakas didn't want to force a particular set of rules on developers, he wanted a system where everyone could choose what's right for them. As a result, ESLint is a plugin based system that allows you to pick and choose, and add any desired rules. The power of ESLint comes from the use of an AST (Abstract Syntax Tree) to provide "hooks" into plugins to analyze the code.
But I'm Using JSCS or JSHint Already!
Luckily, there's a quick and easy fix - the polyjuice package is here to help! Polyjuice allows porting of JSCS or JSHint linting rules to ESLint with a quick command that help up and running with ESLint quickly.
npm install -g polyjuice
polyjuice --jscs .jscsrc.json > .eslintrc.json
An important note is that polyjuice
works with JSON configuration files - so if a project is using a JavaScript or YAML JSCS file, it needs to be converted it into a JSON configuration file.
How to Get Started with ESLint
ESLint is flexible in how it allows specification of rules. The most common practice is to create a .eslintrc.*
file in the base of a project. Another option is to define an eslintConfig
object inside of the project's package.json
but, I advise against this technique. Using the eslintConfig
object can limit discoverability of ESLint usage, unnecessarily pollutes the package.json
file, and breaks the standard in most projects of using the dedicated file.
The easiest way to get started is to start from an existing configuration like the Airbnb JavaScript Style Guide, the Google JavaScript Style Guide, or StandardJS.
Here's a list of some of the most popular ESLint configs:
eslint-config-airbnb-base
eslint-config-google
eslint-config-standard
eslint-config-idiomatic
eslint-config-jquery
eslint-config-node-style-guide
eslint-config-wordpress
It's easy to get up and running with one by npm install
ing it in a project, replacing eslint-config-airbnb-base
with the style guide of choice and the --save-dev
flag to ensure it's only used in development installs.
npm install eslint-config-airbnb-base --save-dev
All ESLint configurations follow a standard naming convention (eslint-conf-*
) which allows us to shorten the name when using it with the extends
property.
With this in mind, once the chosen ESLint config has been npm install
ed, a project's .eslintrc.json
should be updated to include it:
{
"extends": "airbnb-base"
}
See the configuring guide on the ESLint site for more options.
Start Using ESLint
The eslint
package can be installed globally (via npm i -g eslint
) or locally (via npm install --save-dev eslint
). In general, I avoid installing globally as much as possible and rely on a package or project's devDependencies
to resolve execution.
If ESLint has been included in a project's devDependencies
, simple and automated linting commands can be added to the npm scripts
in the project's package.json
:
{
"scripts" : {
"lint": "eslint **/*.js",
"lint-html": "eslint **/*.js -f html -o ./reports/lint-results.html",
"lint-fix": "eslint --fix **/*.js"
}
}
Note: If you want a primer on how to use npm effectively, you should take a look at our article, 11 npm Tricks to Knock Your Wombat Socks Off!
The First Lint
After the package.json
has some linting scrips defined, use them! The first linting npm script defined above can be run with:
npm run lint
This will generate a command line report of errors and what file and line number they occurred.
Getting Better Output from Linting
With the previously defined linting scripts
, the lint-html
script will generate a HTML report.
npm run lint-html
Personally, I find the html
report more valuable because of the links it provides to the documentation. An example of this is no-delete-var, which explains the no-delete-var
rule in further detail than the command line output would spit out. It includes a code example, along with links to the rule source code for further (technical) understanding.
Automating Code Style Fixes
Another great feature is the automatic code fixing. On the rules page individual rules that have a wrench can be automatically fixed.
npm run lint-fix
That command is defined in the package.json
above. This script will automatically use the automatic code fixing feautre of ESLint, and clean up a lot of code style issues according to the project's config.
Setting Linting Rules
In the above example, the airbnb-base
ESLint config was used - which is a great start. That said, there are some rules that may or may not work for any given project - luckily, ESLint allows all rules from a config to be overridden according to the .eslintrc.json
file.
{
"extends": "airbnb-base",
"rules": {
"no-console": "off",
"prefer-arrow-callback": "off"
}
}
Sometimes, though, the defined set of rules don't apply to everything and you need to override on a case by case basis. This can be done inline within the JavaScript files.
Examples of Inline Rules:
Ignore warnings about global variables named var1
and var2
.
/* global var1, var2 */
Disabling for a block of code:
/* eslint-disable */
eval(str);
/* eslint-enable */
Switching from expecting double quotes to single quotes:
/* eslint quotes: ["error", "single"] */
var str = 'he said "I love node.js"'; // Uses single quotes - error free!
var str = "he said 'I love node.js'"; // Uses double quotes - throws an error!
Use Plugins for Specific Needs
ESLint has a vibrant set of plugins from the community. Like the ESLint configs, they follow a standard naming convention: eslint-plugin-*
.
For example, React introduces a new syntax and can easily be linted with a use of an ESLint plugin. The React plugin can be installed to devDependencies
with a simple command:
npm install --save-dev eslint-plugin-react
Once installed, this new syntax and set of rules can be included in the ESLint config by adding the react
plugin to the project's .eslintrc.json
file:
{
"extends": "standard",
"plugins": ["react"]
}
Get ESLint Integrated Into Your Workflow
ESLint has _tons of integrations with text editors, build systems, CLI tools, and even source control hooks. The wide variety of integrations can be explored, for any particular use case, at the integrations user guide on the official ESLint site.
Go Further with ESLint
If you want to use ESLint even more, there is an awesome-eslint list, which has a nice variety of different ESLint configs, parsers, plugins, tools, and tutorials.
What's the Next Step?
Once you're up and linting, defining a style guide and a list of best practices takes time. It is advisable to start within your comfort zone and expand from there. JavaScript has a lot of amazing features but it doesn't mean we have to use every single one to write quality code. Chose the rules and plugins that provide quick wins. Have discussions within your team on pain points and iterate.