Capítulo 266 de 456

ESLint

Core Idea

eslint-config-next é o pacote de configuração ESLint oficial do Next.js, agrupando regras de @next/eslint-plugin-next, eslint-plugin-react e eslint-plugin-react-hooks. Desde a v16, next lint foi removido, o setup e execução agora passam pela CLI padrão do ESLint (flat config).

Key Concepts

  • eslint-config-next: config base com regras Next.js/React/React Hooks, suporta JS e TS.
  • eslint-config-next/core-web-vitals: tudo da base, mais upgrade de regras que afetam Core Web Vitals de warning para error; recomendada para a maioria dos projetos, e incluída automaticamente em apps novos do create-next-app.
  • eslint-config-next/typescript: regras TypeScript-specific via typescript-eslint, usada junto da base ou do core-web-vitals; adicionada automaticamente por create-next-app --typescript.
  • next lint removido na v16: a opção eslint no next.config.js também foi removida; existe um codemod (migrate-from-next-lint-to-eslint-cli) para migrar.
  • rootDir (settings.next): aponta @next/eslint-plugin-next para onde o app Next.js vive, necessário em monorepos onde Next.js não está na raiz do projeto.

Code Examples

import { defineConfig, globalIgnores } from 'eslint/config'
import nextVitals from 'eslint-config-next/core-web-vitals'

const eslintConfig = defineConfig([
  ...nextVitals,
  globalIgnores(['.next/**', 'out/**', 'build/**', 'next-env.d.ts']),
])

export default eslintConfig
  • O que demonstra: setup mínimo recomendado, flat config com core-web-vitals e os ignores default reaplicados manualmente.
import { defineConfig, globalIgnores } from 'eslint/config'
import nextVitals from 'eslint-config-next/core-web-vitals'
import nextTs from 'eslint-config-next/typescript'
import prettier from 'eslint-config-prettier/flat'

const eslintConfig = defineConfig([
  ...nextVitals,
  ...nextTs,
  prettier,
  {
    rules: {
      'react/no-unescaped-entities': 'off',
      '@next/next/no-page-custom-font': 'off',
    },
  },
  globalIgnores(['.next/**', 'out/**', 'build/**', 'next-env.d.ts']),
])

export default eslintConfig
  • O que demonstra: composição completa: core-web-vitals + TypeScript rules + integração com Prettier + override de regras individuais desabilitadas.
import { defineConfig } from 'eslint/config'
import eslintNextPlugin from '@next/eslint-plugin-next'

const eslintConfig = defineConfig([
  {
    files: ['**/*.{js,jsx,ts,tsx}'],
    plugins: { next: eslintNextPlugin },
    settings: { next: { rootDir: 'packages/my-app/' } },
  },
])

export default eslintConfig
  • O que demonstra: uso do plugin diretamente (sem eslint-config-next) num monorepo, apontando rootDir para o app real; útil quando já há plugins conflitantes (react, react-hooks, jsx-a11y, import) ou parserOptions customizados.
const path = require('path')

const buildEslintCommand = (filenames) =>
  `eslint --fix ${filenames.map((f) => `"${path.relative(process.cwd(), f)}"`).join(' ')}`

module.exports = {
  '*.{js,jsx,ts,tsx}': [buildEslintCommand],
}
  • O que demonstra: integração com lint-staged para rodar lint só em arquivos staged do git.

Reference Tables

Regras @next/eslint-plugin-next (todas marcadas ✓ no recommended config): google-font-display, google-font-preconnect, inline-script-id, next-script-for-ga, no-assign-module-variable, no-async-client-component, no-before-interactive-script-outside-document, no-css-tags, no-document-import-in-page, no-duplicate-head, no-head-element, no-head-import-in-document, no-html-link-for-pages, no-img-element, no-page-custom-font, no-script-component-in-head, no-styled-jsx-in-document, no-sync-scripts, no-title-in-document-head, no-typos, no-unwanted-polyfillio.

VersionChanges
v16.0.0next lint e a opção eslint do next.config.js removidos, em favor da CLI do ESLint. Codemod disponível para migração.

Anti-patterns

  • Usar eslint-config-next completo quando já se tem react/react-hooks/jsx-a11y/import configurados via outro preset (ex. airbnb): gera conflito; use @next/eslint-plugin-next diretamente nesse caso.
  • Não reaplicar os globalIgnores default ao spreadar eslint-config-next: as configs flat não herdam ignores automaticamente do jeito que .eslintignore fazia; é preciso declarar .next/**, out/**, build/**, next-env.d.ts explicitamente.
  • Misturar ESLint com regras de formatação e Prettier sem eslint-config-prettier: gera conflitos de regra; adicionar prettier (de eslint-config-prettier/flat) por último na lista da config.

Key Takeaways

  1. Desde a v16, não existe mais next lint: a única forma suportada é eslint puro via CLI, com eslint-config-next fornecendo as regras.
  2. core-web-vitals é o preset recomendado para a maioria dos projetos (upgrade de warning para error nas regras que afetam métricas de performance).
  3. Em monorepo, prefira settings.next.rootDir (path, glob, ou array de ambos) para o plugin achar a app Next.js real.
  4. Ordem importa em flat config: regras posteriores no array sobrescrevem as anteriores para os mesmos arquivos.

Connects To

  • create-next-app: gera o eslint.config.mjs inicial automaticamente com core-web-vitals (e typescript se --typescript).
  • codemods (upgrading/codemods): ferramenta de migração de next lint para ESLint CLI puro.