Search code examples
next.jscreate-react-appeslint

Why is eslint not working after migrating from CRA to Next.js?


I am currently working on migrating an app from CRA to Next.js. Eslint was working beautifully when using CRA (eslint works out-of-the-box).

I want to use the same CRA linting rules in the Next.js app so I installed eslint-config-react-app. I followed the instructions as provided on the NPM page: https://www.npmjs.com/package/eslint-config-react-app:

  1. npm install --save-dev eslint-config-react-app @typescript-eslint/eslint-plugin@^4.0.0 @typescript-eslint/parser@^4.0.0 babel-eslint@^10.0.0 eslint@^7.5.0 eslint-plugin-flowtype@^5.2.0 eslint-plugin-import@^2.22.0 eslint-plugin-jsx-a11y@^6.3.1 eslint-plugin-react@^7.20.3 eslint-plugin-react-hooks@^4.0.8

  2. create the .eslintrc.json file with the following content: { "extends": "react-app" }

However, the linting is not showing up neither in the development console nor in the browser console.

Thanks!


Solution

  • Ok so I found the solution.

    I wanted the eslint output to show up in the console when saving edits to a file directly (just like with CRA). Initially, I did not realize that Next.js has no eslint plugin/loader specified in their webpack config so I extended theirs by adding my own. Now everything works as expected, just like it did when using CRA.

    I actually used (although slightly modified) CRA's config for the eslint-webpack-plugin plugin. If anyone else wants to have an eslint setup in Next.js similar to CRA, add the following to your next.config.js file:

    const path = require('path');
    const fs = require('fs');
    const ESLintPlugin = require('eslint-webpack-plugin')
    
    const appDirectory = fs.realpathSync(process.cwd());
    const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
    
    module.exports = {
        webpack(config) {
            config.plugins.push(new ESLintPlugin({
                // Plugin options
                extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
                eslintPath: require.resolve('eslint'),
                context: resolveApp('src'),
                cache: true,
                cacheLocation: path.resolve(
                    resolveApp('node_modules'),
                    '.cache/.eslintcache'
                ),
                // ESLint class options
                cwd: resolveApp('.'),
                resolvePluginsRelativeTo: __dirname,
                baseConfig: {
                    extends: [require.resolve('eslint-config-react-app/base')],
                    rules: {},
                },
            }))
    
            return config
        }
    }
    

    Note, that when using the above you will need to install eslint-config-react-app and its dependencies (see: https://www.npmjs.com/package/eslint-config-react-app).

    Finally, note that since Next.js only renders (compiles) a page when it is needed in development, eslint will only run on a page when it is displayed in the browser as pointed out here: https://github.com/vercel/next.js/issues/9904. This makes adding the following script to package.json as suggested by Roman very useful if you want to do a "full-scan" of your project.

    "lint": "eslint ."