見出し画像

ESLint v9 アップデートで eslintrc から Flat Config へ移行した話

三菱UFJフィナンシャル・グループ(以下MUFG)の戦略子会社であるJapan Digital Design(以下JDD)で システム開発をしている渡邊 聡美です。

本記事では、ESLint v9neostandard、そして Flat Config への移行に伴うトラブルとその解決方法についてご紹介します。


ESLint v9 に挑む日がやってきた

私の携わっているプロジェクトでは、静的解析ツールに ESLint を採用しています。使用中の ESLint のバージョンは v8.57.0 でしたが、2024年4月に v9.0.0 がリリースされたことを受け、作業当時最新だった v9.12.0 へアップデートする作業を行いました。

特に不安を抱くことなくアップデート作業を始めたのですが、この瞬間から私と ESLint の長い長い闘いが始まるのでした。

環境

  • ESLint : v8.57.0 → v9.12.0

  • eslint-config-standard : v17.1.0

  • neostandard : v0.11.6

ESLintアップデートの第一歩で最初の壁に直面

ESLint との戦いは、ESLint v9.12.0 のインストールから始まりました。

npm install -D --save-exact eslint@9.12.0

依存パッケージの調査と更新作業

ここでインストールに失敗、以下のエラーが出てきました。

peer eslint@"^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" from eslint-plugin-import@2.30.0
peer eslint@"^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" from eslint-plugin-react-hooks@4.6.2

エラーログによれば、「eslint-plugin-import v2.30.0eslint-plugin-react-hooks v4.6.2ESLint v9.12.0 に対応していない」というもの。そのため、各パッケージを調査し、ESLint v9.12.0 に対応しているバージョンにアップデートしてあげれば良さそうです。

それぞれのパッケージの公式サイトで、 ESLint v9.12.0 に対応しているバージョンを確認しました。

  • eslint-plugin-import v2.31.0

  • eslint-plugin-react-hooks v5.0.0

注)これらのバージョン情報は作業日時点のものであり、現在は変更されている可能性があります。

こちらのバージョンが ESLint v9.12.0 に対応していることがわかりましたので、それぞれインストールしていきます。この段階で、ESLint v9.12.0 のインストールが可能になりました。

eslint-config-standard 非対応で直面した課題

次に、同様の警告についても確認します。

peer eslint@"^8.0.1" from eslint-config-standard@17.1.0

eslint-config-standardESLint v9.12.0 に対応しているバージョンを確認したところ、驚愕の事実が判明しました。

なんと、eslint-config-standardESLint v9.12.0 に対応していないというのです!!これは予想外の事態です。

Since we couldn't reach a conclusion on governance (standard/standard#1948 (comment)) some of us are today launching an alternative project today that aims to carry the torch forward in the same spirit as but under an open governance model: neostandard

ガバナンスに関する結論に達することができなかったため、私たちの一部は今日、オープンガバナンスモデルと同じ精神で、しかしオープンなガバナンスモデルのもとで先導することを目的とした代替プロジェクトを立ち上げています:neostandard

eslint-config-standard の代替プロジェクトを立ち上げたとのこと。これは興味深いです。

neostandard とは

neostandard とは、ESLint v9 に対応した JavaScript のスタイルガイドです。eslint-config-standard の代替と公式が謳っておりますし、プロジェクトメンバーと協議した結果、neostandard に移行することに決定いたしました。

Flat Config との出会い

が、ここで問題発生。
neostandardFlat Config のみが利用できるとのこと。従来の .eslintrc は利用できないのです。

Flat Config とは

Flat Config とは、ESLint v9 から推奨される新しい設定形式で、従来の .eslintrc に代わる仕組みです。設定は JavaScript のモジュール(eslint.config.js)として記述され、柔軟な構成とパフォーマンス向上を実現します。

ESLint v9 では .eslintrc を利用することも可能ですが、非推奨とされており、ESLint v10 からは完全撤廃される予定です。さらに、neostandard を利用するには Flat Config 化が必須条件となります。そのため、私の闘いの場は「ESLint v9.12.0 対応」から「Flat Config 移行」へとシフトすることとなりました。

Flat Config では設定ファイルが JavaScript モジュールとして記述され、柔軟な条件指定が可能になりました。従来の .eslintrc よりも構成が直感的です。

// 従来の .eslintrc.js
module.exports = {
  extends: ["eslint:recommended"],
  rules: {
    "no-unused-vars": "warn",
    "eqeqeq": "error"
  }
}
// Flat Config
export default [
  {
    files: ["**/*.js"],
    rules: {
      "no-unused-vars": "warn",
      "eqeqeq": "error"
    }
  }
]

Flat Config 移行への挑戦

migration tool を使ってみる

.eslintrcFlat Config 形式にマイグレーションしてくれるツールがあったので、このツールを使用し、既存の .eslintrc.jseslint.config.js 形式に変換後、Lint を実行しました。

エラー解析と修正ポイント

するとエラー。。一筋縄ではいかないですね。エラーの内容を確認します。

ConfigError: Config (unnamed): Key "plugins": Cannot redefine plugin "n".

n というキーを再定義できないエラーです。 eslint.config.js 内で plugin:n/recommended を extend しているものの複数定義はしていないので、エラー箇所を特定するために eslint.config.js で生成されたルールをログ出力してみます。

{
    name: 'neostandard/base',
    plugins: {
      n: {
        meta: { name: 'eslint-plugin-n', version: '17.14.0' },
      }
    }
    // 省略
}

なるほど、neostandard 内でも eslint-plugin-n を定義していることがわかりました。なお、neostandard の公式によると、以下の plugin を エクスポートしているようです。

  • @stylistic/eslint-plugin

  • eslint-plugin-n

  • eslint-plugin-promise

  • eslint-plugin-react

  • typescript-eslint

したがって、extend している plugin:n/recommended を削除し、neostandard からインポートした eslint-plugin-n の recommended を展開するように修正します。

import { fixupConfigRules } from "@eslint/compat"
import { FlatCompat } from "@eslint/eslintrc"
import neostandard, { plugins } from 'neostandard'
const compat = new FlatCompat({
    // 省略
})
export default [
  ...neostandard(),
  ...fixupConfigRules(compat.extends(
    "eslint:recommended",
    // これを削除
    // "plugin:n/recommended",
)), 
  plugins.n.configs['flat/recommended-script'],
  // 省略
]

他の plugin に関しても同じ修正を行うことで、キーの重複エラーを回避することができました。

fixupConfigRules と FlatCompatについて

fixupConfigRulesFlatCompatFlat Config 化と ESLint v9 への移行を簡素化するためのツールですが、すべてのプラグインでの動作が保証されているわけではありません。マイグレーションツールで変換された eslint.config.js にもこれらが採用されていましたが、今回は長期的な保守性を考慮し、Flat Config に完全対応した設定とパッケージを採用しました。

standard と neostandard が展開するルールの違い

eslint-config-standard には以下のプラグインが含まれています。

  • eslint-plugin-n

  • eslint-plugin-promise

  • eslint-plugin-import

一方、neostandard のプラグイン一覧については、「エラー解析と修正ポイント」で触れています。この違いにより、neostandard への移行後には以下のような指摘が発生する可能性があります。

  • @stylistic/space-before-function-paren

    • 関数宣言時のスペースに関するルール

  • react/jsx-handler-names

    • JSX 内のイベントハンドラーの命名に関するルール

eslint-config-standard から neostandard に移行する際は、ルールの見直しも併せて行うと良いかもしれません。

まとめ

ESLint v9 へのアップデート作業は、想定外の Flat Config への対応にまで及び、予想以上に時間と労力を費やす結果となりました。しかし、いずれ避けて通れない変更であったことを考えると、今回の経験は非常に有意義だったと感じています。また、この作業を通じて ESLint に対する理解が深まり、大きな学びを得ることができました。

今後も新しい技術やパッケージへの対応を積極的に行い、プロジェクト全体の品質向上に努めていきたいと思います。

以上、渡邊 でした。
最後までご覧いただきありがとうございました。


Japan Digital Design株式会社では、一緒に働いてくださる仲間を募集中です。カジュアル面談も実施しておりますので下記リンク先からお気軽にお問合せください。

この記事に関するお問い合わせはこちら

Japan Digital Design 株式会社
Technology & Development Div
Satomi Watanabe