eslint-plugin-prettier を ESLint から 分離するサンプル – Intellij IDEA の設定変更も

エディタでPrettierを実行できるようになり、ESLint と Prettier は個別に設定・適用することが推奨されています。
2020.12.11

すでにこちらの方の解説ブログもありますが、ESLint と Prettier を組み合わせる場合の推奨方法が変わりました。

Prettier と ESLint の組み合わせの公式推奨が変わり plugin が不要になった

本稿では リポジトリに適用してみて Before/After を具体的に見ていきます。

TL;DR

エディタが ESLint にも Prettier にも対応しているならば ESLint から eslint-plugin-prettier を除外し、ESLint と Prettier が個別に実行されるようにする。

コンテンツ

  • 推奨がどう変わったか
  • どこをどう変更すればよいか
  • Intellij IDEA / WebStorm の場合、どの設定を変更すればよいか

推奨がどう変わったか

Prettier はもともと ESLint のプラグインとしても使うことができました。多くのエディタが eslint --fix をサポートしていることから、長らく eslint --fix のついでに整形も行うような形がとられていました。しかし、VSCode や JetBrains が Prettier を個別に実行できるようになり、

  • ESLint のような静的解析ツールの自動修正機能
  • コードフォーマッタである Prettier

これらを個別で実行するようにしてほしい、と変わったようです。Linterとの統合について述べている、こちらのドキュメントを見ます。

Integrating with Linters · Prettier

Prettier vs. Linters · Prettier

意訳すると以下のようなメッセージだと解釈しています。

  • 静的解析ツールである ESLint と、コードフォーマッタである Prettier は本来分けて考えるべきもの
  • ただ、Prettier が出たばかりのときは、エディタが Prettier に対応しておらず、ESLint のプラグインとしてフォーマットを実行できることには意味があった
  • Prettier に対応しているエディタも増えてきた。以下のような理由もあるので Linterのプラグインとしてではなく、Prettier 単体で実行してほしい:
    • 静的解析ツールのプラグインとしてフォーマッタを当てると、エディターに赤い波線がたくさん表示され、煩わしくなる
    • Prettierを直接実行するよりも遅い
    • 不整合が起きる可能性がある

どこをどう変更すればよいか

大きく、

  • eslint.rc.js から eslint-plugin-prettier を除去する
  • package.json のスクリプトで eslint --fix 相当のことをやっていた箇所で eslint --fix && prettier --write に変更する

これらを変更します。

実際に分離した例

TypeScript のバリデータライブラリで試しました。差分のプルリクエストはこちらです。説明用のサンプルとして使います。

fix formatter by cm-wada-yusuke · Pull Request #6 · cm-madlabs/ts-validator

eslint.rc.js から eslint-plugin-prettier を除去する

.eslintrc.js

module.exports = {
    env: {
        node: true,
    },
    parser: '@typescript-eslint/parser',
    plugins: ['node', '@typescript-eslint'],
    parserOptions: {
        sourceType: 'module',
    },
    rules: {
        semi: 'off',
        '@typescript-eslint/semi': ['error'],

        // `export` functions may be listed first.
        '@typescript-eslint/no-use-before-define': [
            'error',
            { functions: true, classes: false, variables: true },
        ],

        // To read environment variables.
        '@typescript-eslint/no-non-null-assertion': 'off',

        // Disable the eslint side because it conflicts with the prettier.
        '@typescript-eslint/indent': 'off',

        // Parameter functions return type is obvious and need not to be explicit.
        '@typescript-eslint/explicit-function-return-type': [
            'error',
            {
                allowExpressions: true,
                allowTypedFunctionExpressions: true,
                allowHigherOrderFunctions: true,
            },
        ],
    },
    extends: [
        'eslint:recommended',
        'plugin:@typescript-eslint/eslint-recommended',
        'plugin:@typescript-eslint/recommended',
        'plugin:prettier/recommended', // 消す
        'prettier', // 追加する
    ],
};

これで eslint --fix では prettier が走らないようになります。

'prettier' は必要?

必要だと思います。たいていの場合、 eslint-plugin-prettier とは別に、ESLint で Prettier と競合するルールを無視するための eslint-config-prettier もインストールされているはずです。競合の回避は必要なので、 ESLintで有効にするため prettier に書き換えます。これで、競合を回避するための設定だけが引き続き ESLint で利用できます。

package.json を修正する

package.json

{
  "name": "@cm-madlabs/ts-validator",
  "version": "1.0.3",
  "description": "true/false generic validator",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "author": "waddy",
  "license": "MIT",
  "private": false,
  "publishConfig": {
    "access": "public"
  },
  "keywords": [
    "TypeScript",
    "Validator"
  ],
  "bugs": {
    "url": "https://github.com/team-mad/ts-validator/issues"
  },
  "homepage": "https://github.com/team-mad/ts-validator#typescript-validator",
  "scripts": {
    "build": "tsc -p tsconfig.json",
    "build:doc": "typedoc",
    "test": "jest",
    "test:coverage": "yarn jest --coverage",
    "lint": "eslint './{lib,src,test}/**/*.{ts,tsx}'",
    "lint-fix": "eslint --fix './{lib,src,test}/**/*.{ts,tsx}' && prettier --write './{lib,src,test}/**/*.{ts,tsx}'",
    "lint-staged": "lint-staged",
    "clean": "shx rm -rf ./dist && shx rm -rf './{src}/**/*.js' && shx rm -rf './{src}/**/*.d.ts'"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.ts": [
      "yarn run lint-fix",
      "yarn run lint",
      "git add"
    ]
  },
  "dependencies": {
    "luxon": "^1.25.0"
  },
  "devDependencies": {
    "@types/luxon": "^1.25.0",
    "@typescript-eslint/eslint-plugin": "^4.4.1",
    "@typescript-eslint/parser": "^4.4.1",
    "codecov": "^3.8.0",
    "eslint": "^7.11.0",
    "eslint-config-prettier": "^6.12.0",
    "eslint-plugin-node": "^11.1.0",
    "husky": "^4.3.0",
    "jest": "^26.5.3",
    "jest-coverage-badges": "^1.1.2",
    "lint-staged": "^10.4.0",
    "prettier": "^2.1.2",
    "shx": "^0.3.2",
    "ts-jest": "^26.4.1",
    "ts-node": "^9.0.0",
    "typedoc": "^0.19.2",
    "typescript": "^4.0.3"
  }
}
  • eslint --fix './{lib,src,test}/**/*.{ts,tsx}' && prettier --write './{lib,src,test}/**/*.{ts,tsx}' のように、どちらも明示的に修正が走るようにします
  • dependencies から eslint-plugin-prettier を消します
  • eslint-config-prettier消しません

yarn lint-fix の結果は変えずに、ESLint と Prettier を分離できました。

Intgllij IDEA で prettier フォーマッタが走るようにする

最後はエディタの設定です。これまでは、Intellijで eslint --fix 相当の自動フォーマットを走らせれば Prettier も動作させることができました。

before.png

追加して、Prettier も走らせられるようにします。

prettier.png

これでフォーマット時に Prettier による整形も実行できます。完全に余談ですが私は「フォーマット」と「保存」は明確に分けて実行したいので保存時にフォーマットする設定は無効にしています。作業を中断する場合など、あえて文法エラーを残して保存しコンテキストを維持する…といった目的です。

まとめ

エディタでPrettierを実行できるようになり、ESLint と Prettier は個別に設定・適用することが推奨されています。本稿がどなたかの参考になれば幸いです。

ソースコード

fix formatter by cm-wada-yusuke · Pull Request #6 · cm-madlabs/ts-validator