Husky and lint-staged for pre-commit in React
Tags: react, webdev, tutorial
Published: 2024-02-07 21:33:41

## Introduction

Who hasn't faced the problem of forgetting to run tests or adjust the code formatting before pushing it, encountering a pipeline failure that validates them? Or having to manually execute routines to follow project standard definition?

The idea of this article is to introduce two libraries that, when used together, allow configuring actions in the pre-commit stage, blocking a commit with failed tests, formatting the code before committing, or performing any other defined action.

## Libs

- husky: It's the library that will allow running pre-commit actions.
- lint-staged: It's the library that will define the actions to be executed for files that are staged in git.

## Libs setup

### 1- Husky

To add Husky to the application, it's necessary to run the following command:

`yarn add --dev husky`

To start the configuration, I suggest executing the following command:

`npx husky init`

It will generate a `pre-commit` file inside the `.husky` folder, which will define the execution of pre-commit actions. It will have the following content:

```
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npm test
```

Initially, by default, it's configured to run npm test, but with the addition of lint-staged, we'll update this file.

Also, a script to install Husky will be generated inside `package.json`.

```
"scripts": {
  (...)
  "prepare": "husky install"
},
```

### 2 - lint-staged

To add lint-staged, it's necessary to run the following command:

`yarn add --dev lint-staged`

To configure the actions that will be executed pre-commit, add to package.json:

```
"lint-staged": {
  "*.js": [
  ]
}
```

`*.js` is the type of files added in stage where pre-commit actions will be executed (I used this type as an example, but it depends on the type defined in your application). Inside "[ ]" is where the actions to be executed in the pre-commit stage will be placed.

Finally, for the lint-staged usage from Husky, it will be necessary to update the `pre-commit` file, resulting in the following:

```
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no-install lint-staged
```

To start running Husky to perform pre-commit actions, it's necessary to install it by running: `yarn prepare`.

## Execution example

Now I will present an example of execution with two objectives: formatting the code before committing and validating if the tests are passing to allow the commit to be made.

For this example, it will be considered an app with a component inside `App.js` and a test file `App.test.js`, both inside the `src` folder. App that uses the `Jest` library to perform tests and `prettier` for code formatting.

In the package.json, it's presented the following scripts:
```
"scripts": {
  "test": "jest",
  "format": "prettier --write \"**/src/*.js\"",
  "prepare": "husky install"
  }
```

The `test` is responsible for running the tests, and `format` for formatting the code.

To define what will be executed on pre-commit, define the commands to be executed inside `lint-staged` in `package.json`:

```
"lint-staged": {
  "src/*.js": [
    "yarn format",
    "yarn test --findRelatedTests --bail"
  ]
}
```

This way, it's defined that for the files staged in git, execute `yarn format` and `yarn test --findRelatedTests --bail` pre-commit.

The `--findRelatedTests` allows that when the App.js component is modified, it runs the associated tests (those presents in App.test.js), and the `--bail` cancels the commit if any test fails. Those comands are for tests executed with Jest, depending of test lib can be other commands to not allow the commit.

Finally, to test the libraries, it's possible to change the App.js component, stage it with `git add`, and then commit. Before the commit is made, the actions defined inside `lint-staged` will be executed. In this example, the modified file will be formatted, and the associated tests will run. If any test fails, the commit will not be completed. If the tests pass, the commit will be completed.

Execution in the terminal:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gf0pnsyqpchlzv2obqlz.gif)

In case you want to generate a commit without pre-commit actions, simply add `--no-verify` at the end of the git commit command, and Husky will not be executed.

## Conclusion

Finally, the idea of this article is to introduce two libraries that, together, enable performing pre-commit actions to prevent pipeline failures or allow running processes that are commonly used in the app, for files staged in git. This aims to streamline the development process.