ESLintとPrettierを役割で分ける

技術ネタ
この記事は約8分で読めます。

お久しぶりです、hisayukiです。

年始に今年は月1は書くぞ!!って意気込んだところから半年経ちました・・・
時間の流れは早いですね😂

さて、今回は後日書きますと謳っておいて半年放置したこちらの記事の続きを書いていこうと思います。

スポンサーリンク

前回の振り返り

半年も前に書いたことなので一度振り返ります。
詳細についてはこちらの記事に記載してますので割愛します。

ESLint

  • ESLintの役割はLinter(コードの構文チェック)
  • 基本はJavaScriptやTypeScriptのファイル形式に対して行う。
  • 構文エラーやコーディング規約を定義してコードの一貫性を保つことが出来る。

Prettier

  • Prettierの役割はFormatter(コードの整形)
  • ファイル形式はJavaScriptやTypeScriptに限らずJSONやMarkdown、CSSに対しても行う
  • 構文エラーやコーディング規約を定義してコードの一貫性を保つことが出来る。

ESLintPrettierもそれぞれの役割があるのですが、その役割が曖昧になってしまう時代背景がありました。
ですが、現状は各役割で分けて使うことをPrettier公式としては推奨してます。

Prettier vs. Linters · Prettier
## How does it compare to ESLint/TSLint/stylelint, etc.?

ここまでが前回の振り返りです。
では、昨今のベストプラクティスはどのような使い方なのかを書いていきたいと思います。

ベストプラクティス

あくまで個人的なものではあります。

ESLintの責務はLinter(主にJS、TSファイル系に限る)、Prettierの責務はFormatter(JS、TSファイルに加えてJSONやtext、Markdownなども含む)

この2つの責務を出来る限り分離する事だと思います。

ESLintからPrettierを動かすことを止める

前回のブログで書きましたが、ESLintとPrettierには以下の時代背景がありました。

  • Prettierが以前はESLintから動かすことを推奨していた
  • ESLintがコードフォーマットも出来てしまう

現状はどちらも非推奨となっています。

Prettierが以前はESLintから動かすことを推奨していた

Prettierにはeslint-plugin-prettierというPluginがあります。
これを使うことでESLintのコマンドと同時にPrettierを実行することができました。

当時はエディタがPrettierに対応していないものが多く、ESLintには対応しているものがあったためESLint経由で使ってもらうために作られました。

現状はPrettierに対応しているエディタも多くネイティブで使うことが出来るため、敢えてESLint経由で使う必要がなくなりました。

The downsides of those plugins are:

・You end up with a lot of red squiggly lines in your editor, which gets annoying. Prettier is supposed to make you forget about formatting – and not be in your face about it!
・They are slower than running Prettier directly.
・They’re yet one layer of indirection where things may break.

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

むしろ、ESLint経由で使うことで以下のデメリットがあります。

  • Linterとしての警告にFormat対象も含まれてしまうため、意図してない警告が増える。
  • ESLint経由で動かすことで、ワンステップ増えてしまい処理が遅くなる
  • ESLintからPrettierを動かすためのレイヤーを1つ挟むため、意図しない挙動をするかもしれない

Prettierが直接利用できるようになった今、

ESLintから実行させるのってデメリットです。

ESLintから実行すればeslintコマンドだけで実行できるから楽と思われるかもですが、package.jsonにnpm scriptでeslint ~~ --fix & prettier ~~ --writeと書けば同時実行は出来るのであまりメリットにもならないですね。

というわけでeslint-plugin-prettierpackage.jsonから削除しましょう。

ESLintがコードフォーマットも出来てしまう

やめさせましょう

Integrating with Linters · Prettier
Linters usually contain not only code quality rules, but also stylistic rules. Most stylistic rules are unnecessary when using Prettier, but worse – they might ...

Luckily it’s easy to turn off rules that conflict or are unnecessary with Prettier, by using these pre-made configs:

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

ESLint側のPluginでeslint-config-prettierというPluginがあります。
これを使うことで、Prettierで設定できるFormat設定をESLintの設定では全てOffに出来ます。

Offになるルールはこちら

eslint-config-prettierのGithubにも書いてありますが、”prettier”は最後に書くようにしましょう。

extends:
  # prettier以外の拡張
  - some-other-config-you-use
  # prettierの追加
  - prettier

理由はextendsは先に書かれた拡張設定を後に書かれた拡張設定が上書きします。
そのため、今回のeslint-config-prettierの設定を最後に上書きするためです。

これでESLint側のFormatを全て無効にすることで、FormatをESLintの責務から外します。
次はFormatの設定はPrettierに書いていきます。

コードの整形はPrettierが全て行う

ESLint側からFormatの責務を外したので、Prettier側にFormatの責務をもたせます。
(ここに書いたのは一例です、他にも追加したい場合はこちらをみてください。)

#  Prettierの設定ファイル 
# 折り返す行の長さ (.editorconfig:max_line_lengthでoverride可能)
printWidth: 80
# インデントごとのスペース数 (.editorconfig:indent_sizeでoverride可能)
tabWidth: 2
# スペースの代わりにタブを利用するか (.editorconfig:indent_styleでoverride可能)
useTabs: false
# 末尾セミコロンの有無
semi: false
# ダブルクォートの代わりにシングルクォート
singleQuote: true
# 必要な場合(間に'-'が入っていたり)オブジェクトのプロパティー名をQuoteで囲む
quoteProps: 'as-needed'
# jsxの場合にダブルクォートの代わりにシングルクォート
jsxSingleQuote: true
# 末尾コンマをなくす (https://prettier.io/docs/en/options.html#trailing-commas)
trailingComma: 'none'
# オブジェクトリテラルの角かっこの間のスペース
bracketSpacing: true
# jsxでhtmlを記述する際にタグの終わり「>」を同じ行に記述する
jsxBracketSameLine: true
# アロー関数の引数(avoid: 可能な限り括弧を省く)
arrowParens: 'avoid'
# @formatのコメントがあるコードのみフォーマットする
requirePragma: false

あとはpackage.jsonにscriptとして、lintとformatを別で設定します

  "scripts": {
    "lint": "eslint --ext .ts,.tsx ./src/* ",
    "lint:fix": "eslint --ext .ts,.tsx --fix ./src/* ",
    "format": "prettier --check --ignore-unknown \"./**/*.{html,ts,tsx,css,md,json}\" ",
    "format:fix": "prettier --write --ignore-unknown \"./**/*.{html,ts,tsx,css,md,json}\" ",
  },

これでlintとformatを分離することができました。

完璧を求めるのは無理

これでESLintとPrettierがやるべきことは一応分けれましたがまだまだ穴はいくつもあります。

eslint-config-prettierを使ったとしても、ruluに書きこんだらruluが優先されちゃったりもしますし、ESLint側はPlugin豊富なのでPrettierが対応していない整形も出来たりします。

Prettierが後発というのもあるのですが、ESLintが多機能すぎるというのもあります。
またESLintは主にJS、TS系のファイルを対象、Prettierはテキストファイル全般を対象に見てるので、どうしても専門的な整形はESLint側で書くこともあります。
(一例としてはTypescriptのimport文の並び替えとか)

どこまで行っても完璧に責務分離をすることは難しいです。

なのでLinterとFormatterの分離と言うよりは、ESLintからPrettierの責務分離をした感じになります。
引き続きESLintで--fixをする機会はあると思います。

まとめ

久々に書いたので内容ぐちゃっとしてるかもです😂
今回伝えたいことは、lintとformatの責務を出来るだけ分けましょうということでした!
でも完璧は無理だよということも追加でお伝えしたかったです。

今回のベストプラクティスもあくまで僕個人の考え方なので、プロジェクトなどによって考え方や方針も変わると思いますので、ご参考程度にみて頂けたらと思います。

コメント