【ESLint】.eslintrc から v10 の flat config へ移行したログ — 実際に壊れた4箇所

旧形式の設定ファイルから新しい flat config へ移り変わる様子を、抽象的なカードと矢印で表したアイキャッチ画像
目次

この記事が解決する悩み

  • .eslintrc.json のまま ESLint v10 に上げたら、設定が見つからないと怒られた
  • 移行ツールを回したのに /* eslint-env */ のエラーが消えず、先に進めない
  • monorepo で「設定の探索範囲が変わった」と言われても、自分の構成で何が起きるか読めない

対象読者: ESLint v8 / v9 のプロジェクトを保守していて、v9 の EOL を機に v10 へ上げようとしているエンジニア。

前提知識: flat config という言葉と、env / globals が何を設定しているかが分かっていれば読めます。

結論

移行は「設定を eslint.config.mjs へ移す → 消えた CLI フラグと /* eslint-env */ コメントを直す → 探索範囲の変更を確認する」の3ステップです。

いちばん大きいのは、旧設定がどんな手段でも読まれなくなったことです。ESLINT_USE_FLAT_CONFIG=false は v10 では効きません。

# 1. 旧設定を flat config に変換する
npx @eslint/migrate-config .eslintrc.json
# 実行結果
# Migrating .eslintrc.json
# Wrote new config to ./eslint.config.mjs

# 2. 移行ツールが要求する依存を入れる
npm install -D globals @eslint/js @eslint/eslintrc

# 3. 変換後の設定で実行する
npx eslint src/app.js
# 実行結果
#   1:1  error    /* eslint-env */ comments are no longer supported
#   3:7  warning  'unusedThing' is assigned a value but never used
# 2 problems (1 error, 1 warning)

移行前の状態

v9 の旧設定で動く小さなプロジェクトを用意しました。設定は .eslintrc.json 1枚だけです。

{
  "root": true,
  "env": { "browser": true, "node": true, "es2022": true },
  "parserOptions": { "ecmaVersion": 2022, "sourceType": "module" },
  "extends": ["eslint:recommended"],
  "rules": { "no-unused-vars": "warn" }
}

lint 対象は、わざと引っかかるコードにしておきます。

/* eslint-env node */
import { readFileSync } from "node:fs";

const unusedThing = 42;

export function loadConfig(path) {
  if (path == null) {
    return {};
  }

  return JSON.parse(readFileSync(path, "utf8"));
}

v9 では ESLINT_USE_FLAT_CONFIG=false を付けると旧設定が読まれ、警告1件で通りました。

ESLINT_USE_FLAT_CONFIG=false npx eslint src/app.js
# 実行結果(抜粋)
# src/app.js
#   4:7  warning  'unusedThing' is assigned a value but never used  no-unused-vars
# 1 problem (0 errors, 1 warning)
# ESLintRCWarning: You are using an eslintrc configuration file, which is deprecated
#   and support will be removed in v10.0.0.

この警告のとおり、v10 で旧形式のサポートが消えます。ここを出発点に、実際に壊れた4箇所を順番に見ていきますね。

実際に壊れた4箇所

1. 旧設定がまったく読まれない

v10 に上げた瞬間、.eslintrc.json は無視されます。

npm install eslint@10
ESLINT_USE_FLAT_CONFIG=false npx eslint src/app.js
# 実行結果
# ESLint: 10.12.0
# ESLint couldn't find an eslint.config.* file.
# (exit code 2)

v9 では「非推奨」で済んでいた逃げ道が、v10 では塞がっています。移行ガイドでも旧形式の削除が最初に挙げられています。

2. eslintrc 専用の CLI フラグが消えた

CI のスクリプトに残りがちなフラグも、まとめて消えました。

npx eslint --no-eslintrc src/app.js
# 実行結果
# Invalid option '--eslintrc' - perhaps you meant '--ext'?

npx eslint --env node src/app.js
# 実行結果
# Invalid option '--env' - perhaps you meant '--ext'?

--ignore-path も同じ扱いで、無視設定は ignores へ移します。エラー文が「もしかして –ext?」と提案してくるので、初見だと原因にたどり着きにくいですね。

3. /* eslint-env */ コメントがエラーになる

ファイル先頭の /* eslint-env node */ は、v9 までなら実行環境を指定するコメントでした。v10 ではエラーとして報告されます。

npx eslint src/app.js
# 実行結果
# src/app.js
#   1:1  error    /* eslint-env */ comments are no longer supported
#   4:7  warning  'unusedThing' is assigned a value but never used   no-unused-vars
# 2 problems (1 error, 1 warning)

置き換え先は languageOptions.globals です。コメントを消して、設定側に globals.node を展開します。

import globals from "globals";

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

4. 設定ファイルの探索がファイル基準になった

v10 では、設定ファイルを「実行したディレクトリ」ではなく「lint するファイルのディレクトリ」から探します。

検証では packages/api/eslint.config.mjs を置いて、リポジトリのルートから実行しました。

# v10: ネストした設定が適用される
npx eslint packages/api/index.js
# 実行結果
# packages/api/index.js
#   2:3  error  Unexpected console statement  no-console
# 1 problem (1 error, 0 warnings)

npx eslint --print-config packages/api/index.js
# 実行結果(抜粋)
# no-console: [2, {}] / rules数: 1

# v9.39.5: 同じコマンドでもネストした設定は使われない
npx --yes eslint@9.39.5 packages/api/index.js
# 実行結果(出力なし = ルートの設定だけが読まれた)

monorepo では、いちばん近い eslint.config.* がそのまま使われます。ルートの設定とマージはされないので、共通ルールは共有設定に切り出しておく必要がありますよ。

生成された設定を手で整理する

移行ツールが出す設定は FlatCompat を使う互換モードです。extends をそのまま持ち込み、eslint:recommended を実行時に解決します。

// 移行ツールの生成物(抜粋)
import js from "@eslint/js";
import { FlatCompat } from "@eslint/eslintrc";

const compat = new FlatCompat({
    baseDirectory: __dirname,
    recommendedConfig: js.configs.recommended,
});

export default defineConfig([{
    extends: compat.extends("eslint:recommended"),
    languageOptions: {
        globals: { ...globals.browser, ...globals.node },
        ecmaVersion: 2022,
        sourceType: "module",
    },
}]);

動きますが、依存が1つ増えて解決も実行時になります。ネイティブな形に書き換えると、extends は1行に畳めます。

import js from "@eslint/js";
import globals from "globals";

export default [
  js.configs.recommended,
  {
    files: ["**/*.js", "**/*.jsx"],
    languageOptions: {
      ecmaVersion: 2022,
      sourceType: "module",
      parserOptions: { ecmaFeatures: { jsx: true } },
      globals: { ...globals.node },
    },
    rules: {
      "no-unused-vars": "warn",
    },
  },
];

この形にすると @eslint/eslintrc を依存から外せます。実行結果もエラーが消えて、警告1件だけになりました。

npx eslint src/app.js
# 実行結果
# src/app.js
#   3:7  warning  'unusedThing' is assigned a value but never used  no-unused-vars
# 1 problem (0 errors, 1 warning)

おまけ: JSX の参照トラッキング

v10 では、JSX 要素として使った識別子も「参照」として数えるようになりました。コンポーネントを定義して1回だけ JSX で使うファイルで、結果がはっきり変わります。

npx eslint src/card.jsx
# 実行結果(v10)
# (出力なし = 未使用の指摘なし)

npx --yes eslint@9.39.5 src/card.jsx
# 実行結果(v9.39.5)
# src/card.jsx
#   1:7  warning  'Card' is assigned a value but never used  no-unused-vars

コンポーネントを定義して JSX で使うだけのファイルは、v9 では「未使用」と誤判定されていました。React のプロジェクトでは、これまで無視していた警告が1つ減る形ですね。

つまずきポイント

  • ESLINT_USE_FLAT_CONFIG=false は v10 では効かない。「v9 と同じ手順で戻せる」と考えると詰まります。
  • 移行ツールは globals / @eslint/js / @eslint/eslintrc を要求する。生成直後の実行は依存不足で失敗します。
  • Node.js の対応バージョンが上がり、20.0〜20.18 と 21 / 23 は対象外。CI の Node を先に上げます。
  • no-shadow-restricted-names が globalThis を既定で報告するようになった。実測では var globalThis = 1; がエラーになります。

まとめ

v9 と v10 で挙動が変わった点を並べておきます。

項目v9v10
旧 .eslintrc.*ESLINT_USE_FLAT_CONFIG=false で読める読まれない(フラグも無効)
eslintrc 専用 CLI フラグ使えるInvalid option で落ちる
/* eslint-env */ コメント環境指定として有効エラーとして報告
設定ファイルの探索実行ディレクトリ基準lint 対象ファイル基準
JSX 要素の参照未使用と誤判定することがある参照として追跡
Node.js の対応18 以上20.19 以上(21 / 23 は対象外)

作業そのものは半日で終わる規模です。壊れる箇所が4つに絞られていれば、あとは淡々と直すだけですよ。

検証環境

OSWindows 11 (build 10.0.26200)
CPUAMD Ryzen 9 PRO 8945HS w/ Radeon 780M Graphics
メモリ28GB
言語/ツールnode 26.7.0 / npm 11.19.0 / ESLint 9.39.5(旧設定の確認用) / ESLint 10.12.0 / globals・@eslint/js・@eslint/eslintrc(移行ツールが要求)
使用コマンドnpx @eslint/migrate-config .eslintrc.json / npx eslint(v10 と v9.39.5 の両方) / npx eslint –print-config
測定日2026-10-06

上記の環境で実際に実行して確認した結果です。環境が異なる場合は挙動が変わることがあります。

ESLint 9.39.5 から 10.12.0 へ上げた移行ログ。旧 .eslintrc が v9 では読めて v10 では読まれないこと、消えた CLI フラグ、/* eslint-env */ コメントがエラーになること、移行ツールの出力、設定の探索がファイル基準に変わること(v9 との比較)、JSX 参照トラッキングと no-shadow-restricted-names の挙動までを1枚にまとめたもの
ESLint 9.39.5 から 10.12.0 へ上げた移行ログ。旧 .eslintrc が v9 では読めて v10 では読まれないこと、消えた CLI フラグ、/* eslint-env */ コメントがエラーになること、移行ツールの出力、設定の探索がファイル基準に変わること(v9 との比較)、JSX 参照トラッキングと no-shadow-restricted-names の挙動までを1枚にまとめたもの

あわせて読みたい

参考

【広告】お名前.comならドメイン取得が格安。

【広告】このサイトはConoHa WINGで運営しています。安定した高速サーバーで快適にブログを書けています。いつもありがとう!!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次