FlatConfig移行時に知っておくとよいかもしれないこと

2025/02/14に公開

はじめに

こんにちは。
2024年はESLint v8がEOLになったり、Next.jsがESLint v9をサポートしたりで設定ファイルをFlat Config形式に移行した方が多いかもしれません。

私自身、業務でそれなりに大きいプロジェクト2つで移行を経験しました。
今回はそこで得た知見をまだ移行していない方向けに書き連ねてみようと思います。

知っておくとよいかもしれないこと

移行ツールを使う

初手は移行ツールで移してしまうのがオススメです。
公式ドキュメントにある通り、ESLintが移行ツールを提供しています。

こちらはFlatCompatを使って、ざっくりと移行できるツールになっています。
.eslintrc.jsでは上手く動作しないケースがあるようですが、とりあえずこれで移行しておくとコマンドを実行できる状態は担保できます。

npx  @eslint/migrate-config .eslintrc.json 

エディタの設定を変更する

vscodeを利用されている方は.vscode/settings.jsonからeslint.useFlatConfigを有効化しましょう。
移行作業中はLegacy Configと行ったり来たりということがよくあるので、プロジェクトフォルダにローカル設定として追加するのがオススメです。
これを忘れるとエディタ上にエラーが表示されなくなりますので、最初のうちに変更してしまいましょう。

typescript-eslintを使用する

typescript向けの設定でよく@typescript-eslint/parser@typescript-eslint/eslint-pluginが開発パッケージに含まれています。

あまりシビア出ない方はtypescript-eslintのパッケージにまとめてしまうことをお勧めします。

typescript-eslintで利用できるconfig関数を使うことで、設定を型補完がある状態で記載できます。

このconfig関数は単に型を提供するだけでなく、以下の機能を提供します。

  1. extends
    extendsを利用することで、設定をある程度まとめることが可能となります。

    // extendsを利用した書き方
    export default tseslint.config({
      files: ['**/*.ts'],
      extends: [
        eslint.configs.recommended,
        tseslint.configs.recommended,
      ],
      rules: {
        '@typescript-eslint/array-type': 'error',
        '@typescript-eslint/consistent-type-imports': 'error',
      },
    });
    
    // ↓と同じ
    export default tseslint.config(
      eslint.configs.recommended,
      tseslint.configs.recommended,
      {
         files: ['**/*.ts'],
         rules: {
           '@typescript-eslint/array-type': 'error',
           '@typescript-eslint/consistent-type-imports': 'error',
         },
       }
    )
    
  2. 内部で配列をフラットにしてくれる
    Flat Configではtseslint.configs.recommendedのように配列の設定を利用する場合、スプレッド構文を利用する必要があります。
    これは利用する設定により異なりますが、mjsで記述する場合、どれが配列でどれがオブジェクトなのかがかなりわかりにくいです。
    このヘルパー関数は内部で配列を展開してくれるため、利用者側がツール側の設定の構造を意識せずに設定することが可能となります。

    // ヘルパー関数を利用しない
    export default [
      eslint.configs.recommended,
      ...tseslint.configs.recommended,
      {
        /*... */
      },
      // ...
    ];
    
    // ヘルパー関数を利用する
    export default tseslint.config(
      eslint.configs.recommended,
      tseslint.configs.recommended,
      {
        /*... */
      },
      // ...
    );
    

設定ファイル用のtsconfigを作成する

typescript用の設定でparserOptions.projectに既存のtsconfig.jsonを指定していると画像のようなエラーが表示されるケースがあります。
これは対象のファイルがtsconfig.jsonincludesに含まれていないことが原因です。

parse project error

エラー内容の通りですが、解決方法としては以下のような選択肢があります。

  • ESLintの対象ファイルからこのファイルを外す
  • tsconfig.jsonincludesに設定ファイルを追加する
  • 新しく設定ファイルを含める設定をしたtsconfig.xxx.jsonを作成し、それをparserOptions.projectに指定する

個人的には一番最後のtsconfig.xxx.jsonを作成する方法がオススメです。
この方法にしておくとあまり考えることなく追加でき、tscの実行時は含めないということが可能になります。
設定の例は以下の通りです。

tsconfig.eslint.json
{
  "extends": ["./tsconfig.json"],
  "compilerOptions": {
    "allowJs": true
  },
  "include": ["**/*.ts", "eslint.config.mjs"]
}
export default tseslint.config({
 // ...
 languageOptions: {
  parserOptions: {
    projectService: "tsconfig.eslint.json",  // 新規作成したtsconfigを指定
  },
},
});

nameプロパティを指定する

各オブジェクトレベルの設定にnameを指定できます。
一番の理由はeslint/config-inspectorで確認する際にわかりやすいという理由です。
しかしながらconfig-inspectorを使わない場合でもこの設定は何の設定なのかの認識コストが下がるのでオススメです。

export default [
  {
    name: "project/ignore",
    /*... */
  },
  {
    name: "project/xxx",
    /*... */
  },
  {
    name: "project/yyy",
    /*... */
  },
];

プラグインを自作する

以前の設定では自作のルール・プラグインの導入にeslint-plugin-local-ruleseslint-plugin-rulesdirといった追加のプラグインが必要でした。
しかしながら、Flat Configではこれらは必要ありません。ローカルルールやプラグインは他のjsファイル同様にimport, requireで使用できます。

eslint/rules/yyy.mjs
/** @type {import('eslint').Rule.RuleModule} */
const rule = {
  meta: {/*... */},
  create: () => {/*... */}
}

export default rule;
eslint/eslint-plugin-xxx.mjs
import yyyRule from "./rules/yyy.mjs"

/** @type {import('eslint').ESLint.Plugin} */
const plugin = {
  meta: {
    name: "eslint-plugin-xxx"
  },
  rules: {
    yyy: yyyRule,
    // ...
  },
  configs: {/*... */},
}

export default plugin;
eslint.config.mjs
import xxxPlugin from "./eslint/eslint-plugin-xxx.mjs"

export default tseslint.config({
  name: "project/root"
  plugin: {
    xxx: xxxPlugin
    // ...
  },
  rules: {
    "xxx/yyy": "error"
    // ...
  }
});

eslintのcliを直接使用する

これはnext lintを使用している方向けです。
v15.1.7時点でnext lintはESLint v9での追加オプションに対応していません。
例えば、Gitフックでステージ上のファイルに対して実行する際に、指定したファイルがignoresに含まれていると警告が出ます。
ESLint v9のcliでは--no-warn-ignoredというオプションにより無効化できますが、next lintでは未サポートです。

利用されるプロジェクトによっては同じようなケースがあるかと思いますので、サポートされるまでは直接ESLintのcliを実行することも手段として持っておくとよいです。

まとめ

今回はFlat Config移行へのTipsをまとめてみました。
ありきたりではありますが、知っていたり気を付けたりすることで設定を移行しながら改善できることは多いです。
何かしら皆さんのお役に立てれば幸いです。

Discussion