Make Commit in Your React Project Format-Test-Build Ready with Husky - A Step-by-Step Guide
SeongKuk Han
Posted on May 24, 2024
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
andprettier
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
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.
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
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'],
},
}));
Create the vitest-setup.js
file, which enables us to utilize features for testing React components.
import '@testing-library/jest-dom/vitest';
Add a type in tsconfig.json
file to provide the necessary types for DOM testing.
...
"types": ["@testing-library/jest-dom"],
...
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');
});
});
Add test
script into package.json
file. We run vitest
file with the option run to execute once.
...
"test": "vitest run"
...
Let's test our code by the command pnpm run test
.
4. Set Up Prettier
Install prettier
.
> pnpm install -D prettier
Create the .prettierrc
file at the root, which serves as the prettier configuration file.
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": true
}
Let's format App.tsx
file using prettier
to see if it works.
> npx prettier --write ./src/App.tsx
Before -
After -
5. Set Up lint-staged
Install lint-staged
.
> pnpm install --save-dev lint-staged
Create the .lintstagedrc
file which is a configuration file for lint-staged.
{
"src/**/*.{ts,tsx}": [
"eslint --fix",
"prettier --write"
]
}
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
Let's test with one file, main.tsx
.
> git add ./src/main.tsx
> npx lint-staged
Before -
After -
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.
eslint
successfully found the problem.
6. Set Up husky
Install husky
.
> pnpm install --save-dev husky
Initialize husky
> npx husky init
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.
Let's customize the pre-commit
hook.
[pre-commit]
pnpm run test
npx lint-staged
pnpm run build
The commit will be ignored if one of those commands fails.
Let's add all the files and make a commit.
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.
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!
Posted on May 24, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.