LoginSignup
187
150

More than 3 years have passed since last update.

ESLint - Prettier連携のやり方と仕組み

Last updated at Posted at 2018-12-16

メモ代わりに関係ない情報も色々含めた。

これまでのあらすじ

ESLint is 何

JSのLinter。めっちゃカスタマイズできる。
eslint --fixコマンドでフォーマットもできる。

Prettier is 何

JSのフォーマッター。eslint --fixよりも強いらしい。
具体例で言うと、「1行80字超えのコードを適切に改行してくれる」らしい。
やたらこの例を推してくる。他の例を知りたい。

Prettier only ダメ is なぜ

フォーマットしかできない

Linterのルールには2種類ある。

  1. フォーマットに関するルール
  2. コードの品質に関するルール

「後者はLinterの仕事。Prettier、ソウイウノ、ヤラナイ。」的なことが公式で案内されている。

カスタマイズ性に乏しい

ESLintほど充実していない。
よりカスタマイズできる版を提供しようっていうフォークプロジェクトがあるぐらい。
応援したい。でも開発止まってるっぽい。

Why don't you ESLintとPrettierを併用?

Yes, I am.

併用 is どうやる

prettierをかましてからeslint --fixをかます。

Code ➡️ prettier ➡️ eslint --fix ➡️ Formatted Code ✨
prettier/prettier-eslint

公式リポジトリにそういうプロジェクトがあるぐらいなので、アリっぽい。
個人的にはそれで良いのか感がすごい。
Prettier流のフォーマットがどれだけ上書きされてるのか知りたい。
やはりPrettierの優位な点をリストアップした資料とかが欲しい。
「80字超え対処」しか強みがないならこれで良いと思う。

ESlintをカスタマイズしてPrettierと連携させる。

prettier/eslint-config-prettier
prettier/eslint-plugin-prettier
この辺を組み込む。すると、eslint --fixをした時にprettier準拠でフォーマットがされることになる。
以下、この辺の仕組みの解説。

※ 2020/12/27 追記
(コメントにて @masato_makino さんから指摘頂いた内容。)
prettierリポジトリにあるドキュメントが2020年6月頃に更新され、「eslint-plugin-prettierは非推奨。まあ特定の状況では便利かもね。」みたいなことが書かれるようになった。

以下、このドキュメントから読み取ったことを雑に羅列。

  • リンターを使わなくてもprettier --check .があるよ。
  • 昔はprettier用のエディタプラグインがなくて、リンター向けのプラグインを使うしかなかったから、しょうがなくリンター経由でprettierしてたかもしれないけど、今時はどのエディタもprettier用のプラグインがあるからその必要はないよ。
  • リンター経由だとエディタ上で赤線出まくったりしてだるいぞ。
  • 直接prettierした方が速いぞ。
  • 間接的なレイヤーを1個挟むことによって、何か余計なバグが生まれるリスクがあるぞ。
  • prettierのフォーマットに気に入らない部分がある?じゃあprettier-eslintでprettier後のコードをeslint --fixして帳尻合わせてくれ。まあ重いけどね。

ということなので、eslint-plugin-prettierを使うより直接prettierコマンドを叩く方が推奨らしい。なお、eslint-config-prettierの使用は問題ない。
以下、その辺を考慮しながら必要な情報だけ取捨選択してもらいたい。
(追記終)

本題

ESLintの設定について

概要

ソース内コメントや設定ファイルによって色々カスタマイズできる。
設定ファイルは、package.json内にeslintConfigフィールドを設けて記述するパターンと、.eslintrc.{js|json|yaml}ファイルを作るパターンがある。

設定の優先順位

高い順に

  1. コメント
  2. CLIコマンドのオプション
  3. 設定ファイル
    • .eslintrc.*を置いたフォルダの子フォルダに更に.eslintrc.*を置いたりできる。
      • チェックするjsファイルについて、近い階層に置いてある.eslintrc.*の設定ほど優先して採用される。
      • .eslintrc.*内でroot: trueを指定すると、それより親フォルダの.eslintc.*は無視される。
    • .eslintrc.*eslintConfigを記載したpackage.jsonの両方が同じ階層にある場合、eslintConfigは無視される。

上記のどれか1つしか採用されないわけではなく全部採用される。競合する設定について優先順位が考慮されるイメージ。
オブジェクト指向的にいえば、設定をどんどんオーバーライドしていってる感じ。

また、ホームディレクトリに.eslintrc.*があるとフォールバックとして働く。
上記の3つが全部無かった時のみここの設定が反映される。

設定できることの一例:ルールのON/OFF

eslintrc.js
module.exports = {
    "rules": {
        // ==を使おうが===を使おうが気にしない。
        "eqeqeq": "off",
        // if文などで{}を略したらwarning。
        "curly": "warn",
        // ダブルクォートを使う。シングルクォートを使ってたらLinterエラー。
        "quotes": ["error", "double"],
        // セミコロンは必須。無かったらLinterエラー。
        "semi": ["error", "always"]
    }
}

他には、環境(ECMAいくつか、nodeかbrowserか、jQuery使ってるか、etc...)、グローバル変数の設定など。

設定の共有

eslint-config-*という名前でnpmモジュールとして設定を共有できる。

例えば、eslint-config-standardは以下の記述で取り込むことができる。

eslintrc.json
{
    "extends": "standard"
}

ただし、記述するだけでなくnpmで自分で落としてこないといけない。
ESLintを入れた場所がプロジェクトローカルならプロジェクトローカルに、グローバルならグローバルに。同じレベルに落とさないと使えない。

複数の設定を取り込むこともできる。

eslintrc.json
{
    "extends": [
        "eslint:recommended",
        "standard"
    ]
}

後のやつが前の設定をどんどんオーバーライドしていく。
取り込んだ後、更に自分でrulesとか設定しだすのもオーバーライドになる。

設定のプラグイン

eslint-plugin-*という名前でnpmモジュールとしてプラグインを作成できる。
ルールを増やしたりできる。共有設定を含めることもできる。

例えば、eslint-plugin-reactは以下の記述で取り込むことができる。

eslintrc.json
{
    "plugins": ["react"]
}

プラグイン内のルールは以下のように指定する。

eslintrc.json
{
    "plugins": ["react"],
    "rules": {
        "react/no-set-state": "error"
    }
}

プラグイン内の共有設定は以下のように取り込む。

eslintrc.json
{
    "plugins": ["react"],
    "extends": ["plugin:react/recommended"]
}

Prettier連携

方針

eslint --fixの仕様についてはちゃんと調べていないが、おそらく「ルール」の中には「どう直すか」も含まれている。
ということは、ESLintの組み込みルールを全部無効にし、Prettierのプラグインルールに差し替えまくればいいことになる。

上の方で、ルールには2種類あると書いた。

  1. フォーマットに関するルール
  2. コードの品質に関するルール

Prettierの担当範囲は前者である。
なので、前者に関するESLintの組み込みルールを全部オフにする。

eslint-config-prettierの使い方

共有設定prettierを取り込むことで、Prettierと競合しそうなESLintの組み込みルールを全部OFFにしてくれる。
reactプラグインの分をOFFにする共有設定prettier/react等、細かい追加分もある。

eslint-plugin-prettierの使い方

これを取り込むことで、Prettierのルールが代わりに追加される。されるのだが...。
なんと、

eslintrc.json
{
    "plugins": ["prettier"],
    "rules": {
       "prettier/prettier": "error"
    }
}

prettierというルール1つしか追加されない。
Prettierが扱う全ルールが、この1つにまとめられている。

つまり、ルール毎にON/OFFを細かく設定できない。
全部offか、全部warningか、全部errorかしかない。

しかし、全くカスタマイズが効かないというわけではない。
例えば、ESLint組み込みのindentルールは、ルールのON/OFFだけでなくインデント幅のルールも設定できる。

eslintrc.js
module.exports = {
    "rules": {
        // インデント幅が2でなければLinterエラー。
        "indent": ["error", 2]
    }
}

同じノリで、prettierルールもオブジェクトを使って色々ルールを設定できる

eslintrc.js
module.exports = {
    "plugins": ["prettier"],
    "rules": {
        // シングルクォートを使う。セミコロンは無し。
        "prettier/prettier": ["error", {"singleQuote": true, "semi": false}]
    }
}

無理やり感がすごい。
ちなみに.prettierrcってファイルで設定する方法もあるらしい。

なお、このプラグインには共有設定recommendedも含まれている。

eslintrc.json
{
    "extends": ["plugin:prettier/recommended"]
}

上記により、下記と同じ効果が得られる。

eslintrc.json
{
    "extends": ["prettier"],
    "plugins": ["prettier"],
    "rules": {
        "prettier/prettier": "error"
    }
}

逆にいうとそれだけ。

手順まとめ

shell.sh
npm install --save-dev eslint
npm install --save-dev eslint-config-prettier
npm install --save-dev eslint-plugin-prettier
npm install --save-dev prettier

Prettier本体は雰囲気で入れてるけど、本当に必要なのかは未検証。

eslintrc.js
module.exports = {
    "extends": ["prettier"],
    "plugins": ["prettier"],
    "rules": {
        "prettier/prettier": [
            "error",
            {
                // 各種設定
            }
        ]
    }
}

他に取り込みたい共有設定があれば、prettierより前にextendする。(prettierでルールOFFにする方が優先順位が高いので。)

愚痴

JavaScript Standard Styleに合わせたいのだが、PrettierにspaceBeforeFunctionParenオプション(関数名と引数名の間にスペースを空ける。ex. function name (arg) { ... })が無いため合わせられない。

  • フォークプロジェクト頑張ってほしい。
  • というか普通にPrettierがカスタマイズ性上げてほしい。
  • というかStandard Styleはこの仕様だけマイナーなのでやめてほしい。
  • というかセミコロン無しのStyleでもっと良いの出てきてほしい。
187
150
4

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
187
150