프론트엔드 개발을 할 때 TypeScript는 이제 선택이 아닌 필수로 자리 잡고 있다. 코드의 안전성과 가독성을 높여줄 뿐만 아니라, 협업 시 발생할 수 있는 오류를 줄여주는 강력한 도구이기 때문이다.
또한 협업 환경에서는 EsLint를 사용하여 코드 규칙을 강제하는 경우가 많다. 물론, 개인 프로젝트에서도 코드의 일관성을 유지하기 위해서 EsLint를 사용하는 경우도 많다.
이러한 환경에서 개발 도중에는 EsLint와 TypeScript가 오류를 알려주기 때문에 바로 문제를 인지하고 수정할 수 있다. 하지만 코드가 GitHub과 같은 저장소에 올라가는 단계에서는 검사 과정을 거치지 않고 코드가 반영될 위험이 있다. 이렇게 되면 문제가 있는 코드가 저장소에 포함될 가능성이 생기며, 이는 협업 시 큰 걸림돌이 될 수 있다.
물론, 모든 개발자가 규칙을 준수하면서 개발하면 이상적이겠지만, 현실은 그렇지 않다. 급하게 코드를 수정하거나 환경 설정을 건너뛰고 코드를 실행하는 경우, 또는 TypeScript 오류를 무시하고 any를 남발하는 경우 ( 안돼요! 싫어요! ) 등이 예시이다. 이러한 코드가 저장소에 반영되면 이를 받아들인 다른 개발자나 미래의 나는 큰 혼란에 빠질 수 있다.
모든 작업이 끝났는데, 많은 곳에서 울려 퍼지는 [ is defined but never used.... ]는 개발자로써는 숨이 막히는 상황이다.
이러한 문제를 방지하기 위한 안전장치로 사용할 수 있는 도구가 바로 Husky이다.
이제 Husky가 무엇인지, 사용하는 것이 왜 중요한지, 그리고 어떻게 설정하고 활용할 수 있는지 알아보려고 한다.
Git Hook
Husky에 대한 이야기를 잔뜩 했는데, 다음 주제가 Git Hook이라 당황하신 분도 있을 수 있다. 이는 Husky의 작동 원리가 Git Hook에 기반하기 때문이다.
Git Hook은 이름 그대로 Git 과 관련된 이벤트가 발생했을 때 특정 스크립트를 실행할 수 있는 기능을 제공한다.
우리가 우려하는 상황은 저장소에 문제가 있는 코드가 들어가는 경우인데, Git Hook을 활용하면 특정 상황에서 우리가 원하는 스크립트를 실행해 이를 방지할 수 있다.
훅은 크게 두 가지로 나뉜다 :
클라이언트 훅
Commit, Merge, Push 등의 작업 전에 클라이언트에서 실행되는 훅이다. 예를 들어, 커밋 전 코드 스타일 검사를 실행하거나 테스트를 진행할 수 있다.
서버 훅
코드가 Push될 때 서버에서 실행되는 훅이다. 이를 통해 서버 차원에서 코드 검증을 진행하거나 추가적인 작업을 수행할 수 있다.
이러한 Git Hook 기반으로 Husky를 실행시켜, 저장소에 안전한 코드만 반영되도록 할 수 있다.
이제 진짜 Husky에 대해서 알아보고 설정하는 방법도 알아보자.
Husky
Husky는 Git Hook을 간편하게 설정하고 적용할 수 있도록 도와주는 라이브러리이다. 일반적으로 Git Hook을 사용하려면 .git/hooks 디렉토리에 직접 스크립트를 작성해야 하지만, 이 디렉토리는 버전 관리가 되지 않는다.
즉, ignore 대상이기 때문에 다른 개발자와 공유할 수 없는 문제가 발생한다.
Husky는 이러한 문제를 해결하기 위해 .husky 폴더를 사용한다. .husky 폴더에 스크립트를 저장하면 해당 설정을 Git 저장소에 포함시킬 수 있어 팀원들과 Git Hook 설정을 쉽게 공유할 수 있다.
이제 Husky를 설치하고 사용하는 방법에 대해서 알아보자.
Husky 설정
1. 환경 설치
npx create-next-app으로 생성된 TypeScript와 ESLint 설정이 포함된 Next.js 프로젝트를 기준으로 설정한다.
yarn add --dev husky prettier eslint-config-prettier lint-staged
npx husky install
- prettier : create-next-app으로 자동 설치되지 않기 때문에 별도로 설치
- eslint-config-prettier : 포맷팅 시 Prettier 기준으로 하게 설정을 위해서 설치
- lint-staged : 효율적인 코드 검사를 위해서 사용한다.
- husky install : husky를 초기화하기 위해 실행
2. prettier 설정
prettier는 반드시 동일하게 설정할 필요 없고 상황에 맞게 사용하면 된다.
// .prettierrc
{
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"bracketSpacing": true,
"trailingComma": "all",
"arrowParens": "always"
}
- tabWidth : 탭을 스페이스바 2개를 기준으로 설정
- semi : 세미클론을 사용 여부
- singleQuote : 작은 따옴표를 사용하게 설정
- bracketSpacing : 객체 선언 시 괄호 양끝에 공백 삽입
- trailingComma : 여러 줄 배열, 객체 등 마지막 요소에 콤마 사용
- arrowParens : 화살표 함수의 매개변수 괄호 표시
3. eslint 설정
// eslint.config.js
import { dirname } from 'path';
import { fileURLToPath } from 'url';
import { FlatCompat } from '@eslint/eslintrc';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
});
const eslintConfig = [
...compat.extends('next/core-web-vitals', 'next/typescript', 'prettier'),
];
export default eslintConfig;
- create-next-app을 통해 자동으로 설정된 React, React Hooks, Next.js 규칙에 Prettier를 추가로 설정하여 포맷팅 충돌을 방지한다.
4. lint-staged & package.json 설정
Husky만 사용하면 커밋 전 전체 프로젝트 코드를 검사하게 되는데, 이는 비효율적이다. 이를 해결하기 위해 lint-staged를 사용하면 변경된 파일만 검사하고, 이전 검사 결과를 캐시에 보관하여 변경이 없을 경우 검사를 건너뛸 수 있다.
// package.json
{
"scripts": {
// ...
"prepare": "husky install"
},
// ...
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
]
}
}
- prepare :
- Husky를 설치할 때 초기화되도록 설정한다. 프로젝트를 사용하는 모든 개발자에게 동일하게 적용된다.
- lint-staged 설정 :
- 변경된 파일만 검사 :
- *.{js,jsx,ts,tsx} : 변경된 JavaScript, TypeScript 파일을 대상으로 한다.
- eslint --fix : ESLint를 실행해 문제를 자동으로 수정한다.
- prettier --write : Prettier를 실행해 코드 포맷팅을 적용한다.
- 변경된 파일만 검사 :
5. husky 설정
echo "npx lint-staged" > .husky/pre-commit
- pre-commit 파일 생성 :
- .husky/pre-commit 파일에 npx lint-staged 명령어를 추가한다.
- 커밋 전 변경된 파일을 대상으로 lint-staged에서 정의한 작업을 실행한다.
총총.
이번에는 Husky를 사용해서 코드를 관리하는 방법에 대해서 알아보았다. 없어도 전혀 개발하는데는 문제가 없는 부분이지만 있다가 없으면 크게 체감이 되는 부분들인 것 같다.
TypeScript, GitHub Actions , ... 모두 개발자가 대체할 수 있는 작업이지만, 추가하면서 개발 환경에 더 좋은 영향을 줄 수 있기 때문에 일부로라도 공부해서 적용할 이유가 되는 것 같다.
'개발환경' 카테고리의 다른 글
Github Actions로 배포 자동화하기 (3) | 2024.12.18 |
---|---|
[개발환경] React Native 개발환경 구성 - Window (2) | 2022.05.23 |
[개발환경] TypeScript 세팅 (2) | 2022.04.14 |
[개발환경] 도커 환경 구성 - Window (1) | 2022.03.11 |
[개발환경] React 개발환경 구성 - Window (2) | 2022.03.07 |