Husky, lint-staged 정복하기.

프론트 깎는 개발자·2023년 2월 19일
4

Intro

협업을 하다 보면 다른 분의 브랜치에서 pull 한 코드에 오류가 있다든지 (eslint 나 prettier 등 불일치 문제) 아니면, push 해서 CI/CD 파이프라인에 프로젝트가 올라갔는데 마지막 단계에서 빌드가 되지 않아 서버를 띄우지 못하는 불상사가 발생할 수 있다.

이런 현상을 방지하기 위해, 일종의 '규칙 강제' 또는 '선 검증 후 커밋' 느낌으로 사용하는 것이 바로 git hooks 이다. 그리고 husky 는 이러한 git hooks 를 잘 활용할 수 있게 도와주는 도구이다.

즉, git commit 하기 전, git push 하기 전 등과 같은 각종 git 명령어를 사용하는 상황에서 작동하여, 코드에 대한 사전에 정의된 일련의 검사를 하고, 그 결과에 따라 commit 이나 push 를 허용 또는 차단하는 것이다.

그러면 나의 NextJS 프로젝트에 이를 세팅하는 법을 알아보자.

(여기서는 husky 와 함께 lint-staged 까지 같이 설치해볼 것이다!)
(husky 는 전체 파일을 검사하는 데에 비해, lint-staged 는 말 그대로 staging 된 파일들만 검사해서 훨씬 효율적이다!)

설치법

우선 본 데모를 위해 빈 Next 프로젝트를 하나 만든다!

npx create-next-app . --typescript --use-npm

eslint 설정

husky 는 코드의 오류를 '정해진' 일련의 규칙으로 검사하기 때문에 그 '규칙' 을 우리가 사전에 정해줘야 한다. eslint 의 rule 을 통해 정할 수 있는데, 이를 위해 두 개의 파일을 생성한다. (root 디렉토리에)

.eslintrc.json

{
  "extends": ["plugin:@typescript-eslint/recommended", "next/core-web-vitals"],
  "plugins": ["@typescript-eslint"],
  "parser": "@typescript-eslint/parser",
  "rules": {
    "no-unused-vars": "off",
    "@typescript-eslint/no-empty-interface": "off",
    "@typescript-eslint/no-unused-vars": [
      "error",
      {
        "vars": "all",
        "varsIgnorePattern": "^_",
        "args": "after-used",
        "argsIgnorePattern": "^_"
      }
    ],
    "require-jsdoc": "off",
    "react/display-name": "off",
    "quotes": ["error", "single"] // 문자열 들을 단일 따옴표로 감싸도록 강제
  }
}
  • 여기서 varsIgnorePattern 이 있는데 _ 를 붙인 변수면, 사용하지 않은 변수라도 (unused var) 이라도 괜찮다고 해 주겠다는 말이다.

가끔 사용하지 않은 변수를 놔둬야 할 필요도 있는데 그 때 요긴하게 쓸 것이다!

이 규칙들은 본인 (또는 프로젝트 진행 인원들) 의 뜻에 따라 바꿀 수 있다!

.eslintignore

.next
next-env.d.ts
yarn.lock
public
next.config.js
README.md
Dockerfile
.nvmrc
.vscode
.idea
.yarn
.pnp.*
test.tsx

이 파일은 eslint 의 검증 대상 목록에서 제외되는 대상이다. (깨알같이 들어있는 test.tsx ... 내가 나의 컴포넌트를 테스트하는 곳이다!)

prettier 설정

prettier 은 많은 분들이 아시다시피 코드의 formatting 을 해 준다. 보통 tabWidth, doubleQuote 등과 같은 옵션들을 지정할 수 있다.

.prettierrc

{
  "trailingComma": "es5",
  "useTabs": false,
  "tabWidth": 2,
  "semi": true,
  "singleQuote": true,
  "printWidth": 100,
  "arrowParens": "always",
  "bracketSpacing": true
}

.prettierignore

.next
next-env.d.ts
public
next.config.js
README.md
Dockerfile
.nvmrc
.vscode
.idea
test.tsx

이들도 마찬가지로 prettier 가 formatting 을 수행하지 않을 대상들의 목록이다.

지금가지 총 4개의 파일을 추가해주자!

husky 설치

npm install husky --save-dev

lint-staged 설치

npm install lint-staged --save-dev

스크립트 두기

그리고 사용할 스크립트들을 넣어 준다. 나는 pre-commit hook 과 pre-push hook 을 쓸 것이다.

다음의 경로에 파일을 추가한다.
.husky/pre-commit

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx lint-staged

.husky/pre-push

#!/bin/sh
. "$(dirname -- "$0")/_/husky.sh"

npm run build

package.json 수정

아래 lint-staged 에 아래 내용 추가. (js, jsx 파일도 linting 을 원할 시 추가해준다!)

{
	...
  "scripts": {
    ...
  },
  "lint-staged": {
    "*.{ts,tsx}": [
      "eslint",
      "prettier --list-different"
    ]
  },
  "dependencies": {
    ...
  },
	...
}

package.jsonnpm run prepare 추가하기

npm pkg set scripts.prepare="husky install"

위를 실행하면 package.json 에 한 줄이 더 추가된다.
"prepare": "husky install"

{
	...
  "scripts": {
    ...
    "prepare": "husky install"
  },
  "lint-staged": {
     ...
  },
  "dependencies": {
    ...
  },
	...
}

끝!

이제 eslint 규칙을 위반한 아래와 같은 코드를 짜면

아래와 같이 검사를 하면서

바로 걸려버린다.

커밋 불가!

나는 ok, 다른 사람들은?

나는 여기서 npm run prepare 이라는 명령어로 husky 를 설치했지만, 보통의 npm 으로 관리되는 프로젝트들은 사람들이 npm install 로 모든 준비가 끝났으면 한다. 그래서 마지막으로 package.json 에...

{
	...
  "scripts": {
    ...
    "prepare": "husky install",
    "postinstall": "husky install"
  },
  "lint-staged": {
     ...
  },
  "dependencies": {
    ...
  },
	...
}

"postinstall": "husky install" 한 줄만 추가해주면 npm install 직후 자동으로 실행되어 이제 다른 사람들은 clone 받은 후 npm install 만으로 husky 가 자동으로 작동한다!

결론

기존에는 husky 만 설치했어서 사용했는데 다음과 같은 두 가지 문제가 있었다.

  1. 지금 커밋하려고 하는 staging 된 파일 이외에도 모든 파일들을 모두 검사해서 시간이 오래걸리는 문제
  2. 다른 파일은 작업 중이지만, 지금 '이 파일' 만 임시 커밋하려고 할 때 커밋 하지도 않을'다른 파일' 에서 나타난 eslint 에러가 '이 파일'의 커밋을 막아버리는 문제

그래서 이렇게 lint-staged 를 도입하게 되었다!
빠르고, 간편하며, formatting 과 linting 을 동시에 진행할 수 있어서 좋다!

도움 주신 분


kangdyu 님: 깃허브 방문 하기

profile
Comfort Zone 에서 벗어나자!

0개의 댓글