DEV Community

Cover image for ESlint and Prettier for React apps (Bonus - Next.js and TypeScript)
Arpit
Arpit

Posted on • Edited on • Originally published at arpit.one

ESlint and Prettier for React apps (Bonus - Next.js and TypeScript)

What if you could catch and fix your bugs before you even run your program. What if you could write code that has the same syntax and follows the same guidelines throughout the entire project. What if all of this could be enforced for your entire team of developers without any headaches. Seems amazing right? This is achieved by the amazing tools called ESlint and Prettier. Read about how you can add these tools to your JavaScript or TypeScript projects to improve your code quality and consistency.

This article will focus on ReactJS and also delve into NextJS with TypeScript, but these tools work for a JavaScript or TypeScript codebase in general and can be configured to work on any JavaScript project, with Prettier you can even target auto formatting for other languages like HTML, CSS, SCSS/SASS, Markdown, JSON, YAML, GraphQL, styled-components and many more!!!


NOTE

Eslint and Prettier are two separate tools, they can be run independently of each other, but we will leverage some very helpful ESlint plugins to combine them for maximum effect with minimal configuration.


ESlint

First I'll talk about ESlint. It is a static code analyzer, that means it tells you errors and mistakes that you may make while you are developing.

These errors can be stuff like -

  • Simple syntax errors eg. not closing a function declaration with }.
  • Dead code detection eg. unused variables, code written after a return statement.
  • Violating code guidelines, these are rules defined by yourself or a combination of predefined standards like the Airbnb styled guide or Google's style guide etc.

Prettier

Prettier is a code formatter, it's only concerned with how your code looks, do you want ensure consistent indentation in the entire project?
Do you want to ensure there're no semicolons in the project? Make your promise chains look perfectly consistent and readable? Prettier can be enabled for the entire project and instead of your team disagreeing about formatting styles, you can just leave it all to Prettier to figure out.

Getting started

Make sure you have npm and Node.js installed.

Let's install the devDependencies for ESlint -

npm i -D eslint \                       # Eslint itself
         prettier \                     # Prettier itself
         eslint-plugin-react \          # Eslint plugin for react
         eslint-plugin-react-hooks \    # Eslint plugin for react hooks, helps you write modern functional react components
         eslint-config-prettier \       # Eslint config for prettier, it will extend the style guide to match prettier
         eslint-plugin-prettier \       # Eslint plugin for prettier, it will raise eslint errors about formatting
         eslint-plugin-jsx-a11y         # Eslint plugin to raise accessibility violation errors
Enter fullscreen mode Exit fullscreen mode

NOTE

If you are using create-react-app then you already have Eslint baked in, you only need install the other plugins etc.


Making the config files -

touch .eslintrc.js .prettierrc
Enter fullscreen mode Exit fullscreen mode

.eslintignore and .prettierignore

These are the files we need for telling eslint and prettier not to target certain files and folder

touch .eslintignore .prettierignore
Enter fullscreen mode Exit fullscreen mode

Just add the following to both files

node_modules
Enter fullscreen mode Exit fullscreen mode

Alternatively if you just wish to use your .gitignore file as ignore path you can pass it with a flag when running ESlint
eg.

eslint --fix . --ignore-path ./.gitignore
Enter fullscreen mode Exit fullscreen mode

Let's populate our configs now -

.prettierrc

This is the config that I use for prettier -

{
    "semi": true,
    "tabWidth": 4,
    "printWidth": 100,
    "singleQuote": true,
    "trailingComma": "none",
    "jsxBracketSameLine": true
}
Enter fullscreen mode Exit fullscreen mode

.eslintrc.js

This is a base config for eslint, we can extend it further with cool plugins.

module.exports = {
    root: true,                 // Make sure eslint picks up the config at the root of the directory
    parserOptions: {
        ecmaVersion: 2020,      // Use the latest ecmascript standard
        sourceType: 'module',   // Allows using import/export statements
        ecmaFeatures: {
            jsx: true           // Enable JSX since we're using React
        }
    },
    settings: {
        react: {
            version: 'detect'   // Automatically detect the react version
        }
    },
    env: {
        browser: true,          // Enables browser globals like window and document
        amd: true,              // Enables require() and define() as global variables as per the amd spec.
        node: true              // Enables Node.js global variables and Node.js scoping.
    },
    extends: [
        'eslint:recommended',
        'plugin:react/recommended',
        'plugin:jsx-a11y/recommended',
        'plugin:prettier/recommended' // Make this the last element so prettier config overrides other formatting rules
    ],
    rules: {
        'prettier/prettier': ['error', {}, { usePrettierrc: true }]  // Use our .prettierrc file as source
    }
};
Enter fullscreen mode Exit fullscreen mode

Running ESlint

You need to add the script to your package.json file.

  "scripts": {
    "lint": "eslint --fix .",
    "format": "prettier --write './**/*.{js,jsx,ts,tsx,css,md,json}' --config ./.prettierrc"
  },
Enter fullscreen mode Exit fullscreen mode

Now simply run

npm run lint
Enter fullscreen mode Exit fullscreen mode

Targeting Next.js

next.js logo
For using Eslint with Next.js not a lot of changes are needed, we'll add two rules -

For handling the need for having react in context while writing JSX code since Next.js doesn't require that.
For handling accessibility related errors raised by the jsx-a11y plugin.
In Next.js we use the Link component for wrapping the <a></a> tag. Instead of passing href attribute to <a></a> we pass it as prop to Link instead. This raises a very common accessibility issue of an anchor tag with no href, and we don't want any eslint errors so we need to figure out a way to handle this situation.

Simply go to your .eslint.js and add our custom rules for it.

{
    rules: {
        'react/react-in-jsx-scope': 'off',
        'jsx-a11y/anchor-is-valid': [
            'error',
            {
                components: ['Link'],
                specialLink: ['hrefLeft', 'hrefRight'],
                aspects: ['invalidHref', 'preferButton']
            }
        ]
    }
}
Enter fullscreen mode Exit fullscreen mode

Targeting TypeScript

typescript logo

For TypeScript, we need to make some additions to our devDependencies.

npm i -D @typescript-eslint/eslint-plugin \     # For extending our rules to work with prettier
         @typescript-eslint/parser              # To enable eslint to parse typescript code
Enter fullscreen mode Exit fullscreen mode

Now we need to modify the .eslintrc.js file -

Add a top level property to our config to handle typescript code parsing

module.exports = {
    parser: '@typescript-eslint/parser'
};
Enter fullscreen mode Exit fullscreen mode

Add the following new items to the extends array.

{
    extends: [
        'plugin:@typescript-eslint/eslint-recommended',
        'plugin:@typescript-eslint/recommended',
        'prettier/@typescript-eslint',
    ]
}
Enter fullscreen mode Exit fullscreen mode

Finally

This is what your .eslintrc.js should look like after Typescript and Next.js additions.

module.exports = {
    root: true,
    parser: '@typescript-eslint/parser',
    parserOptions: {
        ecmaVersion: 2020,
        sourceType: 'module',
        ecmaFeatures: {
            jsx: true
        }
    },
    settings: {
        react: {
            version: 'detect'
        }
    },
    env: {
        browser: true,
        amd: true,
        node: true
    },
    extends: [
        'eslint:recommended',
        'plugin:@typescript-eslint/eslint-recommended',
        'plugin:@typescript-eslint/recommended',
        'plugin:react/recommended',
        'plugin:jsx-a11y/recommended',
        'prettier/@typescript-eslint',
        'plugin:prettier/recommended'   // Make sure this is always the last element in the array.
    ],
    rules: {
        'prettier/prettier': ['error', {}, { usePrettierrc: true }],
        'react/react-in-jsx-scope': 'off',
        'react/prop-types': 'off',
        '@typescript-eslint/explicit-function-return-type': 'off',
        'simple-import-sort/sort': 'error',
        'jsx-a11y/anchor-is-valid': [
            'error',
            {
                components: ['Link'],
                specialLink: ['hrefLeft', 'hrefRight'],
                aspects: ['invalidHref', 'preferButton']
            }
        ]
    }
};
Enter fullscreen mode Exit fullscreen mode

Bonus Content

eslint-plugin-simple-import-sort

Do you find yourself worrying about the order of your import statements. Here's a solution to let eslint worry about all that.

npm i -D eslint-plugin-simple-import-sort
Enter fullscreen mode Exit fullscreen mode

Before - Before sorting
After -
After sorting

Update your .eslintrc.js file to make use of this plugin. Add a top level property plugins.

module.exports = {
    plugins: ['simple-import-sort']
};
Enter fullscreen mode Exit fullscreen mode

husky + lint-staged

To make sure you're code is formatted and has no linting errors you'll have to run npm run lint every time. We should be able to automate this somehow.

Let's go -

npm i -D husky \        # A tool for adding a pre-commit hook to git, It will run a certain command every time you commit
         lint-staged    # A tool for running a certain list of commands over files that staged for committing in git
Enter fullscreen mode Exit fullscreen mode

Now in your package.json add the following at the top level.

{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "./**/*.{js,jsx,ts,tsx}": [
      "eslint --fix",
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Hope you learned something new. Eslint is endlessly customizable and you should explore more to find some plugins and configs that best benefit your project.

All the code snippets can be found here as a Gist on GitHub

Top comments (12)

Collapse
 
bholmesdev profile image
Ben Holmes

Went through a lot of eslint + prettier tutorials without much luck... and this cleared up so much for me. Nice touch on the a11y validation for hrefs inside Link components; that was driving me crazy!

Collapse
 
heyitsarpit profile image
Arpit

Glad you found it helpful!!!

Collapse
 
jayakornk profile image
Bacon

You don't need the red line any more. You only need the blue one according to the update.

.eslintrc.js

Ref: eslint-config-prettier - CHANGELOG.md Version 8.0.0 (2021-02-21)

Collapse
 
sadi304 profile image
Sadi Mahmud

Thanks for the article. I guess you forgot to add

  // .eslintrc.js
  extends: [
   ....,
   'plugin:react-hooks/recommended', <---
  ],
Enter fullscreen mode Exit fullscreen mode
Collapse
 
rodrimaia profile image
Rodrigo Maia • Edited

simple-import-sort rule definitions changed from 'simple-import-sort/sort' to 'simple-import-sort/imports'

Collapse
 
nubpro profile image
nubpro

Typo:
Simply go to your >>> .eslint.js <<< and add our custom rules for it.

Collapse
 
flashblaze profile image
Neeraj Lagwankar

This is beyond amazing! Thanks for putting out such a well thought out article with clear reasoning.

Collapse
 
exedemaio profile image
Exequiel Demaio

The best tutorial to configure eslint + prettier and eslint-plugin-simple-import-sort changed my life haha. Congratulations!

Collapse
 
meesfrenkelfrank profile image
Mees Frenkel Frank • Edited

Great article. What about adding a tsconfig.json (by running tsc --init)...

Collapse
 
oieeaaaa profile image
Joe

thanks!

Collapse
 
marianocodes profile image
Mariano Álvarez 🇨🇷

Love how simple and easy was to set up everything thanks to your post.!