Search code examples
next.jseslintprettier

Next.js 12 Migration and Eslint configuration with Prettier, Airbnb, Jest/react-testing-library


UPDATE: Finally got the config and dep versions to work. I updated my files below in case someone else is having the same issues.

I'm migrating a large app from Next.js 10 to v12. I had minor babel configuration, so decided to remove that, while also using Next.js's linter next lint. We initially used prettier and airbnb eslint plugins. Instead of the eslint-plugin-airbnb, I'm using eslint-plugin-airbnb-base. The reason being eslint-config-next already contains ESLint rules/plugins for eslint, eslint-plugin-import, eslint-plugin-react, eslint-plugin-react-hooks, and eslint-plugin-jsx-a11y, which is basically airbnb

My issue:

  1. I have a small .prettierrc.js file, but the rules are not being applied. ie: printwidth: 80
  2. FIXED: Also getting this error Error: Definition for rule 'jest/expect-expect' was not found

I've been going in circles, some eyes or feedback would be greatly appreciated.

.eslintrc.json

module.exports = {
  root: true,
  plugins: ['simple-import-sort', 'unused-imports'],
  extends: [
    'next',
    'next/core-web-vitals',
    'plugin:jest/recommended',
    'plugin:prettier/recommended',
  ],
  settings: {
    'import/resolver': {
      alias: {
        map: [['@', './']],
        extensions: ['.js', '.jsx', '.ts', '.tsx'],
      },
    },
  },
  rules: { {.....},
 "overrides: { ... typescript overrides },

jest.config.js

const nextJest = require('next/jest');

const createJestConfig = nextJest({ 
  dir: './'
})

const customConfig = {
  rootDir: './',
  moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx'],
  setupFilesAfterEnv: ['<rootDir>/test-utils/jest-setup.ts'],
  moduleNameMapper: {
    '@/(.*)$': '<rootDir>/$1',
  },
  moduleDirectories: ['node_modules', '<rootDir>/'],
  testEnvironment: 'jest-environment-jsdom',
};

module.exports = createJestConfig(customConfig);

prettierrc

module.exports = {
  bracketSpacing: true,
  printWidth: 80,
  singleQuote: true,
  trailingComma: 'es5',
  arrowParens: 'avoid',
};

package.json

  "devDependencies": {
    "@cypress/code-coverage": "^3.9.10",
    "@hookform/devtools": "^4.0.1",
    "@next/eslint-plugin-next": "^12.3.1",
    "@swc/core": "^1.3.3",
    "@swc/jest": "^0.2.23",
    "@testing-library/cypress": "^8.0.0",
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.2.0",
    "@testing-library/react-hooks": "^8.0.1",
    "@types/autosuggest-highlight": "^3.1.1",
    "@types/cookie": "^0.4.1",
    "@types/geojson": "^7946.0.8",
    "@types/google.maps": "^3.45.6",
    "@types/jest": "^26.0.22",
    "@types/js-cookie": "^2.2.6",
    "@types/lodash.throttle": "^4.1.6",
    "@types/mui-datatables": "^3.7.6",
    "@types/qs": "^6.9.6",
    "@types/react": "17.0.2",
    "@types/react-dom": "17.0.2",
    "@types/react-gtm-module": "^2.0.1",
    "@types/react-input-mask": "^3.0.1",
    "@types/react-swipeable-views": "^0.13.1",
    "@types/stripe-v2": "^2.0.2",
    "@typescript-eslint/eslint-plugin": "^5.30.0",
    "cross-env": "^7.0.3",
    "cypress": "^8.6.0",
    "eslint": "^8.21.0",
    "eslint-config-next": "^12.3.1",
    "eslint-import-resolver-alias": "^1.1.2",
    "eslint-plugin-cypress": "^2.11.3",
    "eslint-plugin-jest": "^27.0.4",
    "eslint-plugin-jest-dom": "^4.0.2",
    "eslint-plugin-simple-import-sort": "^5.0.3",
    "execa": "^4.0.3",
    "husky": "^4.2.5",
    "jest": "^29.1.2",
    "jest-environment-jsdom": "^29.1.2",
    "jest-junit": "^12.2.0",
    "lint-staged": "^10.5.1",
    "pg-promise": "^10.6.2",
    "prettier": "^2.7.1",
    "react-test-renderer": "^18.0.0",
    "ts-jest": "^29.0.3",
    "typescript": "^4.5.5"
  },

.lintstagedrc.js

const path = require('path')

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

module.exports = {
  '*.{js,jsx,ts,tsx}': [buildEslintCommand],
}

Solution

    1. If you want to run prettier as part of your linting process, you need eslint-plugin-prettier. I see you have both eslint-plugin-prettier and eslint-config-prettier. They do slightly different things so check their docs and stick to one of them. Personally, I prefer eslint-config-prettier, so I separate the linting from the formatting, but this is a personal choice!
    2. You need to install eslint-plugin-jest, then enable it in the plugins section of your ESLint config.

    If you are happy with Next.js ESLint config, you should check Vercel Style Guide, which includes sensible defaults for ESLint, prettier and TypeScript.