JavaScriptを書く上で必須のツールであるESLintだが、自分はあまりちゃんと理解していない。
最初に設定してしまえばその後はあまり手を加えないし、加えるときも都度調べて対症療法的に対応しているから、基礎は分かっていない。
取り敢えずairbnb
をextendes
しておけば間違いない、くらいの理解。
だがESLintはコードを整理して綺麗にしていくための必須かつ強力なツールだし、新しい環境を作るときにいちいち躓くのも面倒なので、調べることにした。
Lintとは何か、何が素晴らしいか、みたいなことは書かない。個々のルールについても書かない。
ESLint自体の使い方、のような内容を書いていく。
環境は以下。
node
10.9.0
npm
6.2.0
eslint
5.5.0
特に断りが無い限りsrc/
に対象のJSファイルが入っている。
そうすると$ npx eslint src/
でチェックできる。
rules
ルートディレクトリに.eslintrc
を置き、そこにESLintの設定を書いていく。
個別のルールについては、rules
プロパティに書いていく。
例えば以下の設定だと、文末にセミコロンをつけないとエラーになる。error
をwarn
に変えると、エラーではなく警告になる。
{ "rules": { "semi": ["error", "always"] } }
// error Missing semicolon semi
1
/* eslint-disable */
と/* eslint-enable */
で囲むと、その範囲だけESLintを無効に出来る。
/* eslint-disable */ 1 // エラーにならない /* eslint-enable */ 1 // エラーになる
ESLintの実行時に--fix
オプションをつけると自動的にコードを修正してくれる。自動では補完できないルールもある。
$ npx eslint --fix src/
現在有効になっているESLint設定を確認したい場合は、--print-config
オプションを使う。
$ npx eslint --print-config src/ { "globals": {}, "env": {}, "rules": { "semi": [ "error", "always" ] }, "parserOptions": {} }
env
よく使われているルールとして、no-undef
がある。
{ "rules": { "no-undef": "error" } }
これは未定義の変数を使っていないかチェックしてくれる、非常に有用なルールである。これをオフにする理由は基本的にないだろう。
だが一つ問題があって、例えばdocument
オブジェクトを使おうとすると、エラーになってしまう。
// error 'document' is not defined no-undef document.querySelector('#app');
これは、document
オブジェクトはブラウザ環境でのみ使えるオブジェクトであり、JavaScriptそのものには定義されていないから発生している。
この問題を解決するために使うのが、env
プロパティである。
これでbrowser
を設定すると、ブラウザ環境固有のオブジェクトも問題なく使えるようになる。
{ "env": { "browser": true }, "rules": { "no-undef": "error" } }
指定できる環境はbrowser
以外にもたくさんある。
https://eslint.org/docs/user-guide/configuring#specifying-environments
parserOptions
ESLintではデフォルトでは、ES5の構文しか使えない。ES2015以降の構文を使うには設定を上書きする必要がある。
ESLint allows you to specify the JavaScript language options you want to support. By default, ESLint expects ECMAScript 5 syntax. You can override that setting to enable support for other ECMAScript versions as well as JSX by using parser options.
https://eslint.org/docs/user-guide/configuring#specifying-parser-options
具体的にはparserOptions
プロパティを設定できる。
まず、parserOptions
プロパティを何も設定せずに確認してみる。
// error Parsing error: The keyword 'const' is reserved const hoge = 1;
パースできていない。
parserOptions
に"ecmaVersion": 2015
を設定することで、パースできるようになる。
{ "rules": { "no-undef": "error" }, "parserOptions": { "ecmaVersion": 2015 } }
これでES2015を使えるようになったかと思いきや、まだ問題がある。
parserOptions
はあくまでも構文解析に関するオプションなので、ES2015以降に追加された組み込みオブジェクトには対応していない。
そのため例えば、Map
は未定義とされてしまう。
// error 'Map' is not defined no-undef const hoge = Map;
これを解決するには、先程説明したenv
プロパティにes6
を設定すればいい。
ちなみにこの設定では構文解析も拡張してくれるので、parserOptions
は不要になる。
{ "rules": { "no-undef": "error" }, "env": { "es6": true } }
但し、拡張するのはES2015までなので、最新の機能を使うにはparserOptions
が必要になる。
以下はオブジェクトの分割代入だが、パースできていない。
// error Parsing error: Unexpected token .. const { a, b, ...c } = { a: 1, b: 2, x: 3, y: 4, z: 5};
"ecmaVersion": 2018
を指定する必要がある。
{ "rules": { "no-undef": "error" }, "env": { "es6": true }, "parserOptions": { "ecmaVersion": 2018 } }
sourceType
ES2015+の構文のなかでもimport/export
だけは特別扱いであり、専用の設定が必要。
parserOptions
プロパティのなかで"sourceType": "module"
を設定しないとパースできない。
"parserOptions": { "sourceType": "module" }
parser
parser
プロパティを使うことで、パーサーそのものを指定できる。
デフォルトではEspree
というパーサーが使われているが、これでは対応できない構文を使用する際に、他のパーサーを使う。
例えばFlow。
// error Parsing error: Unexpected token : function concat(a: string, b: string) { return a + b; }
パース出来ずにエラーになる。
これを解消するには、パーサーにbabel-eslint
を使用すればよい。
まずは使用したいパーサーのnpmパッケージをインストールする。
$ npm i -D babel-eslint
次に、.eslintrc
でパーサーを指定する。
{ "parser": "babel-eslint" }
これで、Flowもパースできるようになる。
ただ、これは単にパースしているだけなので、Flowの文法についてESLintでチェックしたい場合は後述するプラグインという機能を使う必要がある。
ちなみに、babel-eslint
はいろんな設定を自動的に付加してくれるようで、パーサーをbabel-eslint
にするだけでMap
やimport
などを使えるようになる。
shareable configuration
shareable configuration
という仕組みを使うことで、他人が書いた設定を導入できる。
extendes
プロパティで指定できる。
まずは、ESLintが推奨している設定を導入してみる。
{ "extends": "eslint:recommended" }
個別のルールは何も設定していないが、いくつかのルールが有効になっている。
例えば、no-undef
やno-empty
。
// error 'foo' is not defined no-undef // error Empty block statement no-empty if (foo) { }
extends
してきたルールの一部を上書きすることも可能。
{ "extends": "eslint:recommended", "rules": { "no-undef": "off", "no-empty": "warn" } }
// warning Empty block statement no-empty if (foo) { }
shareable configuration
がnpmパッケージとして公開されていれば、自由にそれを導入できる。
例として、広く使われている設定であるeslint-config-airbnb
を導入してみる。
先程のeslint:recommended
はrules
を設定するだけだったが、eslint-config-airbnb
ではenv
やsourceType
の設定も行ってくれるため、自分で行う設定がかなり少なくて済むようになる。
例えば以下のコードをESLintの対象にするためには、ここまで説明してきたように様々な設定が必要になる。
デフォルトではconst
やexport
をパースできないし、Map
もnot defined
になる。
console.log(Map); const { a, b, ...c } = { a: 1, b: 2, x: 3, y: 4, z: 5, }; export default { a, b, c };
だがeslint-config-airbnb
を使えば、ただそれを継承するだけで、上記のコードが動くようになる。
まずはインストール。
コマンドラインで以下を実行する。
( export PKG=eslint-config-airbnb; npm info "$PKG@latest" peerDependencies --json | command sed 's/[\{\},]//g ; s/: /@/g' | xargs npm install --save-dev "$PKG@latest" )
次に.eslintrc
を編集。
{ "extends": "airbnb" }
この設定だけで、ESLintが先程のコードを理解してくれるようになる。
plugins
プラグインは、ESLintのルールを追加する仕組み。
既存のルールをオン・オフするのではなく、独自のルールを追加できる。
ReactやVueのような特定のライブラリや環境のためのルールを追加するのが、主な目的。
先程少し触れたFlowのためのプラグインもある。
例として、eslint-plugin-react
を使ってみる。
まずはチェック対象であるJSファイルを作る。
import 'react'; function myComponent() { return ( <div>hoge</div> ); };
そしてnpmパッケージをインストールした上で、.eslintrc
を設定する。
$ npm i -D eslint-plugin-react
{ "plugins": [ "react" ], "extends": ["plugin:react/recommended"], "parserOptions": { "sourceType": "module" } }
"extends": ["plugin:react/recommended"]
とすることで、プラグインが推奨するルールが適用され、さらにパーサーの設定も行われるので、JSXがパースされるようになる。
$ npx eslint src/ 5:5 error 'React' must be in scope when using JSX react/react-in-jsx-scope
自分で設定を追加したり上書きしたりも、もちろん出来る。
例えば以下のようにすると、react/react-in-jsx-scope
のエラーは消える。
{ "plugins": [ "react" ], "extends": ["plugin:react/recommended"], "parserOptions": { "sourceType": "module" }, "rules": { "react/react-in-jsx-scope": "off" } }
Vueの場合はeslint-plugin-vue
をインストールした上で、次のようにすればいい。
{ "plugins": [ "vue" ], "extends": ["plugin:vue/essential"] }
一点だけ注意すべきなのが、ESLintはデフォルトでは.js
拡張子のみが対象であるということ。
そのため、.vue
はそもそもESLintの対象にならない。
.js
以外も対象にするためには--ext
オプションを使う。
.js
と.vue
を対象にしたい場合は次のようにすればよい。
$ npx eslint --ext .js,.vue src/