ft_transcendence 02 - 환경설정

2023-08-14

#42SEOUL#6TH_CIRCLE#git#bash#npm#eslint#prettier#husky#commitlint

설계에 이어, 협업을 더 원할하게 하기 위해 개발 환경을 세팅해주었다.

적용해보니 괜찮았던 몇가지 툴에 대해 말해보겠다.

eslint

eslint는 자바스크립트 코드의 문제점 혹은 오류를 찾아 리포트해주는 역할을 수행한다. eslint의 특징은 다음과 같다.

  • 규칙 기반: 다양한 규칙을 제공한다. 이 규칙들은 코드의 특정 패턴이나 문제점을 식별하는 데 사용된다.
  • 확장성: 사용자 정의 규칙을 작성하거나 이미 존재하는 규칙을 수정할 수 있다. 또한, 여러 규칙을 묶어 플러그인 형태로 공유할 수도 있다.
  • 자동 수정: 일부 규칙 위반은 ESLint에 의해 자동으로 수정될 수 있다.
  • 환경과 전역 변수 인식: Node.js, 브라우저, ES6 모듈과 같은 다양한 환경을 인식하고 그에 따른 전역 변수를 제공한다.
  • 플러그인 시스템: 사용자 정의 규칙과 함께 React, Vue, TypeScript 등과 같은 라이브러리 및 프레임워크에 대한 규칙을 추가하는 플러그인도 지원한다.
  • 설정 및 공유: .eslintrc 파일을 통해 프로젝트별로 설정할 수 있다. 이 설정은 재사용하고 공유할 수 있으므로 팀이나 커뮤니티 간에 일관된 코딩 스타일을 유지하는 데 도움이 된다.

여러 특징이 있는데, 이 중 협업할 때 일관된 코딩 스타일을 유지할 수 있도록 도움이 되는것과 에러코드를 파악하는데 도움이 많이 된다는 점이 좋았다.

설치

eslint를 사용하려면 node.js가 설치되어 있어야한다. node.js는 기본적으로 설치되어있다고 생각하고 넘어가도록 한다.

npm init @eslint/config

// 혹은
npm install --save-dev eslint

// 만약 npm install로 설치했다면
touch .eslintrc.js

// .eslintrc.js에 아래 코드 추가
module.exports = {
  "env": {
      "browser": true,
      "es2021": true
  },
  "extends": "eslint:recommended",
  "parserOptions": {
      "ecmaVersion": "latest",
      "sourceType": "module"
  },
}

설치가 되었다면 실행을 한번 해보자.

npx eslint `검사할 파일 혹은 디렉토리`

일부러 틀린 코드를 작성한 뒤, 잘 동작하는지 확인해보도록 하자.

const num = 0;
const str = '0';

console.log(str);

이렇게 작성한 뒤 eslint를 실행시켜보자.

코드에서 num을 선언했는데 사용하지 않아서 eslint에서 잡아주고 있는 것을 확인할 수 있다.

위의 .eslintrc.js에 코드를 추가해서 다양한 규칙을 설정할 수 있다.

commitlint

commitlint는 깃 커밋 메시지에 대한 스타일 가이드를 강제하기 위한 도구이다. commitlint를 사용하면 프로젝트 내의 커밋 메시지의 형식을 일관되게 유지할 수 있다.

커밋 메세지를 일관적으로 유지하는것은 코드의 변경 내역을 더욱 쉽게 파악할 수 있어서 좋다고 생각한다.

commitlint 또한 프로젝트의 상황에 맞게 규칙을 변경해줄 수 있다.

설치

// 설치
npm install -g @commitlint/cli @commitlint/config-conventional

// config 파일 생성
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js

// commitlint test
echo 'foo: bar' | commitlint

마지막 테스트가 잘 동작한다면 설치가 잘 된 것이다.

세팅

commitlint는 다양한 규칙이 존재한다.

현재 commitlint.config.js를 보면 module.exports = {extends: ['@commitlint/config-conventional']}라고 되어있을 텐데, 이 설정은 표준 커밋 메세지 형식을 검사한다는 의미이다. 여기에 rules를 추가해주어 프로젝트에 맞는 규칙들을 생성해주면 된다.

module.exports = {
  extends: ["@commitlint/config-conventional"],
  rules: {
    "subject-empty": [2, "never"],
    "subject-full-stop": [2, "never", "."],
    "type-case": [2, "never"],
    "type-empty": [2, "never"],
    "type-enum": [
      2,
      "always",
      [
        "Feat",
        "Fix",
        "Design",
        "Style",
        "Refactor",
        "Test",
        "Chore",
        "Comment",
        "Rename",
        "Remove",
      ],
    ],
    "header-max-length": [2, "always", 50],
    "references-empty": [2, "never"],
  },
};

이번 프로젝트에서 사용중인 commitlint conf이다.

기존의 extents 외에도 rules를 추가해주었다. 이 부분은 커밋 메시지의 다양한 부분을 검사하기 위한 규칙들을 정의하는 섹션이다. 각 규칙은 [level, applicability, value]의 배열 형태로 구성된다.

  • level: 규칙 위반 시의 심각도를 나타내며, 0은 규칙을 비활성화, 1은 경고, 2는 오류를 의미
  • applicability: 규칙이 항상 적용되어야하는지, 또는 절대 적용되지 않아야 하는지를 지정합니다. 주로 "always" 또는 "never" 중 하나의 값을 가짐
  • value: 규칙의 기대 값을 나타냄

규칙 별 설명:

  • subject-empty: 커밋 메시지의 주제(subject) 부분이 비어있는지 검사한다. "never"로 설정된 경우 주제가 비어있으면 안 된다.
  • subject-full-stop: 커밋 메시지의 주제가 마침표로 끝나는지 검사한다. 지금은 주제가 마침표로 끝나면 안 된다고 설정되어 있다.
  • type-case: 커밋 메시지의 타입 부분의 대소문자를 검사한다.
  • type-empty: 커밋 메시지의 타입이 비어있는지 검사합니다.
  • type-enum: 커밋 메시지의 타입이 지정된 목록에 있는지 검사한다. "Feat", "Fix", "Design" 등의 타입만 허용된다.
  • header-max-length: 커밋 메시지의 헤더 부분의 최대 길이를 검사힌다. 현재는 50자로 제한하고 있다.
  • references-empty: references 부분이 비어있는지 검사합니다. 현재는 깃 레포의 이슈번호를 포함해주어야 한다.

prettier

prettier는 코드 포맷터로써 코드를 일관된 스타일로 자동으로 정리해준다. 이 또한 일관성을 유지하기에 매우 유용하고, eslint와 함께 사용하면 코드의 품질과 스타일을 모두 자동으로 관리해줄 수 있어서 매우 유용하다.

npm install --save-dev --save-exact prettier

echo {}> .prettierrc.json

prettier를 적용하고 싶지 않은 파일 혹은 디렉토리가 있다면 .ignore로 관리해준다.

# .prettierignore
# Ignore artifacts:
build
coverage

husky

위의 eslint와 commitlint 모두 좋은 도구이지만, 단독으로 사용하기에는 굉장히 아쉬운 부분이 있다. 모든 파일을 수정할 때마다 검사해주기란 쉽지 않기 때문에, 커밋할 때 자동적으로 함께 검사해주도록 설정해주는것이 좋다.

husky는 이 작업을 할 수 있게 해준다

husky는 git hook을 쉽게 설정하고 관리할 수 있도록 도움을 주는 도구이다. git hook이란 작업 전후에 실행되는 스크립트로, husky를 사용해 git hook을 프로젝트에 더욱 쉽게 추가하고, 테스트, 커밋 규칙, 코드 검사 등의 작업을 자동화할 수 있다.

lint-staged

lint-staged는 Git의 pre-commit 훅에서 사용되는 Node.js 라이브러리이다. 여기서 pre-commit이란 실제 커밋 전 실행되는 스크립트이고, 이 스크립트에 규칙을 추가해서 commitlint, eslint와 같은 기능들을 사용할 수 있다. lint-staged라는 이름에서 알 수 있듯이, lint-staged는 Git에 staged(즉, 커밋에 추가될 예정인) 상태인 파일들만 대상으로 동작을 수행하게 된다. 이를 통해 커밋하기 전에 특정 규칙 또는 스타일을 위반한 코드를 포함시키는 것을 방지할 수 있다.

이 기능은 husky를 통해 쉽게 설정할 수 있으므로 아래에서 함께 설정해주도록 하겠다.

설치

npm install husky --save-dev

npx husky install

위의 두 줄을 입력해주면, .husky라는 디렉토리가 생성된다.

commitlint 추가

npx husky add .husky/commit-msg  'npx --no -- commitlint --edit ${1}'

위 명령어는 Husky와 commitlint를 함께 사용하여 Git 커밋 메시지의 형식을 검사하기 위한 설정을 추가하는 명령어다. 이 명령어를 한 단계씩 살펴보자.

  • npx husky add: Husky 패키지를 사용하여 Git hook을 추가하는 명령어
  • .husky/commit-msg: Husky에게 어떤 Git hook을 설정하려는지 알려준다. 여기서는 commit-msg 훅을 설정하고 있고, commit-msg 훅은 커밋 메시지가 작성된 후, 커밋이 생성되기 전에 실행된다.
  • 'npx --no -- commitlint --edit ${1}': commit-msg 훅이 실행될 때 수행할 명령어
    • npx --no --: npx 명령어를 사용하여 로컬에 설치된 패키지를 실행한다. --no는 추가 설치를 방지하기 위한 옵션이며 --는 뒤따르는 명령어에 대한 옵션의 시작을 나타낸다.
    • commitlint --edit ${1}: commitlint 명령어를 실행한다. --edit 옵션은 커밋 메시지를 검사하도록 지시하며, ${1}은 커밋 메시지의 경로를 의미한다.

결론적으로, 이 명령어는 Husky를 사용하여 커밋 메시지를 작성할 때마다 commitlint를 실행하여 메시지의 형식이 올바른지 확인하도록 설정해주는 것이고, 메시지 형식이 잘못된 경우, commitlint는 오류를 반환하고 커밋을 중단시킨다.

이 명령어를 입력해주면 다음 파일이 생성된다.

Test

앞서 설정해둔 commitlint 설정파일을 토대로 실패하는 케이스와 성공하는 케이스를 한번씩 커밋 메세지로 작성해보기로 하자.

  • 실패 케이스
git commit -m 'test: failure'

실패했을 때의 오류를 확인해보면, 사전에 conf 파일에 등록해둔 타입에 포함되지 않아 에러가 발생하고 있다. 또, 레퍼런스(이슈번호)가 비어있다고 되어있다.

자세히보면, test라는 타입은 'Test'라는 타입과 동일하지만, 대소문자를 구별하기 때문에 이 또한 오류로 판단되었다.

  • 성공 케이스
git commit -m 'Test: success #134'

오류라고 했던 사항들을 수정하니 커밋이 잘 되는 것을 확인할 수 있었다.

lint-staged 설정

lint-staged를 이용해 eslint와 prettier를 자동화해보자.

npm install --save-dev husky lint-staged
npx husky install
npm pkg set scripts.prepare="husky install"
npx husky add .husky/pre-commit "npx lint-staged"

package.json에 아래 코드 추가

  "lint-staged": {
    "**/*": "prettier --write --ignore-unknown",
    "*.{ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ]
  },

여기까지 해준 뒤, 커밋했을 때 모든 기능이 잘 작동하는지 확인해보자.

Test

테스트를 수행하기 위해 에러 코드가 작성된 파일을 하나 만들자.

const Home = () => {
  return (
      <div>test1</div>
      <div>test2</div>
  );
};

export default Home;

위 코드는 복수의 태그가 하나의 부모 태그로 묶여있지 않기 때문에 에러가 발생되어야 한다.

현재 잘 동작하고 있음을 확인할 수 있다.

쓰다보니 길어져서 다음에 이어서 쓰도록 하겠다.