next.js
907721a6 - eslint-config-next: support ESLint 10 (#99628)

Commit
5 days ago
eslint-config-next: support ESLint 10 (#99628) ## Summary `eslint-config-next` crashes under ESLint 10. This makes it work with both ESLint 9 and 10 without raising Next.js's Node.js minimum (`>=20.9.0`). ESLint 10 itself requires Node.js `^20.19.0 || ^22.13.0 || >=24`, so users on older Node.js 20 versions keep using ESLint 9. ### Upgraded Dependencies that already have releases declaring ESLint 10 support: - `typescript-eslint` `^8.46.0` → `^8.56.0` - `eslint-plugin-react-hooks` `^7.0.0` → `^7.1.0`. 7.1 removed the deprecated `react-hooks/component-hook-factories` rule (now a no-op) from its recommended config, so it's no longer enabled. Fresh installs of the previous `^7.0.0` range already get this version. ### Patched Dependencies with no ESLint 10–compatible release that Next.js can use. The plugin versions below are their latest releases. Their behavior is adapted in `eslint-config-next`; the patches do nothing under ESLint 9. - **Babel parser** (`@babel/eslint-parser` 7.24.6, bundled in `next`): ESLint 10 registers configured and inline (`/* global */`) globals through `scopeManager.addGlobals()`, which this parser's scope manager doesn't have (`TypeError: scopeManager.addGlobals is not a function`). `eslint-config-next/parser` adds it, doing the same scope maintenance ESLint 9 did itself. Babel 8's parser supports ESLint 10 but requires Node.js `^22.18 || >=24.11`. The parser comes from the user's installed `next`, so the method is only added when it's missing. - **`eslint-plugin-react`** (7.37.5) and **`eslint-plugin-import`** (2.32.0): ESLint 10 removed the rule context members `getCwd()`, `getFilename()`, `getPhysicalFilename()`, `getSourceCode()`, `parserOptions` and `parserPath`. `eslint-plugin-react` calls them for `settings.react.version: 'detect'`, and rules such as `import/no-default-export` read `parserOptions`. The rules are patched in place to restore these members, so the plugin objects keep their identity; a wrapped copy breaks configs that also use the plugin's own configs (`Cannot redefine plugin "react"`). - **Import resolvers**: `eslint-plugin-import` loads the configured resolvers by name from the linted file. With ESLint 10, npm doesn't hoist `eslint-plugin-import` and `eslint-import-resolver-typescript` because of the plugin's peer range, so the lookup falls back to the `typescript` package (`Resolve error: typescript with invalid interface loaded as resolver`) and rules such as `import/no-unresolved` can't resolve TypeScript path aliases. The resolvers are referenced by their resolved paths again, as before the flat config rewrite (#84874). As in v15, a user's own `import/resolver` entries are used in addition to these rather than replacing them. ### Unchanged - `eslint-plugin-jsx-a11y` (6.10.2) and `@next/eslint-plugin-next` don't use the removed APIs, and `eslint-plugin-react-hooks` falls back to their replacements. - `eslint-plugin-jsx-a11y` 6.10.2 is its latest release, so there's no newer version to upgrade to. ### Other - **Docs**: ESLint 10 support, its Node.js requirement, and the peer dependency warnings. - **Build**: `@types/node` added as a dev dependency with `"types": ["node"]`, since TypeScript 6 no longer includes `@types` packages automatically and the config now uses `require.resolve`. ### Known limitations `eslint-plugin-react`, `eslint-plugin-import` and `eslint-plugin-jsx-a11y` don't list ESLint 10 in their peer dependencies yet. Until they publish releases that do: - Installs with ESLint 10 show peer dependency warnings (`npm warn ERESOLVE overriding peer dependency`, pnpm `unmet peer`), but succeed and lint correctly. - Installs with strict peer dependencies fail. - With npm, projects that list `eslint-plugin-react` as a direct dependency fail with `ERESOLVE` unless installed with `--legacy-peer-deps` or `--force`, because npm treats peer conflicts in the project's own dependencies as errors. ## Verification - New `test/production/eslint-config-next` test, which installs the packed config with ESLint 9.37.0 and 10.11.0 and requires both to report the same diagnostics for a JavaScript project (Babel parser) and a TypeScript project (typescript-eslint parser). A third case installs with npm and ESLint 10, where the plugins and resolvers are nested under `eslint-config-next`. Disabling each patch in the ESLint 10 installs makes ESLint crash, throw a config error, or fail to resolve imports, so the test fails. - CI runs the test on Node.js 20.9.0. <!-- NEXT_JS_LLM -->
Author
Parents
Loading