逆引きマニュアル: ESLint v9 への移行

投稿日:

やりたいこと

ESLint v9のFlat Configに対応する。

前提条件

  • ESLint v8を使用している(v8.57.0が望ましい)
  • ESLintの設定ファイル名として .eslintrc.cjs を使用している
  • 移行後はESMを使用する
  • パッケージマネージャはpnpmを使用している

概要

ESLint v9からはFlat Configが導入された。これにより、設定ファイルをArray形式で書くことができるようになったが、これに伴い多くのオプションが変更されている。

移行手順は基本的にガイドに従って進めれば問題ないと思われる。

手順

ESLINT_USE_FLAT_CONFIG=trueをつけて実行

まずはv8で ESLINT_USE_FLAT_CONFIG=true をつけてESLintを実行する。

# eslint以降は既存のオプションをそのまま使う
ESLINT_USE_FLAT_CONFIG=true eslint . --ext .js --ext .ts --ext .tsx --ext .jsx --ext .cjs

エラーが出たら対応していく。

--ext を外す

--ext はFlat Configには対応していないため外す。

# --extを外す
ESLINT_USE_FLAT_CONFIG=true eslint .

--format を使っている場合

--format でサポートされなくなったフォーマットがある。この場合はv9で動かなくなるため(ESLINT_USE_FLAT_CONFIG=true だけでは検知できない)、適切なライブラリを追加する。例えば --format junit の場合、次のライブラリを追加する。

pnpm i -D eslint-formatter-junit

ファイル名の変更 + ESM形式に変更

以下のようなエラーが出る。

> ESLINT_USE_FLAT_CONFIG=true eslint .


Oops! Something went wrong! :(

ESLint: 8.57.0

Error: Could not find config file.

ファイル名を .eslintrc.cjs から eslint.config.js ("type": "module" の場合)あるいは eslint.config.mjs に変更する。

単にファイル名を変更しただけだと、以下のようなエラーが出る。ESMになっていないのが原因。

> ESLINT_USE_FLAT_CONFIG=true eslint .


Oops! Something went wrong! :(

ESLint: 8.57.0

ReferenceError: module is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '/path/to/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.

このようになっているのを

module.exports = {
  // 中略
};

このように変更する。ESM形式に変更した上で、後々のことを考えてさらにArrayにする。

export default [
  {
    // 中略
  }
];

“env” を “globals” に変更

env はFlat Configには対応していないため、 globals に変更する。

まず globals をインストールする。

pnpm i -D globals

変更前

export default [
  {
    env: {
      browser: true,
      es2021: true,
      node: true,
    }
    // 以下略
  }
];

変更後

import globals from "globals";

export default [
  {
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.es2021,
        ...globals.node,
      }
    }
    // 以下略
  }
];

extends を修正

次は extends を修正する。

> ESLINT_USE_FLAT_CONFIG=true eslint .


Oops! Something went wrong! :(

ESLint: 8.57.0

A config object is using the "extends" key, which is not supported in flat config system.

Instead of "extends", you can include config objects that you'd like to extend from directly in the flat config array.

Please see the following page for more information:
https://eslint.org/docs/latest/use/configure/migration-guide#predefined-and-shareable-configs

使っているライブラリによるが、今回は次の設定を前提。

extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"]

まずエラーのリンク先にあるように eslint:recommended の代わりとしては @eslint/js をインストールする。また型定義をインストールする。

pnpm i -D @eslint/js @types/eslint__js

同様に、 plugin:@typescript-eslint/recommended の代わりとしては typescript-eslint をインストールする。また、 @typescript-eslint/eslint-plugin@typescript-eslint/parser は不要になるため削除する。

pnpm i -D typescript-eslint
pnpm remove -D @typescript-eslint/eslint-plugin @typescript-eslint/parser

そして次のように修正する。

import eslint from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";

export default [
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  {
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.es2021,
        ...globals.node,
      }
    }
    // 以下略
  }
];

overrides を修正

次はこのエラーを対応する。

> ESLINT_USE_FLAT_CONFIG=true eslint .


Oops! Something went wrong! :(

ESLint: 8.57.0

A config object is using the "overrides" key, which is not supported in flat config system.

Flat config is an array that acts like the eslintrc "overrides" array.

Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#glob-based-configs

overrides はFlat Configには対応していないため、 overrides を削除する。ただし自分は overrides: [] となっていて使っていないので、単に削除。

parsers を修正

次はこのエラーを対応する。

> ESLINT_USE_FLAT_CONFIG=true eslint .


Oops! Something went wrong! :(

ESLint: 8.57.0

A config object is using the "parser" key, which is not supported in flat config system.

Flat config uses "languageOptions.parser" to override the default parser.

Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#custom-parsers

parser: "@typescript-eslint/parser" となっているが、この記述は typescript-eslint によって不要になるため削除する。

parserOptions を修正

次はこのエラーを対応する。

> ESLINT_USE_FLAT_CONFIG=true eslint .


Oops! Something went wrong! :(

ESLint: 8.57.0

A config object is using the "parserOptions" key, which is not supported in flat config system.

Flat config uses "languageOptions.parserOptions" to specify parser options.

Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#configuring-language-options

parserOptionslanguageOptions の中に入れる。

変更前

import globals from "globals";

export default [
  {
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.es2021,
        ...globals.node,
      },
    },
    parserOptions: {
      ecmaVersion: "latest",
      sourceType: "module",
    }
    // 以下略
  }
];

変更後

import eslint from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";

export default [
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  {
    languageOptions: {
      ecmaVersion: "latest",
      sourceType: "module",
      globals: {
        ...globals.browser,
        ...globals.es2021,
        ...globals.node,
      },
    }
    // 以下略
  }
];

plugins を修正

次はこのエラーを対応する。

> ESLINT_USE_FLAT_CONFIG=true eslint .


Oops! Something went wrong! :(

ESLint: 8.57.0


A config object has a "plugins" key defined as an array of strings.

Flat config requires "plugins" to be an object in this form:

    {
        plugins: {
            @typescript-eslint: pluginObject
        }
    }

Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#importing-plugins-and-custom-parsers

If you're using a shareable config that you cannot rewrite in flat config format, then use the compatibility utility:
https://eslint.org/docs/latest/use/configure/migration-guide#using-eslintrc-configs-in-flat-config

plugins: ["@typescript-eslint"] となっているが、この記述は parsers と同様に、 typescript-eslint によって不要になるため削除する。

その他、 plugins はArrayではなくObjectに変更する必要がある。

eslint-plugin-simple-import-sort の場合

移行前は次のようになっている。

module.exports = {
  // 中略
  plugins: ["simple-import-sort"], // その他のプラグインは省略
  rules: {
    "simple-import-sort/imports": "error",
    "simple-import-sort/exports": "error",
  },
};

これを次のように変更する。

import eslint from "@eslint/js";
// プラグインのインポート
import simple_import_sort from "eslint-plugin-simple-import-sort";
import globals from "globals";
import tseslint from "typescript-eslint";

export default [
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  {
    // その他の設定は省略
    // pluginsをObjectに変更
    plugins: {
      "simple-import-sort": simple_import_sort,
    },
    // rulesはそのまま
    rules: {
      "simple-import-sort/imports": "error",
      "simple-import-sort/exports": "error",
    },
  },
];

ignorePatterns を修正

次はこのエラーを対応する。

> ESLINT_USE_FLAT_CONFIG=true eslint .


Oops! Something went wrong! :(

ESLint: 8.57.0

A config object is using the "ignorePatterns" key, which is not supported in flat config system.

Flat config uses "ignores" to specify files to ignore.

Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#ignoring-files

ignorePatternsignores に変更する。

変更前

export default [
  {
    ignorePatterns: ["dist"]
    // 以下略
  }
];

変更後

export default [
  {
    // その他の設定は省略
  },
  {
    ignores: ["dist"]
  }
];

注意点としては独立したオブジェクトとして指定しないといけない。

新しく出るようになったエラーをignoresで対応する

これで ESLINT_USE_FLAT_CONFIG=true eslint . が通るようになるが、新しくエラーが出るようになる。

原因はIgnoring Filesによると、ドットで始まるファイル名 / ディレクトリ名がデフォルトで無視されなくなったため。

In flat config , dotfiles (e.g. .dotfile.js) are no longer ignored by default. If you want to ignore dotfiles, add an ignore pattern of “**/.*”.

その場合はエラーが出るファイル名を確認する。ドットで始まるファイル名 / ディレクトリ名がある場合は、 ignores に追加する。

import eslint from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";

export default [
  eslint.configs.recommended,
  ...tseslint.configs.recommended,
  {
    languageOptions: {
      ecmaVersion: "latest",
      sourceType: "module",
      globals: {
        ...globals.browser,
        ...globals.es2021,
        ...globals.node,
      },
    },
    rules: {},
  },
  {
    ignores: [".astro", "dist"],
  },
];

動作確認

最後に ESLINT_USE_FLAT_CONFIG=true eslint . --debug で動作確認を行い、問題がなければ移行完了。

ESLINT_USE_FLAT_CONFIG=true eslint . --debug

v9へのアップデートとESLINT_USE_FLAT_CONFIGの削除

最後に eslint をアップデートし、 ESLINT_USE_FLAT_CONFIG を削除する。

補足

マニュアル

  • eslint: まだありません。