Adding ESLint to Webpack with React and TypeScript
Tags: react, typescript, webpack, webdev
Published: 2020-07-09 16:56:34

# Background
When working in a team of developers, it is best to have a standard code style. ESLint allows developers to adhere to those basic code conventions by enforcing the same rules and making your code look unified. This helps with maintaining a readable codebase for all developers and avoid any code 💩 smells. ESLint allows you to set up and enforce these rules across the codebase. 

**Note**
With TypeScript, there are 2 linting solutions: 1. ESLint and 2. TSLint. The TypeScript team has highlighted in their roadmap that they will be focusing their efforts on ESLint rather than TSLint where they state: 
> ESLint already has the more-performant architecture... we'll be switching the TypeScript repository over to using ESLint... - [Source](https://github.com/Microsoft/TypeScript/issues/29288#developer-productivity-tools-and-integration) 

## Setting up ESLint with Webpack and TypeScript

- Install dependencies:

```bash
npm install eslint
```
### Add Dependencies

- Install dev dependencies:
 -  [eslint-loader](https://github.com/webpack-contrib/eslint-loader) : eslint webpack loader
 -  [@typescript-eslint/parser](https://www.npmjs.com/package/@typescript-eslint/parser) : The parser that will allow ESLint to lint TypeScript code
 -  [@typescript-eslint/eslint-plugin](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin) : A plugin that contains ESLint rules that are TypeScript specific
 -  [eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react) : React specific linting rules for ESLint

```bash
npm install -D eslint-loader @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react
```

### Add ESLint to Webpack configs

- Update your `webpack.config.js` file with:
 - This will configure ESLInt as part of the Webpack's build process with `eslint-loader`. After each build, any ESLint errors or warnings will be logged in your terminal with ESLint errors preventing your app to compile.

```javascript
rules: [
  /**
   * ESLINT
   * First, run the linter.
   * It's important to do this before Babel processes the JS.
   * Only testing .ts and .tsx files (React code)
   */
  {
    test: /\.(ts|tsx)$/,
    enforce: 'pre',
    use: [
      {
        options: {
          eslintPath: require.resolve('eslint'),

        },
        loader: require.resolve('eslint-loader'),
      },
    ],
    exclude: /node_modules/,
  },
]
```
## Add ESLint configuration file

- Create an `.eslintrc.js` config file:
 - **Note:** By creating a JavaScript file instead of a JSON file (`.eslintrc`) we can add comments for other developers. 

```bash
touch .eslintrc.js
```

- Add ESLint rules to `.eslintrc.js`:

```javascript
module.exports =  {
  parser:  '@typescript-eslint/parser',  // Specifies the ESLint parser
  extends:  [
    'plugin:react/recommended',  // Uses the recommended rules from @eslint-plugin-react
    'plugin:@typescript-eslint/recommended',  // Uses the recommended rules from @typescript-eslint/eslint-plugin
  ],
  parserOptions:  {
    ecmaVersion:  2018,  // Allows for the parsing of modern ECMAScript features
    sourceType:  'module',  // Allows for the use of imports
    ecmaFeatures:  {
      jsx:  true,  // Allows for the parsing of JSX
    },
  },
  rules:  {
    // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
    // e.g. '@typescript-eslint/explicit-function-return-type': 'off',
  },
  settings:  {
    react:  {
      version:  'detect',  // Tells eslint-plugin-react to automatically detect the version of React to use
    },
  },
};
``` 

### Adding pre-commit hook with ESLint

To avoid 💩 code slipping in your codebase, pre-commit checks can be used to lint your code and check for ESLint errors and warnings before each commit (`git commit`). We will configure  [`lint-staged`](https://github.com/okonet/lint-staged) and  [`husky`](https://github.com/typicode/husky)  to run ESLint during the `pre-commit` check. 

- Install dev-dependencies:

```bash
npm i -D husky lint-staged
```  

- Add ESLint scripts to `package.json` file:
 - `npm run lint`: will lint `.ts` and `.tsx` files
 -  `npm run lint:fix`: will lint `.ts` and `.tsx` files **AND** automatically fix any minor ESLint issues.

```json
"scripts": {
    "lint": "eslint --ext .ts,.tsx",
    "lint:fix": "npm run lint -- --fix"
}
```

- Add `husky` and `lint-staged` configs to `packaged.json`:

```json
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "app/**/*.(ts|tsx)": [
      "npm run --silent lint:fix",
      "git add"
    ]
  }
```

During the pre-commit hook check, ESLint will fix any minor linting issues and add those changes directly to the current commit. If ESLint problems persist, `lint-staged` will prevent the commit from being made and log the ESLint errors and warnings to the console allowing for manual fixes.


### Updates:

In v10 and later of lint-staged, we do not need to add `git add` in our lint-staged task. From lint-staged docs:

> From v10.0.0 onwards any new modifications to originally staged files will be automatically added to the commit. If your task previously contained a git add step, please remove this. The automatic behaviour ensures there are less race-conditions, since trying to run multiple git operations at the same time usually results in an error.  -- [Source](https://github.com/okonet/lint-staged#v10)

So we can remove the `git add` step:

```json
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "app/**/*.(ts|tsx)": [
      "npm run --silent lint:fix"
    ]
  }
```


Thank you [Igor Adamenko](https://dev.to/igoradamenko) for catching this.



### Extra Resouces:

- [Intellij ESLint Doc](https://www.jetbrains.com/help/idea/eslint.html)
- [VS Code ESLint Extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)

# Happy Coding 🚀