解決したいこと
フロントエンドをAngular、バックエンドをNestJSで開発します。規模が小さいので一つのソースリポジトリで管理します。リポジトリ内ではESLintの設定とPrettierの設定を統一したいです。
結論
eslintrc.json
とprettierrc.json
はルートパッケージで管理するのがよさそうでした。フロントエンドとバックエンドで異なる設定を定義するには、overrides
キーを使います。
ESLintの設定を共通化する方法
ESLintの設定を共通化する方法はいくつかあります。この記事では3つの方法を紹介します。 結論で書いた内容は、方法3で説明します。
方法1. ルートパッケージとサブパッケージにそれぞれ設定ファイルを配置する
ESLintはLint対象のファイルからファイルパスを遡ってESLintの設定ファイルを探し、複数の設定ファイルが見つかったら設定をマージします。同じキーの設定内容はLint対象のファイルに近いディレクトリの設定内容が優先されます。root: true
と定義された設定ファイルを見つけたら、それ以上設定ファイルを探索しません。この仕様を利用し、以下のように設定ファイルを定義します。
. +-- eslintrc.js (root: true) +-- backend/ | `-- eslintrc.js (root: false) `-- frontend/ `-- eslintrc.js (root: false)
パッケージ固有の設定をサブパッケージで定義して、共通の設定をルートパッケージで定義します。サブパッケージの設定ファイルにroot: false
と定義すれば、サブパッケージの設定ファイルとルートパッケージの設定ファイルの両方を参照してLintを実行してくれます。
方法2. ルートパッケージの設定をサブパッケージで拡張する
方法1ではESLintがLint対象のファイルパスを遡って設定ファイルを探索するのに任せていました。方法2では、以下のようにサブパッケージでルートパッケージの設定を拡張するように明示します。
modules.exports = { "root": true, "extends": [ "../.eslintrc.js" ] }
サブパッケージでルートパッケージの設定を拡張するように明示しているので、サブパッケージの設定にもroot: true
と書けます。方法1より冗長ですが、明示的で分かりやすいと感じました。
方法3. ルートパッケージの設定にディレクトリごとの設定を記述する
方法1と方法2では、共通の設定とサブパッケージ固有の設定をそれぞれの別のファイルに定義しました。方法3では、共通の設定とサブパッケージ固有の設定をともにルートパッケージにの設定ファイルに定義します。
modules.exports = { "overrides": [ { "files": "backend/**/*.ts", "exntends": [ "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended" ] }, { "files": "frontend/**/*.ts", "extends": [ "plugin:@angular-eslint/recommended", "plugin:@angular-eslint/template/process-inline-templates", "plugin:prettier/recommended" ] }, { "files": "frontend/**/*.html", "extends": [ "plugin:@angular-eslint/template/recommended" ] } ] }
設定が一つのファイルにまとまって管理しやすくなりました。複数のファイルに設定が分かれていると無秩序な設定上書きが不安になります。
フレームワーク固有のESLintプラグインをルートパッケージでインストールしたり、1ファイルの設定内容が多くなったりするので、好みは分かれそうです。
まとめ
わたしのケースでは以下の背景から方法3を選択しました。
- プロジェクトの規模がとても小さいこと
- バックエンドとフロントエンドの2つしかサブパッケージがないこと
- Linterの設定を緩いルールに上書きしてほしくないこと
ESLintの設定を共通化する方法はいくつか用意されているので、場合によって最適と思われる方法を選択すると良いと思います。