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 codebase. Linting is one approach to establishing consistency and clarity by enforcing coding rules and standards.
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.
In this article, you will explore the reasons why we should utilize a linter like ESLint and how to customize it in a Create React App
project.
To complete this tutorial, you’ll need:
This tutorial was verified with Node v16.4.2, npm
v7.19.1, react
v17.0.2, and eslint
v7.11.0.
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 discovering errors before we even execute our code.
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.
The focus of this article will be on project-level linting with ESLint
.
Let’s use Create React App
to quickly set up a React project. If you aren’t familiar with it and need a little help getting started, consult Getting Comfortable with Create React App.
First, in the terminal run:
- npx create-react-app linter-demo
Navigate to the directory:
- cd linter-demo
Then start the application:
- 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 and issues that Create React App
disables the rules that it suggests following.
To apply new configurations, we will need to eject.
Warning: This article is specifically designed to guide you through the ejecting of the demo project. If you are attempting to eject an existing project, please consult the documentation to ensure this is the desired course of action for your project as it is a one-way operation.
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.
In the terminal run:
- npm run eject
Confirm the prompt and the script will eject your project.
Among the dependencies added to the project are @babel/core
, babel-loader
, babel-eslint
, eslint
,eslint-webpack-plugin
, and eslint-plugin-react
.
eslint
is the core JavaScript
linter.eslint-loader
tells webpack that you want to use eslint
in our buildbabel-loader
transpiles our code with webpackbabel-eslint
provides linting for valid ES6 codeeslint-plugin-react
extends ESLint rules to cover ReactNow you have an ejected Create React App project.
ESLint rules can be configured in various files: .eslintrc.js
, .eslintrc.cjs
, .eslintrc.yaml
, .eslintrc.yml
, .eslintrc.json
. For this demo, we will modify the existing package.json
file.
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.
Open package.json
in your code editor and add rules
to eslintConfig
:
{
"name": "linter-demo",
"version": "0.1.0",
"private": true,
"dependencies": {
// ...
},
"scripts": {
// ...
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
],
"rules": {
"no-undef": [ 1 ]
}
},
"browserslist": {
// ...
},
"jest": {
// ...
},
"babel": {
"presets": [
"react-app"
]
}
}
This code defines the rule
for no-undef
(no undefined).
If we don’t have a linter set up in our project, it’s difficult to spot errors until the code is compiled.
Can you find the errors we added below?
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;
Without a linter, the problem might be hard to identify. The correct version should look like this:
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;
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.
Linters like ESLint
allow us to create rules for how we want our code to look. These rules include anything from enforcing consistent indentation (indent
) to requiring spaces in our curly braces (space-in-brackets
).
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.
We’ve all seen, or even wrote, code that resembles something like the example below:
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;
This code is riddled with inconsistency. The wild indentation and spacing make it difficult to read and understand. 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.
Earlier we modified package.json
file with a single rule. Let’s add some more complex rules to observe what happens to our file:
{
// ...
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
],
"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"]
}
}
// ...
}
Save your changes.
Note: Be sure to close and reopen your App.js
file or reload your editor window to see the linter changes reflected.
After you reopen the file, it should display the following errors:
Take a moment to investigate five of the rules that were applied further:
quotes
: allows you to define strings in one of three ways: single quotes, double quotes, or backticks.semi
: enforce or disallow semicolonsreact/jsx-curly-spacing
: enforce or disallow spaces inside curly braces in JSX props and expressionsreact/jsx-indent
: validates indentions (spaces, tabs)no-undef
: disallows undefined variablesFor more info on rules and how to modify them, check out eslint
and eslint-plugin-react
’s rules.
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 and 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:
- ./node_modules/eslint/bin/eslint.js --fix src/App.js
This command reveals that there is one remaining error:
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.
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:
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 in a file, add the following comment to the first line:
/* eslint-disable class-methods-use-this */
Rerun the command and it will ignore this rule.
In this article, you explored the reasons why we should utilize a linter like ESLint and how to customize it in a Create React App
project.
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:
var
where you could have used let
or const
?undefined
variables.Now that we have customized ESLint rules for our project, we never need to have the tabs versus spaces debate again!
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
.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!