ReactReduxを学ぶために、開発環境というかプロジェクトテンプレートをスクラッチから作っている。 (最終的な成果はGitHubに置いた。)

前回はReactをセットアップした。

(2018/11/21更新)

フォーマッタとリンタ

プロジェクトにフォーマッタとリンタを導入する。

フォーマッタはソースの体裁を整えるツール。 フォーマッタを使うことで体裁が統一され、ソースが読みやすくなり、品質向上につながる。

リンタはソースを静的解析して、潜在的なバグ、構造的な問題、体裁の問題を検出して警告してくれるツール。 フォーマッタは体裁だけ整えるのに対し、リンタは論理構造にも制約を課せるので、コーディングスタイルがより統一できたり、ミスをしやすい論理構造が無くなったりして、品質向上につながる。

JavaScriptのような動的型付け言語では、実行時まで顕在化しないバグを作りこみやすく、また実行時エラーの原因解析が静的型付け言語に比べて難しいので、フォーマッタとリンタでプログラム実行前に問題をできるだけ取り除いておくのが重要。 またチーム開発では、コードレビューでコーディンスタイルを見る必要がなくなり、効率化につながる。

Prettier

フォーマッタにはPrettierを使う。

Prettierは2017年1月にリリースされた新しいツール。 構文解析をしてASTを構築し、そこからフォーマット済みコードを出力するので、従来のツールよりも厳密な整形(e.g. 行の最大長を考慮した整形)ができる。

また、opinionated(独断的)であることも特徴で、Prettierプロジェクトが推奨するフォーマットをほぼ強制し、設定がほとんどない。 このため導入が簡単だけど、かゆいところに手が届かないこともある。

JavaScriptの他、JSX、CSS、Markdown、GraphQLのフォーマットにも対応している。


まずプロジェクトにインストールする。

$ yarn add -D prettier

v1.15.2が入った。


設定prettier.config.jsというファイルを書いてプロジェクトルートに置けばいい。

prettier.config.js:

module.exports = {
  printWidth: 100, // 行の最大長
  tabWidth: 2, // インデント長
  singleQuote: true, // 文字列をシングルクオートで囲う
  trailingComma: 'all', // オブジェクトのプロパティとか関数の引数を複数行で書いたときに、全行の末尾にカンマをつける
};


また、フォーマット対象外のファイルを指定するファイルである.prettierignoreをプロジェクトルートに置く。

.prettierignore:

node_modules/
dist/

node_modulesはnpmパッケージが入るディレクトリ。 実際はnode_modulesはデフォルトで無視されるから書かなくていいんだけど。

prettier-ignoreコメントを書くことで、ソースを部分的にフォーマット対象外とすることもできる。


最後に、npmスクリプトを書く。

package.json:

 (前略)
   "scripts": {
+    "format": "prettier --write **/*.jsx **/*.js **/*.css",
     "build": "webpack --config webpack.prod.js",
     "start": "webpack-dev-server --hot --config webpack.dev.js"
   },
 (後略)

これで、yarn formatを実行するとプロジェクト内ソースを一通りフォーマットできる。

ESLint

リンタにはデファクトスタンダードのESLintを使う。

ESLintは2013年6月にリリースされたそこそこ歴史のあるツール。 リンティングルールがプラガブルで、豊富なルールを細かく制御できるのが特徴。 フォーマッタとしての機能もあるけど、そこはPrettierにまかせることにする。

JavaScriptもJSXもリンティングできる。

リンティングルールはAirbnbによるeslint-config-airbnbが有名なのでこれを使う。


ESLintを導入するために、以下のパッケージをプロジェクトにインストールする。

  • eslint: ESLint本体。
  • eslint-loader: webpackからESLintを実行するやつ。
  • eslint-config-airbnb: ESLintルール設定集。
  • eslint-plugin-import: eslint-config-airbnbのピア依存。import文を処理するためのESLintプラグイン。
  • eslint-plugin-jsx-a11y: eslint-config-airbnbのピア依存。JSXを処理するためのESLintプラグイン。
  • eslint-plugin-react: eslint-config-airbnbのピア依存。React特有のリンティングルールを追加するESLintプラグイン。
  • eslint-config-prettier: Prettierが施すコード整形とコンフリクトするルールを無効にするESLintルール設定集。

ピア依存をインストールするのにはちょっとコツがいるので、eslint-config-airbnbのドキュメントを参照すべし。

今回は以下のコマンドでインストールした。

$ yarn add -D "eslint@>=1.6.0 <5.0.0" eslint-loader eslint-config-airbnb "eslint-plugin-import@^2.12.0" "eslint-plugin-jsx-a11y@^6.0.3" "eslint-plugin-react@^7.9.1" eslint-config-prettier

ESlintはv4.19.1が入った。


ESlintの設定は、設定ファイルである.eslintrc.jsをプロジェクトルートに置けばいい。

.eslintrc.js:

module.exports = {
  env: {
    browser: true,
  },
  extends: ['airbnb', 'prettier'],
};

アプリの実行環境はブラウザなのでenv.browserをtrueにしている。 これにより、ブラウザ環境でデフォルトで使えるグローバル変数(e.g. document)を使うときにESLintに怒られないようになる。

extendseslint-config-airbnbeslint-config-prettierのルール設定を取り込むように書いている。 prettierが最後でなければいけないことに注意。


また、リンティング対象外のファイルを指定するファイルをプロジェクトルートに置く。

.eslintignore:

node_modules/*
dist/*

node_modulesはnpmパッケージが入るディレクトリ。 実際はnode_modulesはデフォルトで無視されるから書かなくていいんだけど。

eslint-disableコメントを書くことで、ソースを部分的にリンティング対象外としたり、特定のルールを無効化することもできる。


webpackからESLintを実行し、エラーがなくならない限りビルド成功できないようにする。

webpack.common.js:

 (前略)
   module: {
     rules: [
+      {
+        test: /\.(js|jsx)$/,
+        include: [path.resolve(__dirname, 'src')],
+        enforce: 'pre',
+        loader: 'eslint-loader',
+        options: {
+          configFile: './.eslintrc.js',
+          failOnError: true,
+        },
       },
       {
         test: /\.(js|jsx)$/,
         include: [path.resolve(__dirname, 'src')],
         loader: 'babel-loader',
       },
     ],
   },
 (後略)


あとはnpmスクリプト書くだけ。

package.json:

 (前略)
   "scripts": {
     "format": "prettier --write **/*.jsx **/*.js **/*.css",
+    "lint": "eslint **/*.jsx **/*.js",
     "build": "webpack --config webpack.prod.js",
     "start": "webpack-dev-server --hot --config webpack.dev.js"
   },
 (後略)

これで、yarn lintを実行するとプロジェクト内ソースを一通りリンティングできる。


以上で、フォーマッタとリンタを導入できた。

次回はCSS周りの処理系を追加する。