Linting React Using ESLint with Create React App

Holly White

Despite whether you like spaces or tabs, semicolons or none, single or double quotes, we can all agree on the importance of consistency and clarity in a code base. In this article, we’re going to go over the reasons why we should utilize a linter like ESLint and how to customize it with Create React App.

Projects created using Create React App have linting with ESLint already working and configured out of the box with sensible defaults. For most scenarios that means that you don’t have anything else to do and everything will just work. The following article should come-in handy in cases where you’d want to customize the linting rules.

Also, This article discusses customizing linting rules by ejecting from Create React App, but there’s also an alternative solution using react-app-rewired and react-app-rewire-eslint.

Why Lint?

Coding always leaves room for errors, especially with loosely typed languages like JavaScript. By implementing a linter in our code editor and our project, we can save time by finding an error before we even execute our code. In this article, we’re going to go over why linting is a life saver and also how to customize the linter in a Create React App project.

Local linting vs project linting

Most popular code editors either automatically include a linter for the language you’re using or offer multiple extensions so that you can configure how you prefer to lint locally.

While linting locally can and will save us time, there is always the bigger picture - like different code editors and dev environments. In this article, we’re going to focus our attention specifically on the project level with ESLint.

Customizing Create React App and ESLint

Let’s use Create React App to quickly setup a React project. If you aren’t up to speed and need a little help getting started, check out our spiffy article Getting Comfortable with Create React App.

In the terminal run:

$ create-react-app linter-demo
$ cd linter-demo
$ npm start

Voila, we've now got a project to test.

Like most things in development, Create React App is practically magic right up until you’re ready to get into some nitty gritty customizations.

One drawback with the defaults in a project created using Create React App is that you can only configure ESLint by ejecting or forking the project which leaves a lot to be desired for most advanced developers. Sadly you can’t integrate Prettier, change rules to fit your team’s style and you’re locked into the version Create React App deems as the most stable version despite what releases might solve your unique problems. It leaves a lot to be desired in terms of flexibility. There are even complaints/issues that Create React App disables the rules that it suggests following.

How Do We Get Around That?

First of all we need to eject. If you’re deep in a project, we’d suggest doing some research on the consequences for your specific project.

Essentially when we eject, we no longer get updates on our project from the Create React App core. It’s certainly not the end of the world, though, and it allows for more linting customization.

A good analogy of Create React App versus an ejected app is “It’s kind of like pulling in Bootstrap CSS via CDN as opposed to downloading the source code and injecting it directly into your project.” That is, we now have to make manual changes to our packages.

Once we’re confident and comfortable let’s get on with it! In the terminal run:

$ npm run eject

Next just hit y and we’re ready to get rolling.

Linter Installation

From your root folder, install the following linter packages:

$ npm install --save-dev eslint eslint-loader babel-loader babel-eslint eslint-plugin-react

These package extensions work together in our React project to provide linter feedback for JavaScript, JSX and React.

  • eslint is the core JavaScript linter.
  • eslint-loader tells webpack that you want to use eslint in our build
  • babel-loader transpiles our code with webpack
  • babel-eslint provides linting for valid ES6 code
  • eslint-plugin-react extends ESLint rules to cover React

Next create an ESLint file to configure our settings. This file is where you can add, remove and edit configurations. In the terminal run:

$ touch .eslintrc

If we don’t quite know where to start, style guides like eslint-config-airbnb allow us to configure our project similar to industry leaders like Airbnb. All that we need to do to implement their style guide is install the corresponding packages. Since their rules are a little strict to start with, we’re going to start with something a little simpler.

Place the following in .eslintrc file you just created:

.eslintrc

{
  "parser": "babel-eslint",
  "plugins": [
    "react"
  ],
  "rules": {
    "no-undef": [ 1 ],
  }
}

Show Me the Money!

Let’s start with the obvious! Spotting errors. 🙈

If we don’t have a linter setup in our project, it’s difficult to spot errors until the code is compiled.

Can you find the errors we added below?

App.js

import React, { Component } from 'react';
import ReactLogo from './logo.svg';
import './App.css';

class Demo extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p classname="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
      </div>
    );
  }
}

export default App;

You're absolutely right! We changed our logo's name in the import but forgot to change it in the src prop. We also changed our class name but forgot to change it in the export. Without a linter, the problem might be hard to identify. The correct version should look like this:

App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
      </div>
    );
  }
}

export default App;

Fairly easy to miss, right? 🤔 With a linter, an error would appear immediately and tip us off that there’s a big problem. Much like how spellcheck gives a squiggly red line when you misspell a word, the linter will give you a squiggly red line when an error is present. If we hover over the related squiggle the linter will give us more information on the specific error and even provide a link for more info on that specific rule.

Linter Error Example

Setting some standards for clear, beautiful code! 😍

Linters like ESLint allow us to create rules for how we want our code to look. These rules include anything from enforcing consistent indentation to requiring spaces in our curly braces.

We've all seen, or even wrote, code that resembles something like the example below. 🤫

App.js

import React, { Component } from 'react';

import logo from './logo.svg';
import './App.css';

class App extends Component {
      render() {
return (
      <div className="App">

        <header className='App-header'>
          <img src={logo}
          className="App-logo"
          alt="logo" />
                    <h1
                    className="App-title">
            Welcome to React</h1>
        </header>
              <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
      </div>
    );
  }
}

export default App;

Imagine if the codebase was large. Digging through the code would seem daunting, frustrating and might make you want to call-in sick 😷🤢.

If we are using linting rules to prevent this, the linter will quickly let us know that this isn’t acceptable.

Configuring Specific Rules

Linting rules are far from black and white. They're actually quite flexible.

One of the driving principles of ESLint is that it empowers the developer to decide their own rules and does do not enforce or encourage any specific standards.

All rules can be required, used as a warning, modified or even disabled. In ESLint not only can you completely customize a single rule, but you can disable an entire file, a line, or even just a rule related to a specific line in our code.

Earlier we created an .eslintrc file with a couple simple rules. Let’s add some more complex rules to see what happens to our file.

Be sure to close and reopen your `App.js` file or reload your editor window to see the linter changes reflected.

.eslintrc


{
  "parser": "babel-eslint",
  "plugins": [
    "react"
  ],
  "rules": {
    "space-in-parens": [ 0, "always" ],
    "template-curly-spacing": [ 2, "always" ],
    "array-bracket-spacing": [ 2, "always" ],
    "object-curly-spacing": [ 2, "always" ],
    "computed-property-spacing": [ 2, "always" ],
    "no-multiple-empty-lines": [ 2, { "max": 1, "maxEOF": 0, "maxBOF": 0 } ],
    "quotes": [ 1, "single", "avoid-escape" ],
    "no-use-before-define": [ 2, { "functions": false } ],
    "semi": [0, "never"],
    "prefer-const": 1,
    "react/prefer-es6-class": 0,
    "react/jsx-filename-extension": 0,
    "react/jsx-curly-spacing": [ 2, "always" ],
    "react/jsx-indent": [ 2, 4 ],
    "react/prop-types": [ 1 ],
    "react/no-array-index-key": [ 1 ],
    "class-methods-use-this": [ 1 ],
    "no-undef": [ 1 ],
    "no-case-declarations": [ 1 ],
    "no-return-assign": [ 1 ],
    "no-param-reassign": [ 1 ],
    "no-shadow": [ 1 ],
    "camelcase": [ 1 ],
    "no-underscore-dangle" : [0, "always"],
  }
}

After you reopen the file, it should look something like this:

After Linter Rules Added

Tell me more about some of those rules…

Since we could spend hours explaining linter rules, we selected our top five to highlight and explain.

  • quotes: allows you to define strings in one of three ways: single quotes, double quotes, or backticks.
  • semi: enforce or disallow semicolons
  • react/jsx-curly-spacing: enforce or disallow spaces inside curly braces in JSX props and expressions
  • react/jsx-indent: validates indentions (spaces, tabs)
  • no-undef: disallows undefined variables

For more info on rules and how to modify them, check out eslint and eslint-plugin-react’s rules.

Oof But So Many Things to Fix!

So you have a giant project and didn’t know about ESLint, eh? Now you’re linting and are somewhat terrified with the hundreds or even thousands of errors you’re seeing? Not to fear! ESLint has a feature where you enter the file path + eslint --fix and it automatically fixes every simple error that won’t cause a dumpster fire in our project.

To try this in our current project, run the following from your terminal:

$ eslint --fix src/App.js

The result tells us that there is one remaining error.

After Linter Rules Added

Though we’d love for eslint --fix to be able to fix everything in our file, it has the capability to do some damage. All projects are not created equally so ESLint treads lightly with some fixes.

What about that last error?

The last error, class-methods-use-this make a good point, class methods should use this to refer to the current class. We will probably want to change that later but since our project is brand new, we’re just going to ignore it for now.

We could go about ignoring this in three different ways:

  • Disabling the rule across the project
  • Disabling the rule in that file
  • Disabling the rule in the line above the code block

Since this is something that we probably want in other files, we don’t want to disable it across the project and since we want it to be found pretty easily we’re just going to disable it for this specific file.

To disable the rule, add the the comment below on line one of your file.

/* eslint-disable class-methods-use-this */

Life-Saving Specific Benefits

We brainstormed with a few developers on how ESLint has saved them time and here’s a short list of what we came up with.

  • Do not pass go, do not collect…: The linter can stop the build if the project has any errors.
  • Stop those old habits!: Did you really just say var?! ESLint will quickly remind you if you need to use let or const
  • Smaller Packages: You have a const, or a var… but it’s not used? Guess what? It’ll let you know that you haven’t used it!
  • Hate repeating yourself?: Good news, ESLint will remind you to use object destructing!
  • Undefined…: Need I say much more? We’ve all had our fair share of frustration with anything undefined related. ESLint notifies you when you have an undefined variable in the file.
  • Missing Something?: Maybe you’re looking at a colleague’s file and wondering why something isn’t working… When you hit that file, ESLint will let you know that you’re missing something, an npm package. It’ll even give you the line to install from the terminal.

👉 Good news. Now that we have customized ESLint rules for our project, we never need to have the tabs vs spaces debate again!

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#