ESLint を v9 にアップデートして Flat Config に移行する
はじめに
ESLint v8 は 2024/10/05 に EOL(End Of Life
の略。要はサポート終了 )を迎えています。
今後 dependabot 等でセキュリティエラーが検出されても更新されないため、なる早で v9 にアップデートする必要があります。
また、V9 へのアップデートは後述の通りほとんど Flat Config への移行作業です。
特に各プラグインが Flat Config に対応しているか調査し、設定を移行する作業が一番大変でした。
(最初からそれがわかっていれば簡単だったのですが、どうやって移行するべきかとか調べてたら結構大変でした。。)
ただ、v9 で recommend に変更があるのと、各プラグインのバージョンも上げる必要があるため、多少コードの修正も必要になると思います。
(とはいえこちらはルール通りに変更するだけなのでそんなに大変ではない・・・はず。。)
リンク
ESLint のサポート状況
ESLint 公式の flat config への移行ガイド
v9 の変更内容
Flat Config について
v9 以降では従来の設定ファイル(eslintrc)は非推奨となり、Flat Config と呼ぶ新しい設定ファイルがデフォルトになります。
Flat Config について
Flat Config への移行について
移行しない場合
Flat Config に移行しない場合は環境変数の ESLINT_USE_FLAT_CONFIG
を false にすることで無効にすることができます。(逆に true にすることで v8 でも Flat Config を試せます。)
参考(package.json でやる場合)
{
"scripts": {
"lint": "ESLINT_USE_FLAT_CONFIG=false eslint './**/*.{ts,tsx,js,jsx}' ",
}
}
移行する場合
移行の際の注意点
基本的に後述の移行ツールで簡単に移行できますが、使用しているプラグインが Flat Config に対応しているかどうか注意する必要があります。
多くのプラグインは v9(Flat Config)への対応が進んでいますが、まだ移行がされていないプラグインも存在します。(eslint-plugin-react-hooks などは 2024/11/03 時点ではまだ対応していません。)
対応してないプラグインは fixupPluginRules を使って Flat Config に適用させる必要があります。
@typescript-eslint の話
多くのプロジェクトで使用しているであろう以下のプラグインですが、Flat Config に対応していません。
- @typescript-eslint/eslint-plugin
- @typescript-eslint/parser
公式ドキュメントにもあるように typescript-eslint
をインストールする必要があります。
また公式ドキュメントに明記されていませんが、parser
もデフォルトでは指定する必要がなくなっています。
(後述の移行ツールで parser
が残っておりここでハマりました。。大体こいつのせい)
ちなみにですが、@typescript-eslint/eslint-plugin
と @typescript-eslint/parser
は Legacy ESLint Setup の中に記載されています。
移行ツール
従来の設定ファイルから Flat Config への移行は、公式が用意している移行ツール(@eslint/migrate-config)が利用でき、以下のコマンドで実行できます。
npx @eslint/migrate-config [設定ファイル(.eslintrc、.eslintrc.json etc...)]
# 例
# npx @eslint/migrate-config .eslintrc.js
(ちなみにこのコマンドは v8 でも実行できます。)
このコマンド実行すると以下のように追加のパッケージをインストールするよう求められますのでインストールします。
workman@MacBook-Air MyProject % npx @eslint/migrate-config .eslintrc.json
Migrating .eslintrc.json
Wrote new config to ./eslint.config.mjs
You will need to install the following packages to use the new config:
- @eslint/compat
- globals
- @eslint/js
- @eslint/eslintrc
You can install them using the following command:
# この部分
npm install @eslint/compat globals @eslint/js @eslint/eslintrc -D
The following messages were generated during migration:
- The 'node' environment is used, but the sourceType is 'module'. Using sourceType 'module'. If you want to use CommonJS modules, set the sourceType to 'commonjs'.
移行ツールの注意点
各ルールの設定などは概ね問題なく移行されますが、各プラグインの適用には注意が必要です。
現時点ではプラグインが Flat Config に対応してようが、していまいがすべて fixupPluginRules に記載されます。
こんな感じになります。
import { fixupConfigRules, fixupPluginRules } from '@eslint/compat';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
// 省略
export default [
...fixupConfigRules(
compat.extends(
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
),
),
{
plugins: {
react: fixupPluginRules(react),
'react-hooks': fixupPluginRules(reactHooks),
'@typescript-eslint': fixupPluginRules(typescriptEslint),
},
// 省略
前述の通り、@typescript-eslint は別の node module をインストールする必要がありますし、eslint-plugin-react は Flat Config に対応しているので Flat Config 用の記述をする必要があります。
それぞれのプラグインが Flat Config に対応しているかどうかは、それぞれのプラグインのドキュメントを参照するしかなく、またそれぞれ書き方が異なるので必ずドキュメントを参照する必要があります。
特に eslint-config-prettier などは他の設定の後に記述するよう指定があるので注意が必要です。
移行手順
前置きが長くなりましたがここからが本題です。
もっとシンプルにできればよかったのですが、ESLint をアップデートするタイミングや npm install
するタイミングを間違えるとすぐに依存関係のエラーで失敗したため、最終的に以下のような手順になりました。(良い方法があれば教えて下さい🙇)
-
Flat Config に移行(公式の移行ツールを実行)
# 移行前の設定ファイルが .eslintrc.json の場合 npx @eslint/migrate-config .eslintrc.json
上記コマンド実行後、
eslint.config.mjs
が作成されます。
既存の設定ファイル(上記例だと.eslintrc.json
)は削除されないので、commit(push)する前に削除する必要があります。 -
各種プラグインを最新版に更新
Flat Config 対応のバージョンであれば最新版でなくても大丈夫です。npm install [プラグイン名]@latest
-
各種プラグインを Flat Config に移行
@typescript-eslint の移行 とか プラグインが Flat Config に対応しているかどうか調べる方法 を参考にアップデートしてもらえればと思います🙏
-
ESLint を v9 にアップデート
npm install eslint@latest
-
移行ツールの関連ライブラリをインストール
2で控えておいたコマンドを実行して関連ライブラリをインストールします。
# 移行後の eslint.config.mjs の内容によりますが、大体以下のような感じだと思います。 npm install @eslint/compat globals @eslint/js @eslint/eslintrc -D
-
eslint
コマンドを実行 -
実行後、lint エラーが発生した場合は修正
前述の通り v9 で recommend に変更があるので、多くのプロジェクトでは修正が必要になると思います。
余談
プラグインが Flat Config に対応しているかどうか調べる方法
調べたいプラグインのリポジトリで、eslint.config.js
や flat
で検索すると幸せになれると思います。
大体以下のような感じで記載されています。
@typescript-eslint の移行
こいつの移行に大変苦労したのでメモを残しておきます。
詳しくは公式のドキュメントを参照ください。(ただし現状 migrate ガイドのようなものはありません。。)
-
typescript-eslint をインストール
npm install typescript-eslint -D
-
古いプラグインを削除
npm uninstall @typescript-eslint/eslint-plugin -D npm uninstall @typescript-eslint/parser -D
-
eslint.config.mjs
を修正eslint.config.mjsimport { fixupConfigRules, fixupPluginRules } from '@eslint/compat'; import react from 'eslint-plugin-react'; import reactHooks from 'eslint-plugin-react-hooks'; -import typescriptEslint from '@typescript-eslint/eslint-plugin'; +import tseslint from 'typescript-eslint'; import globals from 'globals'; -import tsParser from '@typescript-eslint/parser'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import js from '@eslint/js'; import { FlatCompat } from '@eslint/eslintrc'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const compat = new FlatCompat({ baseDirectory: __dirname, recommendedConfig: js.configs.recommended, allConfig: js.configs.all, }); export default [ + ...tseslint.configs.recommended, ...fixupConfigRules( compat.extends( 'eslint:recommended', - 'plugin:@typescript-eslint/eslint-recommended', - 'plugin:@typescript-eslint/recommended', 'prettier', 'plugin:react/recommended', 'plugin:react-hooks/recommended', ), ), plugins: { // 各種設定 }, { languageOptions: { // 各種設定 - parser: tsParser, }, settings: { // 各種設定 }, rules: { // 各種ルール }, }, ];
Next.js の場合
Next.js では独自の ESLint を実行するコマンド(next lint)を持っており、多くのプロジェクトが使っているであろう v14 以前では Flat Config(v9)に対応していません。
v14 以前でも Flat Config を導入する方法はありますが、v15 にアップデートすることをおすすめします。
上記記事には記載されていませんが、next/core-web-vitals
を fixupConfigRules に適用しても良さそうです。(試していませんが。。)
こんな感じ
export default [...compat.extends("next/core-web-vitals")];
以下の記事が参考になりました🙏
Discussion