🤦‍♀️

うわっ...私の.eslintrc、無駄が多すぎ...?

2021/06/23に公開
2

例えばこんな.eslintrc

{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:react/recommended",
    "prettier"
  ],
  "plugins": [
    "@typescript-eslint",
    "react"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "rules": {
    "react/prop-types": "off",
    "react/react-in-jsx-scope": "off"
  }
}

最近ESLintの設定を見直すことがあったのですが、完全に上のような設定を書いていました。。
実は重複が多く、こんな感じで省略しても同じ設定になります。

{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended",
    "prettier",
  ],
  "rules": {
    "react/prop-types": "off",
    "react/react-in-jsx-scope": "off"
  }
}

.eslintrcのextends設定

recommendedなどを使うときにextendsを使いますが、公式ドキュメントの説明はこうです。

A configuration file, once extended, can inherit all the traits of another configuration file (including rules, plugins, and language options) and modify all the options

簡単にいうと、あらかじめ用意されている設定を読み込んでおき、上書きで設定を追加・変更できるということです。冒頭の例ではこの5つをextendsに含めています。

{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:react/recommended",
    "prettier"
  ],
  ...

では実際はどのような設定をextendしているのか見てみましょう。

extends設定のソースコードの追い方

eslint:recommended だけちょっと特殊なので最後に説明します。

plugin: がついているもの

公式ドキュメントを要約すると

  • plugin:の後にパッケージ名/設定名を指定する
  • パッケージ名は eslint-plugin- は省略した形で指定できる
    • (書いてないけど) @スコープがあるときは @スコープ/eslint-plugineslint-plugin は省略できる
{
  "extends": [
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:react/recommended",
  ],
  ...

よって、ソースコードを探しに行く場合は以下のようになります。

extends ソースコードがあるパッケージ
"plugin:@typescript-eslint/recommended" @typescript-eslint/eslint-plugin
"plugin:react/recommended" eslint-plugin-react

GitHubにソースコードがありました。ここに recommendedeslint-recommended の設定がありそうです。
https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin

ようやくrecommend設定を見つけることができました。よく見ると設定の中でさらにextendsしています。

...

export = {
  extends: ['./configs/base', './configs/eslint-recommended'],
  rules: {
    ...

./configs/baseはこうなっていました。

export = {
  parser: '@typescript-eslint/parser',
  parserOptions: { sourceType: 'module' },
  plugins: ['@typescript-eslint'],
};

そうです!ここでparser,parserOptions,pluginsの設定がしてあります!
ということは冒頭の例では書かなくてもextendsによってすでに設定されているものがあるので、削除することができます。

{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended", // ここに設定されている
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:react/recommended",
    "prettier"
  ],
  "plugins": [
-    "@typescript-eslint",
    "react"
  ],
-  "parser": "@typescript-eslint/parser",
  "parserOptions": {
-    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "rules": {
    "react/prop-types": "off",
    "react/react-in-jsx-scope": "off"
  }
}

さらにrecommend設定の中で './configs/eslint-recommended' もextendsしており、追ってみると plugin:@typescript-eslint/eslint-recommended と同じ設定を見ていました!ということで plugin:@typescript-eslint/eslint-recommended も削除することができます。

{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended", // ここに設定されている
-    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:react/recommended",
    "prettier"
  ],
  "plugins": [
    "react"
  ],
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "rules": {
    "react/prop-types": "off",
    "react/react-in-jsx-scope": "off"
  }
}

plugin:@typescript-eslint/reactの設定

同様に、eslint-plugin-reactのソースコードはこちらにありました。
https://github.com/yannickcr/eslint-plugin-react

そしてrecommend設定を見てみると、

module.exports = {
  ...
  configs: {
    recommended: {
      plugins: [
        'react'
      ],
      parserOptions: {
        ecmaFeatures: {
          jsx: true
        }
      },
      rules: {
        ...

ここにもplugins,parserOptions設定がありました!
ということで重複している設定は削除できます。

{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended", // ここに設定されている
    "prettier"
  ],
-  "plugins": [
-    "react"
-  ],
-  "parserOptions": {
-    "ecmaFeatures": {
-      "jsx": true
-    }
-  },
  "rules": {
    "react/prop-types": "off",
    "react/react-in-jsx-scope": "off"
  }
}

plugin:がついていないもの

公式ドキュメントを要約すると

  • パッケージ名を指定する
  • ただしパッケージ名から eslint-config- は省略した形で指定できる
    • (書いてないけど) @スコープがあるときは @スコープ/eslint-configeslint-config は省略できる
{
  "extends": [
    "prettier"
  ],
  ...

よって、 ソースコードを探しに行く場合は以下のようになります。

extends ソースコードがあるパッケージ
"prettier" eslint-config-prettier

ありました。

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

index.tsを見てみたところrule設定のみで、ruleの内容も冒頭の設定とは重複はありませんでした。

eslint:recommended

eslint:プレフィックスのものは特殊で、ソースコードとしてはこのあたりで.eslintrcのextends設定を読んでいますが、ファイルとしてはeslint/eslintconf/eslint-recommended.jsを設定しています。

https://github.com/eslint/eslint/blob/master/conf/eslint-recommended.js

最終的にはこのような設定

重複を取り除くとこのような設定になりました。

{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended",
    "prettier"
  ],
  "rules": {
    "react/prop-types": "off",
    "react/react-in-jsx-scope": "off"
  }
}

このようにすっきりしましたが、重複していても問題はないのでわかりやすさのために書いておくのもありかと思います。ただ知っておくことに損はないと思いましたのでこの記事を書きました。

注意点としては、.eslintrcの設定は下に書くほど優先が高い(上書きされていく)ので、順番をミスって設定変わってしまったということがあるかもしれないのと、提供されている設定はアップデートにより変更されるため、変更に追従する必要があるということかなと思います。

もし間違いなどあれば指摘ください🙇‍♂️
ちなみにextendsとpluginsの違いはこの記事がとてもわかりやすかったです。ありがとうございました。

https://blog.ojisan.io/eslint-plugin-and-extend

.eslintrcのenv設定についてもまとめてみたので、知りたい方はぜひ!
https://zenn.dev/kimromi/articles/546923b7281dcb

では快適なESLint生活を!

Discussion

カーーズカーーズ

重複していても問題はないのでわかりやすさのために書いておくのもありかと思います。ただ知っておくことに損はないと思いましたのでこの記事を書きました。

「ルールの改善, 保守をする時に毎回それぞれのextendsを探るのは、骨が折れる作業になると思うため重複があってもルールを明示しておいた方が良く、無駄ではないのでは🤔」と思っていました。ですが、引用した背景を見つけて納得しました。記事の投稿、ありがとうございます。

kimromikimromi

コメントありがとうございます😄
ほんとにおっしゃる通りでextends探るのは大変なので、あえて明示しておくのも全然ありだと思います!
eslint-config-airbnbなども見ましたが、それぞれに切り出したファイルごとで重複しても書いていたりしますし、一概に省略するのが正しいとは全く思っておりません👍