Automating code patterns with Husky
Tags: tutorial, javascript, node
Published: 2023-11-02 20:10:47

In the world of software development, maintaining consistent code quality and ensuring that the codebase adheres to predefined patterns and guidelines is crucial. However, manually enforcing these standards can be time-consuming and error-prone. This is where automation tools like [Husky](https://typicode.github.io/husky), [Lint-Staged](https://github.com/lint-staged/lint-staged), [Commitlint](https://commitlint.js.org), and [Commitizen](https://github.com/commitizen/cz-cli) come to the rescue. In this post, we will explore how these tools can be combined to streamline your development workflow.

## What are Husky, Lint-Staged, Commitlint, and Commitizen?

- **Husky**: Husky is a tool that helps you set up Git hooks for your project. Git hooks are scripts that run at certain points in the Git workflow, such as pre-commit, pre-push, etc. Husky allows you to automate tasks or checks when specific Git events occur.
- **Lint-Staged**: Lint-Staged is a tool that runs linters (such as ESLint, Prettier, or TSLint) on pre-committed files in a Git repository. It ensures that you only lint and format the code that is part of your current commit, saving time and resources.
- **Commitlint**: Commitlint is a tool for enforcing conventional commit messages. Conventional commits follow a specific format, such as `feat: add new feature` or `fix: resolve a bug`. Commitlint checks your commit messages against these conventions and ensures that your commit history is well-structured and easy to understand.
- **Commitizen**: Commitizen is a tool that helps you create consistent, structured commit messages. It provides a guided interface for generating conventional commit messages, making it easy for developers to follow commit message conventions.

## Benefits of Automating code patterns

Automating code patterns with Husky, Lint-Staged, Commitlint, and Commitizen offers several advantages:

- **Consistency**: By automating code quality checks and standards, you can ensure that all contributors follow the same best practices.
- **Reduced Errors**: Pre-commit and pre-push hooks catch errors and issues before they are committed or pushed to the repository, reducing the likelihood of introducing bugs.
- **Improved Collaboration**: Husky helps maintain a clean and organized codebase, making it easier for developers to collaborate and review code changes.
- **Automated Testing**: Running tests automatically before pushing code to the remote repository ensures that only code that passes tests is merged, enhancing code quality.
- **Customizable**: Husky is highly customizable, allowing you to define your own hooks and scripts to meet your project's specific needs.

## Getting Started
### Husky

To start using Husky, you need to install it as a development dependency in your project. But first, make sure you've already started a Git repository. To do this, run the following command:

```bash
git branch -a
```

If you don't get any errors, it means you've already started a Git repository and can skip this step. Now if you receive the error `fatal: not a git repository`, it means that you have not yet started a Git repository. Then start a repository with the `git init` command.

Now install and start Husky with the following command:

```bash
# NPM
npx husky-init && npm install

# Yarn
yarn dlx husky-init --yarn2 && yarn

# PNPM
pnpx husky-init && pnpm install

# Bun
bunx husky-init && bun install
```

It will:
1. Add `prepare` script to `package.json`
2. Create a sample `pre-commit` hook that you can edit (by default, `npm test` will run when you commit)
3. Configure Git hooks path

### Lint-Staged

To set up Lint-Staged, install it and configure it in your project:

```bash
# NPM
npm install lint-staged --save-dev

# Yarn
yarn add lint-staged -D

# PNPM
pnpm add lint-staged -D

# Bun
bun add lint-staged -D
```

Next, add lint-staged configuration in your package.json file:
```json
"lint-staged": {
  "*.{js,ts,tsx}": ["eslint --fix", "prettier --write"],
  "*.{md,json}": ["prettier -w"]
}
```

Now set the `pre-commit` hook to run Lint-Staged:
```bash
# NPM
npx husky set .husky/pre-commit 'npm run lint-staged'

# Yarn
yarn dlx husky set .husky/pre-commit 'yarn lint-staged'

# PNPM
pnpx husky set .husky/pre-commit 'pnpm lint-staged'

# Bun
bunx husky set .husky/pre-commit 'bun lint-staged'
```

This configuration tells Lint-Staged to run ESLint and Prettier on staged files with extension `.js`, `.ts` and `.tsx` and Prettier on staged files with extension `.md`, and `.json`.

### Commitlint

Install Commitlint by running:

```bash
# NPM
npm install @commitlint/cli @commitlint/config-conventional --save-dev

# Yarn
yarn add @commitlint/cli @commitlint/config-conventional -D

# PNPM
pnpm add @commitlint/cli @commitlint/config-conventional -D

# Bun
bun add @commitlint/cli @commitlint/config-conventional -D
```

Set up Commitlint configuration by creating a `commitlint.config.cjs` file in your project's root directory:
```js
module.exports = { extends: ["@commitlint/config-conventional"] };
```

Now define the `commit-msg` hook to run Commitlint:
```bash
# NPM
npx husky set .husky/commit-msg 'npx --no -- commitlint --edit ${1}'

# Yarn
yarn dlx husky set .husky/commit-msg 'npx --no -- commitlint --edit ${1}'

# PNPM
pnpx husky set .husky/commit-msg 'npx --no -- commitlint --edit ${1}'

# Bun
bunx husky set .husky/commit-msg 'npx --no -- commitlint --edit ${1}'
```

### Commitizen

Install Commitizen by running:

```bash
# NPM
npm install commitizen @commitlint/cz-commitlint --save-dev

# Yarn
yarn add commitizen @commitlint/cz-commitlint -D

# PNPM
pnpm add commitizen @commitlint/cz-commitlint -D

# Bun
bun add commitizen @commitlint/cz-commitlint -D
```

Next, add commitizen configuration in your `package.json` file:
```json
"config": {
  "commitizen": {
    "path": "@commitlint/cz-commitlint"
  }
}
```

Now define the `prepare-commit-msg` hook to run Commitizen:

```bash
# NPM
npx husky set .husky/prepare-commit-msg 'exec < /dev/tty && npx cz --hook || true'

# Yarn
yarn dlx husky set .husky/prepare-commit-msg 'exec < /dev/tty && npx cz --hook || true'

# PNPM
pnpx husky set .husky/prepare-commit-msg 'exec < /dev/tty && npx cz --hook || true'

# Bun
bunx husky set .husky/prepare-commit-msg 'exec < /dev/tty && npx cz --hook || true'
```