Skip to content

Commit 300bfe5

Browse files
[BREAKING] Support ESLint v9 in plugin, config and next lint (#71218)
> [!WARNING] > **Breaking Change:** Now uses `[email protected]` which has a new violation disallowing Component names starting with anything but an uppercase letter. See https://github.com/facebook/react/releases/tag/eslint-plugin-react-hooks%405.0.0 for more details. Adds support of ESLint v9 to `eslint-plugin-next`, `eslint-config-next` and `next lint`. Does not require using the new flat config format. `next lint` will automatically ensure the old config format can be used. ### Why? As `eslint-plugin-react-hooks` has been updated for ESLint v9 support and is a helpful package for Next v15 upgrade, unblock the restrictions to upgrade to ESLint v9. Also, ESLint v8 is [End of Life](https://eslint.org/blog/2024/09/eslint-v8-eol-version-support/#:~:text=ESLint%20v8.-,x%20end%20of%20life%20is%20October%205%2C%202024,x%20on%20October%205%2C%202024.) support since Oct 5th, so is good to unblock v9 now. Plugins bumped: - [x] [@rushstack/eslint-patch](microsoft/rushstack#4719) ([v1.10.3](https://www.npmjs.com/package/@rushstack/eslint-patch/v/1.10.3?activeTab=versions) no release post, confirmed on NPM) - [x] [@typescript-eslint/eslint-plugin](typescript-eslint/typescript-eslint#9002) ([v8.0.0](typescript-eslint/typescript-eslint#9002 (comment))) - [x] [eslint-plugin-import](import-js/eslint-plugin-import#2996) ([v2.31.0](https://github.com/import-js/eslint-plugin-import/releases/tag/v2.31.0)) - [x] [eslint-plugin-jsx-a11y](jsx-eslint/eslint-plugin-jsx-a11y#1009) ([v6.10.0](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/releases/tag/v6.10.0)) - [x] [eslint-plugin-react](jsx-eslint/eslint-plugin-react#3759) ([v7.35.0](https://github.com/jsx-eslint/eslint-plugin-react/releases/tag/v7.35.0)) - [x] [eslint-plugin-react-hooks](facebook/react#28773) ([v5.0.0](https://github.com/facebook/react/releases/tag/eslint-plugin-react-hooks%405.0.0)) We have to switch to ESLint v9 in our repo due to a pnpm bug where it automatically uses ESLint v9 even though we only installed it via `eslint-v9: npm:[email protected]`. This is a pnpm bug that wouldn't happen with Yarn v1, v4 nor NPM. Closes #64409 Closes #64114 Closes #64453 Closes NEXT-3293 --------- Co-authored-by: Sebastian "Sebbie" Silbermann <[email protected]>
1 parent 863168d commit 300bfe5

File tree

67 files changed

+3666
-2332
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+3666
-2332
lines changed

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ packages/next-swc/docs/assets/**/*
4545
test/lib/amp-validator-wasm.js
4646
test/production/pages-dir/production/fixture/amp-validator-wasm.js
4747
test/e2e/async-modules/amp-validator-wasm.js
48+
test/development/next-lint-eslint-formatter-compact/**/*.js
4849

4950
# turbopack crates
5051
turbopack/crates/*/tests/**

.eslintrc.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@
6666
"@typescript-eslint/array-type": "off",
6767
"@typescript-eslint/ban-ts-comment": "off",
6868
"@typescript-eslint/ban-tslint-comment": "off",
69-
"@typescript-eslint/ban-types": "off",
69+
"@typescript-eslint/no-empty-object-type": "off",
70+
"@typescript-eslint/no-restricted-types": "off",
71+
"@typescript-eslint/no-unsafe-function-type": "off",
72+
"@typescript-eslint/no-wrapper-object-types": "off",
7073
"@typescript-eslint/class-literal-property-style": "off",
7174
"@typescript-eslint/consistent-generic-constructors": "off",
7275
"@typescript-eslint/consistent-indexed-object-style": "off",
@@ -77,6 +80,7 @@
7780
"@typescript-eslint/no-empty-interface": "off",
7881
"@typescript-eslint/no-explicit-any": "off",
7982
"@typescript-eslint/no-inferrable-types": "off",
83+
"@typescript-eslint/no-require-imports": "off",
8084
"@typescript-eslint/no-var-requires": "off",
8185
"@typescript-eslint/prefer-for-of": "off",
8286
"@typescript-eslint/prefer-function-type": "off",
@@ -104,6 +108,7 @@
104108
"args": "none",
105109
"ignoreRestSiblings": true,
106110
"argsIgnorePattern": "^_",
111+
"caughtErrors": "none",
107112
"caughtErrorsIgnorePattern": "^_",
108113
"destructuredArrayIgnorePattern": "^_",
109114
"varsIgnorePattern": "^_"
@@ -178,6 +183,7 @@
178183
{
179184
"args": "all",
180185
"argsIgnorePattern": "^_",
186+
"caughtErrors": "none",
181187
"ignoreRestSiblings": true
182188
}
183189
]
@@ -308,6 +314,7 @@
308314
"error",
309315
{
310316
"args": "none",
317+
"caughtErrors": "none",
311318
"ignoreRestSiblings": true
312319
}
313320
],

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ dist
55
target
66
packages/next/wasm/@next
77
tarballs/
8-
packages/next/*.tgz
8+
packages/**/*.tgz
99

1010
# dependencies
1111
node_modules

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"typescript",
1717
"typescriptreact"
1818
],
19+
"eslint.useFlatConfig": false,
1920
// Set Jest runMode to on-demand as otherwise it will start running all tests the first time.
2021
// Equivalent to deprecated option "jest.autoRun": "off"
2122
"jest.runMode": "on-demand",

examples/with-supertokens/app/config/frontend.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import ThirdPartyReact from "supertokens-auth-react/recipe/thirdparty";
22
import EmailPasswordReact from "supertokens-auth-react/recipe/emailpassword";
33
import Session from "supertokens-auth-react/recipe/session";
44
import { appInfo } from "./appInfo";
5-
import { useRouter } from "next/navigation";
5+
import { type useRouter } from "next/navigation";
66
import { SuperTokensConfig } from "supertokens-auth-react/lib/build/types";
77
import { ThirdPartyPreBuiltUI } from "supertokens-auth-react/recipe/thirdparty/prebuiltui";
88
import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui";

lint-staged.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module.exports = {
22
'*.{js,jsx,mjs,ts,tsx,mts}': [
33
'prettier --with-node-modules --ignore-path .prettierignore --write',
4-
'eslint --fix',
4+
'cross-env ESLINT_USE_FLAT_CONFIG=false eslint --config .eslintrc.json --fix',
55
],
66
'*.{json,md,mdx,css,html,yml,yaml,scss}': [
77
'prettier --with-node-modules --ignore-path .prettierignore --write',

package.json

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"git-clean": "git clean -d -x -e node_modules -e packages -f",
3535
"typescript": "tsc --noEmit",
3636
"lint-typescript": "turbo run typescript",
37-
"lint-eslint": "eslint . --ext js,jsx,ts,tsx --config .eslintrc.cli.json --no-eslintrc",
37+
"lint-eslint": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint . --ext js,jsx,ts,tsx --config .eslintrc.cli.json --no-eslintrc",
3838
"lint-ast-grep": "ast-grep scan",
3939
"lint-no-typescript": "run-p prettier-check lint-eslint lint-language",
4040
"types-and-precompiled": "run-p lint-typescript check-precompiled validate-externals-doc",
@@ -121,8 +121,8 @@
121121
"@types/relay-runtime": "14.1.13",
122122
"@types/string-hash": "1.1.1",
123123
"@types/trusted-types": "2.0.3",
124-
"@typescript-eslint/eslint-plugin": "7.16.0",
125-
"@typescript-eslint/parser": "7.16.0",
124+
"@typescript-eslint/eslint-plugin": "8.0.0",
125+
"@typescript-eslint/parser": "8.0.0",
126126
"@vercel/devlow-bench": "workspace:*",
127127
"@vercel/fetch": "6.1.1",
128128
"@vercel/og": "0.6.3",
@@ -144,15 +144,16 @@
144144
"dd-trace": "4.12.0",
145145
"es5-ext": "0.10.53",
146146
"escape-string-regexp": "2.0.0",
147-
"eslint": "8.56.0",
147+
"eslint": "9.12.0",
148148
"eslint-config-next": "workspace:*",
149149
"eslint-formatter-codeframe": "7.32.1",
150150
"eslint-plugin-eslint-plugin": "5.2.1",
151-
"eslint-plugin-import": "2.29.1",
151+
"eslint-plugin-import": "2.31.0",
152152
"eslint-plugin-jest": "27.6.3",
153153
"eslint-plugin-jsdoc": "48.0.4",
154-
"eslint-plugin-react": "7.33.2",
155-
"eslint-plugin-react-hooks": "4.6.0",
154+
"eslint-plugin-react": "7.35.0",
155+
"eslint-plugin-react-hooks": "5.0.0",
156+
"eslint-v8": "npm:eslint@^8.57.0",
156157
"event-stream": "4.0.1",
157158
"execa": "2.0.3",
158159
"expect-type": "0.14.2",

packages/eslint-config-next/package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@
1111
"homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config",
1212
"dependencies": {
1313
"@next/eslint-plugin-next": "15.0.0-canary.190",
14-
"@rushstack/eslint-patch": "^1.3.3",
14+
"@rushstack/eslint-patch": "^1.10.3",
1515
"@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
1616
"@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
1717
"eslint-import-resolver-node": "^0.3.6",
1818
"eslint-import-resolver-typescript": "^3.5.2",
19-
"eslint-plugin-import": "^2.28.1",
20-
"eslint-plugin-jsx-a11y": "^6.7.1",
21-
"eslint-plugin-react": "^7.33.2",
22-
"eslint-plugin-react-hooks": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705"
19+
"eslint-plugin-import": "^2.31.0",
20+
"eslint-plugin-jsx-a11y": "^6.10.0",
21+
"eslint-plugin-react": "^7.35.0",
22+
"eslint-plugin-react-hooks": "^5.0.0"
2323
},
2424
"peerDependencies": {
25-
"eslint": "^7.23.0 || ^8.0.0",
25+
"eslint": "^7.23.0 || ^8.0.0 || ^9.0.0",
2626
"typescript": ">=3.3.1"
2727
},
2828
"peerDependenciesMeta": {

packages/next/src/cli/next-lint.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,23 @@ export type NextLintOptions = {
2323
config?: string
2424
dir?: string[]
2525
errorOnUnmatchedPattern?: boolean
26-
ext: string[]
2726
file?: string[]
2827
fix?: boolean
2928
fixType?: string
3029
format?: string
3130
ignore: boolean
32-
ignorePath?: string
33-
inlineConfig: boolean
34-
maxWarnings: number
3531
outputFile?: string
3632
quiet?: boolean
33+
strict?: boolean
34+
// TODO(jiwon): ESLint v9 unsupported options
35+
// we currently delete them at `runLintCheck` when used in v9
36+
ext: string[]
37+
ignorePath?: string
3738
reportUnusedDisableDirectivesSeverity: 'error' | 'off' | 'warn'
3839
resolvePluginsRelativeTo?: string
3940
rulesdir?: string
40-
strict?: boolean
41+
inlineConfig: boolean
42+
maxWarnings: number
4143
}
4244

4345
const eslintOptions = (

packages/next/src/compiled/assert/assert.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)