ESLint + Prettier をセットアップするといつも苦しむからちゃんと理解する (2020年10月版)

## 前置き

JavaScript/TypeScript の開発環境を整えるとき、当然 Lint や Formatter はしっかりとセットアップしておきたいです。最近の主流では [ESLint](https://eslint.org/) + [Prettier](https://prettier.io/) の構成をとると思いますが、使用するライブラリが多くてなにかと変化も激しいため、いつも設定に苦しみます。

そこで、それぞれのライブラリの役割を理解しながら、基本の構成を整理していきます。

#### 想定プロジェクト

Webフロントエンドを TypeScript + React で開発する想定でいきます。 (一番よくやるので。)
エディタは VSCode を使用し、ファイル保存時に自動整形されるようにします。

## TL;DR

[**`eslint-config-prettier`**](https://github.com/prettier/eslint-config-prettier) だけ使っとけ。

## 1. ESLint をインストールする

以下のコマンドで主役の ESLint を導入します。
(`yarn` ユーザは適宜読み替えてください。)

```bash
npx eslint --init
```

いくつか質問されるので答えていきます。

```bash:出力
? How would you like to use ESLint? ...
> To check syntax and find problems
? What type of modules does your project use? ...
> JavaScript modules (import/export)
? Which framework does your project use? ...
> React
? Does your project use TypeScript?
> Yes
? Where does your code run? ...
> Browser
? What format do you want your config file to be in? ...
> JSON
? Would you like to install them now with npm?
> Yes
```

すると、以下の4つの依存がインストールされます。

* `eslint`
* `eslint-plugin-react`
* `@typescript-eslint/eslint-plugin`
* `@typescript-eslint/parser`

設定ファイルもいい感じにつくってくれます。便利。

```json:.eslintrc.json
{
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:react/recommended",
        "plugin:@typescript-eslint/recommended"
    ],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "ecmaFeatures": {
            "jsx": true
        },
        "ecmaVersion": 12,
        "sourceType": "module"
    },
    "plugins": [
        "react",
        "@typescript-eslint"
    ],
    "rules": {
    }
}
```

## 2. Prettier をインストールする

次は、もうひとつの主役 Prettier をインストールします。

```bash
npm install --save-dev prettier
```

設定ファイルを作ります。お好みでどうぞ。

```json:.prettierrc
{
    "semi": false
}
```

## 3. ESLint と Prettier の衝突を解消する

さて、ここからが本番です。

ESLint と Prettier は、コード整形の機能が衝突します。
だったら ESLint だけでいいのでは？と思うかもしれませんが、 ESLint の整形では不十分なのです。そのため、コード整形は Prettier で、バグ防止のための Lint は ESLint で行うという役割分担をします。

ここで必要になるのが [**`eslint-config-prettier`**](https://github.com/prettier/eslint-config-prettier) です。
これは、 ESLint のコード整形の機能をオフにします。そうすれば衝突しません。単純ですね。

インストールは以下の通りです。

```bash
npm install --save-dev eslint-config-prettier
```

`.eslintrc.json` に設定を追加します。
優先度の高い下側に追加することに注意しましょう。

```diff:.eslintrc.json
    "extends": [
        "eslint:recommended",
        "plugin:react/recommended",
        "plugin:@typescript-eslint/recommended"
+       "prettier",
+       "prettier/@typescript-eslint"
    ],
```

#### 似たようなライブラリが他にもなかった？

* [`eslint-plugin-prettier`](https://github.com/prettier/eslint-plugin-prettier)

    ESLint を実行したときに Prettier を統合して実行する機能のライブラリです。
    以前はこれを使うのが一般的でした。しかし現在は、 [Prettier 公式が非推奨と言っています](https://prettier.io/docs/en/integrating-with-linters.html)。
    フォーマットに関する警告は邪魔、動作が遅いといった理由があるようです。

* [`prettier-eslint`](https://github.com/prettier/prettier-eslint)

    Prettier → ESLint の順に実行してくれるライブラリです。
    ESLint によるコード整形が後勝ちするので、コード整形は Prettier でという役割分担に反します。

## 4. import 順もフォーマットしたい

コード整形は、誰が書いても同じようにフォーマットされるのがいいところです。
しかし、 Prettier は import 順の並び替えはしてくれません。公式に対応する気もないようです。
[`prettier-plugin-import-sort`](https://github.com/ggascoigne/prettier-plugin-import-sort) といったプラグインもありますが、バージョンが `0.0.6` と低く、動作も安定していないように思います。

この用途で一般的なのは、 [**`eslint-plugin-import`**](https://github.com/benmosher/eslint-plugin-import) です。

結局 ESLint もコード整形の役割を一部担うことになってしまうので、釈然としないのですが、現状ではしょうがないですね。
(こういうのがややこしさに拍車をかけてる気がします。)

インストールは以下の通りです。

```bash
npm install --save-dev eslint-plugin-import
```

`rules` の部分は好みに応じて変更しましょう。 (参照: [import/order](https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/order.md))

```diff:.eslintrc.json
    "extends": [
        "eslint:recommended",
        "plugin:react/recommended",
        "plugin:@typescript-eslint/recommended"
+       "plugin:import/warnings",
+       "plugin:import/typescript",
        "prettier",
        "prettier/@typescript-eslint"
    ],
...
    "rules": {
+       "import/order": [
+           "warn",
+           {
+               "alphabetize": { "order": "asc" },
+               "newlines-between": "always"
+           }
+       ]
    }
```

## 5. ファイル保存時に自動整形する

VSCode に以下の拡張機能をインストールします。

* [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
* [Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)

プロジェクト用の VSCode 設定ファイルを用意して、自動整形をオンにします。

```json:.vscode/settings.json
{
    "editor.formatOnSave": true,      // Prettier を実行
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true  // ESLint を実行
    }
}
```

ついでに、拡張機能についてもファイルに残しておきましょう。
これを書いておくと、新しくプロジェクトに参加した人が VSCode を開いたときに、拡張機能のインストールを促すメッセージが出ます。

```json:.vscode/extensions.json
{
    "recommendations": [
        "esbenp.prettier-vscode",
        "dbaeumer.vscode-eslint"
    ]
}
```

## 6. すべてのファイルをフォーマットする

最後に、既存のファイルをまとめてフォーマットするために、スクリプトを用意しておきます。

```diff:package.json
  "scripts": {
+   "lint": "eslint . --ext ts,tsx,js,jsx",
+   "format": "prettier --write \"**/*.{ts,tsx,js,jsx}\" && npm run lint -- --fix"
  }
```

## さいごに

今までは `eslint-plugin-prettier` を使っていましたが、いつのまにかスタンダードが変わっていたようですね。

本当のプロジェクトでは、 [`stylelint`](https://stylelint.io/) を入れたり、 CSS プロパティのソートをさせたりしていますが、長くなるので別記事にしたいと思います。
[`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks) や [`eslint-plugin-css-modules`](https://github.com/atfzl/eslint-plugin-css-modules) もよく使ってますね。

ご意見・質問等あればコメントください。