LoginSignup
13
0

More than 3 years have passed since last update.

create-react-appをベースにeslint(airbnb)とprettierを導入

Last updated at Posted at 2021-03-17

create-react-appをベースに作っているWebアプリに、途中からeslint-config-airbnbの設定およびコード整形ツールのprettierを入れたくなることがあり、想定以上に苦戦したのでメモ。

なお、便宜上0からセットアップするような形で書いている(検証している)が、ある程度動いているものに導入して移行するようなケースを想定している。

0. 前提条件など

検証環境:

  • Linux(Ubuntu20.04LTS)
  • node 14.16.0
    • npm6.14.11

nodejsまわりのパッケージインストール・管理はyarnではなくnpmを使って行っている。

1. 構築手順

1-1. create-react-app

最新版(執筆時: 4.0.3)ではグローバルインストールが非推奨になった(参考: 公式README)ので、以下のように適当なディレクトリ上にcreate-react-appをインストールする:

mkdir tmp
cd tmp
npm init -y
npm i create-react-app

上記の例ではtmp/にcreate-react-appがインストールされる。

実際にアプリ(gitプロジェクト)を作る場所をtmpの下に作る場合はnpx create-react-app hogeなどのようにすれば良いが、今回は外側に作りたかったので例えば以下のようにする

# create-react-appをインストールしてあるtmpの上のディレクトリへ移動
cd ..

# tmp下の実行ファイルの絶対パスを指定してcreate-react-appを実行
tmp/node_modules/.bin/create-react-app path/to/test-app

上記のようにすると指定したパスにtest-appという名前でreactアプリが作成される:

cd path/to/test-app; tree -a -L 1
# .
# ├── .git
# ├── .gitignore
# ├── README.md
# ├── node_modules
# ├── package-lock.json
# ├── package.json
# ├── public
# └── src

1-2. eslint

上記で作ったtest-appに移動し、eslintの設定を行う。

eslintはデフォルトでcreate-react-appで生成されたアプリ内に含まれているため、そのままnpxで実行出来る。

オススメ設定などはnpx eslint --initで自動的に設定することができ、今回は人気の高そうなairbnb設定を入れてみる

npx eslint --init

# 対話形式で色々聞かれるので、今回は以下のように設定
? How would you like to use ESLint? …
  ▸ To check syntax, find problems, and enforce code style
? What type of modules does your project use? …
  ▸ JavaScript modules (import/export)
? Which framework does your project use? …
  ▸ React
? Does your project use TypeScript?
  ▸ No
? Where does your code run? … (Press <space> to select, <a> to toggle all, <i> to invert selection)
  ✔ Browser
? How would you like to define a style for your project? …
  ▸ Use a popular style guide
? Which style guide do you want to follow? …
  ▸ Airbnb: https://github.com/airbnb/javascript
? What format do you want your config file to be in? …
  ▸ JavaScript
? Would you like to install them now with npm? 
  ▸ Yes # yarnを使う人はNo

これにより、開発用パッケージ(devDependencies)にeslint関係のものがいくつかインストールされ、.eslintrc.jsが生成される。しかし、そのままだと不都合な部分もあるのでここなどを参考に次のように編集しておく:

.eslintrc.js
module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    'plugin:react/recommended',
    'airbnb',
    'react-app', // 手動で追加
    'react-app/jest', // 手動で追加
  ],
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    sourceType: 'module',
  },
  plugins: [
    'react',
  ],
  rules: {
    'react/react-in-jsx-scope': 'off', // 手動で追加: suppress errors for missing 'import React' in files
    'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],     // 手動で追加: allow jsx syntax in js files (for next.js project), should add ".ts" if typescript project
  },
};

↑で"手動で追加"と入れている部分がデフォルトで生成されているものに手を加えた箇所。

extends部分について、実はcreate-react-appにより生成されたpackage.json内にデフォルトでeslintの設定があるため、その部分を移動させたもの。

package.json(抜粋)
...
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
...

上記部分を.eslintrc.jsに移し、package.jsonからは不要(優先順位的に読み込まれない、参考)ので消しておく。

rules部分について、

  • 'react/react-in-jsx-scope': 'off'
    • 例えば分割されて呼び出されるソースコードなどでは必ずしも明示的にimport React from 'react'を行わなくても良い
  • 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }]
    • デフォルトでは拡張子が.jsのファイルでjsxを使うとエラーになるため、それを抑制する
    • create-react-appがデフォルトで作るApp.jsが上記エラーに対象になり、不便なため

ここまでである程度は設定出来ているが、eslintでエラーが出る状況だとnpm run startnpm run buildが通らない:

npm run start

# 以下のようなエラーが出て実行(コンパイル)出来ない

Failed to compile.

src/App.js
  Line 10:16:  `code` must be placed on a new line                          react/jsx-one-expression-per-line
  Line 10:39:  ` and save to reload.        ` must be placed on a new line  react/jsx-one-expression-per-line

src/index.js
  Line 11:34:  Missing trailing comma  comma-dangle

src/reportWebVitals.js
  Line 1:25:  Expected parentheses around arrow function argument  arrow-parens
  Line 3:32:  Expected a line break after this opening brace       object-curly-newline
  Line 3:74:  Expected a line break before this closing brace      object-curly-newline

Search for the keywords to learn more about each error.

厳格にやる場合はこれが正しい挙動だが、既存プロジェクトに途中から導入する、移行するといったケースでは正直かなり不便である。(更にeslintの設定に過不足があるケースも考えられる。)そこで、アプリの実行やビルドは許容するようにしたい。

上記の問題に対しては、developmentおよびproduction用の環境変数を設定して対処する:

今回はnpm run startnpm run build両方を実行出来るようにするため、以下の2つのファイルを作成してプロジェクトのルートディレクトリに配置する:

.env.development
SKIP_PREFLIGHT_CHECK=true
ESLINT_NO_DEV_ERRORS=true
EXTEND_ESLINT=true

(↑開発時のみの設定、EXTEND_ESLINT=trueは不要かも?)

.env.production
DISABLE_ESLINT_PLUGIN=true

(プロダクション用ビルド時のみの設定、eslintのエラーを全無視するので本来良くないが、移行時などでは暫定的にOKとする)

とりあえず以上の設定でeslintの導入をしつつ、実行やビルドは出来るようになった。

1-3. prettier

実際に動かしているアプリなどだと上記まででおびただしい数のerrorが出てくる。いちいち手作業で直すのも面倒だし、コード整形自体はeslintよりもprettierの方が得意そうなので簡単に設定してみる。

まずはprettierと、eslintとの連携ツール(eslint-config-prettier)のインストール:

npm i -D prettier eslint-config-prettier

なお、eslint-plugin-prettierは最近非推奨になったとの話なので入れないでおく。

次に、

などを参考にして必要に応じて.prettierrc.jsなどを用意し、prettier用の設定を作成:

.prettierrc.js
module.exports = {
  printWidth: 80,
  tabWidth: 2,
  singleQuote: true,
  semi: true,
  trailingComma: 'all',
};

次に、prettierを実行しやすいようにpackage.jsonscripts部分に"format": "prettier --write ./src/**/*.{js,jsx}"を入れておく:

package.json(抜粋)
...
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "format": "prettier --write ./src/**/*.{js,jsx}" // 追加
  },
...

これで、

npm run prettier

のように実行することでsrc/以下の*.js, *.jsxの拡張子のファイルがprettierで整形されるようになる。

また、prettierで整形する部分についてはeslintの設定を切るようにすることが出来る(というか、eslintとpretterで競合しないようにするためにあった方が良いらしい)。

これは先程インストールしたeslint-config-prettierを使って行うものであり、今回であれば.eslintrc.jsextends最後prettierを追加すれば良い(※参考):

.eslintrc.js(変更後)
module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    'plugin:react/recommended',
    'airbnb',
    'react-app',
    'react-app/jest',
    'prettier', // 追加
  ],
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    sourceType: 'module',
  },
  plugins: [
    'react',
  ],
  rules: {
    'react/react-in-jsx-scope': 'off',
    'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],
  },
};

これによってeslintの出すエラー・警告からprettierで整形する部分が除外される。

2. まとめ

create-react-appで生成したものに対して、手作業でファイルの編集や追加をいくつかやったので最後に簡単にまとめておく。

上記の手順を実行後のプロジェクトのファイルは以下のような感じ:

tree -a -L 1
.
├── .env.development # 追加
├── .env.production # 追加
├── .eslintrc.js # 追加、変更
├── .git
├── .gitignore
├── .prettierrc.js # 追加
├── README.md
├── node_modules
├── package-lock.json # 変更(但し、自動的に編集されるので意識しない)
├── package.json # 変更
├── public
└── src

各ファイルの変更・追加内容は基本的にこれまでの記述の通り。
但し、package.jsonについてはいきなり最終形のものを置いてnpm iなどを実行すればこれまでの手順のnpm i -D ***などを省くことが出来る。そこで、以下に最終的なpackage.jsonを掲載する:

package.json(最終形)
{
  "name": "test-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.9",
    "@testing-library/react": "^11.2.5",
    "@testing-library/user-event": "^12.8.3",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-scripts": "4.0.3",
    "web-vitals": "^1.1.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "format": "prettier --write ./src/**/*.{js,jsx}"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "eslint": "^7.22.0",
    "eslint-config-airbnb": "^18.2.1",
    "eslint-config-prettier": "^8.1.0",
    "eslint-plugin-import": "^2.22.1",
    "eslint-plugin-jsx-a11y": "^6.4.1",
    "eslint-plugin-react": "^7.22.0",
    "eslint-plugin-react-hooks": "^4.2.0",
    "prettier": "^2.2.1"
  }
}

3. 今後の課題など

  • node-sassによりsassを導入したりcss-moduleを使いつつ、prettierによる整形をcssやscssにも適用したい(stylelintなど?)
  • jsdocの導入
    • ドキュメントのビルド
    • jsdoc部分のフォーマットチェックもlinterで行う
    • eslint-plugin-jsdoc などが使えそう
  • git commitするときに自動でeslint --fixprettier --writeを対象ファイルにかける
  • typescriptを使った場合(create-react-app --template typescript)で同様の設定を出来るようにする
  • create-react-appだけでなく、nextjsやgatsbyなど他のフレームワークでも同様のことが出来ると嬉しい

など

(追記)

eslint --fix

eslint自体にもフォーマット機能があり、例えばpackage.jsonscripts

package.json(抜粋)
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "eslintfmt": "eslint --fix ./src/**/*.{js,jsx}" // 追記
  },

のように追記しておき、

npm run eslintfmt

のようにして実行する事ができる。
修正内容はeslintの設定次第だが、varやletを適切にconstなどに変える、などprettierでは出来ないような修正もやってくれたりする。

ただ、筆者の環境だと行末に余分な空白が入ったり、みたいなことも起こったりする。
設定が悪いだけかもしれないが、単純な整形自体はprettierの方が得意な気がするので、個人的には

  • eslintで修正 → prettierで再整形

のような感じで両方使って整形している。

.prettierignore, .eslintignore

上記の設定だと、src/の下にあるファイル全てがeslint, prettierをかける対象となるが、
自動生成されたjsファイルなど、編集したくないものが対象内になってしまうことがある。
そこで、

を参考に、
.gitignoreのような感覚で.prettierignoreおよび.eslintignoreファイルをプロジェクトのルートディレクトリに配置すれば対象から除外することが出来る。


参考

13
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
0