Formatting and linting with ESLint and Prettier

March 17, 2020

In this article we'll use ESLint and Prettier to lint and format our code. We'll go through the configuration process and make sure the two libraries play nicely together.

This is part two of the series Create a React App From Scratch With Webpack and Babel, but you don't need to have read part one to follow along.

You can read part one here.

(This series has a companion Git repository: github.com/nicoqh/react-boilerplate)


Coding style guides help you avoid stylistic inconsistencies and potential problems in your code base.

A style guide consists of a set of rules. Using these rules, a linter or a formatter analyzes your source code and flags (or automatically fixes) potential problems and stylistic errors.

Rules are generally divided into two categories:

  • Formatting rules enforce the formatting of your code (how your code looks). For example, the rule "lines should be no longer than 80 characters" is a rule that affects how your code is formatted, but it doesn't affect the code's runtime behavior.

  • Code quality rules enforce coding (best) practices and aim to reduce bugs and incorrect code. For example, the rule "eliminate unused variables" is a rule that helps you remove unused variables from your code base (these variables could be left over from a refactoring). The rule has nothing to do with formatting; the code can be perfectly formatted even though it contains an unused variable.

We'll use two popular tools to lint and format our source code: ESLint and Prettier.

Linting with ESLint

ESLint is the most popular linter for JavaScript. It analyzes your code to find both stylistic (formatting) errors and code quality issues.

Before we start using ESLint, let's go through some important concepts.

ESLint offers a long list of rules, but none are enabled by default. To use a rule, you add it to an ESLint configuration file. For example, if you want to eliminate variables that are declared but not used, add the no-unused-vars rule to your .eslintrc.js configuration file:

rules: {
  "no-unused-vars": "error"
}

Configuration files can be shared between projects. Instead of maintaining your own list of rules, you can extend another configuration file. Many configuration packages have been published on npm. These are named eslint-config-<name> by convention.

To extend a configuration package, your create an extends array in your ESLint config file, and add the name of the config package (omitting the eslint-config- prefix):

extends: [
  "standard" // Extend eslint-config-standard
],
rules: {
  "no-unused-vars": "error" // Your own rules
}

Your own rules take precedence over the extended configurations.

What if you need rules that aren't provided by ESLint?

In addition to the rules provided by ESLint, there are several ESLint plugins that can help you with specific enforcements. Plugin packages are named eslint-plugin-<name> by convention, and you can omit the eslint-plugin- prefix when referencing them in your own ESLint config.

For example, the plugin eslint-plugin-react provides a set of rules that are useful for React and JSX projects. Adding this plugin to your .eslintrc.js config makes its rules available for use:

plugins: [
  "react", // eslint-plugin-react
],
rules: {
  "react/no-typos": "warn", // Use the 'no-typos' rule from eslint-plugin-react
}

In addition to providing custom rules, ESLint plugins often contain configuration files. For example, the React plugin provides both React specific rules, and configuration files that use those rules. This is a convenient way to provide users with a recommended way of using the provided rules.

These plugin-provided configurations can also be extended from your ESLint config:

extends: [
  "plugin:react/recommended", // A configuration from the React plugin
]
plugins: [
  "react", // eslint-plugin-react
],
rules: {
  "react/no-typos": "warn", // Your own rules
}

The syntax of the extends array can be a bit confusing. How you reference an external configuration depends on whether it's a local file, a configuration package or a configuration provided by a plugin. You can read more about the "extends" property if you're interested. Here's an overview of the differences:

extends: [
  "./myConfigFile.js", // Local file
  "standard", // Configuration npm package `eslint-config-standard`
  "plugin:react/recommended" // A configuration from a plugin
]

Let's get started by installing ESLint locally:

npm install eslint --save-dev

We won't add any rules or configurations manually. Instead, we'll extend a a popular configuration created by AirBnB.

We won't even create a configuration file manually. ESLint can do this for us. By answering a set of questions, ESLint can install any necessary plugins and configurations, and then automatically create a configuration file.

To set up a configuration file, run the ESLint initialization command:

./node_modules/.bin/eslint --init

You will be presented with a set of questions. I answered them like this:

  • How would you like to use ESLint? To check syntax, find problems, and enforce code style
  • Which framework does your project use? React
  • Does your project use TypeScript? No
  • Where does your code run? Browser
  • How would you like to define a style for your project? Use a popular style guide
  • Which style guide do you want to follow? Airbnb
  • What format do you want your config file to be in? JavaScript

Answer yes when it asks to install the dependencies required by the configuration. The AirBnB configuration, which we will extend, extends other configurations and plugins that need to be installed.

Your ESLint config file has been written to .eslintrc.js (view commit). If you open the file you'll see that it extends the airbnb style guide. At the bottom you'll find an empty rules object. You can use this to add additional rules, or to overwrite the ones provided by AirBnB.

To see the result of your config file and all the active rules, run ESLint with the --print-config flag:

./node_modules/.bin/eslint --print-config .eslintrc.js

Let's lint our index.js file and look for errors and inconsistencies:

./node_modules/.bin/eslint src/index.js

5:10  error  JSX not allowed in files with extension '.js'  react/jsx-filename-extension

There's an error! AirBnB has configured the rule react/jsx-filename-extension to only allow JSX in files with the .jsx extension. Let's overwrite the rule and allow JSX in .js files as well. Open .eslintrc.js and add a modified version of the rule (view commit):

  // ...
  rules: {
    "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }]
  }
  // ...

This is how you override rules from the configuration(s) you're extending.

To integrate ESLint with your code editor, check out the available integrations.

Formatting with Prettier

Prettier is a code formatter. It parses your code and re-prints it according to a set of opinionated formatting rules. Prettier doesn't care about the meaning of the code, only about how it looks.

Prettier can enforce consistent maximum line lengths, make sure you don't mix single and double quotes, add trailing commas to each array item, and help you with other formatting concerns.

Let's install Prettier:

npm install prettier --save-dev --save-exact

(The Prettier documentation recommends using the --save-exact flag, which saves an exact version to your package.json instead of a version range.)

Then, run Prettier on a JavaScript file using the default formatting rules:

./node_modules/.bin/prettier src/index.js

Prettier will parse the code and re-print it according to its default rules. The command's output is the new code, correctly formatted. It didn't change (write to) the file, because we didn't tell it to.

Instead of manually running Prettier from the command line, check out the official documentation on how to integrate Prettier with your text editor.

Prettier formatting options

Prettier offers a set of customizable formatting options (rules about how the code should be formatted). The number of options is intentionally limited in order to avoid bike-shedding (arguing over trivial stuff). Due to the limited number of formatting options, Prettier can be seen as a style guide as well as a formatter. A big selling point for Prettier is that you don't need to argue with your co-workers on how the code should be formatted.

In this guide we'll use Prettier's default formatting options, except for one: use single quotes (') instead of double quotes (").

Prettier has a "singleQuote" option that we can use.

Create the config file .prettierrc (notice the leading dot) and add the following JSON (view commit):

{
  "singleQuote": true
}

This will tell Prettier to prefer single quotes.

Using Prettier with ESLint

As mentioned, ESLint can detect both stylistic (formatting) errors and coding errors.

The recommended approach is to use Prettier for code formatting, and let ESLint take care of code quality concerns.

This means we should disable any existing formatting rules in ESLint. Since we currently extend AirBnB's ESLint configuration, this is hard to do manually.

To achieve this, Prettier provides an ESLint configuration package that disables all formatting rules that conflict with Prettier.

Install eslint-config-prettier:

npm install --save-dev eslint-config-prettier

In order for this configuration to overwrite and disable ESLint formatting rules, it must be the last configuration we extend from .eslintrc.js (view commit):

// ...
  extends: [
    'plugin:react/recommend',
    'airbnb',
    'prettier', // Add this
  ],
// ...

In summary, we still extend the AirBnB configuration, but we let Prettier's ESLint config disable any formatting rules from ESLint. Now, only Prettier is responsible for code formatting concerns.

You should integrate Prettier with your text editor so that your code is formatted automatically.

(It's also possible to have ESLint report formatting errors detected by Prettier. The ESLint plugin eslint-plugin-prettier runs Prettier as an ESLint rule and reports formatting errors as individual ESLint issues. We won't do that in this article, but check it out if it makes sense to your workflow.)

Unobtrusive ESLint style guides

An alternative to extending the AirBnB style guide, which is very opinionated and includes lots of formatting rules that must be disabled if used with Prettier, you can consider something less obtrusive, like eslint-config-unobtrusive.

This configuration doesn't include any formatting rules. As the author notes:

I wanted an ESLint config that would stay silent most of the time, but when it spoke up, it would be helpful rather than annoying. Thus, unobtrusive was born.

The package publishes several configurations which can be extended, including one for React.

That's it for now. This series of articles will likely be expanded in the future to cover more Wepack, Babel and React concepts. For now, you can check out the bottom of the first article for tips on what to do next.