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

  • 14
    いいね
  • 2
    コメント
この記事は最終更新日から1年以上が経過しています。

ある程度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指定が捗るようになる。やったぜ。

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-2stage-1以上の指定が必要。
(イベントハンドラってbindする必要あったんだっけ…?)

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

ESLintは2.3.0からES7に対応したらしい。
ES7(ES2016)で新たに入るのは以下の二つのみ。

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

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

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

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

.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
.eslintrc
{
  "parser": "babel-eslint",
  "env": {
    "browser": true
  },
  "plugins": [
    "react"
  ],
  "rules": {
    //...
  }
}

ここで、estraverse-fbが存在しないと怒られたら手動で入れる

$ npm i -D estraverse-fb

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

ビルド環境

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

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'
      }
    ]
  }
}];
.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"
  }
}
.babelrc
{
  "presets": ["es2015", "stage-0", "react"]
}