🪄

ESLint と Prettier の使い分け

2023/11/03に公開

ESLint と Prettier は多くのプロジェクトで併用されるが、ツールの違いや使い分けが少しわかりづらいので、改めて調べて整理する。

前提知識

ESLint はいわゆる Linter と呼ばれるツール (公式サイト)
Prettier はいわゆる Formatter と呼ばれるツール(公式サイト)

Linter とは

プログラムコードを解析して指定したルールに沿ってコーディングが行われているか、バグに繋がりそうなコードはないかなどをチェックするツール。コードの品質を担保するために使用する。

Formatter とは

プログラムコードの自動整形を行うツール。インデントの付け方、行の折り返しなどを一定のルールに沿って自動で整形する。コードの一貫性や可読性向上のために使用する。

棲み分けがわかりにくいと感じる理由

例えば Linter であるESLint で適用することのできるルールには コード品質に関するものだけではなく、フォーマットに関するルールも存在 している。
さらに、提供されるCLIコマンドには検知に加えて自動で修正を行ってくれるオプションも存在しているため整形の機能もあると言える。

従ってPrettierと少し役割が被っていることが、両者のツールの違いや棲み分けがわかりづらいと感じる理由に感じた。

ただし、Linter はあくまで検知することに特化したツールであり整形を専門としたツールではない。

ESLint のルール例

コード品質に関するルール

例)no-unused-vars
エラーになる例

var x; // 使われていない変数定義に対してエラーを出す

var y = 10;
console.log(y);

エラーにならない例

var x;
console.log(x);

var y = 10;
console.log(y);

https://eslint.org/docs/latest/rules/no-unused-vars

フォーマットに関するルール

例)max-len
エラーになる例

/*eslint max-len: ["error", { "code": 80 }]*/

// 一行の長さが指定した文字数以上だとエラーになる
var foo = { "bar": "This is a bar.", "baz": { "qux": "This is a qux" }, "difficult": "to read" };

エラーにならない例

var foo = {
  "bar": "This is a bar.",
  "baz": { "qux": "This is a qux" },
  "easier": "to read"
};

https://eslint.org/docs/latest/rules/max-len

ESLint と Prettier で被っているルールの例

ESLint と Prettier で被っているルールとしては例えば以下のようなものがある。

以下はどちらも statement(文)の最後に ; をつけるかどうかに関するルール。

ESLint

  • ルール名:semi 🔗
  • ルールの内容:Require or disallow semicolons instead of ASI
// .eslintrc.json
{
  "rules": {
    "semi": ["error", "always"],
  }
}

Prettier

  • ルール名:Semicolons 🔗
  • ルールの内容:Print semicolons at the ends of statements
// .prettierrc.json
{
  "semi": true
}

ESLint と Prettier の棲み分け

ここまでみてきたように、ESLint自身でコードの書式(フォーマット)に関することを検知し修正することもできるが、コードの整形については Prettierの方が専門性があるので、公式ドキュメントにもあるように以下のように使い分けるのがよい。

  • コードの書式(フォーマット)に関すること … Prettier
  • コードの品質に関すること … ESLint

Use Prettier for code formatting concerns, and linters for code-quality concerns

https://prettier.io/docs/en/integrating-with-linters

ESLint と Prettierでルールがコンフリクトする可能性がある

ESLint と Prettierで役割を棲み分けようとしたとしても、ESLint と Prettier には同じ内容のルールが存在しているため、両方のツールを一緒に使うときにルールがコンフリクトしてしまう可能性がある。

コンフリクトする例

; に関するルールを ESLint / Prettier それぞれで適用していたとする

Prettier

Prettier では 文の最後に ;つけないというルールを適用

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

ESLint

ESLint では文の最後に ;つける(ついていないとエラーを出す)というルールを適用

// .eslintrc.json

{
  "rules": {
    "semi": ["error", "always"]
  }
}

Prettier を実行すると ; がない状態に整形される

// index.js
console.log("Hello World!");
$ npx prettier --write ./src/index.js

以下のように ; が削除された状態で出力される

// index.js
console.log("Hello World!")

ESLint を実行すると ; がない状態ではエラーになる

// index.js
console.log("Hello World!")
$ npx eslint ./src/index.js

このように ESLint と Prettier を併用するとそれぞれで違うことをいってる!!という状態になってしまう可能性がある🥲

ルールのコンフリクトを防ぐ仕組み

そうしたことが発生しないように、ESLintのルールとPrettierで被っているルールについて、ESLint側でルールをオフにすることのできる仕組みが用意されている。

これを利用することで、コードの書式に関することは基本的にPrettierに寄せることができるようになる。

eslint-config-prettier
https://github.com/prettier/eslint-config-prettier

( 具体的にオフになるルールはこちら

このパッケージをインストールし、 .eslintrc.*extends フィールドを設定してあげることで、ESLint と Prettier 両者に存在しているルールをESLint側でオフにすることができる

※ ただし、オフにできるのはextendsで有効になっているルールが対象で、 rulesフィールドの中で設定されているものはオフにならない。

{
  "extends": [
    "some-other-config-you-use",
    "prettier" // some-other-config-you-use に入っているルールに対してPrettierとかぶっているものを無効化する
  ],
  "rules": {
    "indent": "error" // rulesの中身には触れない
  }
}

"eslint:recommended" に含まれているルールの中で no-extra-semi というルールは Prettierにも存在するルールなので、これを例に見てみる。(参照

検査対象のファイル

以下のように ; が2つ付けられているコードを検査対象とする。

// index.json
var foo = 1;;

extends で prettier を指定しない時

以下のように設定した上で、eslint を実行すると、"eslint:recommended"には"no-extra-semi": "error"のルールが含まれているため、エラーが発生する。

// .eslintrc.json
{
  "extends": [
    "eslint:recommended"
  ]
}

extends で prettier を指定する時

eslint-config-prettierをインストールした上で extendsprettier を指定すると、Prettier にも存在している"no-extra-semi"のルールは無効になるため、eslintを実行してもエラーにはならない。

// .eslintrc.json
{
  "extends": [
    "eslint:recommended",
    "prettier"
  ]
}

rulesにも設定がある場合

ただし、以下のように rules フィールドで no-extra-semiに関するルールを設定していた場合はそのルールが適用されてしまい、エラーが発生する。

{
  "extends": [
    "eslint:recommended",
    "prettier"
  ],
  "rules": {
    "no-extra-semi": ["error"]
  }
}

コンフリクトを検知する便利ツール

そうしたときに、prettier が提供してくれている eslint-config-prettier というコマンドを使うことでコンフリクトするルールを検知することができる

npx eslint-config-prettier path/to/main.js

先ほどの設定の状態でコマンドを実行すると以下のようにコンフリクトしているルールを教えてくれる

結論

  • ESLint と Prettier は以下のように使い分けるのがよい
    • ESLint:コードの品質に関すること
    • Prettier:コードの書式(フォーマット)に関すること
  • ESLint と Prettier で設定するルールがコンフリクトする可能性があるので、被っているルールをESLint側でルールをオフにできる仕組みを一緒に導入するのが良い

Discussion