How To Add Prettier and ESLint Automation to a React Codebase
Tags: react, javascript, webdev
Published: 2021-05-25 22:32:58

---
title: How To Add Prettier and ESLint Automation to a React Codebase
published: true
description: Automated code quality with GitHub Actions, Husky, Lint-staged, Prettier, and ESLint
tags: React, JavaScript, Webdev
slug: prettier-eslint-react
canonical_url: https://www.swyx.io/prettier-eslint-react
cover_image: https://miro.medium.com/max/1400/1*N9n5F63ne3HimpJ10d1HEw.jpeg
disclosure: I just did this as of May 2021 so your mileage may vary
---

> "Civilization advances by extending the number of important operations which we can perform without thinking about them." — Alfred North Whitehead

I've just implemented Prettier + ESLint on my React codebase [at work](https://github.com/temporalio/documentation/pull/451/commits/cae25e5ee08ef6ba840596679b7d37e79585ce4b) and figured I'd better share my notes in case others need to figure this out.

My setup includes:

- See lint violations inline in VSCode
- Prettify after PR merge with GitHub actions
- Prettify before git commit (some folks dislike this)
- Ability to manually run checks locally

Even if you use TypeScript, you'll want BOTH Prettier and ESLint in your codebase. Prettier [doesn't always do what you mean](https://twitter.com/swyx/status/1191452690930376705) and ESLint checks things that Prettier doesn't. For historical reasons, this codebase doesn't use TypeScript, don't @ me, my love for [TypeScript is well documented](https://react-typescript-cheatsheet.netlify.app/).

## Step 1: Dependencies

```bash
yarn add -D eslint eslint-plugin-react husky lint-staged prettier

# or npm i -D eslint eslint-plugin-react husky lint-staged prettier
```

as of time of writing these are the versions I am working with:

```json
{
  "devDependencies": {
    "eslint": "^7.27.0",
    "eslint-plugin-react": "^7.23.2",
    "husky": "^6.0.0",
    "lint-staged": "^11.0.0",
    "prettier": "^2.3.0"
  }
}
```

Note that this setup requires more work if you [using Husky v6 with Yarn 2](https://typicode.github.io/husky/#/?id=manual).


## Step 2: Scripts

add stuff to package.json...

```json
{
  "scripts": {  
    "format": "prettier --write .",
    "prepare": "husky install"
  },
  "lint-staged": {
    "**/*": "prettier --write --ignore-unknown"
  },
}
```

You can now run `npm run format` to prettify your existing codebase as a oneoff.

In case you were wondering:

- [Husky](https://typicode.github.io/husky/#/) adds a git commit hook so that...
- [`Lint-staged`](https://github.com/okonet/lint-staged) only runs Prettier on new stuff that you stage in git

## Step 3: Prettier Settings

Commence bikeshedding! Use the [Prettier Playground](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEAzArlMMCW0AEAEnADYkQDqEATiQCYAUwA5tXHLlM-gLz4A6IABalyggDT5W7eHV74A5IKq06ghZIDOOEghjzUAQxKa4k6AFkI6UwHkAbnGriAvgEp8wflG-58OVAYAQmkOHC43YDYYdGoofCh0MhcAbm9fPz8Aeiz8ABVbABFbJHxC6AV9Gzh8akMoOggAW394tganDN19RJa+C0MYIQA6VHIafAYBoeG6huaGDwAqfABGAFEAagB2N2GYCABlGGpw5kXZuAAHEkMwOAYs-n5h57pNrJxmSUFBN3T4rUOLF4gAeOg4ez4MC3TSaAByhiacB4CmIZEoNHoCnwuBguh4wAABgBNaz4QxsfD2HDaA7UBLoJoAIyc+AAJMBGS0XESXPhLNY7I5qITBdUHE4XAA+AGZfCgzQnaDMaVc0KcZjDTQkHD3Bj4AAMklW+D2BwAqlcrk4AMKGUyLfCbKRsMJcbW6-Wrc0QAAyEAA7naHQ8PC5QVkldQVbLAX4WG7NcMEHRNBQcEMGBI-vgAPwCECF-ClRVXer4JUATwJwGAkHI1FKSn40irChcMokhcjmnLUGl+BcGT8oLgTTj-Bg6qTcDkw58MEj47j8q5DG0ulg-3jmQLgleIBHmVKgiCggXx8jEPs0rSPigLhA4hAECuuGgmmQoEpMcDAAVKQQL8UGMQNDCrL8X2ZOowAAaw4Q5yzAM5kCMEwzBAcdWToOg5z9epmHQQxmDgAAxGgmkGTVkBAQx0AOZ9hBgJoSAoIRMzgPs7jgQ5gMzSFMyrWiwDhJjwlMagYH-OpmCotDjFMF8ACtNAADwAIVghCYEOJE4D9cI4AUjCVPUw4zl0ABFdAIHgEylJActqEk2jmUMVkSCYq5TlgDM6CGZAAA5jScmNTAoOorlonyuKcRwmIAR1s+AZLfEC6M0ABaKB2DwugmLYZKcDYGSSPkpB0Mc0wmhwBzMO0LhrJS4ykBOdBMJgDz-MCpAACYXxOQwdDOW1mgqrDNAAViY6o8g8kCqsw+wOoASQ6WBDjAU53wAQQaY4a1apbOyAA) to decide on what settings your team wants.

Put this in `.prettierrc.json`

```json
{
    "arrowParens": "always",
    "bracketSpacing": false,
    "embeddedLanguageFormatting": "auto",
    "htmlWhitespaceSensitivity": "css",
    "insertPragma": false,
    "jsxBracketSameLine": false,
    "jsxSingleQuote": false,
    "printWidth": 80,
    "proseWrap": "preserve",
    "quoteProps": "as-needed",
    "requirePragma": false,
    "semi": true,
    "singleQuote": false,
    "tabWidth": 2,
    "trailingComma": "es5",
    "useTabs": false,
  } 
```

Step 4: ESLint

You know you gotta...

```js
module.exports = {
    "env": {
        "browser": true,
        "es2021": true,
        "node": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:react/recommended"
    ],
    "parserOptions": {
        "ecmaFeatures": {
            "jsx": true
        },
        "ecmaVersion": 12,
        "sourceType": "module"
    },
    "plugins": [
        "react"
    ],
    "rules": {
        "react/prop-types": [0, {}], // this is dumb, why is this still recommended
        "react/no-unescaped-entities": [0, {}],
        "no-unused-vars": [1, {}],
    }
};
```

> Recommended: also enable the [ESLint VSCode plugin](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) to see the eslint feedback in your editor!!!

Step 5: Automate

We'll just add a nifty little GitHub Action in `.github/workflows/autoformat.yml`:

```yaml
name: Continuous Integration

# This action works with pull requests and pushes
on:
  pull_request:
  push:
    branches:
      - master

jobs:
  prettier:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          # Make sure the actual branch is checked out when running on pull requests
          ref: ${{ github.head_ref }}

      - name: Prettify code
        uses: creyD/prettier_action@v3.3
        with:
          # This part is also where you can pass other options, for example:
          prettier_options: --write **/*.{js,md}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

That's it!