この記事について
当記事は、ESLint v9とNext.js 15の組み合わせに由来すると思われるエラーへのworkaround(暫定対応)を説明します。
注意
当記事の内容は2025/06/22時点での暫定対応であり、Next.js公式やESLint公式が発表する対処方法ではありません。今後のアップデートで解消される可能性が高いです。
概要
Next.js 15導入済みプロジェクトに対して、ESLint v9でlintを実行すると、以下のエラーが発生。
Error: Failed to patch ESLint because the calling module was not recognized.If you are using a newer ESLint version that may be unsupported, please create a GitHub issue:
PS D:\05_experiment\payload-template-eslint-error\xpicks> pnpx eslint --fix-dry-run
Oops! Something went wrong! :(
ESLint: 9.29.0
Error: Cannot read config file: D:\05_experiment\payload-template-eslint-error\xpicks\node_modules\.pnpm\eslint-config-next@15.3.0_e_c6e9941d6a1be25bc046eca583a699f1\node_modules\eslint-config-next\index.js
Error: Failed to patch ESLint because the calling module was not recognized.
If you are using a newer ESLint version that may be unsupported, please create a GitHub issue:
https://github.com/microsoft/rushstack/issues
Referenced from: D:\05_experiment\payload-template-eslint-error\xpicks\node_modules\.pnpm\eslint-config-next@15.3.0_e_c6e9941d6a1be25bc046eca583a699f1\node_modules\eslint-config-next\core-web-vitals.js
at Object.<anonymous> (D:\05_experiment\payload-template-eslint-error\xpicks\node_modules\.pnpm\@rushstack+eslint-patch@1.11.0\node_modules\@rushstack\eslint-patch\lib\_patch-base.js:167:19)
at Module._compile (node:internal/modules/cjs/loader:1730:14)
at Object..js (node:internal/modules/cjs/loader:1895:10)
at Module.load (node:internal/modules/cjs/loader:1465:32)
at Function._load (node:internal/modules/cjs/loader:1282:12)
at TracingChannel.traceSync (node:diagnostics_channel:322:14)
at wrapModuleLoad (node:internal/modules/cjs/loader:235:24)
at Module.require (node:internal/modules/cjs/loader:1487:12)
at require (node:internal/modules/helpers:135:16)
at Object.<anonymous> (D:\05_experiment\payload-template-eslint-error\xpicks\node_modules\.pnpm\@rushstack+eslint-patch@1.11.0\node_modules\@rushstack\eslint-patch\lib\modern-module-resolution.js:11:23)
環境
| 項目 | 名前 |
|---|---|
| OS | Windows 11 |
| Node.jsバージョン | v22.15.1 |
| パッケージ管理ツール | pnpm(10.11.1) |
| ESLintバージョン | v9.29.0 |
| Next.jsバージョン | 15.3.0 |
背景(再現手順)
Payload CMSのcreate-payload-appでプロジェクトを作成後、lintをかけたら再現しました。
$ pnpx create-payload-app
$ cd ./project_name
$ pnpx eslint --fix-dry-run
想定原因
どうもnext/core-web-vitals がESLint 9に対応しきれていないっぽい?
下のIssueで、eslint-config-nextとの関連性が議論されています。
対策
next/core-web-vitalsとnext/typescriptの読み込み方法を変更します。
手順1:ESLintプラグインをインストール
$ pnpm install @next/eslint-plugin-next --save-dev
$ pnpm install @typescript-eslint/eslint-plugin@latest --save-dev
手順2:eslint.config.mjs 修正
修正箇所
import { dirname } from 'path'
import { fileURLToPath } from 'url'
import { FlatCompat } from '@eslint/eslintrc'
+import nextPlugin from '@next/eslint-plugin-next'
const eslintConfig = [
- ...compat.extends('next/core-web-vitals', 'next/typescript'),
+ {
+ name: 'next/core-web-vitals',
+ plugins: {
+ '@next/next': nextPlugin,
+ },
+ rules: {
+ ...nextPlugin.configs.recommended.rules,
+ ...nextPlugin.configs['core-web-vitals'].rules,
+ },
+ },
+ ...compat.extends('next/typescript'),
修正後のeslint.config.mjs
import { dirname } from 'path'
import { fileURLToPath } from 'url'
import { FlatCompat } from '@eslint/eslintrc'
import nextPlugin from '@next/eslint-plugin-next'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const compat = new FlatCompat({
baseDirectory: __dirname,
})
const eslintConfig = [
{
name: 'next/core-web-vitals',
plugins: {
'@next/next': nextPlugin,
},
rules: {
...nextPlugin.configs.recommended.rules,
...nextPlugin.configs['core-web-vitals'].rules,
},
},
...compat.extends('next/typescript'),
{
rules: {
'@typescript-eslint/ban-ts-comment': 'warn',
'@typescript-eslint/no-empty-object-type': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': [
'warn',
{
vars: 'all',
args: 'after-used',
ignoreRestSiblings: false,
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
destructuredArrayIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^(_|ignore)',
},
],
},
},
{
ignores: ['.next/'],
},
]
export default eslintConfig
手順3:修正確認
lintの実行結果が表示されれば成功!
$ pnpx eslint --fix-dry-run
D:\05_experiment\nextjs15-eslint9-bug\test\src\Header\Component.client.tsx
24:5 error Definition for rule 'react-hooks/exhaustive-deps' was not found react-hooks/exhaustive-deps
29:5 error Definition for rule 'react-hooks/exhaustive-deps' was not found react-hooks/exhaustive-deps
D:\05_experiment\nextjs15-eslint9-bug\test\src\collections\Posts\hooks\populateAuthors.ts
8:71 warning 'req' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars
D:\05_experiment\nextjs15-eslint9-bug\test\src\utilities\useClickableCard.ts
52:5 error Definition for rule 'react-hooks/exhaustive-deps' was not found react-hooks/exhaustive-deps
74:5 error Definition for rule 'react-hooks/exhaustive-deps' was not found react-hooks/exhaustive-deps
95:5 error Definition for rule 'react-hooks/exhaustive-deps' was not found react-hooks/exhaustive-deps
✖ 6 problems (5 errors, 1 warning)
おわりに
たかだかlintかけるだけなのに、結構な労力を使ってしまいました…
TypeScriptのライブラリバージョン管理の難しさは時に理不尽さを感じます。
これが個人開発ならESLintのエラーに1日費やしても笑って済ませられますが、実務でそれやったら「え、環境構築も出来ないの?」って思われかねないなと思いました。
その意味では、実務では迂闊にバージョンを上げられませんね…
また、これを機にBiomeに切り替えようかとも考えたのですが、まだNext.jsへの対応が終わっていないようなので一旦諦めました。
それと、この問題の解消をCursorにお願いしたら、「万策尽きました。」とか言って匙を投げて笑いました。
