アカベコマイリ

HEAR NOTHING SEE NOTHING SAY NOTHING

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.jsonscripts やシェルで完結するスタイルなら、この方法がよさそう。

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 から SublimeLinterSublimeLinter-contrib-eslint をインストール。

これだけでチェックが有効になっているはず。適当な JavaScript ファイルを作成してコメントや .eslintrc による ESLint 設定を試してみよう。

私の環境では .eslintrc を変更してもプロジェクトを読みなおすか Sublime Text を再起動しないと設定が反映されなかった。bash の source コマンドみたいにこのファイルだけ明示的に読み直せればよいのだけど、そういう方法があるのか不明。

はじめて ESLint を利用するなら、既存の JavaScript ファイルをいくつか開いて ESLint のエラーがなくなるまでコメントで設定を書き最後にそれを .eslintrc 化するのがオススメ。

ESLint と Sublime Text プラグインを入れてもチェックが実行されない場合は Sublime Text のメニューから Tools → SublimeLinter → Toggle Linter... を選択して eslintenable になっていることを確認する。もし disable なら eslint と書かれている部分をクリックすることで enable に切り替わる。

まとめ

JSHint に比べて設定が非常に多く、値も数値でモード指定するものとフラグ形式が混在しているため初見だと分かりにくく感じる。

しかし pluggable と宣言しているとおり特定の設定を押し付けることなく好きなようにカスタマイズさせる設計は好ましい。私は JSLint がインデントなどの細かな記法までチェックするのが嫌で JSHint に移ったクチなので、より自由な ESLint はかなり気に入った。

また記事冒頭でも書いたとおり React JSX に対応しているのも嬉しい。これまで SublimeLinter だと jshint/jsxhint を併用していたが ESLint へ一本化できてスッキリした。

意外に慣れるので他に強力な競合があらわれない限り、しばらくは ESLint を利用してみようと思う。