ESLint with Gatsby
Tags: javascript, eslint, gatsby, tooling
Published: 2020-09-21 18:52:22

---
title: ESLint with Gatsby
published: true
date: 2020-09-16 00:00:00 UTC
tags: #javascript, #eslint, #gatsby, #tooling
canonical_url: https://www.mariokandut.com/how-to-use-and-customize-eslint-with-gatsby/
---

_This article was originally published on [mariokandut.com](https://www.mariokandut.com/how-to-use-and-customize-eslint-with-gatsby)._

I have great news for you, my linting friend. **Gatsby ships with built-in ESLint setup.** According to the [Gatsby docs](https://www.gatsbyjs.com/docs/eslint/),the provided eslint config is suitable for most of its users.

So why customize then? Well, there could be several reasons for customization of the "standard" ESLint setup, for example:

- project requirements
- company requirements
- internal testing
- personal preferences, etc.

If you want to know more about **Linting** and if ESLint is the right choice, have a look at this article [What is Linting](https://www.mariokandut.com/what-is-linting-and-how-can-it-help-you/).

## How to customize ESLint

I assume, you’ll start with customizing from the ESLint config Gatsby ships with, so you can then add additional presets, plugins, and rules.

See below the ESLint provided by the Gatsby starter or on [github](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/utils/eslint-config.ts).

```
module.exports = {
  extends: [
    require.resolve(`eslint-config-react-app`),
  ],
  plugins: [`graphql`],
  rules: {
    // New versions of react use a special jsx runtime that remove the requirement
    // for having react in scope for jsx. Once the jsx runtime is backported to all
    // versions of react we can make this always be `off`.
    // I would also assume that eslint-config-react-app will switch their flag to `off`
    // when jsx runtime is stable in all common versions of React.
    'react/react-in-jsx-scope': usingJsxRuntime
      ? `off`
      : `error`, // Conditionally apply for reactRuntime?
    'import/no-webpack-loader-syntax': [0],
    'graphql/template-strings': [
      `error`,
      {
        env: `relay`,
        schemaString: printSchema(schema, {
          commentDescriptions: true,
        }),
        tagName: `graphql`,
      },
    ],
    'react/jsx-pascal-case': `off`, // Prevents errors with Theme-UI and Styled component
    // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/master/docs/rules
    'jsx-a11y/accessible-emoji': `warn`,
    'jsx-a11y/alt-text': `warn`,
    'jsx-a11y/anchor-has-content': `warn`,
    'jsx-a11y/anchor-is-valid': `warn`,
    'jsx-a11y/aria-activedescendant-has-tabindex': `warn`,
    'jsx-a11y/aria-props': `warn`,
    'jsx-a11y/aria-proptypes': `warn`,
    'jsx-a11y/aria-role': `warn`,
    'jsx-a11y/aria-unsupported-elements': `warn`,
    // TODO: It looks like the `autocomplete-valid` rule hasn't been published yet
    // "jsx-a11y/autocomplete-valid": [
    // "warn",
    // {
    // inputComponents: [],
    // },
    // ],
    'jsx-a11y/click-events-have-key-events': `warn`,
    'jsx-a11y/control-has-associated-label': [
      `warn`,
      {
        ignoreElements: [
          `audio`,
          `canvas`,
          `embed`,
          `input`,
          `textarea`,
          `tr`,
          `video`,
        ],
        ignoreRoles: [
          `grid`,
          `listbox`,
          `menu`,
          `menubar`,
          `radiogroup`,
          `row`,
          `tablist`,
          `toolbar`,
          `tree`,
          `treegrid`,
        ],
        includeRoles: [`alert`, `dialog`],
      },
    ],
    'jsx-a11y/heading-has-content': `warn`,
    'jsx-a11y/html-has-lang': `warn`,
    'jsx-a11y/iframe-has-title': `warn`,
    'jsx-a11y/img-redundant-alt': `warn`,
    'jsx-a11y/interactive-supports-focus': [
      `warn`,
      {
        tabbable: [
          `button`,
          `checkbox`,
          `link`,
          `progressbar`,
          `searchbox`,
          `slider`,
          `spinbutton`,
          `switch`,
          `textbox`,
        ],
      },
    ],
    //"jsx-a11y/label-has-for": `warn`, was deprecated and replaced with jsx-a11y/has-associated-control in v6.1.0
    'jsx-a11y/label-has-associated-control': `warn`,
    'jsx-a11y/lang': `warn`,
    'jsx-a11y/media-has-caption': `warn`,
    'jsx-a11y/mouse-events-have-key-events': `warn`,
    'jsx-a11y/no-access-key': `warn`,
    'jsx-a11y/no-autofocus': `warn`,
    'jsx-a11y/no-distracting-elements': `warn`,
    'jsx-a11y/no-interactive-element-to-noninteractive-role': `warn`,
    'jsx-a11y/no-noninteractive-element-interactions': [
      `warn`,
      {
        body: [`onError`, `onLoad`],
        iframe: [`onError`, `onLoad`],
        img: [`onError`, `onLoad`],
      },
    ],
    'jsx-a11y/no-noninteractive-element-to-interactive-role': `warn`,
    'jsx-a11y/no-noninteractive-tabindex': `warn`,
    'jsx-a11y/no-onchange': `warn`,
    'jsx-a11y/no-redundant-roles': `warn`,
    'jsx-a11y/no-static-element-interactions': `warn`,
    'jsx-a11y/role-has-required-aria-props': `warn`,
    'jsx-a11y/role-supports-aria-props': `warn`,
    'jsx-a11y/scope': `warn`,
    'jsx-a11y/tabindex-no-positive': `warn`,
  },
};
```

First we need the necessary ESLint dependencies.

```
npm install --save-dev eslint-config-react-app
```

Then create a file `.eslintrc.js` through your editor/IDE or in the terminal `touch .eslintrc.js` and copy the code snippet below in the file.

```
module.exports = {
  globals: {
    __PATH_PREFIX__ : true,
  },
  extends: `react-app`,
};
```

That's it. Now you are ready to add all the additional presets, plugins and rules your project requires.

#### Keep in mind Gatsby specifics for the ESLint-file

1. NO `ESLint file`: Gatsby adds by default a ESLint loader, which pipes all the feedback from ESLint into your terminal/browser console.
2. YES there is a `ESLint-file`: When you add a custom `.eslintrc` file, Gatsby gives you full control over the ESLint configuration.This means also it overrides the built-in eslint-loader and no default rules will be loaded.

## Customizing ESLint

You have now several options:

- Now just copy your project specific rules in the `.eslintrc` and that's it.
- If you want to start from scratch and apply your **own linting rules** , I recommend **copying the rules from Gatsby** and modify from that point on.
- Another option would be to configure ESLint from scratch. The docs from ESLint have a great user guide for [Configuring ESLint](https://eslint.org/docs/user-guide/configuring).
- One way to customize the Gatsby ESLint is by using the **community plugin** [gatsby-plugin-eslint](https://www.gatsbyjs.com/packages/gatsby-plugin-eslint/).

### Using gatsby-plugin-eslint

I recommend this plugin, have a look at the [plugin page](https://www.gatsbyjs.com/plugins/gatsby-plugin-eslint/) or [github](https://github.com/mongkuen/gatsby-plugin-eslint).

1. Install the gatsby-plugin-eslint plugin`npm install --save-dev gatsby-plugin-eslint`
2. Install [ESLint](https://eslint.org/) and [eslint-loader](https://github.com/webpack-contrib/eslint-loader):`npm install --save-dev eslint eslint-loader`
3. Create a .eslintrc file in your project root.
4. Add the plugin to `gatsby-config.js`.

```
module.exports = {
  plugins: ['gatsby-plugin-eslint'],
};
```

1. Use the options of the plugin to specify the rules.

#### Options for gatsby-plugin-eslint

The default options are:

1. Lint .js and .jsx files.
2. Exclude `node_modules`, `.cache`, and `public` folders from linting.
3. Only lints in development in the 'develop' stage.
4. Default [ESLint-Loader](https://github.com/webpack-contrib/eslint-loader#options) options.

Customize the linting filetypes, exclusions, and ESLint-Loader options:

```
{
      resolve: 'gatsby-plugin-eslint',
      options: {
        test: /\.js$|\.jsx$/,
        exclude: /(node_modules|.cache|public)/,
        stages: ['develop'],
        options: {
          emitWarning: true,
          failOnError: false
        }
      }
    }
```

An easy way to start linting is with these two linting plugins.

#### eslint-plugin-react

React specific linting rules for ESLint.

1. Install the [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react)

`npm install --save-dev babel-eslint eslint-plugin-import eslint-plugin-react`

1. Update `.eslintrc` file:

```
{
  "parser": "babel-eslint",
  "rules": {
    "strict": 0
  },
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended"
  ]
}
```

#### AirBnB’s eslint-config-airbnb Linting

This package provides the **eslint-config** `.eslintrc` as an extensible shared config from Airbnb.

1. Install [eslint-config-airbnb](https://www.npmjs.com/package/eslint-config-airbnb)

`npm install --save-dev eslint-config-airbnb eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react`

1. Add or update `.eslintrc`:

```
{
  "extends": "airbnb"
}
```

#### Disabling ESLint

Just to be `feature-complete` with this blogpost, and I don't recommend this, but you can do it, if you really want to disable ESLint.Just create an empty `.eslintrc` file, and it will disable the `eslint-loader` and with it all the imported lint rules.

Thanks for reading and if you have any **questions** , use the **comment** function or **send me a message** **[@mariokandut](https://www.twitter.com/mariokandut)**.

References (and Big thanks):[Gatsby docs](https://www.gatsbyjs.com/docs/eslint/), [Gatsby ESLint community plugin](https://www.gatsbyjs.com/plugins/gatsby-plugin-eslint/), [SPeshov](https://dev.to/speshov/how-to-setup-gatsbyjs-starter-with-typescript-eslint-prettier-4jh3), [ESLint](https://eslint.org/docs/user-guide/configuring)