Class Propertiesを使ったReactコンポーネントをESLintで静的検証

ある程度Babelとか知ってる人向きです。

# 要約

1. Class Property DeclarationsでReactのPropTypes指定が捗る
2. ESLintそのままではClass Property Declarationsに対応してない
3. babel-eslintパーサ使えば解決（ただしestraverse-fbは手動で入れろ）

以上。estraverse-fb周りはそのうち修正されそう。

# Class Property DeclarationsでReactのPropTypes指定が捗る

ES.nextのClass Property Declarationsでクラスにプロパティ生やせるよう提案されている。
それを使えばReactのpropTypes指定が捗るようになる。やったぜ。

```jsx:MyButton.jsx
import React from 'react';

export default class MyButton extends React.Component {
  static propTypes = {
    onClick: React.PropTypes.func.isRequired
  };

  handleClick(){
    this.props.onClick();
  }
  render(){
    return (
      <button onClick={::this.handleClick}>ClickMe!</button>
    );
  }
}
```

使うにはBabelの~~stage-2~~stage-1以上の指定が必要。
（イベントハンドラってbindする必要あったんだっけ…？）

# ESLintそのままではClass Property Declarationsに対応してない

[ESLintは2.3.0からES7に対応した](http://eslint.org/blog/2016/03/eslint-v2.3.0-released)らしい。
ES7(ES2016)で新たに入るのは以下の二つのみ。

* Array.prototype.includes
* Exponentiation Operator(``**``)

仕様は以下から見られる。

* [ECMAScript® 2016 Language Specification](http://tc39.github.io/ecma262/2016/)

ES7が固まった以上、昔ES7 async/awaitなんて言ってたりしたのはもはや誤用なのだが、
Class Property Declarationsが入ると勘違いして試してコケた。
誤用については以下のリンクも参考になる。

* [ES2016の追加機能が決定、あるいはES7言うな問題](http://teppeis.hatenablog.com/entry/2016/01/es2016-feature-freeze)

※指摘をいただいたので上記を修正

```js:.eslintrc
{
  "parserOptions": {
    "ecmaVersion": 7
  },
  "env": {
    "browser": true,
    "es6": true
  },
  "ecmaFeatures": {
    "classes": true,
    "jsx": true
  },
  "plugins": [
    "react"
  ],
  "rules": {
    //...
  }
}
```

```
$ eslint MyButton.jsx
/src/MyButton.jsx
  4:20  error  Parsing error: Unexpected token =
```

／(^o^)＼

# babel-eslintパーサ使えば解決

というわけで、babel-eslintを入れよう。
babelパーサならES.nextの仕様のコードでも読んでくれる。
パーサ自体がbabel用なためか、いろいろオプション抜いても平気で動く。

```
$ npm i -D babel-eslint
```
```js:.eslintrc
{
  "parser": "babel-eslint",
  "env": {
    "browser": true
  },
  "plugins": [
    "react"
  ],
  "rules": {
    //...
  }
}
```

ここで、[estraverse-fbが存在しないと怒られたら手動で入れる](https://github.com/eslint/eslint/issues/5476)。

```
$ npm i -D estraverse-fb
```

estraverse-fbは2.3.0から利用しなくなったESLintの依存モジュールらしい。
babel-eslintがESLintのためにそれを読んでるとかなんとか。
上のリンクでそのうちbabel-eslintが対応すると思うので``-D``は付けてないよ、ってコメントあるけど、
めんどいので``-D``つけたよ。お好みで。

# ビルド環境

実際はeslint直接ぶっ叩いてるわけじゃなくてwebpackのpreLoaderとして使ってる。
現状の趣味プロジェクトのビルド環境晒しとく。多分そのうち変わる。
しかし最近のjs環境って本当にカオスですよねー
~~みんなHaxe使えばいいのに~~

```js:webpack.config.js
const path = require('path');

module.exports = [{
  entry: {
    bundle: './src/entry.jsx'
  },
  resolve: {
    extensions: ['', '.js', '.jsx']
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  module: {
    preLoaders: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'eslint-loader'
      }
    ],
    loaders: [
      {
        test: /\.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.scss$/,
        loaders: ['style-loader', 'css-loader', 'sass-loader']
      },
      {
        test: /\.jade$/,
        loader: 'jade-react-loader'
      }
    ]
  }
}];
```

```json:.eslintrc
{
  "parser": "babel-eslint",
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended"
  ],
  "env": {
    "browser": true
  },
  "plugins": [
    "react"
  ],
  "rules": {
    "indent": [
      "error",
      2
    ],
    "quotes": [
      "error",
      "single"
    ],
    "linebreak-style": [
      "error",
      "unix"
    ],
    "semi": "error",
    "no-unused-vars": "warn",
    "no-console": "warn"
  }
}
```

```json:.babelrc
{
  "presets": ["es2015", "stage-0", "react"]
}
```