ESLint Flat Configの深淵:プラグイン競合を「構造的」に解決するアーキテクトの視点
多くのチームがESLintの「Flat Config (`eslint.config.js`)」への移行で躓くのは、単なる構文の変化ではありません。「設定の継承という名のブラックボックス」が崩壊し、プラグインの読み込み順序や型定義の衝突が、これまで以上に露骨に表面化するようになったからです。
本稿では、複雑化した大規模プロジェクトにおいて、ESLint内部で何が起きているのかを可視化し、一瞬でボトルネックを特定するための「アーキテクト流デバッグ術」を伝授します。
—
1. なぜFlat Configで「循環参照」や「競合」が起きるのか
旧来の `.eslintrc` では、`extends` がマージ戦略を隠蔽してくれていました。しかし、Flat Configは「ただの配列」です。配列の要素として定義されたプラグインが、同じAST(抽象構文木)ノードに対して異なるルールを適用しようとした際、誰が優先権を持つのかは「配列のインデックス」に依存します。
特にTypeScriptの型情報が必要な `parserOptions.project` を伴うプラグイン(`@typescript-eslint`等)が複数存在する場合、「型情報の計算コストの重複」と「名前空間の衝突」が、ESLintのモジュール解決プロセスを著しく遅延させます。
—
2. 内部挙動を可視化する「インスペクション・テクニック」
「どのルールがどこで上書きされているか」を調べるために、闇雲に `eslint.config.js` を書き換えてはいけません。以下のデバッグ手法を武器にしてください。
A. `–print-config` による解決済み設定のダンプ
最も確実なのは、ESLintが最終的に生成した「解決済みコンフィグ」を標準出力に書き出すことです。
特定のファイルに対する最終的な設定構成をjsonで出力する
npx eslint –print-config src/components/Button.tsx > resolved-config.json
この出力された `resolved-config.json` を眺めると、`rules` オブジェクトの末尾に、意図せず他のプラグインを破壊しているルールが必ず見つかります。
B. DEBUG環境変数によるモジュール解決の追跡
ESLintがどのプラグインをどのパスからロードしているかを知ることで、循環参照やバージョン不整合を特定できます。
ESLintの内部解決プロセスを全て標準エラーに出力する
DEBUG=eslint: npx eslint src/main.ts
ここで出力されるログの「Plugin load: …」を追うと、「本来読み込まれるべきはずのプラグインが、別のプラグインの依存関係として、古いバージョンで再ロードされている」瞬間を特定できます。これが、多くの「謎の型エラー」の正体です。
—
3. 実践:チーム開発を加速させる「疎結合」な構成例
プラグインの競合を防ぐための鉄則は、「責務の分離」と「プラグインの明示的登録」です。以下の構成は、大規模プロジェクトで私が採用しているベストプラクティスです。
import tsEslint from ‘@typescript-eslint/eslint-plugin’;
import reactHooks from ‘eslint-plugin-react-hooks’;
export default [
// 1. 基盤ルール:全ファイルに適用(競合のリスクを最小化)
{
ignores: [“/dist/“, “/node_modules/“]
},
// 2. TS専用設定:型情報を扱う場合は独立させる
{
files: [“/.{ts,tsx}”],
plugins: {
“@typescript-eslint”: tsEslint
},
rules: {
…tsEslint.configs.recommended.rules,
“@typescript-eslint/no-explicit-any”: “error”
}
},
// 3. チーム固有のルールオーバーライド(最優先)
{
files: [“/.{ts,tsx}”],
rules: {
// プラグイン間で競合する可能性があるルールはここで明示的に上書き
“indent”: [“error”, 2],
“react-hooks/rules-of-hooks”: “error”
}
}
];
—
4. 生産性を極限まで高める「神ツール」と隠し技
絶対に入れるべき「神プラグイン」
- `eslint-plugin-perfectionist`: インポート文やオブジェクトのキーを自動ソートします。人間がソート順で悩む時間は無駄です。CIでこれを強制することで、コードレビューのノイズを完全に除去します。
開発効率を最大化するキーボードショートカット (VS Code)
- `Ctrl + Shift + P` -> `ESLint: Restart ESLint Server`:
設定を変更した際、再起動を待つのは時間の浪費です。このショートカットを `Alt + E` 等にカスタムキーバインドしておき、設定変更後は必ず叩く習慣をつけます。
- `Ctrl + .` (Quick Fix):
「修正をすべてのファイルに適用」を選択することで、一括リファクタリングをIDEの裏側で完結させます。
—
5. アーキテクトからの提言:設定の「共有化」ルール
大規模プロジェクトでは、`eslint.config.js` をモノリスにしてはいけません。
1. Config Factory パターン: 設定を関数化し、`getTsConfig(options)`, `getReactConfig(options)` のようにモジュール分割してください。
2. 型安全性の確保: `eslint.config.js` を `eslint.config.ts` に変更し、`Linter.FlatConfig` 型を適用します。これにより、設定ミスをランタイムではなくコンパイルタイムで排除できます。
「なぜそのルールが必要か?」をコメントで明記できないルールは、プロジェクトから削除すべきです。静的解析は、開発者の思考を制限するためではなく、「開発者が重要な意思決定に集中するために、些末な議論を自動化する」ために存在します。
この深淵を理解した貴方なら、もはやESLintの挙動に振り回されることはありません。設定ファイルは、プロジェクトの規律そのものです。美しく、論理的に構築してください。