create-react-appで作成した雛形 + VSCodeにESLintとPrettierを導入する

前回、DockerでReact + Swagger 環境を作ろうという記事を書いたのですが、VSCodeにESLint導入時に少し手間取ったので別記事にしました。
あわせてコード整形ツールであるPrettierも導入したので、その手順を書いておきます。

※この記事はQiitaからの転載です。

ESLint #

静的解析ツールです。
コーディングする上でのルールを決められるので、チーム開発するうえでコードのスタイルを統一することができます。

導入 #

手順 #

1.パッケージ
create-react-appで作成された雛形では、すでにESLintに関するパッケージが導入されており、yarn.lockでreact-scriptsの依存関係となっているのを確認することができます。

以下はcreate-react-app@3.4.0の例です。

※一部抜粋
react-scripts@3.4.0:
  version "3.4.0"
  resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-3.4.0.tgz#f413680f0b5b937c8879ba1ffdae9b8c5b364bf5"
  integrity sha512-pBqaAroFoHnFAkuX+uSK9Th1uEh2GYdGY2IG1I9/7HmuEf+ls3lLCk1p2GFYRSrLMz6ieQR/SyN6TLIGK3hKRg==
  dependencies:
    "@babel/core" "7.8.4"
    "@svgr/webpack" "4.3.3"
    "@typescript-eslint/eslint-plugin" "^2.10.0"
    "@typescript-eslint/parser" "^2.10.0"
    babel-eslint "10.0.3"
    babel-jest "^24.9.0"
    babel-loader "8.0.6"
    babel-plugin-named-asset-import "^0.3.6"
    babel-preset-react-app "^9.1.1"
    camelcase "^5.3.1"
    case-sensitive-paths-webpack-plugin "2.3.0"
    css-loader "3.4.2"
    dotenv "8.2.0"
    dotenv-expand "5.1.0"
    eslint "^6.6.0"
    eslint-config-react-app "^5.2.0"
    eslint-loader "3.0.3"
    eslint-plugin-flowtype "4.6.0"
    eslint-plugin-import "2.20.0"
    eslint-plugin-jsx-a11y "6.2.3"
    eslint-plugin-react "7.18.0"
    eslint-plugin-react-hooks "^1.6.1"
    file-loader "4.3.0"
    fs-extra "^8.1.0"
    html-webpack-plugin "4.0.0-beta.11"
    identity-obj-proxy "3.0.0"
    jest "24.9.0"
    jest-environment-jsdom-fourteen "1.0.1"
    jest-resolve "24.9.0"
    jest-watch-typeahead "0.4.2"
    mini-css-extract-plugin "0.9.0"
    optimize-css-assets-webpack-plugin "5.0.3"
    pnp-webpack-plugin "1.6.0"
    postcss-flexbugs-fixes "4.1.0"
    postcss-loader "3.0.0"
    postcss-normalize "8.0.1"
    postcss-preset-env "6.7.0"
    postcss-safe-parser "4.0.1"
    react-app-polyfill "^1.0.6"
    react-dev-utils "^10.2.0"
    resolve "1.15.0"
    resolve-url-loader "3.1.1"
    sass-loader "8.0.2"
    semver "6.3.0"
    style-loader "0.23.1"
    terser-webpack-plugin "2.3.4"
    ts-pnp "1.1.5"
    url-loader "2.3.0"
    webpack "4.41.5"
    webpack-dev-server "3.10.2"
    webpack-manifest-plugin "2.2.0"
    workbox-webpack-plugin "4.3.1"
  optionalDependencies:
    fsevents "2.1.2"

2.設定
設定に関してはpackge.jsonに記述があり、デフォルトではこの設定でESLintが動作します。

※一部抜粋
"eslintConfig": {
    "extends": "react-app"
  },

3.VSCodeに導入
拡張機能:ESLintをインストールして再起動

Error対応 #

基本的には上記手順だけで動作するはずなのですが、自分の場合以下のエラーが表示されて動作してくれませんでした。

[Error - 16:37:59] 
Failed to load plugin 'import' declared in 'app\package.json » eslint-config-react-app': Cannot find module 'eslint-plugin-import'

調べたところ、VSCodeのESLint拡張は、ワークスペースに追加したフォルダの直下に設定ファイル(.eslintrc.js、package.jsonなど)がある前提で動作するとのこと。

直下にない場合はフォルダの設定ファイルにパスを指定してあげればいいそうです。
(※2019/12/31追記 設定ファイル名をsettings.jsonに修正しました。すみません。)

  1. ファイル→基本設定→設定を開く

  2. フォルダーで該当のフォルダを選択

  3. eslintで設定の検索

  4. ESLint: Working Directoriesの個所からsettings.jsonで編集を選択

  5. settings.jsonに以下を追記

※例(app直下に設定ファイルがある場合)
{
  "eslint.workingDirectories": [
	"./app"
  ]
}

Warning対応 #

エラー対応して動作するようにはなったのですが、以下のようなWarningが出ました。

Warning: React version was set to "detect" in eslint-plugin-react settings, but the "react" package is not installed. Assuming latest React version for linting.

eslint-plugin-reactパッケージでプロジェクトのReactのバージョンを指定しているのですが、デフォルトがdetectとなっており、自動でバージョンを検知するようになっている模様。

自分の場合、Dockerの中にNode.js環境を作り、ローカルにはNode.jsがなかったためか、うまく検知ができなかったようです。

ESLintの設定に、明示的にバージョンを指定することで出なくなりました。

以下はpackage.jsonの例

※一部抜粋
  "eslintConfig": {
    "extends": "react-app",
    "settings": {  ←以下追加
      "react": {
        "version": "16.11"
      }
    }
  },

設定のカスタマイズ #

設定ファイルについて #

package.jsonのeslintConfigキーでも設定が書けますが、別ファイル(.eslintrc.jsなど)に切り出すことができます。
package.jsonと.eslintrc両方が存在する場合は、後者の方が優先されました。

設定の記述方式は公式を参照してください。
ESLint - Configuring ESLint

最初は$ yarn ejectをしないと、設定がカスタマイズできないかと思っていましたが、ESLintの場合は必ずしも行う必要はないようです。
追加でパッケージが必要になる場合は、yarnでインストールして、それを使用するように設定を記述すれば、ちゃんと動作してくれました。

Airbnbのルールを使用する例

1.パッケージをインストール

$ yarn add -D eslint-config-airbnb

2.設定にルールを追記
以下はpackage.jsonの例

※一部抜粋
"eslintConfig": {
    "extends": [
      "react-app",
      "airbnb" ←追記
    ],
    "settings": {
      "react": {
        "version": "16.11"
      }
    }
  },

ウィザードで設定ファイルを作成して使用 #

いくつかの質問に回答する形で、その回答内容に応じた設定ファイルを作成することができます。
はじめはこれで作成して、後から細かなカスタマイズをするとお手軽に導入できます。

ESLintの設定作成

$ ./node_modules/.bin/eslint --init

ESLintをどのように使用しますか?

? How would you like to use ESLint?
  To check syntax only
  To check syntax and find problems
❯ To check syntax, find problems, and enforce code style 

どんなモジュールを使用していますか?

? What type of modules does your project use? (Use arrow keys)
❯ JavaScript modules (import/export)
  CommonJS (require/exports)
  None of these

どのフレームワークを使用していますか?

? Which framework does your project use? (Use arrow keys)
❯ React
  Vue.js
  None of these

TypeScriptは使用していますか?

? Does your project use TypeScript? (y/N) N

コードはどこで実行されますか?

? Where does your code run? (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◉ Browser
 ◯ Node

プロジェクトのスタイルをどのように定義しますか?

? How would you like to define a style for your project? (Use arrow keys)
❯ Use a popular style guide
  Answer questions about your style
  Inspect your JavaScript file(s)

どのスタイルガイドをフォローしますか?

? Which style guide do you want to follow? (Use arrow keys)
❯ Airbnb (https://github.com/airbnb/javascript)
  Standard (https://github.com/standard/standard)
  Google (https://github.com/google/eslint-config-google)

設定ファイルのフォーマットはどれにしますか?

? What format do you want your config file to be in? (Use arrow keys)
❯ JavaScript
  YAML
  JSON

npmでこれらのパッケージをインストールしますか?
(yarnでインストールしたい場合はnを選択して、案内されたパッケージをコピペして手動でインストールする必要があるみたいです)

Checking peerDependencies of eslint-config-airbnb@latest
Local ESLint installation not found.
The config that you've selected requires the following dependencies:

eslint-plugin-react@^7.14.3 eslint-config-airbnb@latest eslint@^5.16.0 || ^6.1.0 eslint-plugin-import@^2.18.2 eslint-plugin-jsx-a11y@^6.2.3 eslint-plugin-react-hooks@^1.7.0
? Would you like to install them now with npm? (Y/n)

既存の設定ファイルを使用 #

$ ./node_modules/.bin/eslint --initせずに別プロジェクトなどで使用している設定ファイルをコピーしてきて使用することも、もちろん可能です。

一度、テンプレートとなる設定を自分で持っておくと流用できて楽です。

Prettier #

コード整形ツールです。
ESLintと連携させて動作させることができるので、あわせて導入しておくとコードの品質向上に繋がります。

react-scriptsのパッケージ依存関係にPrettierに関するものはないので、追加でインストールしていく必要があります。

コマンドラインとしてESLint連携 #

1.yarnで必要パッケージをインストール

$ yarn add -D prettier prettier-eslint prettier-eslint-cli

2.package.jsonにformatコマンドを追記

※一部抜粋
"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "format": "prettier-eslint --write 'src/**/*.js'" ←追加
  },

これで以下のコマンドで実行することができます。
prettier-eslintを利用することで、Prettierで整形されたコードがESLintに渡されて、ESLintで整形されます。

$ yarn format

VSCode上でESLint連携 #

1.yarnで必要なパッケージをインストール

$ yarn add -D eslint-config-prettier eslint-plugin-prettier

2.ESLintの設定にPrettierのルールを追加
以下はpackage.jsonでの例

※一部抜粋
"eslintConfig": {
    "extends": [
      "react-app",
      "plugin:prettier/recommended" ←追加
    ],
    "settings": {
      "react": {
        "version": "16.11"
      }
    }
  },

この一文を追加するだけで以下と同じ効果が得られるそうです。

"eslintConfig": {
    "extends": ["prettier"],
    "plugins": ["prettier"],
    "rules": {
        "prettier/prettier": "error"
    }
  },

これでESLintとPrettier両方のルールでコードをチェックしてくれるようになります。
ESLintとPrettier連携の仕組みについては以下の記事が参考になります。
ESLint - Prettier連携のやり方と仕組み

設定のカスタマイズ #

設定ファイル #

package.jsonのprettierキーでも設定が書けますが、別ファイル(.prettierrc.jsなど)に切り出すことができます。
package.jsonと.prettierrc両方が存在する場合は、前者の方が優先されました。

設定の記述方式は公式を参照してください。
Prettier - Configuration File

ファイル保存時に自動整形 #

ここらへんはお好みで。

フォルダの設定ファイル(settings.json)に以下を追記。

{
  "eslint.workingDirectories": [
	"./app"
  ],
  "editor.formatOnSave": false, ←追記
  "eslint.autoFixOnSave": true, ←追記
}

editor.formatOnSaveはtrueにすると、自動整形が衝突するそうなのでfalseにしています。
eslint.autoFixOnSaveをtrueにすることで、ファイル保存時に自動整形が動作してくれます。

※2019/12/21追記
ESLint拡張のバージョンがv2になり、eslint.autoFixOnSaveは廃止されたそうです。代わりにeditor.codeActionsOnSaveを使うようにしましょう。
変更された設定方法については以下の記事で解説されています。
vscode-eslint v2

{
  "eslint.workingDirectories": [
	"./app"
  ],
  "editor.formatOnSave": false,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
}

参考リンクまとめ #