背景
ESLint v9からflat configがデフォルトとなり、将来のリリースで古いconfigの書き方は廃止される予定なのは把握していた。その後本格的に調べないままになっていたが、そろそろまずいかもなと思って概要だけでも調査したメモ。
先に簡単なまとめ
- 次のメジャーバージョンv10で古いconfigは廃止だが、そのリリースは2024年末〜2025年初頭
- 移行は @eslint/migrate-config を使いつつ Configuration Migration Guide を参照
flat configとは何か
ESLintの新しい設定システム(config system)のこと。
flat config導入の背景
このあたりに書いてそうだったが、あまり詳しくは理解していない。
ESLintも最初にリリースしてから10年が経過し、複雑化したため、よりシンプルで直感的な設計を目指したぽい。
flat configの書き方
従来は .eslintrc.*
という名前の設定ファイルでJSだけでなくYAMLやJSONもサポートしていたが、flat configでは eslint.config.js
(または ~.mjs
, ~.cjs
)というようにJSに統一された。
eslint.config.js
については、 package.json
に "type: "module"
と書かれていればESM形式、そうでなければCommonJS形式とみなされる。
flat config の中身は、configuration objectと呼ばれるオブジェクトを配列形式で並べたもの。
// eslint.config.mjs (ESM形式) import customConfig from "eslint-config-custom"; export default [ customConfig, // configuration object その1 // configuration object その2 { files: ["**/*.js", "**/*.cjs"], rules: { "semi": "error", "no-unused-vars": "error" } }, // configuration object その3 { files: ["**/*.js"], rules: { "no-undef": "error", "semi": "warn" } } ];
各configuration objectはこれらのプロパティで構成される。
name
- configuration objectの名前。Configuration Naming Conventions によれば “optional, but it is recommended to provide a name for each configuration object, especially when you are creating shared configurations.” とのこと
files
- configuration object を適用したいファイルを、globパターンの配列で指定する。省略した場合、他のconfiguration objectによってマッチしたすべてのファイルが対象になる
ignores
- configuration objectの適用対象外にしたいファイルを、globパターンの配列で指定する
languageOptions
ecmaVersion, sourceType, globals, parser, parserOptions
を設定する
linterOptions
: 以下、どちらも元からあったプロパティnoInlineConfig
:インラインコメントでのルール適用を禁止する(あればエラーになる)reportUnusedDisableDirectives
:コメントでenable/disableしたものの、コードの修正によって意味をなさなくなっているものをどう扱うか(error | warn | off)
processor
- 使ったことないので割愛
plugins
rules
- ルール。従来通りの記述
settings
- すべてのルールで共有できるkey-value形式の値
注意点として、あるファイルに対して複数のconfiguration objectがマッチした場合、それらはマージされ、配列の前から順番に適用されるような挙動となる。つまりconfiguration object間でプロパティがバッティングしていた場合は後勝ちとなる。
従来のconfigとの違い
参考:https://eslint.org/docs/latest/use/configure/migration-guide
上記記事の Key Differences between Configuration Formats に主な変更点が記載されている。が、それでも量が多い。
ここでは特に気になったものだけ書く。
また、日本語記事ではこちらがわかりやすかった。
ESLint を eslintrc から Flat Config に移行する、ハマりポイントを添えて。 #JavaScript - Qiita
プラグインのインポート方法
eslintrc では外部のプラグインは以下のように文字列で指定していた。
// .eslintrc.js(抜粋) module.exports = { // ...other config plugins: ["jsdoc"], ... }
flat configでは使用するプラグインはconfigファイル内で明示的にimportし、key-valueのペアで使用するプラグイン名とプラグインオブジェクトを指定する。
// eslint.config.js import jsdoc from "eslint-plugin-jsdoc"; export default [ { files: ["**/*.js"], plugins: { jsdoc: jsdoc, }, rules: { "jsdoc/require-description": "error", "jsdoc/check-values": "error", }, }, ];
これにより、従来はプラグイン名を eslint-plugin-
で始めないといけなかったが、その制約がなくなった。
.eslintignore
は廃止
同様に eslintrc の ignorePatterns
も廃止。configuration object の ignores
を使う。
env
プロパティは廃止
特定のランタイム向けのグローバル変数は globals
というnpmパッケージをインストールし、 globals
プロパティに指定して使う
before
// before (.eslintrc.js) module.exports = { env: { browser: true, }, globals: { myCustomGlobal: "readonly", }, parserOptions: { ecmaVersion: 2022, sourceType: "module" } // ...other config }
after
// eslint.config.js import globals from "globals"; export default [ { languageOptions: { ecmaVersion: 2022, sourceType: "module", globals: { ...globals.browser, myCustomGlobal: "readonly" } } // ...other config } ];
従来のconfigからの移行方法
ESLint Configuration Migrator (@eslint/migrate-config
) というCLIが提供されている。
https://eslint.org/docs/latest/use/configure/migration-guide#migrate-your-config-file
npx @eslint/migrate-config .eslintrc.json
実行すると eslint.config.js
が生成される(未確認)。
注意点として、公式ドキュメントには
not guaranteed to work immediately without further modification
とあるのでこれだけではうまくいかないケースもあるらしい。
また、 .eslintrc.js
に対してはうまく動かないらしい。
手作業での移行は、先ほども記載した
https://eslint.org/docs/latest/use/configure/migration-guide
を読んで差分を理解し、移行するしかない。
flat config未対応のconfig・pluginを使っている場合
参考:Configuration Migration Guide > Using eslintrc Configs in Flat Config
依存している shareable config がまだ flat config に対応していない場合、FlatCompat
というユーティリティを使うことで eslintrc フォーマットから flat config フォーマットに変換できる。
FlatCompat
は @eslint/eslintrc
というパッケージのインストールが必要。
このように、FlatCompat インスタンスを作成した後に適宜メソッドを呼び出して flatconfig 未対応の config 名を渡す。
import { FlatCompat } from "@eslint/eslintrc"; import path from "path"; import { fileURLToPath } from "url"; // mimic CommonJS variables -- not needed if using CommonJS const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const compat = new FlatCompat({ baseDirectory: __dirname }); export default [ // mimic ESLintRC-style extends ...compat.extends("eslint-config-my-config"), ];
.extends()
以外にもいくつかメソッドがあるみたい。詳しくは
https://github.com/eslint/eslintrc
のREADME参照。
いつまでに移行が必要?
参考:Flat config rollout plans - ESLint - Pluggable JavaScript Linter
すでに、2024年4月にリリースされた ESLint v9.0.0 からはflat configがデフォルトになっており、従来の config は非推奨(deprecated)という扱い。
v9.0.0 以降で従来の config を使用する場合、ESLINT_USE_FLAT_CONFIG
という環境変数を false
に設定する必要がある。
$ ESLINT_USE_FLAT_CONFIG=false npx eslint src
さらに、v10.0.0 では従来の config は完全に削除される。
v10.0.0 のリリースは参考先のブログ記事では2024年末か2025年初頭と書かれている。
flat config のTypeScript型定義
参考:https://eslint.org/docs/latest/use/configure/migration-guide#typescript-types-for-flat-config-files
DefinitelyTyped にある。
$ npm i -D @types/eslint
eslint.config.js
に
/** @type import("eslint").Linter.FlatConfig[] */ export default [ ... ]
と書くと補完が効くようになる。
参考リンク
公式ドキュメント
- Configuration Files - ESLint - Pluggable JavaScript Linter
- Configuration Migration Guide - ESLint - Pluggable JavaScript Linter
- ESLint's new config system, Part 2: Introduction to flat config - ESLint - Pluggable JavaScript Linter
- Flat config rollout plans - ESLint - Pluggable JavaScript Linter
ブログ記事
- Flat Config導入完了! 新しいESLintの設定フォーマットを使ってみた
- ESLintのeslintrcをFlat Configに移行してみた
- ✅ 新卒エンジニアがESLintのFlat Config移行と格闘した話 - ドワンゴ教育サービス開発者ブログ
- つまりそうなポイントと、移行前後で設定が変わってないことの確認方法は参考になりそう
- ✅ ESLint を eslintrc から Flat Config に移行する、ハマりポイントを添えて。 #JavaScript - Qiita
- 書き方の変更点がわかりやすい
- configに型をあてる方法も紹介されている。@types/eslintインストールが必要だったか