eslintのpluginsとextendsの違いを理解する
本記事は「つながる勉強会 Advent Calendar 2022」の 20日目の記事です。
19日目はあっこさんの以下の記事でした。
結構色んな方が記事書いてるのでよかったら見てみてください。
*普段のブログは常体で書いてるのですが、Advent Calendarということもあり、今回は敬体で書くことにします。
さて、数ヶ月前にeslintのflat configが発表されました。
これは設定ファイルの書き方に関するもので、これまでの書き方と色々と違うところがありますが、簡単に言うとよりシンプルな記述で設定を書けることを意図したものらしいです。
詳細は以下の記事がとても参考になりました。
確かにeslintの設定ファイルって複雑になりがちでかなり読みにくいです。
結局どのpluginが読み込まれてるのかわかりにくいし、特定のファイルのみに適用するルールの場合は全体でonにして、overridesで一部offに上書きという仕様はあまり直感的ではないように思います。
そういったモヤモヤしたのがflat config使うとスッキリ解決するとのこと。
というわけで従来していた設定をflat configで書き直そう!
と思ったんですが、そのためにはそもそも従来通りの設定をちゃんと理解する必要があるというわけで、この記事ではこれまで雰囲気で書いていたeslintの設定の意味をちゃんと調べて理解できたことをメモしていくことにします。
特にpluginsとextendsの挙動の違いが理解できてなかったのでその内容が中心になります。
そして次回の記事で実際にflat configを使って書くと記述がどう変わるのかを見ていきます。
本記事では主に以下のことを書いています。
- プロパティにある
extendsとpluginsの挙動の違い - eslint-config-xxxとeslint-plugin-xxxの違い
十分調べて書いたつもりですが、間違っていたら教えてください。
pluginsとは
おそらくpluginsの方から説明する方がわかりやすい気がしたのでpluginsから。
pluginとは、ESLintに様々な拡張機能を追加するためのnpmパッケージです。
新しいルールの追加やshareable configsのexportができるようになります。
shareable configsの話はextendsの際に説明するので一旦後回しにして、最も基本的な?新しいルールの追加機能を見ていきます。
例としてimportに関するあれこれのルールを追加できるeslint-plugin-importというパッケージをインストールします。
そして以下のようにpluginsにimportを書いて、rulesの中に該当ルールを記載すれば適用されます。
{
"plugins": ["import"],
"rules": {
"import/no-unresolved": "error"
}
}pluginsの中に書いたimportはeslint-plugin-importを使用することを指しています。
このパッケージによらず、eslint-plugin-は省略して書くことができる仕様になっているようです。
この時、pluginはあくまでルールセットを拡張するだけなので、実際にどのルールを適用させるかはrulesの中に記載する必要があります。
(*後に記載するshareable configsを使わない場合は)
extendsとは
shareable configsに書かれた設定を継承するためのプロパティです。
shareable configsとは?
先ほどもpluginsで出てきたのでここでちゃんと説明しておきます。
eslintの設定は様々なプロジェクトで何度も同じような設定を書いて使うことが多いです。
そのため、そういった一連の設定をnpmパッケージで管理しておいて読み込んで使えると簡単に共有できて良さそうに思えます。
これを実現したのがshareable configsであり、簡単に言えば色んな設定が既に書かれたeslintの設定ファイルと言って差し支えないのではないでしょうか。
先述したpluginsだけでなくrulesやenvなど、eslintの設定ファイルに記載する内容があらかじめ定義されています。
つまり、該当のnpmパッケージをinstallして、extendsで読み込めば適用されるようになっています。
読み込み方はpluginの時と似ていて、eslint-config-fooというnpm packageならばeslint-config-の部分は省略できます。
つまり、eslint-config-prettierをinstallして、"extends": ["prettier"]と書けばeslint-config-prettierの内容が適用されます。
参考までにeslint-config-prettierの中身を見てみると以下のようになっていました。
module.exports = {
rules: {
// The following rules can be used in some cases. See the README for more
// information. (These are marked with `0` instead of `"off"` so that a
// script can distinguish them.)
"curly": 0,
"lines-around-comment": 0,
"max-len": 0,
...
}
}様々なルールが設定されているのが見てとれます。
そのため、pluginsとは違って、extendsで読み込めばrulesの中を自分で設定しなくても適用されるルールが存在し得ます。
extendsの中で被った設定に関しては後の方が優先して適用される仕様になっています。
prettierとeslintを同時に使う際に競合しないようにするには、現在上記の方法が推奨になっていますが一番最後に書くのも納得です。
pluginによるshareable configsのexport
plugins内の記述で「shareable configsのexportができる」と記載しました。
例としてeslint-plugin-reactの中身を見てみると、以下のようなconfigsというプロパティが見つかります。
configs: {
recommended: {
plugins: [
'react',
],
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
rules: {
'react/display-name': 2,
'react/jsx-key': 2,
'react/jsx-no-comment-text',
...
},
},
all: { ... },
'jsx-runtime': { ... }
}ここにはrecommendedとallとjsx-runtimeが存在していて、それぞれに必要なルールをはじめとしてpluginsとparserOptionsが設定されています。
そう、これはまるでshareable configsであり、eslint-plugin-fooというパッケージの中でconfigsにshareable configsを設定してexportすることができるということです。
これはextendsで以下のように記載すれば適用されます。
"extends": ["plugin:[plugin名]/[config名]"]ここでも例によってplugin名のところはeslint-plugin-を省略できます。
従って以下の設定はeslint-plugin-reactのパッケージの中にあるconfigsのrecommended部分を適用するという意味になります。
"extends": ["plugin:react/recommended"]pluginsに明記しなくてもルールが適用されるケース
実はextendsに以下のように設定した場合はplugins: ["react"]を記載しなくても適用されます。
"extends": ["plugin:react/recommended"]その理由は、このrecommendedの設定の中でplugins: ['react']が既に記載されているためです。
上書きしたり追加したりしたいルールがあった場合はそのままrulesの中に書けば適用されます。
pluginsに書いてないのにルールが適用されるというのはこのようなextendsした中で既にpluginsが記載されているというケースのはずです。
ただし、実際に使うpluginのnpmパッケージ自体はインストールしておく必要があります。
まとめ
esling-plugin-fooは様々な拡張機能を追加するためのnpmパッケージであり、以下のことができるようになります。
- 新しいルールの追加 (
pluginsに記載) - shareable configsのexport (
extendsにplugin: [plugin名]/[config名]の形で記載)
eslint-config-fooは再利用可能な様々な設定を含んだnpmパッケージであり、extendsに書くことでルールをはじめとした諸々の設定が適用されます。
個人的にはeslint-plugin-が省略されるみたいな仕様は逆に依存関係がわかりにくくなってかなり微妙だなと思ってます(実際今回ちゃんと調べるまで理解できてなかったです)
ただしそれもflat configを使うと依存関係が明示的になっていてよかったので次の記事で紹介します




