Linting is important in a code project. Among many other things, it can ensure all the code is using the same formatting standards, there are no unused variables or unresolved imports.

Sitecore JSS projects can really benefit using a linter.

Default Linting

The JSS sample React application is created using react-scripts and create-react-app. When running jss start, ESLint is used with a default configuration to execute basic validations like unresolved imports.

ESLint Configuration File

The JSS sample React application comes with a more advanced .eslintrc file. However, it is not used when running jss start. It could be used with a globally installed ESLint and an ESLint extension in the text editor. However, the .eslintrc file references packages that are not installed when running jss create such as eslint-plugin-prettier, eslint-plugin-import, and eslint-plugin-react. This causes warnings when editing source files as the ESLint extension is unable to lint.

Cannot find module ‘eslint-plugin-prettier’ Referenced from: C:\jss-react-app-root.eslintrc

Manually Running ESLint

The first step is to configure the project to lint on demand using a script.

NOTE: react-scripts specifically requires ESLint version 4.19.1.

To install ESLint and all referenced packages locally:

yarn add eslint@4.19.1 eslint-plugin-import eslint-plugin-react eslint-plugin-prettier eslint-config-prettier -D

or

npm install eslint@4.19.1 eslint-plugin-import eslint-plugin-react eslint-plugin-prettier eslint-config-prettier --save-dev

Next, the script to run ESLint must be added to the package.json file:

{
  "scripts": {
    "lint": "node .\\node_modules\\eslint\\bin\\eslint.js **/*.js"
  }
}

Finally, to run ESLint:

yarn run lint

or

npm run lint

On the first run, there are hundreds of errors.

✖ 788 problems (788 errors, 0 warnings)
  606 errors and 0 warnings potentially fixable with the `--fix` option.

error Command failed with exit code 1.

Fixing Issues

Some ESLint errors can be automatically fixed in the codebase. This is the case of code formatting issues identified by Prettier.

To fix issues:

yarn run lint --fix

or

npm run lint --fix

After fixing, there are 182 errors remaining:

✖ 182 problems (182 errors, 0 warnings)

error Command failed with exit code 1.

Most of them are unresolved imports:

error  Unable to resolve path to module 'react'                             import/no-unresolved

Those are caused by a missing configuration in the .eslintrc file. The import/resolver plugin does not know how to resolve imports when running inside nodejs.

The solution is to add a setting to tell it to resolve the imports as JavaScript files:

{
  "settings": {
    "import/resolver": {
      "node": {
        "extensions": ['.js']
      }
    }
  }
}

Running ESLint again gives only 1 error:

C:\jss-react-app-root\server\server.js
  11:27  error  Unable to resolve path to module '../build/index.html'  import/no-unresolved

✖ 1 problem (1 error, 0 warnings)

error Command failed with exit code 1.

This error is not important at the moment as this file gets created later in the development process when switching away from the code-first development mode.

Using the Local ESLint Configuration in jss start

At this point, jss start is still using a default ESLint configuration instead of the local .eslintrc file. This is caused by react-scripts.

One option is to eject but it highly complexifies an application as it now have full control on everything react-scripts are doing under the cover.

Instead, to keep all the advantages of react-scripts but only take control of ESLint, a better option is to rewire only the ESLint portion using a simple override configuration. Two packages must be installed first:

yarn add react-app-rewired react-app-rewire-eslint

or

npm install react-app-rewired react-app-rewire-eslint

Then, a small config-overrides.js file must be created at the root of the application besides the package.json file:

const rewireEslint = require("react-app-rewire-eslint");

module.exports = function override(config, env) {
  config = rewireEslint(config, env);
  return config;
};

Lastly, all the package.json scripts using react-scripts must be modified to instead use react-app-rewired:

{
  "scripts": {
    "start:react": "react-app-rewired start",
    "build:client": "cross-env-shell PUBLIC_URL=$npm_package_config_sitecoreDistPath \"react-app-rewired build\"",
    "test": "react-app-rewired test --env=jsdom",
    "eject": "react-app-rewired eject"
  }
}

Now, the next time jss start is run, it is using the local ESLint configuration file. There is a warning about the react version that is not important:

Warning: React version not specified in eslint-plugin-react settings. See https://github.com/yannickcr/eslint-plugin-react#configuration.

It can be removed by specifying the React version in the .eslintrc file. At the time of writing these lines, the version is 16.3.2:

{
  "settings": {
    "react": {
      "version": "16.3.2"
    }
  }
}