Create a reusable ESLint config

Motivation

There are probably as many coding styles out there as there are developers. Even given programming language syntax restrictions, coding is a very personal craft.

That being said, conventions help establish a readable and maintainable codebase. Luckily, there are tools that can help us achieve a healthy level of code uniformity. In the JavaScript ecosystem, two popular choices are

  • ESLint - linter (can check for syntax errors/style)
  • Prettier - code formatter

In this article, I will guide you through the process of defining your personal/team coding style as an ESlint configuration. What's more, you will be able to easily share the same configuration across projects.

Check my personal ESLint configs for applied examples of this tutorial:

Creating an ESLint config package

Step 1: Scaffolding

  1. Create a new npm package. By convention, it should start with eslint-config-:

    mkdir eslint-config-example
    cd eslint-config-example
    npm init -y
  2. Create an index.js file under the project's root. We will define our rules here.

  3. Create a .gitignore file with the following contents:

    node_modules
  4. (Optional) It is often a good idea to do some housekeeping in your package:

    • Add a README.md file
    • Add a LICENSE file
    • Update the default package.json fields (keywords, author, license etc)

Step 2: Pick a base config (optional)

This step is optional but I find it very convenient. Instead of having to define an extensive set of rules, you can pick an existing config and adjust it to your needs.

In this example, I will use the popular Airbnb Style Guide as the base config. The following command installs the airbnb config package as well as its plugin dependencies:

npm install eslint-plugin-import eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-jsx-a11y

Step 3: Install additional plugins

There is a multitude of great ESLint plugins out there. In this example, we'll add eslint-plugin-import, which enables linting of import statements:

npm install eslint-plugin-import

Step 4: Install Prettier for ESlint (optional)

Again, this is an optional but recommended step. Prettier is a highly opinionated code formatter. This seems to be its basic strength: it works out of the box and results in an arguably elegant formatting.

npm install eslint-config-prettier eslint-plugin-prettier

Step 5: Specify peer dependencies

Our package includes all the required packages as dependencies, except for the most basic:

  • eslint
  • prettier (if you followed Step 4)

We will specify those as peer dependencies instead. The reason is that they are not strictly required by the plugins, but rather the other way around:, eslint and prettier are "host' packages which will load our config/plugins. I suggest reading this npm blog post for a more detailed explanation.

This is also an effective way to specify the supported host package versions. An example:

{
"peerDependencies": {
"eslint": "^6 || ^7.2.0",
"prettier": ">= 1.13"
}
}

Step 6: Configure ESLint

And now time for the real action! Everything comes together in the index.js file, where we will specify our selected configs, rules and plugins.

Each config file will be uniquely suited to your needs and taste. For our example:

module.exports = {
// eslint-configs
extends: ['airbnb', 'plugin:prettier/recommended'],
// eslint-plugins
plugins: ['simple-import-sort'],
// enabling/disabling/changing level of rules
rules: {
'class-methods-use-this': 'off',
'import/order': 'warn',
'import/prefer-default-export': 'off',
'no-plusplus': 'off',
'no-restricted-globals': 'off',
'prettier/prettier': [
'error',
// configure Prettier for ESLint
{
arrowParens: 'avoid',
printWidth: 100,
singleQuote: true,
trailingComma: 'all',
},
],
radix: 'off',
},
};

We have plenty of options here: luckily, the ESLint documentation is very helpful. A few key points:

  • A config/plugin will not be loaded by ESLint unless if you specify it here!
  • The precedence of items in extends and plugins follows the order they are listed. This is important in case some items conflict each other
  • A rule can be either specified as
    • a string/number indicating its level: 'off' | 'warn' | 'error', 0 | 1 | 2
    • an array of [level, options] where options is used to configure the rule. You can look at each rule's documentation for the available options, for example: import/order options

Usage

Publishing

Our style guide should be now ready for consumption! Before we add it in our superCoolProject, there is one last step: we need to publish it. We have two main options:

  • npm: publish your package, then simply install it running

    npm install {{packageName}}
  • a git repository: GitHub, GitLab etc. Publish your package, then

    npm install git+{{gitUrl}}

    # Example:
    npm install git+https://github.com/kael89/eslint-config-kael89.git

Don't forget to update your package's version with each change, which will allow you to pick up any updates in your projects.

Installation

  1. Install the peer dependencies as devDependencies in our project:

    npm install -D eslint prettier
  2. Install our config. For npm packages:

    npm install {{packageName}}

    For git repositories:

    npm install git+{{gitUrl}}

    # Example:
    npm install git+https://github.com/organisation/packageName.git
  3. Configure ESLint to use our package. There are many ways to do so, the simplest probably is adding an eslintConfig field in our project's package.json file:

    {
    "extends": "{{configName}}"
    }

🤓Tip: We can omit the eslint-config- prefix in our package's name. Eg if our package is called eslint-config-example:

{
"extends": "example"
}

Next steps

Rules breaking between version updates is not at all uncommon. If your config is used by multiple users, it may be a good idea to add some tests to ensure there is no regression when you update it.

You may prefer to publish a personal style guide just on your GitHub account, and not in the npm registry. I will describe how to maintain a versioned node package in GitHub in a future article.

Until then, rock the code with your tailor-made ESLint config! 🤘🤓