📝

忙しい人のためのESLint Flat Configの設定例(主要なプラグイン込み)

2025/02/20に公開

前書き

v9からFlat Configという新しい記法がデフォルトとなったeslintですが、
v10からeslintrcの機構が無くなるようです。

https://eslint.org/blog/2023/10/flat-config-rollout-plans/#eslintrc-removed-in-eslint-v10.0.0

先んじてFlat Config化に取り組みまして、その際の設定の最終系を記します。

前提

  • ここでの記載は以下の技術スタック向けに書かれています。
    • TypeScript
    • React
    • Next.js
    • ※他のプラグインでも応用可能かと思います。
  • eslint及び関連プラグインは、執筆時点(2025/02/20)での最新バージョンとします。
{
  "@eslint/compat": "^1.2.6",
  "@eslint/js": "^9.20.0",
  "@next/eslint-plugin-next": "^15.1.7",
  "@typescript-eslint/parser": "^8.24.1",
  "eslint": "9.20.1",
  "eslint-config-next": "15.1.7",
  "eslint-config-prettier": "^8.10.0",
  "eslint-import-resolver-typescript": "^3.7.0",
  "eslint-plugin-import": "^2.31.0",
  "eslint-plugin-import-x": "^4.6.1",
  "eslint-plugin-jsx-a11y": "^6.10.2",
  "eslint-plugin-react": "^7.37.4",
  "eslint-plugin-react-hooks": "^5.1.0",
  "eslint-plugin-unused-imports": "^4.1.4",
  "globals": "^15.15.0",
  "typescript-eslint": "^8.24.1"
}

結論

あくまで一例のため、お使いの環境に合わせてカスタムしてください。

実行コマンド

$ eslint
# auto fix
$ eslint --fix

設定ファイル

eslint.config.mjs
import globals from 'globals';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { FlatCompat } from '@eslint/eslintrc';
import pluginJs from '@eslint/js';
import pluginConfigPrettier from 'eslint-config-prettier';
import pluginJsxA11y from 'eslint-plugin-jsx-a11y';
import pluginReact from 'eslint-plugin-react';
import pluginReactHooks from 'eslint-plugin-react-hooks';
import pluginImport from 'eslint-plugin-import';
import pluginUnusedImports from 'eslint-plugin-unused-imports';
import typescriptEslint from 'typescript-eslint';
import typescriptEslintParser from '@typescript-eslint/parser';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
  baseDirectory: __dirname,
});

export default [
  {
    ignores: ['.next', 'dist/**', '**/*.css.d.ts', '**/*.css.d.ts.map'],
  },
  pluginJs.configs.recommended,
  ...typescriptEslint.configs.recommended,
  pluginReact.configs.flat.recommended,
  ...compat.config({
    extends: ['next'],
  }),
  pluginConfigPrettier,
  {
    files: ['**/*.{js,ts,tsx}'],
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.node,
      },
      parser: typescriptEslintParser,
      parserOptions: {
        projectService: {
          allowDefaultProject: [
            'eslint.config.mjs',
            'stylelint.config.mjs',
            'postcss.config.js',
            'next.config.js',
          ],
        },
        tsconfigRootDir: import.meta.dirname,
        project: './tsconfig.json',
        ecmaFeatures: {
          jsx: true,
        },
      },
    },
    plugins: {
      import: pluginImport,
      'unused-imports': pluginUnusedImports,
      'jsx-a11y': pluginJsxA11y,
      'react-hooks': pluginReactHooks,
    },
    rules: {
      ...pluginReactHooks.configs.recommended.rules,
      '@next/next/no-img-element': 'off',
      'import/no-default-export': 'error',
      'import/no-anonymous-default-export': ['error', { allowArray: false }],
      'unused-imports/no-unused-imports': 'error',
      'unused-imports/no-unused-vars': [
        'error',
        {
          vars: 'all',
          varsIgnorePattern: '^_',
          args: 'all',
          argsIgnorePattern: '^_',
        },
      ],
      '@typescript-eslint/no-unused-vars': 'off',
      '@typescript-eslint/explicit-module-boundary-types': 'error',
      '@typescript-eslint/consistent-type-imports': 'error',
      '@typescript-eslint/consistent-type-definitions': ['error', 'type'],
    },
  },
  {
    files: ['*.mjs'],
    rules: {
      'import/no-anonymous-default-export': ['error', { allowArray: true, allowObject: true }],
    },
  },
];

解説

コマンド

大きな差分としては、--extによる拡張子の指定が不要になった点になります。

https://eslint.org/docs/latest/use/command-line-interface#--ext

$ eslint
# auto fix
$ eslint --fix

プラグイン

eslintrc記法との大きな差分としては、各プラグインに対して明示的なimportが必要になったことです。
また、各プラグインの対応方針や状況により組み込みの記述が変わるため、それぞれに対して解説を記していきます。
(基本的には各所のREADMEを参考にしております。)

@eslint/js

eslintrcでは"extends": "eslint:recommended"として定義していたプラグインに相当します。

Flat Config向けの新規パッケージとなるため、eslintrcから移行されるとしても新規にインストールが必要になります。

https://eslint.org/docs/latest/use/getting-started#manual-set-up

$ npm install --save-dev @eslint/js
import pluginJs from '@eslint/js';

export default [
  ...
  pluginJs.configs.recommended,
  ...
]

eslint-config-prettier

prettierを併用する場合に推奨されるプラグインです。
prettierの設定と競合するルールをオフにするのが責務なため、他のプラグインをoverrideする位置に定義するのが望ましいです。

https://www.npmjs.com/package/eslint-config-prettier

import pluginConfigPrettier from 'eslint-config-prettier';

export default [
  ...
  pluginConfigPrettier,
  ...
]

typescript-eslint

typescriptを使用しているのであれば必須のプラグインとなります。

  • typescriptへのeslint適用
  • typescriptのルール追加

が主な責務となります。

Flat Config向けの新規パッケージとなるため、eslintrcから移行されるとしても新規にインストールが必要になります。

$ npm install --save-dev typescript-eslint

特にカスタムルールを設けないようであれば以下の設定のみで動きます。

export default [
  ...
  ...typescriptEslint.configs.recommended,
  ...
]

ここでは更に、@typescript-eslint/no-unused-varsなど型情報が求められるルールのカスタムを行なっているためparserの使用が求められます。
従来の@typescript-eslint/parserを使用して、以下の記述で動作いたします。

import typescriptEslint from 'typescript-eslint';
import typescriptEslintParser from '@typescript-eslint/parser';

export default [
  ...
  ...typescriptEslint.configs.recommended,
  ...
  {
    languageOptions: {
      ...
      parser: typescriptEslintParser,
      ...
    }
  }
]

eslint-plugin-import

import周りのルールを設定してくれるプラグインです。

https://www.npmjs.com/package/eslint-plugin-import

import pluginImport from 'eslint-plugin-import';

export default [
  ...
  {
    plugins: {
      import: pluginImport,
    }
  }
]

eslint-plugin-unused-imports

未使用のimport文を自動で削除してくれるプラグインです。

https://www.npmjs.com/package/eslint-plugin-unused-imports

import pluginUnusedImports from 'eslint-plugin-unused-imports';

export default [
  ...
  {
    plugins: {
      'unused-imports': pluginUnusedImports,
    }
  }
]

eslint-plugin-react

react向けのルールが纏められたプラグインです。

https://www.npmjs.com/package/eslint-plugin-react

import pluginReact from 'eslint-plugin-react';

export default [
  ...
  pluginReact.configs.flat.recommended,
  ...
]

eslint-plugin-react-hooks

reactにおけるhooksについてのルールが纏められたプラグインです。

https://www.npmjs.com/package/eslint-plugin-react-hooks

import pluginReactHooks from 'eslint-plugin-react-hooks';

export default [
  ...
  {
    plugins: {
      'react-hooks': pluginReactHooks,
    },
    rules: {
      ...pluginReactHooks.configs.recommended.rules,
    },
  }
]

eslint-plugin-jsx-a11y

https://www.npmjs.com/package/eslint-plugin-jsx-a11y

reactにおけるjsx向けのアクセシビリティルールが纏められたプラグインです。

import pluginJsxA11y from 'eslint-plugin-jsx-a11y';

export default [
  ...
  {
    plugins: {
      'jsx-a11y': pluginJsxA11y,
    },
  }
]

@next/eslint-plugin-next

Next.js向けのルールが纏められたプラグインです。

https://nextjs.org/docs/app/api-reference/config/eslint

執筆時点ではFlat Configの記法に対応していないようなので、
FlatCompatというEslint公式が提供しているeslintrc -> Flat Configの変換を行ってくれるパッケージを使用します。

https://eslint.org/docs/latest/use/configure/migration-guide#using-eslintrc-configs-in-flat-config

import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { FlatCompat } from '@eslint/eslintrc';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
  baseDirectory: __dirname,
});

export default [
  ...
  ...compat.config({
    extends: ['next'],
  }),
  ...
]

globals

eslintrcglobalsキーのObject内で設定していた内容について、
主要なものはglobalsパッケージで提供されております。

https://www.npmjs.com/package/globals

そのため、そちらのインストールも行う必要があります。

https://eslint.org/docs/latest/use/configure/migration-guide#configuring-language-options

$ npm install --save-dev globals
import globals from 'globals';

export default [
  ...
  {
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.node,
      }
  },
  ...
]

後書き

まだあまり情報が落ちてなく手探りではありましたが、主要プラグインについては思ったより苦戦することなく移行ができました。

皆さんの移行作業の一助となれば幸いです。

余談

Flat Config自体の仕組みやメリットなどは以下の記事が大変参考になります。

https://zenn.dev/cybozu_frontend/articles/about-eslint-flat-config

Discussion