ESLint を試す
これまで JavaScript の構文チェックに JSHint を利用していたが ES6 と React JSX に対応していること、より細かく柔軟なルール設定が可能なことから ESLint へ移行してみる。
インストール
ESLint は npm で配布されている。Sublime Text など様々なアプリから参照することになるだろうからグローバルにインストールしておく。
$ npm i -g eslint
CLI を提供しているのでコマンドラインから実行可能。バージョン情報は eslint -v
、オプション全般は eslint -h
で確認。
$ eslint -v
v0.20.0
$ eslint -h
eslint [options] file.js [file.js] [dir]
Options:
-h, --help Show help
-c, --config path::String Use configuration from this file
--rulesdir [path::String] Use additional rules from this directory
-f, --format String Use a specific output format - default: stylish
-v, --version Outputs the version number
--reset Set all default rules to off - default: false
--no-eslintrc Disable use of configuration from .eslintrc
--env [String] Specify environments
--ext [String] Specify JavaScript file extensions - default: .js
--plugin [String] Specify plugins
--global [String] Define global variables
--rule Object Specify rules
--ignore-path path::String Specify path of ignore file
--no-ignore Disable use of .eslintignore
--no-color Disable color in piped output
-o, --output-file path::String Specify file to write report to
--quiet Report errors only - default: false
--stdin Lint code provided on <STDIN> - default: false
--stdin-filename String Specify filename to process STDIN as
ルールの定義
ESLint のルールを定義する方法は以下。
JavaScript コメント
構文チェックしたい JavaScript のコメントとして定義する方法。設定は JSON 風に記述。プロパティ名をダブルクォートで囲わなくてもエラーにならないから JSON ではないかも。
/*eslint eqeqeq:2, curly: 2, quotes: [2, "single"]*/
var arr = [
"a",
'b',
];
if( arr.length == 2 ) {
// test
}
この JavaScript ファイルを適当な場所へ保存して eslint
コマンドでチェックすると定義に基づき以下のエラーが出力されるはず。
$ eslint temp.js
temp.js
4:2 error Strings must use singlequote quotes
5:5 error Unexpected trailing comma comma-dangle
8:15 error Expected '===' and instead saw '==' eqeqeq
✖ 3 problems (3 errors, 0 warnings)
エラー情報は親切でチェックに対応する設定も教えてくれる。ESLint のドキュメントを読んでもピンとこない設定があれば、このように小さなサンプルを作成して試すと理解しやすい。
.eslintrc
ユーザー HOME 直下、またはプロジェクトのディレクトリ直下に .eslintrc
というファイルを作成する。前者はグローバル、後者はプロジェクト限定の設定になる。
ファイル書式は JSON または YAML から選ぶ。YAML は Ansible ぐらいでしか使わないので馴染みなく設定をグローバルに定義するのに抵抗があるため、私は JSON 形式でプロジェクトのディレクトリ直下に定義する方法を採用。
ES6 と React JSX で利用するための設定として .eslintrc
を以下のように定義してみた。
{
"env": {
"browser": true,
"node": true
},
"rules": {
"curly": 2,
"eqeqeq": 2,
"no-multi-spaces": false,
"no-underscore-dangle": false,
"quotes": [2, "single"],
"strict" : false
},
"ecmaFeatures": {
"arrowFunctions": true,
"binaryLiterals": true,
"blockBindings": true,
"classes": true,
"defaultParams": true,
"forOf": true,
"generators": true,
"modules": true,
"objectLiteralComputedProperties": true,
"objectLiteralDuplicateProperties": true,
"objectLiteralShorthandMethods": true,
"objectLiteralShorthandProperties": true,
"octalLiterals": true,
"regexUFlag": true,
"regexYFlag": true,
"superInFunctions": true,
"templateStrings": true,
"unicodeCodePointEscapes": true,
"globalReturn": true,
"jsx": true
}
}
ルールは最小、ES6 関連は現時点のフル機能を利用するようにしてある。それにしても、なぜ ecmaFeatures
に JSX の設定があるのだろうか。Babel もだけど React JSX は ECMAScript 界隈で特別視されている?
余談だが *.jsx
という拡張子は DeNA の JSX や Adobe の ExtendScript でも採用されており、これらも ECMAScript/JavaScript 系なのでややこしい。
package.json
Node モジュールまたは npm を利用するプロジェクトであれば package.json
を用意することになるが、この中に ESLint の設定も定義できる。プロパティ名は eslintConfig
となる。記法は JSON 形式の .eslintrc
と同様。
{
"name": "eslint-sample",
"version": "1.0.0",
"description": "Sample for ESLint.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "akabeko",
"license": "MIT",
"eslintConfig": {
"rules": {
"curly": 2,
"eqeqeq": 2,
"no-multi-spaces": false,
"no-underscore-dangle": false,
"quotes": [2, "single"],
"strict" : false
}
}
}
Web フロントエンドのビルドに gulp などのタスクランナーを利用せず package.json
の scripts
やシェルで完結するスタイルなら、この方法がよさそう。
gulp から利用する
gulp のタスクから ESLint による構文チェックを実行したいなら gulp-eslint を利用。タスク定義は以下のようになる。
/*global
require
*/
/*eslint
"strict": [2, "never"],
"eqeqeq": 2,
"curly": 2,
"quotes": [2, "single"],
"no-mixed-requires": [1, true],
"no-multi-spaces": 0
*/
var gulp = require( 'gulp' );
var $ = require( 'gulp-load-plugins' )();
gulp.task( 'lint', function() {
return gulp.src( './src/js/*.js' )
.pipe( $.eslint() )
.pipe( $.eslint.format() )
.pipe( $.eslint.failOnError() );
} );
せっかくなので gulp タスク自体を ESLint チェックすることを考慮してコメント方式の指定も加えてみた。既に .eslintrc
が設定されているなら、コメントを消してそちらを利用したほうがよい。このタスクを実行するとコマンドライン実行と同様のチェックとエラー出力がおこなわれる。gulp.watch
に組み込んで watchify などと一緒に実行するとよいだろう。
Sublime Text で利用する
テキスト エディターからリアルタイムに ESLint チェックを実行できると便利なので、愛用している Sublime Text から利用できるように設定してみる。事前に ESlint を npm で入れたうえで Sublime Text の Package Control から SublimeLinter と SublimeLinter-contrib-eslint をインストール。
- Installation
- Welcome to SublimeLinter 3 — SublimeLinter 3.4.24 documentation
- roadhump/SublimeLinter-eslint
これだけでチェックが有効になっているはず。適当な JavaScript ファイルを作成してコメントや .eslintrc
による ESLint 設定を試してみよう。
私の環境では .eslintrc
を変更してもプロジェクトを読みなおすか Sublime Text を再起動しないと設定が反映されなかった。bash の source
コマンドみたいにこのファイルだけ明示的に読み直せればよいのだけど、そういう方法があるのか不明。
はじめて ESLint を利用するなら、既存の JavaScript ファイルをいくつか開いて ESLint のエラーがなくなるまでコメントで設定を書き最後にそれを .eslintrc
化するのがオススメ。
ESLint と Sublime Text プラグインを入れてもチェックが実行されない場合は Sublime Text のメニューから Tools → SublimeLinter → Toggle Linter... を選択して eslint
が enable
になっていることを確認する。もし disable
なら eslint
と書かれている部分をクリックすることで enable
に切り替わる。
まとめ
JSHint に比べて設定が非常に多く、値も数値でモード指定するものとフラグ形式が混在しているため初見だと分かりにくく感じる。
しかし pluggable と宣言しているとおり特定の設定を押し付けることなく好きなようにカスタマイズさせる設計は好ましい。私は JSLint がインデントなどの細かな記法までチェックするのが嫌で JSHint に移ったクチなので、より自由な ESLint はかなり気に入った。
また記事冒頭でも書いたとおり React JSX に対応しているのも嬉しい。これまで SublimeLinter だと jshint/jsxhint を併用していたが ESLint へ一本化できてスッキリした。
意外に慣れるので他に強力な競合があらわれない限り、しばらくは ESLint を利用してみようと思う。