【Next.js 15】ESLintのFlat Configの設定方法

Next.js

はじめに

こんにちは、株式会社TOKOSのツキヤです!
Next.jsのバージョン15の内容の中に、「ESLint 9 Support」という内容がありましたね。
これにより、Next.jsでのFlat Configへの対応が可能となりました!

今回の記事では、ESLintのFlat Configの対応方法を記述します!

対象読者

  • Next.jsとESLintを使用している方
  • Flat Configに対応したい方

今回はFlat Configの細かい説明は省かせていただきます🙏
超簡単に言うと、「ESLintの新しい設定方法」です!
ESLintのバージョン9からはデフォルトの設定方法となっており、バージョン10からは既存の設定方法は廃止となる予定なので、今後もESLintを使っていきたい人は必須で対応する必要があります🥺

対応方法

既存の設定ファイルの削除

まず行ったこととして、既存の設定ファイルである.eslintrc.jsを削除しました!
(自分はyamlの形式が好きだったので、.eslintrc.ymlファイルを使っていました)

周辺ライブラリのアップデート

次に、ESLint関連のパッケージをまとめてアップデートしました!
対応リポジトリに入れていたパッケージは下記になっています。

  • @typescript-eslint/eslint-plugin
  • @typescript-eslint/parser
  • eslint
  • eslint-config-next
  • eslint-config-prettier
  • eslint-plugin-import
  • eslint-plugin-react
  • eslint-plugin-react-hooks
  • eslint-plugin-tailwindcss
  • eslint-plugin-unused-imports

けっこうありました😳
それぞれがどういうルールか気になった方はぜひ調べて見て下さい!

typescript-eslint系の追加ライブラリのインストール

次に、一番大きそうなtypescript-eslintの対応します!
公式ドキュメントを見たところ、何やら追加でライブラリが必要そうな雰囲気を感じたので、インストールしておきます!

ターミナル
npm install --save-dev @eslint/js typescript-eslint

これで準備OKです!

eslint.config.mjsの設定

いよいよ新しいファイルであるeslint.config.mjsの設定をしていきます!

早速、ファイルの中身を示します!

eslint.config.mjs
import path from "node:path"
import { fileURLToPath } from "node:url"
import { FlatCompat } from "@eslint/eslintrc"
import eslint from "@eslint/js"
import tseslint from "typescript-eslint"
import tailwind from "eslint-plugin-tailwindcss"
import importPlugin from "eslint-plugin-import"
import unusedImports from "eslint-plugin-unused-imports"
import eslintConfigPrettier from "eslint-config-prettier"

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const compat = new FlatCompat({ baseDirectory: __dirname })

export default tseslint.config(
  {
    // グローバルで読み込むファイルの拡張子
    files: ["*.js", "*.jsx", "*.ts", "*.tsx"],
  },
  {
    // グローバルで無視するファイル
    ignores: ["**/.next/**/*", "*.config.*"],
  },
  eslint.configs.recommended,
  tseslint.configs.strictTypeChecked,
  tseslint.configs.stylisticTypeChecked,
  ...compat.extends("next/core-web-vitals"),
  ...tailwind.configs["flat/recommended"],
  {
    // tailwindcssに関する設定
    settings: {
      tailwindcss: {
        whitelist: ["hidden-scrollbar", "-webkit-scrollbar"],
      },
    },
  },
  {
    // @typescript-eslintに関する設定
    languageOptions: {
      parser: tseslint.parser,
      parserOptions: {
        project: true,
        tsconfigRootDir: __dirname,
      },
    },
    rules: {
      "@typescript-eslint/consistent-type-definitions": ["error", "type"],
      "@typescript-eslint/no-unsafe-assignment": "off",
      "@typescript-eslint/no-misused-promises": "off",
    },
  },
  {
    // eslint-plugin-importに関する設定
    plugins: {
      import: importPlugin,
    },
    rules: {
      "import/order": [
        "error",
        {
          groups: ["builtin", "external", "internal"],
          alphabetize: { order: "asc", caseInsensitive: true },
        },
      ],
      "import/newline-after-import": "error",
      "import/no-duplicates": "error",
    },
  },
  {
    // eslint-plugin-unused-importsに関する設定
    plugins: {
      "unused-imports": unusedImports,
    },
    rules: {
      "unused-imports/no-unused-imports": "error",
    },
  },
  {
    // その他設定
    files: ["src/**/*.{js,jsx,ts,tsx}"],
    linterOptions: {
      reportUnusedDisableDirectives: "error",
    },
    languageOptions: {
      globals: {
        React: "readonly",
      },
    },
    rules: {
      "react/jsx-boolean-value": "error", // JSXの中でのbooleanの使用
      "react/jsx-curly-brace-presence": "error", // JSXの中での余分な{}の使用
    },
  },
  // prettierとの競合を防ぐためにeslint-config-prettierを読み込む
  eslintConfigPrettier,
)

基本的に公式ドキュメントを参考にしながら進めていきました!
上記から重要そうな部分を説明します!

FlatCompatによる旧設定のマイグレーション

まずはexportの行の上にある部分です!

eslint.config.mjs(抜粋)
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const compat = new FlatCompat({ baseDirectory: __dirname })

ここでは、まだFlat Configに対応していないプラグインのための設定になります!
ESLintのプラグインをそれぞれについて、まだFlat Configに対応できていないものがあります!
(今回で言うと、next/core-web-vitals)
そのプラグインに対して、FlatCompatというものを使うとFlat Config対応できるようになります✨
上記の記述をした上で、...compat.extends("next/core-web-vitals")と記載すれば、ちゃんとルールが効いてくれるようになります💪
詳しくは、公式ドキュメントを確認してみてください。

typescript-eslint

次に、@typescript-eslintに関するカスタム設定の部分です!

eslint.config.mjs(抜粋)
  {
    // @typescript-eslintに関する設定
    languageOptions: {
      parser: tseslint.parser,
      parserOptions: {
        project: true,
        tsconfigRootDir: __dirname,
      },
    },
    rules: {
      "@typescript-eslint/consistent-type-definitions": ["error", "type"],
      "@typescript-eslint/no-unsafe-assignment": "off",
      "@typescript-eslint/no-misused-promises": "off",
    },
  },

languageOptions として上記のような記述を行わないとESLintの実行時にエラーになります🥲
こちらも詳しくは公式ドキュメントを見ていただきたいです🙏

その他のプラグイン

その他のプラグインに関しては、それぞれの公式ドキュメントを見ながら設定を行いました!

例えばeslint-plugin-tailwindcssは、ドキュメントのこのあたりを参考にして、...tailwind.configs["flat/recommended"]とするだけでした✨
プラスアルファで、カスタムしたclassNameを無視するための追加設定を入れました。

eslint.config.mjs(抜粋)
  ...tailwind.configs["flat/recommended"],
  {
    // tailwindcssに関する設定
    settings: {
      tailwindcss: {
        whitelist: ["hidden-scrollbar", "-webkit-scrollbar"],
      },
    },
  },

他の設定も同じような手順で設定を行っていき、無事動作することを確認できました💪

ちなみに、実行コマンドは以降前と同じnext lintです!

おわりに

今回は、Next.jsでのFlat Config対応方法を説明しました!
パッとできるかなーと思ってたら、想像より時間がかかって手こずりました🤮

この記事でそういった方の手助けになれると嬉しいです✨

Xをやっているので、良かったらフォローも宜しくお願いします🙏