DEV Community

Cover image for Make Commit in Your React Project Format-Test-Build Ready with Husky - A Step-by-Step Guide
SeongKuk Han
SeongKuk Han

Posted on

Make Commit in Your React Project Format-Test-Build Ready with Husky - A Step-by-Step Guide

How often have you encountered build failures, test failures lint errors, or inconsistent code formatting after committing your code?

In this article, I will show you how to avoid those issues step by step using husky and lint-staged.

Before diving in, let's explorer what each tool is used for.

  • Husky: It enables us to easily use git hooks. We can define commands when a specific behavior happens. We will use pre-commit, which is hooked before creating a commit.
  • Eslint: It analyzes our code to quickly find problems. We will use the default setup provided by Vite.
  • Prettier: It makes our code prettier by formatting. It supports many languages and editors.
  • lint-staged: It enables us to run linters against staged git files. eslint and prettier will be executed by it.

I will use pnpm as a package manager, but feel free to use any package you prefer.


1. Set Up React Project With Vite



> pnpm create vite


Enter fullscreen mode Exit fullscreen mode

created vite project

After setting a project, let's install the dependencies by executing the command pnpm install.

Run the dev server, and let's see if the project was successfully installed.

Start Page


2. Set Up Vitest for React

Let's write some test code to be executed during pre-commit stage. I will use vitest and testing-library in this project to test our code.



> pnpm install -D @testing-library/jest-dom vitest jsdom @testing-library/react


Enter fullscreen mode Exit fullscreen mode

Create the vitest.config.ts file to configure the test environment.



import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react-swc';

export default defineConfig(({ mode }) => ({
  plugins: [react()],
  resolve: {
    conditions: mode === 'test' ? ['browser'] : [],
  },
  test: {
    environment: 'jsdom',
    setupFiles: ['./vitest-setup.js'],
  },
}));


Enter fullscreen mode Exit fullscreen mode

Create the vitest-setup.js file, which enables us to utilize features for testing React components.



import '@testing-library/jest-dom/vitest';


Enter fullscreen mode Exit fullscreen mode

Add a type in tsconfig.json file to provide the necessary types for DOM testing.



...
    "types": ["@testing-library/jest-dom"],
...


Enter fullscreen mode Exit fullscreen mode

3. Write Test Code

Now, we are ready to test React components. Let's test our App component.

Create the App.test.tsx file in the same directory where App.tsx file is.



import { describe, test, expect } from 'vitest';
import { render } from '@testing-library/react'

import App from './App';

describe('App',()=>{
  test('count should be increased when the button is clicked.', async () => {
    const app = render(<App />);

    const button = await app.findByText(/^count/);
    expect(button.textContent).toBe('count is 0');

    await button.click();

    expect(button.textContent).toBe('count is 1');
  });
});


Enter fullscreen mode Exit fullscreen mode

Add test script into package.json file. We run vitest file with the option run to execute once.



...
    "test": "vitest run"
...


Enter fullscreen mode Exit fullscreen mode

Let's test our code by the command pnpm run test.

test


4. Set Up Prettier

Install prettier.



> pnpm install -D prettier


Enter fullscreen mode Exit fullscreen mode

Create the .prettierrc file at the root, which serves as the prettier configuration file.



{
  "trailingComma": "es5",
  "tabWidth": 2,
  "semi": true,
  "singleQuote": true
}


Enter fullscreen mode Exit fullscreen mode

Let's format App.tsx file using prettier to see if it works.



> npx prettier --write ./src/App.tsx


Enter fullscreen mode Exit fullscreen mode

Before -

before formatting

After -

after formatting


5. Set Up lint-staged

Install lint-staged.



>  pnpm install --save-dev lint-staged


Enter fullscreen mode Exit fullscreen mode

Create the .lintstagedrc file which is a configuration file for lint-staged.



{
  "src/**/*.{ts,tsx}": [
    "eslint --fix",
    "prettier --write"
  ]
}


Enter fullscreen mode Exit fullscreen mode

I will lint only typescript files but you can configure it whatever you want.

To test git-staged files, we need to initialize git first.



> git init


Enter fullscreen mode Exit fullscreen mode

Let's test with one file, main.tsx.



> git add ./src/main.tsx
> npx lint-staged


Enter fullscreen mode Exit fullscreen mode

Before -

before lint-staged

After -

After lint-staged

lint-staged console output

As you can see, the code is formatted by prettier.
I will make an error in the main.ts file and add it to the git staged.
Let's see if eslint lets us know there is a problem.

unused import package

eslint error

eslint successfully found the problem.


6. Set Up husky

Install husky.



> pnpm install --save-dev husky


Enter fullscreen mode Exit fullscreen mode

Initialize husky



> npx husky init


Enter fullscreen mode Exit fullscreen mode

After this command, you will see the .husky directory under the root. You don't need to worry about the _ folder, it comes with husky when installed and handles the git hooks for us.

husky folder

Let's customize the pre-commit hook.

[pre-commit]



pnpm run test
npx lint-staged
pnpm run build


Enter fullscreen mode Exit fullscreen mode

The commit will be ignored if one of those commands fails.

Let's add all the files and make a commit.

pre-commit fails

Our commit failed because of the unused imported package we added in the last step, and as you can see, the commit is ignored since eslint throws an error.

Let's get rid of the error and create a commit again.

first output

second output

Our new commit is successfully done.


Wrap up

Now, each commit guarantees you that the commit is formatted, tested, and buildable.
Keep in mind that the configuration can be different depending on your project or your goal. Since we could write any command in pre-commit, it could do more complex tasks.

I hope you found this article helpful.

Happy Coding!

Top comments (0)