Skip to content

Commit 8f9b45c

Browse files
authored
feat: add Next.js support (#731)
1 parent 652110c commit 8f9b45c

File tree

12 files changed

+136
-2
lines changed

12 files changed

+136
-2
lines changed

README.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
- Designed to work with TypeScript, JSX, Vue, JSON, YAML, Toml, Markdown, etc. Out-of-box.
88
- Opinionated, but [very customizable](#customization)
99
- [ESLint Flat config](https://eslint.org/docs/latest/use/configure/configuration-files-new), compose easily!
10-
- Optional [React](#react), [Svelte](#svelte), [UnoCSS](#unocss), [Astro](#astro), [Solid](#solid) support
10+
- Optional [React](#react), [Next.js](#nextjs), [Svelte](#svelte), [UnoCSS](#unocss), [Astro](#astro), [Solid](#solid) support
1111
- Optional [formatters](#formatters) support for formatting CSS, HTML, XML, etc.
1212
- **Style principle**: Minimal for reading, stable for diff, consistent
1313
- Sorted imports, dangling commas
@@ -623,6 +623,25 @@ Running `npx eslint` should prompt you to install the required dependencies, oth
623623
npm i -D @eslint-react/eslint-plugin eslint-plugin-react-hooks eslint-plugin-react-refresh
624624
```
625625

626+
#### Next.js
627+
628+
To enable Next.js support, you need to explicitly turn it on:
629+
630+
```js
631+
// eslint.config.js
632+
import antfu from '@antfu/eslint-config'
633+
634+
export default antfu({
635+
nextjs: true,
636+
})
637+
```
638+
639+
Running `npx eslint` should prompt you to install the required dependencies, otherwise, you can install them manually:
640+
641+
```bash
642+
npm i -D @next/eslint-plugin-next
643+
```
644+
626645
#### Svelte
627646

628647
To enable svelte support, you need to explicitly turn it on:

eslint.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export default antfu(
99
solid: true,
1010
svelte: true,
1111
astro: true,
12+
nextjs: true,
1213
typescript: true,
1314
formatters: true,
1415
pnpm: true,

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
},
4545
"peerDependencies": {
4646
"@eslint-react/eslint-plugin": "^1.38.4",
47+
"@next/eslint-plugin-next": "^15.4.0-canary.115",
4748
"@prettier/plugin-xml": "^3.4.1",
4849
"@unocss/eslint-plugin": ">=0.50.0",
4950
"astro-eslint-parser": "^1.0.2",
@@ -63,6 +64,9 @@
6364
"@eslint-react/eslint-plugin": {
6465
"optional": true
6566
},
67+
"@next/eslint-plugin-next": {
68+
"optional": true
69+
},
6670
"@prettier/plugin-xml": {
6771
"optional": true
6872
},
@@ -146,6 +150,7 @@
146150
"@antfu/ni": "catalog:dev",
147151
"@eslint-react/eslint-plugin": "catalog:peer",
148152
"@eslint/config-inspector": "catalog:dev",
153+
"@next/eslint-plugin-next": "catalog:peer",
149154
"@prettier/plugin-xml": "catalog:peer",
150155
"@types/node": "catalog:dev",
151156
"@unocss/eslint-plugin": "catalog:peer",

pnpm-lock.yaml

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

pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ catalogs:
2525
vitest: ^3.2.4
2626
peer:
2727
'@eslint-react/eslint-plugin': ^1.52.3
28+
'@next/eslint-plugin-next': ^15.4.0-canary.115
2829
'@prettier/plugin-xml': ^3.4.2
2930
'@unocss/eslint-plugin': ^66.3.3
3031
astro-eslint-parser: ^1.2.2

scripts/typegen.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import fs from 'node:fs/promises'
33
import { flatConfigsToRulesDTS } from 'eslint-typegen/core'
44
import { builtinRules } from 'eslint/use-at-your-own-risk'
55

6-
import { astro, combine, comments, formatters, imports, javascript, jsdoc, jsonc, jsx, markdown, node, perfectionist, react, regexp, solid, sortPackageJson, stylistic, svelte, test, toml, typescript, unicorn, unocss, vue, yaml } from '../src'
6+
import { astro, combine, comments, formatters, imports, javascript, jsdoc, jsonc, jsx, markdown, nextjs, node, perfectionist, react, regexp, solid, sortPackageJson, stylistic, svelte, test, toml, typescript, unicorn, unocss, vue, yaml } from '../src'
77

88
const configs = await combine(
99
{
@@ -24,6 +24,7 @@ const configs = await combine(
2424
markdown(),
2525
node(),
2626
perfectionist(),
27+
nextjs(),
2728
react(),
2829
solid(),
2930
sortPackageJson(),

src/cli/constants-generated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export const versionsMap = {
22
"@eslint-react/eslint-plugin": "^1.52.3",
3+
"@next/eslint-plugin-next": "^15.4.0-canary.115",
34
"@unocss/eslint-plugin": "^66.3.3",
45
"astro-eslint-parser": "^1.2.2",
56
"eslint": "^9.31.0",

src/cli/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ export const dependenciesMap = {
108108
formatterAstro: [
109109
'prettier-plugin-astro',
110110
],
111+
nextjs: [
112+
'@next/eslint-plugin-next',
113+
],
111114
react: [
112115
'@eslint-react/eslint-plugin',
113116
'eslint-plugin-react-hooks',

src/configs/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export * from './jsdoc'
1010
export * from './jsonc'
1111
export * from './jsx'
1212
export * from './markdown'
13+
export * from './nextjs'
1314
export * from './node'
1415
export * from './perfectionist'
1516
export * from './pnpm'

src/configs/nextjs.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import type { OptionsFiles, OptionsOverrides, TypedFlatConfigItem } from '../types'
2+
import { GLOB_SRC } from '../globs'
3+
import { ensurePackages, interopDefault } from '../utils'
4+
5+
function normalizeRules(rules: Record<string, any>): Record<string, any> {
6+
return Object.fromEntries(
7+
Object.entries(rules).map(([key, value]) =>
8+
[key, typeof value === 'string' ? [value] : value],
9+
),
10+
)
11+
}
12+
13+
export async function nextjs(
14+
options: OptionsOverrides & OptionsFiles = {},
15+
): Promise<TypedFlatConfigItem[]> {
16+
const {
17+
files = [GLOB_SRC],
18+
overrides = {},
19+
} = options
20+
21+
await ensurePackages([
22+
'@next/eslint-plugin-next',
23+
])
24+
25+
const pluginNextJS = await interopDefault(import('@next/eslint-plugin-next'))
26+
27+
return [
28+
{
29+
name: 'antfu/nextjs/setup',
30+
plugins: {
31+
'@next/next': pluginNextJS,
32+
},
33+
},
34+
{
35+
files,
36+
languageOptions: {
37+
parserOptions: {
38+
ecmaFeatures: {
39+
jsx: true,
40+
},
41+
},
42+
sourceType: 'module',
43+
},
44+
rules: {
45+
...normalizeRules(pluginNextJS.configs.recommended.rules),
46+
...normalizeRules(pluginNextJS.configs['core-web-vitals'].rules),
47+
48+
// overrides
49+
...overrides,
50+
},
51+
settings: {
52+
react: {
53+
version: 'detect',
54+
},
55+
},
56+
},
57+
]
58+
}

0 commit comments

Comments
 (0)