Biblioteca de componentes React e typescript, parte 4: pré-commit com Husky e lint-staged
Introdução English version: React and typescript components lib, part 4: pre-commit with Husky and lint-staged Na parte quatro, será adicionada ações de pre-commit na aplicação a partir do uso de duas libs, Husky e lint-staged. O objetivo é mostrar a parte prática da adição delas nesse artigo, para uma referência segue o artigo Husky e lint-staged para pré-commit em React, que foi o primeiro que escrevi em dev.to. Libs Husky: é a lib que vai permitir executar ações pre-commit lint-staged: é a lib que vai definir as ações pre-commit serem executadas e aplicadas nos arquivos em stage do git, ou seja, que foi dado o git add neles Ações pre-commit As ações pre-commit são executadas após se executar o git commit no terminal, mas logo antes do commit ser finalizado de fato. Para a aplicação serão definidas três ações pre-commit: Formatar os arquivos adicionados na stage do git, seguindo as regras de lint definidas para ela, logo antes do commit ser finalizado Formatar os arquivos adicionados na stage do git, seguindo as regras de prettier definidas para ela, logo antes do commit ser finalizado Executar os testes relacionados aos componentes alterados que foram adicionados no git, para validar se estão passando, logo antes do commit ser finalizado Setup Husky Adição do Husky: yarn add husky --dev No momento desse artigo gerou a seguinte versão: "husky": "^9.1.7" Para fazer a configuração, rodar no terminal: npx husky init Ele vai gerar na raiz do projeto uma pasta .husky, dentro dela terá uma pasta _ com todos os git hooks disponíveis mas que não estão definidos para executar dentro do projeto. E fora da pasta _ um arquivo pre-commit, com uma ação inicial definida para executar dentro dele, mas como não corresponde a comandos da app o arquivo vai ser modificado. Além de gerar a pasta comentada acima, também irá gerar um comando que instala o Husky dentro da app em package.json: "scripts": { //... "prepare": "husky" }, Setup lint-staged Adição do lint-staged: yarn add lint-staged --dev No momento desse artigo gerou a seguinte versão: "lint-staged": "^15.5.0" Para configurar o Husky para executar as ações pre-commit em conjunto com lint-staged é necessário modificar o arquivo dentro da pasta .husky: pre-commit npx --no-install lint-staged Ações pre-commit No momento a app está com três comandos referentes as ações a serem adicionadas no pre-commit: package.json //... "scripts": { //... "lint-src-fix": "eslint src --fix", "format-src-fix": "prettier src --write", "test": "jest" } Colocando essas ações para serem executadas, o pre-commit funcionará com sucesso, os arquivos adicionados na stage do git serão atualizados logo antes do commit ser finalizado, mas o lado ruim é que executará o comando para todos o arquivos de src, sendo que o pre-commit em si só irá impactar os arquivos que estão na stage do git. Então para tornar as ações pre-commit mais performáticas serão criados dois novos scripts: package.json //... "scripts": { //... "lint-fix": "eslint --fix", "format-fix": "prettier --write" } Se tentar executar diretamente os comandos no terminal, eles não serão executados com sucesso, pois dependem de ser passado o arquivo ou a pasta a ser executado no estilo: yarn lint-fix {caminho da pasta ou arquivo} yarn format-fix {caminho da pasta ou arquivo} Só que quando são colocados para serem executados com lint-staged, é observado os arquivos que estão na stage do git e executado o comando neles com sucesso. Para definir as ações pre-commit a serem executadas a partir do Husky com lint-staged, é necessário adicionar em package.json: "lint-staged": { "yarn lint-fix", "yarn format-fix", "yarn test --findRelatedTests --bail" }, No caso dos testes estamos passando duas coisas a mais: --findRelatedTests: vai executar os testes dos arquivos que foram adicionados na stage do git e os relacionados a eles. Quando digo relacionado, quero dizer que ao modificar e dar git add em um arquivo de componente Component.tsx e não ter modificado o arquivo de teste Component.test.tsx, esse comando sabe qual o teste associado ao componente e mesmo sem estar o arquivo de teste adicinado em stage do git, vai validar os testes --bail: caso tenha teste quebrando vai encerrar com falha a execução dos testes, abortando o commit Agora as ações pre-commit estão mais performáticas para agirem diretamente com base nos arquivos adicionados na stage do git. Mas podemos deixar ainda mais específico para as extensões de arquivo que cada ação vai ser executada. No caso de padronização de código em relação as regras de lint e prettier, a ideia é executar nos arquivos dentro da pasta de componentes com extensão typescript .ts e .tsx. No caso dos testes seriam os arquivos especificamente de componentes e testes .tsx. Dessa forma, para fazer o lint-staged levar em consi

Introdução
English version: React and typescript components lib, part 4: pre-commit with Husky and lint-staged
Na parte quatro, será adicionada ações de pre-commit na aplicação a partir do uso de duas libs, Husky e lint-staged. O objetivo é mostrar a parte prática da adição delas nesse artigo, para uma referência segue o artigo Husky e lint-staged para pré-commit em React, que foi o primeiro que escrevi em dev.to.
Libs
- Husky: é a lib que vai permitir executar ações pre-commit
- lint-staged: é a lib que vai definir as ações pre-commit serem executadas e aplicadas nos arquivos em stage do git, ou seja, que foi dado o
git add
neles
Ações pre-commit
As ações pre-commit são executadas após se executar o git commit
no terminal, mas logo antes do commit ser finalizado de fato.
Para a aplicação serão definidas três ações pre-commit:
- Formatar os arquivos adicionados na stage do git, seguindo as regras de lint definidas para ela, logo antes do commit ser finalizado
- Formatar os arquivos adicionados na stage do git, seguindo as regras de prettier definidas para ela, logo antes do commit ser finalizado
- Executar os testes relacionados aos componentes alterados que foram adicionados no git, para validar se estão passando, logo antes do commit ser finalizado
Setup Husky
Adição do Husky:
yarn add husky --dev
No momento desse artigo gerou a seguinte versão:
"husky": "^9.1.7"
Para fazer a configuração, rodar no terminal:
npx husky init
Ele vai gerar na raiz do projeto uma pasta .husky
, dentro dela terá uma pasta _
com todos os git hooks disponíveis mas que não estão definidos para executar dentro do projeto. E fora da pasta _
um arquivo pre-commit
, com uma ação inicial definida para executar dentro dele, mas como não corresponde a comandos da app o arquivo vai ser modificado.
Além de gerar a pasta comentada acima, também irá gerar um comando que instala o Husky dentro da app em package.json:
"scripts": {
//...
"prepare": "husky"
},
Setup lint-staged
Adição do lint-staged:
yarn add lint-staged --dev
No momento desse artigo gerou a seguinte versão:
"lint-staged": "^15.5.0"
Para configurar o Husky para executar as ações pre-commit em conjunto com lint-staged é necessário modificar o arquivo dentro da pasta .husky
:
- pre-commit
npx --no-install lint-staged
Ações pre-commit
No momento a app está com três comandos referentes as ações a serem adicionadas no pre-commit:
- package.json
//...
"scripts": {
//...
"lint-src-fix": "eslint src --fix",
"format-src-fix": "prettier src --write",
"test": "jest"
}
Colocando essas ações para serem executadas, o pre-commit funcionará com sucesso, os arquivos adicionados na stage do git serão atualizados logo antes do commit ser finalizado, mas o lado ruim é que executará o comando para todos o arquivos de src
, sendo que o pre-commit em si só irá impactar os arquivos que estão na stage do git.
Então para tornar as ações pre-commit mais performáticas serão criados dois novos scripts:
- package.json
//...
"scripts": {
//...
"lint-fix": "eslint --fix",
"format-fix": "prettier --write"
}
Se tentar executar diretamente os comandos no terminal, eles não serão executados com sucesso, pois dependem de ser passado o arquivo ou a pasta a ser executado no estilo:
yarn lint-fix {caminho da pasta ou arquivo}
yarn format-fix {caminho da pasta ou arquivo}
Só que quando são colocados para serem executados com lint-staged, é observado os arquivos que estão na stage do git e executado o comando neles com sucesso.
Para definir as ações pre-commit a serem executadas a partir do Husky com lint-staged, é necessário adicionar em package.json:
"lint-staged": {
"yarn lint-fix",
"yarn format-fix",
"yarn test --findRelatedTests --bail"
},
No caso dos testes estamos passando duas coisas a mais:
- --findRelatedTests: vai executar os testes dos arquivos que foram adicionados na stage do git e os relacionados a eles. Quando digo relacionado, quero dizer que ao modificar e dar
git add
em um arquivo de componenteComponent.tsx
e não ter modificado o arquivo de testeComponent.test.tsx
, esse comando sabe qual o teste associado ao componente e mesmo sem estar o arquivo de teste adicinado em stage do git, vai validar os testes - --bail: caso tenha teste quebrando vai encerrar com falha a execução dos testes, abortando o commit
Agora as ações pre-commit estão mais performáticas para agirem diretamente com base nos arquivos adicionados na stage do git. Mas podemos deixar ainda mais específico para as extensões de arquivo que cada ação vai ser executada.
No caso de padronização de código em relação as regras de lint e prettier, a ideia é executar nos arquivos dentro da pasta de componentes
com extensão typescript .ts
e .tsx
. No caso dos testes seriam os arquivos especificamente de componentes e testes .tsx
. Dessa forma, para fazer o lint-staged levar em consideração alés dos arquivos adicionados na stage do git, mas também os que se quer que atue as ações pre-commit, ficará da seguinte forma:
"lint-staged": {
"src/components/**/*.{ts,tsx}": [
"yarn lint-fix",
"yarn format-fix"
],
"src/components/**/*.tsx": "yarn test --findRelatedTests --bail"
},
package.json
No momento o package.json
está da forma abaixo:
{
"name": "react-example-lib",
"version": "0.3.0",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/griseduardo/react-example-lib.git"
},
"scripts": {
"build": "rollup -c --bundleConfigAsCjs",
"lint-src": "eslint src",
"lint-src-fix": "eslint src --fix",
"lint-fix": "eslint --fix",
"format-src": "prettier src --check",
"format-src-fix": "prettier src --write",
"format-fix": "prettier --write",
"test": "jest",
"prepare": "husky"
},
"lint-staged": {
"src/components/**/*.{ts,tsx}": [
"yarn lint-fix",
"yarn format-fix"
],
"src/components/**/*.tsx": "yarn test --findRelatedTests --bail"
},
"devDependencies": {
"@babel/core": "^7.26.10",
"@babel/preset-env": "^7.26.9",
"@babel/preset-react": "^7.26.3",
"@babel/preset-typescript": "^7.26.0",
"@eslint/js": "^9.19.0",
"@rollup/plugin-commonjs": "^28.0.2",
"@rollup/plugin-node-resolve": "^16.0.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "11.1.6",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0",
"@types/jest": "^29.5.14",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"eslint": "^9.19.0",
"eslint-plugin-react": "^7.37.4",
"husky": "^9.1.7",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-styled-components": "^7.2.0",
"lint-staged": "^15.5.0",
"prettier": "^3.4.2",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"rollup": "^4.30.1",
"rollup-plugin-dts": "^6.1.1",
"rollup-plugin-peer-deps-external": "^2.2.4",
"styled-components": "^6.1.14",
"typescript": "^5.7.3",
"typescript-eslint": "^8.23.0"
},
"peerDependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0",
"styled-components": "^6.1.14"
}
}
Será mudada a versão para 0.4.0, uma vez que uma nova versão da lib será disponibilizada:
{
"name": "react-example-lib",
"version": "0.4.0",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/griseduardo/react-example-lib.git"
},
"scripts": {
"build": "rollup -c --bundleConfigAsCjs",
"lint-src": "eslint src",
"lint-src-fix": "eslint src --fix",
"lint-fix": "eslint --fix",
"format-src": "prettier src --check",
"format-src-fix": "prettier src --write",
"format-fix": "prettier --write",
"test": "jest",
"prepare": "husky"
},
"lint-staged": {
"src/components/**/*.{ts,tsx}": [
"yarn lint-fix",
"yarn format-fix"
],
"src/components/**/*.tsx": "yarn test --findRelatedTests --bail"
},
"devDependencies": {
"@babel/core": "^7.26.10",
"@babel/preset-env": "^7.26.9",
"@babel/preset-react": "^7.26.3",
"@babel/preset-typescript": "^7.26.0",
"@eslint/js": "^9.19.0",
"@rollup/plugin-commonjs": "^28.0.2",
"@rollup/plugin-node-resolve": "^16.0.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "11.1.6",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0",
"@types/jest": "^29.5.14",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"eslint": "^9.19.0",
"eslint-plugin-react": "^7.37.4",
"husky": "^9.1.7",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-styled-components": "^7.2.0",
"lint-staged": "^15.5.0",
"prettier": "^3.4.2",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"rollup": "^4.30.1",
"rollup-plugin-dts": "^6.1.1",
"rollup-plugin-peer-deps-external": "^2.2.4",
"styled-components": "^6.1.14",
"typescript": "^5.7.3",
"typescript-eslint": "^8.23.0"
},
"peerDependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0",
"styled-components": "^6.1.14"
}
}
Arquivo CHANGELOG
No momento o CHANGELOG.md
está da forma abaixo:
## 0.3.0
_Mar. 24, 2025_
- setup jest and testing-library
- add components tests
## 0.2.0
_Fev. 24, 2025_
- setup typescript-eslint and prettier
- add custom rules
## 0.1.0
_Jan. 29, 2025_
- initial config
Como uma nova versão será disponibilizada, será adicionado sobre o que foi modificado no arquivo:
## 0.4.0
_Abr. 29, 2025_
- setup husky and lint-staged
- define pre-commit actions
## 0.3.0
_Mar. 24, 2025_
- setup jest and testing-library
- add components tests
## 0.2.0
_Fev. 24, 2025_
- setup typescript-eslint and prettier
- add custom rules
## 0.1.0
_Jan. 29, 2025_
- initial config
Estrutura de pastas
A estrutura de pastas está da seguinte forma, sendo que além da modificação de alguns arquivos, foi adicionada a pasta do .husky
com o arquivo pre-commit
:
Publicação nova versão
Primeiro passo a ser realizado é ver se a execução do rollup ocorre com sucesso. Para isso será executado o yarn build
no terminal, que foi definido em package.json
.
Executando com sucesso, é realizar a publicação da nova versão da lib: npm publish --access public
Conclusão
A ideia desse artigo foi fazer o setup do Husky e lint-staged para definir regras de pre-commit para a aplicação. O objetivo é garantir que as alterações feitas no código sigam as regras de padronização de lint e prettier, e validar que o testes continuam passando antes de finalizar o commit.
Segue o repositório no github e a lib no npmjs com as novas modificações.