背景
ESLint v9からflat configがデフォルトとなり、将来のリリースで古いconfigの書き方は廃止される予定なのは把握していた。その後本格的に調べないままになっていたが、そろそろまずいかもなと思って概要だけでも調査したメモ。
先に簡単なまとめ
flat configとは何か
ESLintの新しい設定システム(config system)のこと。
flat config導入の背景
ESLint's new config system, Part 2: Introduction to flat config - ESLint - Pluggable JavaScript Linter
このあたりに書いてそうだったが、あまり詳しくは理解していない。
ESLintも最初にリリースしてから10年が経過し、複雑化したため、よりシンプルで直感的な設計を目指したぽい。
flat configの書き方
参考: Configuration Files
従来は .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と呼ばれるオブジェクトを配列形式で並べたもの。
import customConfig from "eslint-config-custom";
export default [
customConfig,
{
files: ["**/*.js", "**/*.cjs"],
rules: {
"semi": "error",
"no-unused-vars": "error"
}
},
{
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 では外部のプラグインは以下のように文字列で指定していた。
module.exports = {
plugins: ["jsdoc"],
...
}
flat configでは使用するプラグインはconfigファイル内で明示的にimportし、key-valueのペアで使用するプラグイン名とプラグインオブジェクトを指定する。
import jsdoc from "eslint-plugin-jsdoc";
export default [
{
files: ["**/*.js"],
plugins: {
jsdoc: jsdoc,
},
rules: {
"jsdoc/require-description": "error",
"jsdoc/check-values": "error",
},
},
];
これにより、従来はプラグイン名を eslint-plugin-
で始めないといけなかったが、その制約がなくなった。
同様に 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
import globals from "globals";
export default [
{
languageOptions: {
ecmaVersion: 2022,
sourceType: "module",
globals: {
...globals.browser,
myCustomGlobal: "readonly"
}
}
}
];
従来の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";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname
});
export default [
...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
に
export default [
...
]
と書くと補完が効くようになる。
参考リンク
公式ドキュメント
ブログ記事