🔧

ESLintとPrettierの設定をドキュメントを丹念に見ながらやる(2022年2月時点)

2022/02/11に公開

(2022/2/17 更にドキュメントを詳しく参照するように加筆と、一部コマンドを修正しました✍)

ESLintとPrettierの設定、皆さんどうされていますか?🤔

私は結構雰囲気でググった記事を参考にやっていました。
ですが、いろんなところで言及されているところですが、ESLintとPrettier周りは過去推奨だったものが現在非推奨になっていたりと、移り変わりがあります。
今では非推奨になっているプラグインを用いている過去記事などあり、それをあたっている方もいらっしゃるかもしれません。
各々その時々ドキュメントを参照するのがベストですが、今回は、2022年2月現在、最新のドキュメントを丹念に見ながらESLintとPrettierの設定をしてみます。

おまけとして、husky+lint-stagedとeslint-plugin-importの設定もしていきます。

ESLintの設定から

まず設定するのに、今回適当なViteのTypeScriptプロジェクトを用意しました。

コマンドでプロジェクトを作成していきましょう。

yarn create vite my-eslint-prettier-husky --template vanilla-ts

git initしてここでinitial commitしておきます。
こちらのドキュメントを参考にやっていきます。

https://eslint.org/docs/user-guide/getting-started

yarn add eslint --devします。簡単に始めたかったら、対話式のyarn create @eslint/configしてねと書かれているので、そちらを試してみます。

聞かれた全文と私の回答は下記になります。

(訳)どのように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? … 
❯ JavaScript modules (import/export)
  CommonJS (require/exports)
  None of these

(訳)使用しているフレームワークは?
? Which framework does your project use? … 
  React
  Vue.js
❯ None of these

(訳)TypeScriptは使っているか?
? Does your project use TypeScript?  No / › Yes

(訳)コードはどこで走らせるか?
? 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 a popular style guide
    Answer questions about your style

(訳)どのスタイルガイドにするか?
? Which style guide do you want to follow? … 
  Airbnb: https://github.com/airbnb/javascript
  Standard: https://github.com/standard/standard
❯ Google: https://github.com/google/eslint-config-google
  XO: https://github.com/xojs/eslint-config-xo

(訳)設定ファイルの拡張子は?
? What format do you want your config file to be in? … 
❯ JavaScript
  YAML
  JSON

@typescript-eslint/eslint-plugin@latest eslint-config-google@latest @typescript-eslint/parser@latest
(訳)これらのパッケージを今npm installするか?
? Would you like to install them now with npm? › No / Yes

最後のは、yarnでインストールしたかったのでスキップしました。なので

yarn add @typescript-eslint/eslint-plugin@latest eslint-config-google@latest @typescript-eslint/parser@latest --dev

します。

出来上がった.eslintrc.jsが下記になります。

.eslintrc.js
module.exports = {
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": [
        "google"
    ],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
    "plugins": [
        "@typescript-eslint"
    ],
    "rules": {
    }
}

yarn eslint src/main.tsでLintのチェックを走らせてみます。

/Users/ユーザー名/products/my-eslint-prettier-husky/src/main.ts
  1:21  error  Missing semicolon  semi
  3:60  error  Missing semicolon  semi
  8:2   error  Missing semicolon  semi

✖ 3 problems (3 errors, 0 warnings)
  3 errors and 0 warnings potentially fixable with the `--fix` option.

Googleのスタイルではセミコロンはありになっているようです。

https://github.com/google/eslint-config-google

ここでyarn eslint src/main.ts --fixを走らせると警告のあった箇所が修正されファイルにセミコロンが追加されます。
私はセミコロンなしのプロジェクトにすることが多いので、セミコロンなし設定を追加します。

.eslintrc.js
    ...
    "rules": {
        "semi": ["off", "always"],
    }
    ...

Get Startedページにある通り、rulesは、下記のように設定できます。
"off" or 0 - turn the rule off ルールをオフにする
"warn" or 1 - turn the rule on as a warning (doesn't affect exit code) 警告を出す(コードは終了しない)
"error" or 2 - turn the rule on as an error (exit code will be 1) エラーを出す(コードを1で終了する)

配列の二番目のオプション(上記で言えばalways)や、どのようなルールがあるかは下記から参照していってください。

https://eslint.org/docs/rules/

distを出しておきたいので、一旦ここでyarn buildします。

distをESLintからignoreしたいので、.eslintignoreファイルを作り、下記を設定します。

dist/**/*.js

node_modulesは予めignoreされているようなので安心ですね。

In addition to any patterns in the .eslintignore file, ESLint always follows a couple of implicit ignore rules even if the --no-ignore flag is passed. The implicit rules are as follows:

  • node_modules/ is ignored.
  • dot-files (except for .eslintrc.*), as well as dot-folders and their contents, are ignored.

https://eslint.org/docs/user-guide/configuring/ignoring-code#the-eslintignore-file

さて、この段階で思った。—fixでフォーマットできるならPrettierは不要なのではないか?(素人)

Prettier公式に答えがあります。
https://prettier.io/docs/en/comparison.html

PrettierはFormatting rulesを助けてくれるが、Code-quality rulesについては何もしません、とあります。

In other words, use Prettier for formatting and linters for catching bugs!

言い換えれば、フォーマットにはPrettierを使用し、バグをキャッチするにはリンターを使用してください。とのことです。

上記ドキュメントで例として挙げられているもので言えば、
Formatting rules
max-len コードの1行の文字数の制限
no-mixed-spaces-and-tabs スペースとタブが混合していないか
keyword-spacing if文などのスペースの調整
comma-style カンマのスタイル

Code-quality rules
no-unused-vars 未使用の変数の警告
no-extra-bind 不要なbindの警告
no-implicit-globals グローバルスコープでの宣言の警告
prefer-promise-reject-errors Promiseのrejectにエラーオブジェクトオブジェクト必須の警告

と、内容を見てみると2つの性質の違いがわかってきました。

ここからPrettierを入れていきます。

Prettierの設定

下記参考にやっていきます。

https://prettier.io/docs/en/install.html

yarn add --dev --exact prettier
echo {}> .prettierrc.json
touch .prettierignore
.prettierignoreにdistを記述

Prettierもnode_modulesは予めignoreされています。

Prettier CLI will ignore files located in node_modules directory. To opt out from this behavior, use --with-node-modules flag.

https://prettier.io/docs/en/cli.html

下記部分を読むと、eslint-config-prettierをインストールして、ESLintとPrettierが互いにうまく機能するようにします、とあります。こちらを設定すると、Prettierと競合する可能性のあるESLintルールをオフにしてくれます。

https://prettier.io/docs/en/install.html#eslint-and-other-linters

こちらにLinterと併用する場合のドキュメントがあります。

https://prettier.io/docs/en/integrating-with-linters.html

eslint-config-prettierのドキュメントを見ながらやっていきます。

https://github.com/prettier/eslint-config-prettier

yarn add eslint-config-prettier --devします。

必ず他の設定を上書きするよう、"prettier""extends"の最後にしてねとありますのでそのようにします。

Then, add "prettier" to the "extends" array in your .eslintrc.* file. Make sure to put it last, so it gets the chance to override other configs.

{
  "extends": [
    "some-other-config-you-use",
    "prettier"
  ]
}

yarn prettier --write .してみます。
セミコロンがつく、ダブルクオーテーションになるという修正がなされたので、差分が出ないよう.prettierrc.jsonに下記記述を入れます。

.prettierrc.json
{
  "semi": false,
  "singleQuote": true
}

ここまででPrettierの設定はおしまいです。
ここからおまけでhuskyとeslint-plugin-importの設定をしていきます。

おまけ:huskyとeslint-plugin-importの設定

下記を見ながらhuskyの設定をします。

https://prettier.io/docs/en/install.html#git-hooks

huskyとlint-stagedを組み合わせると、コミット時にコマンドを実行することが出来ます。
こちらでコミット時にESLintとPrettierを走らせていきます。

yarn add --dev husky lint-staged
npx husky install
npm set-script prepare "husky install" // これいま上手く行かないかも。エラー吐いたので私は手動でpackage.jsonのscripts”にprepare": "husky install”を追加しました。
npx husky add .husky/pre-commit "npx lint-staged"

.lintstagedrc.jsonに拡張子ごとに走ってほしいコマンドを設定します。

{
  "*.ts": "eslint --fix",
  "*.{ts,json,md}": "prettier --write"
}

私はlint-stagedのコマンドがVSCodeのGUIのみyarnやnpxがnot foundのエラーになってしまうこともあったのですが、下記記事(古い記事ですが)のパスを通すのをホームディレクトリの.huskyrcでおこなったところ解消されました。

https://zenn.dev/nishinama/articles/e1095e7f2e50726c5319

huskyが動作しているかどうか見てみましょう(長い文とダブルクオーテーション)

import './style.css'

const app = document.querySelector<HTMLDivElement>('#app')!

const longLongMessage = "長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ"

app.innerHTML = `
  <h1>Hello Vite!</h1>
  <p>${longLongMessage}</p>
  <a href="https://vitejs.dev/guide/features.html" target="_blank">Documentation</a>
`

↓コミットしたところ、フォーマットされました。

import './style.css'

const app = document.querySelector<HTMLDivElement>('#app')!

const longLongMessage =
  '長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ長い長いメッセージだよ'

app.innerHTML = `
  <h1>Hello Vite!</h1>
  <p>${longLongMessage}</p>
  <a href="https://vitejs.dev/guide/features.html" target="_blank">Documentation</a>
`

今度はeslint-plugin-importの設定をしていきます。
いままで参加させていただいたプロジェクトで、importのorderをプラグインで並べ替えていたことがあったので再現してみたくなりました。

こちらのプラグインを使用することになります。
https://github.com/import-js/eslint-plugin-import

TypeScriptでは、@typescript-eslint/parsereslint-import-resolver-typescriptを準備してくれよなと書いてあるので入っていない場合はインストールしておきます。

デフォルトではルールはオフになっている模様なので、設定していきます。

All rules are off by default. However, you may configure them manually in your .eslintrc.(yml|json|js), or extend one of the canned configs:

.eslintrc.js
  ...
  plugins: ['@typescript-eslint', 'import'], // import追加
  rules: {
    semi: ['off', 'always'],
    "import/order": [2, {"alphabetize": { "order": "asc" }}], // 追加
  },
  ...

設定については下記にドキュメントがあります。

https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/order.md

こちらで下記のように書いたimportが

import { testB } from './test-modules/test-b'
import { testA } from './test-modules/test-a'

下記のようにコミット時並べ替えられるようになりました。

import { testA } from './test-modules/test-a'
import { testB } from './test-modules/test-b'

これにて設定は一旦終了です!
特に見どころはないですが、ここまでの作業は下記リポジトリにあります。

https://github.com/hiroko-ino/my-eslint-prettier-husky

最後に

最近は一次情報に当たる、ドキュメントを検索しまくって情報を掘り当てるというのにハマっていますが、この記事も普段ゴリゴリにESLintとPrettierを使っている人にとっては当たり前の記事だったかもしれません。
今回ほぼドキュメントの内容を掘っているだけですしね。
でも、ESLintとPrettierについて、ドキュメントベースの記事がもっとあってもいいのではないかと思っていたので、書いてみました。
何か不備ありましたらご指摘いただけると喜びます!

Discussion