Setup Eslint + Prettier para padronização de código em React
Tags: react, eslint, prettier, webdev
Published: 2024-05-27 21:18:03

## Introdução

Durante o processo de desenvolvimento, torna-se importante a definição de um padrão de projeto visando legibilidade, manutenção e aumento da qualidade de código. Para isso, esse artigo vai trazer duas libs que em conjunto permitem verificar o código na busca/solução de problemas e a formatação dele, dada as regras definidas.     

## Libs

- prettier: é a lib responsável pela formatação de código
- eslint: é a lib que vai analisar o código visando a busca e solução de problemas

## Setup

Para adicionar o prettier:

``yarn add prettier --dev``

Para adicionar o eslint:

``yarn add eslint@8.57.0 eslint-config-prettier --dev``

- `eslint@8.57.0`: vai adicionar a versão 8.57.0 (a mais recente abaixo da 9), dado a alguns [problemas](https://github.com/jsx-eslint/eslint-plugin-react/issues/3699) relacionados com o plugin de react a partir da versão 9, que estão sendo analisados
- `eslint-config-prettier`: vai desativar as regras do eslint que conflitam com o prettier

Para adicionar os plugins do eslint:

``yarn add eslint-plugin-prettier eslint-plugin-react eslint-plugin-react-hooks --dev``

- `eslint-plugin-prettier`: vai permitir rodar o prettier em conjunto com o eslint
- `eslint-plugin-react`: vai trazer as regras de linting específicas para aplicações React
- `eslint-plugin-react-hooks`: vai trazer as regras de linting para hooks em React

Para permitir executar o eslint para aplicação React que tem o Babel como compilador:

``yarn add @babel/eslint-parser --dev``

Após a instalação das libs, adicionar na raiz do projeto o arquivo `.eslintrc.json` para configurar a execução do eslint. Ele vai ser incrementado aos poucos a medida que vão sendo explicadas as configurações:

#### env

Traz variáveis globais predefinidas.

- `"browser": true`: referentes ao browser
- `"node": true`: referentes ao Node.js
- `"jest": true`: referentes ao Jest

```js
{
  "env": {
    "browser": true,
    "node": true,
    "jest": true
  },
}
```

Por exemplo, se tenho uma app que usa Jest para os testes e não defino a env `"jest": true`, ao executar o eslint vai ser levantados erros do tipo: `describe, it, expect não estão definidos`.
Quando coloco a env `"jest": true`, ao executar o eslint ele já saberá que são termos usados nos testes e não vai levantar erros por causa deles.

#### extends

Traz configurações adicionais para o eslint.

- `eslint:recommended`: traz regras recomendadas do eslint
- `plugin:react/recommended`: traz regras recomendadas para react (é possível usar devido a adição do plugin `eslint-plugin-react`)
- `plugin:react-hooks/recommended`: traz regras recomendadas para hooks em React (é possível usar devido a adição do plugin `eslint-plugin-react-hooks`)
- `prettier`: remove as regras do eslint que podem conflitar com o prettier (é possível usar devido a adição da lib `eslint-config-prettier`)

```js
{
  //...
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:react-hooks/recommended",
    "prettier"
  ],
}
```

#### parser

- `@babel/eslint-parser`: permite executar o eslint para aplicações que usam o babel como compilador

```js
{
  //...
  "parser": "@babel/eslint-parser",
}
```

#### parserOptions

- `ecmaVersion`: especifica a ECMAScript syntax usada (`latest` corresponde a mais recente versão suportada)
- `sourceType`: especifica se a aplicação está usando ESM: `module` ou se está usando CommonJS: `script`
- `ecmaFeatures` - `"jsx": true`: especifica se inclui syntax jsx

```js
{
  //...
  "parserOptions": {
    "ecmaVersion": "latest",
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
}
```

#### plugins

Permite adicionar plugins para extender o eslint, que podem adicionar regras de validação, configurações, envs.

- `prettier`: plugin do prettier
- `react`: plugin do React
- `react-hooks`: plugin de hooks em React

```js
{
  //...
  "plugins": [
    "prettier",
    "react",
    "react-hooks"
  ],
}
```

#### settings

- `react` - `"version": "detect"`: detecta automaticamente a versão do React da aplicação

```js
{
  //...
  "settings": {
    "react": {
      "version": "detect"
    }
  },
}
```

#### ignorePatterns

Arquivos que serão ignorados quando rodar o eslint.

- `*.stories.tsx`:  foi colocado no artigo somente como exemplo, nesse caso o eslint não iria olhar os arquivos que terminam com `.stories.tsx`

```js
{
  //...
  "ignorePatterns": ["*.stories.tsx"],
}
```

#### rules

Permite adicionar as regras do prettier para serem executadas em conjunto com o eslint:

```js
{
  //...
  "rules": {
    "prettier/prettier": ["error"]
  }
}
```

- `prettier/prettier`: adiciona as regras do prettier quando for executado o eslint
- `error`: define que caso alguma regra do prettier não seja satisfeita, retorne erro. Além de `error`, é possível passar `warn` que levantaria um `warning` se alguma regra não fosse satisfeita. Ou `off` para desativar as regras

Permite customizar as regras do eslint:

```js
{
  //...
  "rules": {
    "react/jsx-uses-react": "off",
    "react/react-in-jsx-scope": "off",
    "prettier/prettier": ["error"]
  }
}
```

`"react/jsx-uses-react": "off"` e `"react/react-in-jsx-scope": "off"`: desativa no eslint a regra que retorna erro se não é colocado o `import React from 'react'` nos arquivos. Bom para versões de React 17 para frente que não tem essa necessidade

Permite customizar as regras do prettier:

```js
{
  //...
  "rules": {
    "react/jsx-uses-react": "off",
    "react/react-in-jsx-scope": "off",
    "prettier/prettier": [
      "error",
      {
        "singleQuote": true
      }
    ]
  }
}
```

`singleQuote`: define como regra de formatação as strings terem aspas simples

Após finalizar a definição do arquivo de configuração, adicionar em package.json os scripts:

```js
"scripts": {
  //...
  "lint": "eslint .",
  "lint-files": "eslint",
  "lint-fix": "eslint . --fix",
  "lint-fix-files": "eslint --fix",
},
```

Por default seguindo essa configuração, o eslint vai olhar os arquivos `.js`. Para verificar outros tipos de arquivos é nos scripts acima adicionar depois de eslint `--ext=js,{outro_tipo_de_arquivo}` 

- `eslint .`: ao rodar `yarn lint` vai verificar em todos os arquivos se estão de acordo com as regras do eslint e prettier
- `eslint`: ao rodar `yarn lint-files {nome_do_arquivo ou nome_da_pasta}` vai verificar o arquivo passado ou todos os arquivos da pasta passada, se estão de acordo com as regras do eslint e prettier
- `eslint . --fix`: ao rodar `yarn lint-fix` vai formatar e corrigir o código seguindo as regras do eslint e prettier
- `eslint --fix`: ao rodar `yarn lint-fix-files {nome_do_arquivo ou nome_da_pasta}` vai formatar e corrigir o código seguindo as regras do eslint e prettier, para o arquivo ou todos os arquivos da pasta passada

Sugestão: caso sempre é executado para uma pasta específica (por exemplo `src`), para facilitar pode trocar os `.` dos scripts para `src`.

## Exemplo

Vamos partir do arquivo de configuração completo definido acima:

```js
{
  "env": {
    "browser": true,
    "node": true,
    "jest": true
  },
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:react-hooks/recommended",
    "prettier"
  ],
  "parser": "@babel/eslint-parser",
  "parserOptions": {
    "ecmaVersion": "latest",
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "plugins": [
    "prettier",
    "react",
    "react-hooks"
  ],
  "settings": {
    "react": {
      "version": "detect"
    }
  },
  "ignorePatterns": ["*.stories.tsx"],
  "rules": {
    "react/jsx-uses-react": "off",
    "react/react-in-jsx-scope": "off",
    "prettier/prettier": [
      "error",
      {
        "singleQuote": true
      }
    ]
  }
}
```

Arquivo de exemplo:

```js
import Component from "./Component";

const Example = () =>   <p>Eslint article</p>;

export default Example;
```

Ao executar `yarn lint-files` para esse arquivo:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bdnalf5c5c8pzbjh9qsi.png)

Ele retorna 3 erros, 2 do prettier e 1 do eslint, informando que dois são corrigidos pelo `--fix`:

- Primeiro erro: referente a regra do eslint que retorna erro para variável declarada mas não usada no código
- Segundo erro: referente a regra customizada definida para usar aspas simples no prettier
- Terceiro erro: referente a regra do prettier de espaçamento

Ao executar `yarn lint-fix-files` para esse arquivo:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9t4o82hf2scu0k84v8wa.png)

Ele corrige dois dos erros que tinha levantado, e continua avisando do que não era auto corrigível. Ficando o arquivo dessa forma:

```js
import Component from './Component';

const Example = () => <p>Eslint article</p>;

export default Example;
```

Removendo o import que não é utilizado, não terá mais erros aparecendo na execução do eslint.

## Conclusão

A ideia foi trazer as libs necessárias para configuração do eslint com o prettier, focando em como executar eles em conjunto e mostrar onde é possível customizar as regras referentes a ambos. Tentei trazer de forma geral o que representa os elementos do arquivo de config, dependendo da app pode ser que não seja necessário a adição de todos os elementos mostrados acima ou uma pequena alteração em um deles, segue a doc referente a [versão 8.57.0](https://eslint.org/docs/v8.x/) do eslint. No próximo artigo vou focar em trazer regras que são interessantes se customizar tanto para o prettier quanto ao eslint.