Introduction
This article is for the developers in our community. Centreon’s own developer team is always looking to improve code quality, but above all productivity, so we can all focus on what makes coding interesting: building great apps! Hence the following tutorial, combining two tools we like, ESLint and Prettier, which we use to work better as a team and keep a clean house code-wise.
Let’s start with some basics—if you’re already aware of what code linting is, you can move on to the tutorial on how to enhance teamwork within a React project with ESLint and Prettier.
What is code linting?
Think of the residual stuff in your dryer, lint, which needs to be kept off clean laundry. In programming, a linter refers to a static code analysis tool which is used to keep code error-free and ensure coding style and construction remain coherent no matter the coder.
As does the greater part of the JavaScript community, we favor the ESLint tool which scans code without having to run it. This highly flexible tool combines a rich plugin library meeting a range of needs and offering the benefit of ready to use configurations. Today, we’re focusing on the Prettier plugin, a tool that allows to automatically reformat code, ensuring consistent rules for indentation, spacing, semicolons, and quotes.
We hope you’ll like this tutorial which tells you how to configure ESLint and the Prettier plugin in a React environment.
Installation and configuration
For this tutorial, we’re going to take the example of a React application. The easiest way to get started is to use create-react-app, so that everything needed to start a React application is bootstrapped for us.
$ npx create-react-app my-app |
ESLint is installable as any other npm package. We’re then going to install it using:
$ cd my-app $ npm install —save-dev eslint |
Then, we need to initiate a configuration file in order to tell ESLint what rules to follow when performing its checks:
$ npx eslint –init |
The CLI is going to ask a bunch of questions. Answer the following:
How would you like to use ESLint? To check syntax, find problems, and enforce code style
What type of modules does your project use? JavaScript modules (import / export)
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
After answering these questions, the required dependencies are going to be installed on your project.
Airbnb JavaScript Style Guide has become a solid standard for JavaScript guidelines, and comes up with a well maintained ESLint configuration, which is why we decided to use it as a base for our projects at Centreon, and we suggest you do the same.
Let’s now add a script to your package.json file in order to check the linting problems, as well as one for fixing those that can be fixed:
// package.json { "name": "my-app", ... }, "scripts": { ... "eslint": "eslint src --ext .js,.jsx", "eslint:fix": "npm run eslint -- --fix" }, ... } |
Then, let’s check the linting issues we get:
$ npm run eslint > my-app@0.1.0 eslint > eslint src --ext .js,.jsx /Users/brunodauria/my-app/src/App.js 6:5 error 'React' must be in scope when using JSX react/react-in-jsx-scope 6:5 error JSX not allowed in files with extension '.js' react/jsx-filename-extension 7:7 error 'React' must be in scope when using JSX react/react-in-jsx-scope 8:9 error 'React' must be in scope when using JSX react/react-in-jsx-scope 9:9 error 'React' must be in scope when using JSX react/react-in-jsx-scope 10:16 error `code` must be placed on a new line react/jsx-one-expression-per-line 10:16 error 'React' must be in scope when using JSX react/react-in-jsx-scope 10:39 error ` and save to reload. ` must be placed on a new line react/jsx-one-expression-per-line 12:9 error 'React' must be in scope when using JSX react/react-in-jsx-scope /Users/brunodauria/my-app/src/App.test.js 4:1 error 'test' is not defined no-undef 5:10 error 'React' must be in scope when using JSX react/react-in-jsx-scope 5:10 error JSX not allowed in files with extension '.js' react/jsx-filename-extension 7:3 error 'expect' is not defined no-undef /Users/brunodauria/my-app/src/index.js 8:3 error JSX not allowed in files with extension '.js' react/jsx-filename-extension 11:34 error Missing trailing comma comma-dangle /Users/brunodauria/my-app/src/reportWebVitals.js 1:25 error Expected parentheses around arrow function argument arrow-parens 3:32 error Expected a line break after this opening brace object-curly-newline 3:74 error Expected a line break before this closing brace object-curly-newline ✖ 18 problems (18 errors, 0 warnings) 6 errors and 0 warnings potentially fixable with the `--fix` option. |
First things first, let’s tackle the low hanging fruits by automatically fixing some errors:
$ npm run eslint:fix > my-app@0.1.0 eslint:fix > npm run eslint -- --fix > my-app@0.1.0 eslint > eslint src "--fix" /Users/brunodauria/my-app/src/App.js 6:5 error 'React' must be in scope when using JSX react/react-in-jsx-scope 6:5 error JSX not allowed in files with extension '.js' react/jsx-filename-extension 7:7 error 'React' must be in scope when using JSX react/react-in-jsx-scope 8:9 error 'React' must be in scope when using JSX react/react-in-jsx-scope 9:9 error 'React' must be in scope when using JSX react/react-in-jsx-scope 12:11 error 'React' must be in scope when using JSX react/react-in-jsx-scope 16:9 error 'React' must be in scope when using JSX react/react-in-jsx-scope /Users/brunodauria/my-app/src/App.test.js 4:1 error 'test' is not defined no-undef 5:10 error 'React' must be in scope when using JSX react/react-in-jsx-scope 5:10 error JSX not allowed in files with extension '.js' react/jsx-filename-extension 7:3 error 'expect' is not defined no-undef /Users/brunodauria/my-app/src/index.js 8:3 error JSX not allowed in files with extension '.js' react/jsx-filename-extension ✖ 12 problems (12 errors, 0 warnings) |
We can see a bunch of errors indicating that React must be in scope within JSX files. Since in React v17 this is no longer required, we’ll disable that rule in the .eslintrc.js file:
module.exports = { ... rules: { 'react/react-in-jsx-scope': 'off', }, }; |
Let’s rename the files containing JSX using the .jsx extension:
$ mv src/App.js src/App.jsx $ mv src/index.js src/index.jsx $ mv src/index.test.js src/index.test.jsx |
We’re now left with two errors:
$ npm run eslint > my-app@0.1.0 eslint > eslint src --ext .js,.jsx /Users/brunodauria/my-app/src/App.test.jsx 4:1 error 'test' is not defined no-undef 7:3 error 'expect' is not defined no-undef ✖ 2 problems (2 errors, 0 warnings) |
Since they are directly linked to the way Jest works (JavaScript testing framework), we can either disable them within the test files (ending with .test.js or .test.jsx), or add a dedicated ESLint plugin. We’re going to do the latter as it will prevent us from writing code that potentially won’t be caught by our linter.
Let’s install the plugin:
$ npm install --save-dev eslint-plugin-jest
|
Then, add the plugin to the eslint configuration:
// .eslintrc.js module.exports = { env: { ... 'jest/globals': true, }, ... plugins: [ ... 'jest', ], ... }; |
Which should let us free from linting issues.
Adding formatting rules using the Prettier plugin
Formatting the code automatically to make it clear and readable is crucial when working in a team (and helps tremendously when working alone as well). It can save a lot of time, particularly when reviewing diffs coming from a PR, and make you focus on the actual code you write instead of trying to arrange it esthetically.
Prettier does this for you, with minimal configuration, and in an opinionated way so that you don’t have to worry about too many rules. Luckily for us, it has an ESLint plugin, so that it’s completely integrated, avoiding the use of different tools. Any formatting violation becomes a linting issue and gets caught when ESLint runs.
First off, we need to tell ESLint which rules need to be disabled in order to avoid conflicts with Prettier. This is done by the package eslint-config-prettier. Let’s install it:
$ npm install --save-dev eslint-config-prettier
|
Then, add it to the eslint config file:
// .eslintrc.js module.exports = { ... extends: [ ... 'prettier', ], ... }; |
Now, we’re going to install the plugin to integrate Prettier with our ESlint rules:
$ npm install --save-dev eslint-plugin-prettier
|
Then, add the plugin to the ESLint config file, as well as the corresponding rule:
//.eslintrc.js module.exports = { ... plugins: [ ... 'prettier' ], ... rules: { ... "prettier/prettier": "error", }, }; |
Now, let’s check the ESLint output:
$ npm run eslint > my-app@0.1.0 eslint > eslint src --ext .js,.jsx /Users/brunodauria/my-app/src/App.jsx 1:18 error Replace `'./logo.svg'` with `"./logo.svg"` prettier/prettier 2:8 error Replace `'./App.css'` with `"./App.css"` prettier/prettier 10:15 error Replace `⏎··········{'·'}⏎··········<code>src/App.jsx</code>⏎··········{'·'}⏎·········` with `·<code>src/App.jsx</code>` prettier/prettier /Users/brunodauria/my-app/src/App.test.jsx 1:32 error Replace `'@testing-library/react'` with `"@testing-library/react"` prettier/prettier 2:17 error Replace `'./App'` with `"./App"` prettier/prettier 4:6 error Replace `'renders·learn·react·link'` with `"renders·learn·react·link"` prettier/prettier /Users/brunodauria/my-app/src/index.jsx 1:19 error Replace `'react'` with `"react"` prettier/prettier 2:22 error Replace `'react-dom'` with `"react-dom"` prettier/prettier 3:8 error Replace `'./index.css'` with `"./index.css"` prettier/prettier 4:17 error Replace `'./App'` with `"./App"` prettier/prettier 5:29 error Replace `'./reportWebVitals'` with `"./reportWebVitals"` prettier/prettier 11:27 error Replace `'root'),` with `"root")` prettier/prettier /Users/brunodauria/my-app/src/reportWebVitals.js 3:12 error Replace `'web-vitals').then(({⏎······getCLS,·getFID,·getFCP,·getLCP,·getTTFB,⏎···` with `"web-vitals").then(({·getCLS,·getFID,·getFCP,·getLCP,·getTTFB` prettier/prettier /Users/brunodauria/my-app/src/setupTests.js 5:8 error Replace `'@testing-library/jest-dom'` with `"@testing-library/jest-dom"` prettier/prettier ✖ 14 problems (14 errors, 0 warnings) 14 errors and 0 warnings potentially fixable with the `--fix` option. |
The good thing is that the vast majority of Prettier errors can be fixed automatically. To fix the ones reported above, we just need to run:
$ npm run eslint:fix |
Which should now set us free of issues.
We’re going to see in the next section that there is a way to catch all these issues even faster, directly within VSCode, if that’s the editor you’re using, and if not, it might be the time to do so :).
Configure ESLint within VSCode
One of the great things about VSCode is the impressive amount of extensions available. ESLint is one of them and it helps shorten the feedback loop of the linting process. To install it, open up the extension manager, search for ESLint and install it:
Then, you need to allow the extension to check the files by clicking on the ESlint button inside the task bar at the bottom of the screen. When this is done, you should have a double check icon appearing beside it:
Then, in order to indicate which source types need to be validated by ESLint when coding, you need to add the following parameter to your settings.json file (Files > Preferences > Settings):
... "eslint.validate": [ "javascript", "javascriptreact" ] |
Finally, to automatically fix the resulting issues when saving a file, add the following parameter:
... "editor.codeActionsOnSave": { "source.fixAll.eslint": true } |
Now, in addition to having the linting issues (including the formatting ones coming from Prettier), saving a file will also fix all the fixable issues:
And we’re all setup!
If you have any questions or comments, ask on The Watch.
Bruno D’Auria, Team Leader – Modern UX/UI
An IMT Atlantique graduate, Bruno holds a master’s degree in computer science, networks, and telecommunications. Bruno worked as a software developer in a wide range of industries: telecommunications, sports, energy, real estate, and home automation before his decision to specialize in web and mobile interface development. Bruno joined Centreon in 2018, leading today the Modern UI/UX team. Bruno’s mission is to design and implement next-generation interfaces for always more intuitive, enjoyable user experiences.