ESLintのeslintrcをFlat Configに移行してみた
はじめに
みなさん、ESLint の Flat Config 移行は進んでいますか?
先日、ESLint の Flat Config への移行に関するブログが公開されました。
ざっくり下記のような流れで移行していくとのことです。
- ESLint v9 (今年末 ~ 来年の初めにリリース予定)で flat config がデフォルトになり、eslintrc は非推奨になる。
- eslint v10 (2024年末 ~ 2025 年初頭にリリース予定)で eslintrc が削除される
徐々に Flat Config に移行していかなければ...ということで、以前、筆者が作成した vite-plugin-sri2 で使用している eslintrc を Flat Config に移行してみました。
本記事では移行する時に対応したことを列挙していきます。
移行前後の比較
先に移行前の eslintrc と移行後の Flat Config の設定ファイルをそれぞれ載せておきます。
Before
module.exports = {
root: true,
extends: [
'eslint:recommended',
'plugin:node/recommended',
'plugin:@typescript-eslint/eslint-recommended',
'prettier'
],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
},
plugins: ['@typescript-eslint', 'html', 'markdown'],
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020
},
ignorePatterns: ['**/fixtures/**'],
rules: {
'no-console': 'off',
'no-debugger': 'error',
'node/no-deprecated-api': 'off',
'node/no-unpublished-import': 'off',
'node/no-unpublished-require': 'off',
'node/no-unsupported-features/es-syntax': 'off',
'no-process-exit': 'off',
'node/no-missing-import': 'off'
}
};
After
import { FlatCompat } from '@eslint/eslintrc';
import eslintConfigPrettier from 'eslint-config-prettier';
import html from 'eslint-plugin-html';
import markdown from 'eslint-plugin-markdown';
import js from '@eslint/js';
import typeScriptESLint from '@typescript-eslint/eslint-plugin';
import typeScriptESLintParser from '@typescript-eslint/parser';
const compat = new FlatCompat();
export default [
{
ignores: ['**/fixtures/**', '**/dist/**']
},
js.configs.recommended,
eslintConfigPrettier,
...compat.extends('plugin:node/recommended', 'plugin:@typescript-eslint/eslint-recommended'),
{
plugins: {
typeScriptESLint,
html,
markdown
},
languageOptions: {
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
},
parser: typeScriptESLintParser,
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020
}
},
rules: {
'no-console': 'off',
'no-debugger': 'error',
'node/no-deprecated-api': 'off',
'node/no-unpublished-import': 'off',
'node/no-unpublished-require': 'off',
'node/no-unsupported-features/es-syntax': 'off',
'no-process-exit': 'off',
'node/no-missing-import': 'off'
}
}
];
Flat Config に移行する時にやったこと
ここからは実際に Flat Config へ移行する時に対応したことを列挙していきます。
公式でマイグレーションガイドが用意されているので、こちらを参考にしながら対応していきました。
Flat Config を有効にする
プロジェクトのルートに eslint.config.js
を配置するか、環境変数の ESLINT_USE_FLAT_CONFIG
を true
にすることで Flat Config を有効化できます。
今回は環境変数の設定はせず、eslint.config.js
の配置だけします。
export default [
]
--ignore-pattern を ignores に置き換える
eslintrc の時は下記のように lint を実行する npm scripts に --ignore-path
オプションを指定していました。これにより、lint 実行時も .gitignore で除外しているファイルを除外できます。
{
"scripts": {
"lint": "eslint --ignore-path .gitignore '**/*.{js,ts,html,md}'",
}
}
Flat Config には --ignore-pattern
オプションがないので、代わりに ignores
プロパティで除外したいファイルを指定しました。
export default [
+ {
+ ignores: ['**/fixtures/**', '**/dist/**']
+ },
]
また、--ignore-path
オプションは削除しています。
{
"scripts": {
- "lint": "eslint --ignore-path .gitignore '**/*.{js,ts,html,md}'",
+ "lint": "eslint '**/*.{js,ts,html,md}'",
}
}
extends を移行する
eslintrc の時は下記のように extends
プロパティを指定していました。
module.exports = {
extends: [
'plugin:node/recommended',
'plugin:@typescript-eslint/eslint-recommended',
'prettier'
],
}
Flat Config には extends
プロパティがないので対応が必要です。
eslint:recommended を移行する
まずは、他の共有設定と比べて指定方法が少し特殊な eslint:recommended
から設定していきます。Flat Config では、@eslint/jsという別パッケージに切り出されています。
まずはパッケージをインストールします。
pnpm add -D @eslint/js
設定ファイルに追記します。
+ import js from '@eslint/js';
export default [
{
ignores: ['**/fixtures/**', '**/dist/**']
},
+ js.configs.recommended,
];
Flat Config 対応が完了している共有設定を移行する
これまでは、パッケージの解決を ESLint 側が担っていました。
Flat Config では、設定ファイルの形式を JS のみに絞ったことで、JS の機能を活用できるようになり、 import
などが使えるようになりました。
その結果、下記のように設定を書く側でパッケージの解決をする形に変わりました。
+ import eslintConfigPrettier from 'eslint-config-prettier';
import js from '@eslint/js';
export default [
{
ignores: ['**/fixtures/**', '**/dist/**']
},
js.configs.recommended,
+ eslintConfigPrettier,
];
Flat Config 対応が完了していない共有設定を移行する
2023/11/05 時点だと、eslint-plugin-nodeや@typescript-eslint/eslint-pluginはまだ Flat Config へ移行されていませんでした。
ですが、安心してください、このような問題を解決するために公式がツールを用意してくれています。(ありがたい🙏)
具体的には、eslintrc 形式から Flat Config 形式に変換してくれる FlatCompat を使用していきます。
FlatCompat も別パッケージに切り出されているのでまずはインストールから。
pnpm add -D @eslint/eslintrc
次に FlatCompat 経由で共有設定を読み込みます。
+ import { FlatCompat } from '@eslint/eslintrc';
import eslintConfigPrettier from 'eslint-config-prettier';
import js from '@eslint/js';
+ const compat = new FlatCompat();
export default [
{
ignores: ['**/fixtures/**', '**/dist/**']
},
js.configs.recommended,
eslintConfigPrettier,
+ ...compat.extends(
+ 'plugin:node/recommended',
+ 'plugin:@typescript-eslint/eslint-recommended',
+ 'prettier'
),
];
globals を移行する
これまでは下記のように指定していました。
module.exports = {
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
},
}
Flat Config では languageOptions
プロパティ内の globals
プロパティに指定します。
import { FlatCompat } from '@eslint/eslintrc';
import eslintConfigPrettier from 'eslint-config-prettier';
import js from '@eslint/js';
const compat = new FlatCompat();
export default [
{
ignores: ['**/fixtures/**', '**/dist/**']
},
js.configs.recommended,
eslintConfigPrettier,
...compat.extends(
'plugin:node/recommended',
'plugin:@typescript-eslint/eslint-recommended',
),
+ {
+ languageOptions: {
+ globals: {
+ Atomics: 'readonly',
+ SharedArrayBuffer: 'readonly'
+ },
+ },
+ }
];
plugins を移行する
これまでは下記のように指定していました。
module.exports = {
plugins: ['@typescript-eslint', 'html', 'markdown'],
}
Flat Config では共有設定の時と同様に設定を書く側で import
してから plugins
プロパティに指定します。
import { FlatCompat } from '@eslint/eslintrc';
import eslintConfigPrettier from 'eslint-config-prettier';
+ import html from 'eslint-plugin-html';
+ import markdown from 'eslint-plugin-markdown';
import js from '@eslint/js';
+ import typeScriptESLint from '@typescript-eslint/eslint-plugin';
const compat = new FlatCompat();
export default [
{
ignores: ['**/fixtures/**', '**/dist/**']
},
js.configs.recommended,
eslintConfigPrettier,
...compat.extends(
'plugin:node/recommended',
'plugin:@typescript-eslint/eslint-recommended',
),
{
+ plugins: {
+ typeScriptESLint,
+ html,
+ markdown
+ },
languageOptions: {
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
},
},
}
];
parser を移行する
これまでは下記のように指定していました。
module.exports = {
parser: '@typescript-eslint/parser',
}
Flat Config では languageOptions
プロパティ内の parser
プロパティに指定します。
また、共有設定の時と同様に設定を書く側で import
してから parser
プロパティに指定します。
import { FlatCompat } from '@eslint/eslintrc';
import eslintConfigPrettier from 'eslint-config-prettier';
import html from 'eslint-plugin-html';
import markdown from 'eslint-plugin-markdown';
import js from '@eslint/js';
import typeScriptESLint from '@typescript-eslint/eslint-plugin';
+ import typeScriptESLintParser from '@typescript-eslint/parser';
const compat = new FlatCompat();
export default [
{
ignores: ['**/fixtures/**', '**/dist/**']
},
js.configs.recommended,
eslintConfigPrettier,
...compat.extends(
'plugin:node/recommended',
'plugin:@typescript-eslint/eslint-recommended',
),
{
plugins: {
typeScriptESLint,
html,
markdown
},
languageOptions: {
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
},
+ parser: typeScriptESLintParser,
},
}
];
parserOptions を移行する
これまでは下記のように指定していました。
module.exports = {
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020
},
}
Flat Config では languageOptions
プロパティ内に parserOptions
オプションを含めます。
import { FlatCompat } from '@eslint/eslintrc';
import eslintConfigPrettier from 'eslint-config-prettier';
import html from 'eslint-plugin-html';
import markdown from 'eslint-plugin-markdown';
import js from '@eslint/js';
import typeScriptESLint from '@typescript-eslint/eslint-plugin';
import typeScriptESLintParser from '@typescript-eslint/parser';
const compat = new FlatCompat();
export default [
{
ignores: ['**/fixtures/**', '**/dist/**']
},
js.configs.recommended,
eslintConfigPrettier,
...compat.extends(
'plugin:node/recommended',
'plugin:@typescript-eslint/eslint-recommended',
),
{
plugins: {
typeScriptESLint,
html,
markdown
},
languageOptions: {
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
},
parser: typeScriptESLintParser,
+ parserOptions: {
+ sourceType: 'module',
+ ecmaVersion: 2020
+ }
},
}
];
rules を移行する
これまでは下記のように指定していました。
module.exports = {
rules: {
'no-console': 'off',
'no-debugger': 'error',
'node/no-deprecated-api': 'off',
'node/no-unpublished-import': 'off',
'node/no-unpublished-require': 'off',
'node/no-unsupported-features/es-syntax': 'off',
'no-process-exit': 'off',
'node/no-missing-import': 'off'
},
}
rules に関しては非互換な変更はないのでそのままコピペでOKです。
import { FlatCompat } from '@eslint/eslintrc';
import eslintConfigPrettier from 'eslint-config-prettier';
import html from 'eslint-plugin-html';
import markdown from 'eslint-plugin-markdown';
import js from '@eslint/js';
import typeScriptESLint from '@typescript-eslint/eslint-plugin';
import typeScriptESLintParser from '@typescript-eslint/parser';
const compat = new FlatCompat();
export default [
{
ignores: ['**/fixtures/**', '**/dist/**']
},
js.configs.recommended,
eslintConfigPrettier,
...compat.extends(
'plugin:node/recommended',
'plugin:@typescript-eslint/eslint-recommended',
),
{
plugins: {
typeScriptESLint,
html,
markdown
},
languageOptions: {
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
},
parser: typeScriptESLintParser,
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020
}
},
+ rules: {
+ 'no-console': 'off',
+ 'no-debugger': 'error',
+ 'node/no-deprecated-api': 'off',
+ 'node/no-unpublished-import': 'off',
+ 'node/no-unpublished-require': 'off',
+ 'node/no-unsupported-features/es-syntax': 'off',
+ 'no-process-exit': 'off',
+ 'node/no-missing-import': 'off'
+ }
}
];
おわりに
ここまで Flat Config へ移行する時に対応したことを列挙していきました。
マイグレーションガイドがかなり手厚く、特に詰まるところもなかったのでありがたいですね...🙏
残っているプロジェクトも徐々に移行していこうと思います💪
Discussion