티스토리 뷰

개인 프로젝트가 아닌 협업 프로젝트를 진행할 때, 코딩 스타일을 일치시키지 않는다면 코드를 합치거나 비교할 때 매우 불편할 것이다. 코딩 스타일은 팀의 자율에 따라 결정되지만 강제성이 없기 때문에 취약하다. 

코드 리뷰나 작성을 할 때에도 의식하지 않으면 많은 에너지가 소모되므로 자동화될 수 없는 컨벤션은 최소화하고 필요한 경우에는 반드시 문서화시켜야 한다. 

자동화 툴들이 아무것도 없이 시작하는 것보다 시간을 들여서라도 초기세팅에 공을 들여놓으면 지속적인 개발 생산성 향상에 도움을 주기 때문에 꼭 알아둬야 한다. 

ESLint & Prettier

ESLint는 일관되고 버그를 피할 수 있는 코드를 짜기 위해서 만들어진 코드 분석 툴이다. 

작성된 코드의 구문을 분석하여 버그가 발생할 여지가 있거나, 불필요한 코드, 혹은 보안상 위험한 코드에 대한 경고를 띄워준다. 간단히 말하면 JS 문법체커라고 생각하면 된다. 

Prettier는 코드 포맷팅 툴이다. 이 포맷팅 룰(설정)은 커스터마이징이 가능하다. 린트가 문법을 체킹해줬다면 프리티어는 코드의 형식을 맞춰준다. 

[ 설치 방법 ]

1. eslint 

npm install eslint --save-dev 혹은 yarn add -D eslint
  • 리액트 프로젝트를 CRA로 만들 경우, 내장되어 있어 따로 설치하지 않아도 된다.

2. prettier

npm install prettier --save-dev

3. eslint-config-prettier

  • eslint는 linting 기능을, prettier는 formatting을 담당하는 구조가 이상적이다. 하지만, eslint에는 일부 formatting과 관련된 rule이 포함되어 있어 이 rule들이 prettier와 설정이 충돌할 수 있다. 
  • 따라서, eslint에서 formatting관련 rule들을 모두 해제할 필요가 있다.(수동 세팅법도 있지만 eslint-plugin이 존재하기 때문에 이를 설치해서 하는게 편하다)
npm install eslint-config-prettier --save-dev

optional 

  • 패키지들을 설치하면 terminal에서 명령어를 통해 eslint와 prettier를 실행할 수 있다. 
  • IDE에서는 일반적으로 terminal 명령어로 실행하는 것 뿐만 아니라 에디터 차원에서 파일을 저장할 때 formatting을 적용해주고, 에디터에서 eslint의 메세지를 확인할 수 있게 해주는 기능들을 플러그인 형태로 제공하기에 원할 시에 사용할 수 있다. => 사용하고 있는 IDE가 vscode라면 마켓플레이스에서 Prettier와 ESLint 플러그인을 설치해주면 된다. 

[ Prettier 설정 ] #설정 쉬움

  • 프로젝트 루트 디렉토리에 `.prettierrc.확장자`파일을 통해서 설정가능하다.
  • 설정파일의 확장자 형식은 JSON, YAML, JS, TOML 등 다양하게 지원한다. (e.g.) .prettierrc.json)
  • 포매팅에 관련된 룰들을 원하는 것들만 추려서 설정해주면 된다. 
  • 추가 옵션들은 공식 홈페이지를 통해서 확인하면 된다. Options Prettier
// .prettierrc.js

module.exports = {
  printWidth: 100, // printWidth default 80 => 100 으로 변경
  singleQuote: true, // "" => ''
  arrowParens: "avoid", // arrow function parameter가 하나일 경우 괄호 생략
};

[ ESLint 설정 ] #설정 다소 어려움

  • eslint 설정은 커스터마이징할 수 있는 부분이 많고, 언어별(js,ts 등) 환경별(web, node, react 등) 세팅을 해줘야할 부분이 많아 다소 복잡하다.
  • 처음부터 모든 rule을 하나하나 설정하는 것이 불필요하거나 불편하다고 판단될 경우 다른 사람이 이미 정의해놓은 config를 설치한 후 확장해서 사용할 수 있다. => 하나하나 조작할 만큼 편하지 않으면 만들어진 것을 갖다 쓰기
  • eslint에서 기본적으로 제공되지 않는 특정 환경을 위한 rule들을 추가하고 싶을 때에는 plugin을 이용할 수 있다.
// .eslintrc

{
  "extends": ["react-app", "eslint:recommended", "prettier"],
  "rules": {
    "no-var": "error", // var 금지
    "no-multiple-empty-lines": "error", // 여러 줄 공백 금지
    "no-console": ["error", { "allow": ["warn", "error", "info"] }], // console.log() 금지
    "eqeqeq": "error", // 일치 연산자 사용 필수
    "dot-notation": "error", // 가능하다면 dot notation 사용
    "no-unused-vars": "error" // 사용하지 않는 변수 금지
  }
}

[ Husky ]

git hook 설정을 도와주는 npm package이며, 번거로운 git hook 설정이 편하고 npm install 과정에서 사전에 세팅해둔 git hook을 다 적용시킬 수 있어 모든 팀원이 git hook이 실행되도록 하기 편하다. 
husky를 통해 pre-commit, pre-push hook 설정이 가능하다.

1. 도입해야 하는 이유

  • 위에서 prettier, eslint 를 도입해놓고 작업자(개발자)가 사용하지 않으면 효과가 없다. 
  • 하지만 개인이 매번 확인해서 실행하는 것은 실수가 발생할 여지가 있으며 강제성이 없다.
  • git hook 설정은 까다롭고 모든 팀원이 사전에 repo를 클론받고 메뉴얼하게 사전 과정을 수행해야하지만 hook이 실행됨을 보장할 수 있다. 실수로 사전과정을 까먹으면 hook이 실행되지 않는다. => 이 부분을 husky를 통해 해결가능

2. 문제해결

  • 자동화를 통해 신경쓰지 않아도 자동으로 적용이 되게하고 특정 상황에서 강제로 적용
  • commit된 코드는 무조건 formatting이 완료되어야 하고, push된 코드는 무조건 eslint가 pass된 상태에서 push가 되도록 자동화를 구축해야 함

3. Husky를 통한 Git Hook 적용 

3-1. 허스키 설치

npm install husky --save-dev #개발환경에서만 적용

3-2. (처음 husky를 세팅하는 사람만 실행 필요)

npx husky install
  • 위의 명령어는 huksy에 등록된 hook을 실제 .git에 적용시키기 위한 스크립트이다. 

3-2-1. package.json에 postinstall 스크립트 추가하기 

// package.json

{
  "scripts": {
    "postinstall": "husky install",
    "format": "prettier --cache --write .",
	"lint": "eslint --cache .",
  },
}
  • 이후 클론받아 사용하는 팀원들은 npm install 후에 자동으로 husky install 이 될 수 있도록 하는 설정이다. 
  • eslint 명령어를 위한 lint 스크립트와 prettier 명령어를 위한 format 스크립트도 추가해준다. 

[lint 명령어 옵션에 관련된 추가 설명]

// package.json

"lint": "eslint --cache --max-warings=0",
  • 린트 명령어에서 warning도 엄격하게 하나도 허용하고 싶지 않다면 eslint --max-warnings=0 으로 옵션을 붙여서 스크립트를 실행시켜주면 된다. 
"lint": "eslint --cache src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
  • 위의 코드에서 --cache 옵션을 제외한 명령어는 기존 ts + vite + react 프로젝트에 내장되어 있던 명령어이다. 
  • --ext 옵션은 특정 파일을 대상으로 정적 분석을 해주는 옵션이라고 한다. 즉 뒤에있는 ts,tsx를 정적 분석하는 것이다.
    • 정적 분석(Static analysis)은 프로그램의 소스 코드를 컴파일하지 않고도 프로그램의 동작과 구조를 분석하는 프로세스 

4. pre-commit, pre-push hook을 추가하기

npx husky add .husky/pre-commit "npm run format"
npx husky add .husky/pre-push "npm run lint"

 

  • 위의 명령어를 실행하면 husky install 시 생겼던 .husky 폴더 내에 pre-commit이라는 파일이 생긴다. 
  • husky를 통해 pre-commit 시, npm run format 명령어를 실행시키다는 의미이다.
  • yarn의 경우는 "yarn format", "yarn lint" 로 명령어를 써주면 되겠죠? 

4-1. pre-commit 추가 설명

  • lint-staged와 결합해서 사용한다. => 포매팅을 수행한 뒤 git add 명령어를 자동으로 수행되게 할 수 있다. 
  • 포매팅을 전체 파일 대상이 아닌 현재 git stage에 올라온 변경사항 대상으로만 수행할 수 있다. 

5. 참고 사항

  • git hook에서 eslint ERROR가 발견되면 실행중인 script가 종료되기 때문에 이 rule에 대해서 error로 설정할 것인지 warn으로 설정할 지 잘 고려해야 한다. warn은 코드 push가 되지만 error는 코드 push가 안된다. 

[ Vite, react, typescript 에서 eslint 설정 파일 세팅하기]

  • 우선 Vite로 ts + react 프로젝트를 만들면 아래와 같은  .eslintrc.cjs가 자동으로 만들어진다. 
/* eslint-env node */

module.exports =
  {
    root: true,
    env: {
      browser: true,
      es2020: true,
    },
    extends:
      [
        'eslint:recommended',
        'plugin:@typescript-eslint/recommended',
        'plugin:@typescript-eslint/recommended-requiring-type-checking',
        'plugin:react-hooks/recommended',
      ],
    parser:
      '@typescript-eslint/parser',
    parserOptions:
      {
        ecmaVersion:
          'latest',
        sourceType:
          'module',
        project: true,
        tsconfigRootDir:
          __dirname,
      },
    plugins:
      [
        'react-refresh',
      ],
    rules:
      {
        'react-refresh/only-export-components':
          [
            'warn',
            {
              allowConstantExport: true,
            },
          ],
        '@typescript-eslint/no-non-null-assertion':
          'off',
      },
     
  };

나는 setting을 확인해보고 싶어서 초기화부터 진행했다. .cjs가 아닌 .JSON형식으로 아래와 같이 만들어주었다. 

yarn eslint --init #해당 명령어를 입력하면 물음을 통해 원하는 세팅을 하도록 도와준다.
{
  "env": {
    "browser": true,
    "es2021": true
  },
  "extends": [
    "plugin:prettier/recommended",
    "plugin:react/recommended",
    "plugin:react/jsx-runtime",
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:react-hooks/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": "latest",
    "sourceType": "module",
    "project": "./tsconfig.json"
  },
  "plugins": ["@typescript-eslint", "react", "react-refresh"],
  "rules": {
    // //리액트 17버전 이상부터는 React를 필수로 import하지 않아도되기 때문에 off로 설정
    // "react/react-in-jsx-scope": "off",
    "react-refresh/only-export-components": [
      "warn",
      {
        "allowConstantExport": true
      }
    ],
    "@typescript-eslint/no-non-null-assertion": "off"
  }
}
  •  
  • 기존에 React 를 쓰지 않더라도 import를 꼭해야했는데 17버전 이후부터는 React를 임포트하지 않더라도 쓸 수 있게됐다.
  • 린트 에러가 났을 때 해결방법으로 "react/react-in-jsx-scope": "off", 를 옵션값으로 주는 방법도 있지만 오류 메세지로 "plugin:react/jsx-runtime",를 확장에 넣으라는 안내를 받을 수 있다. 주의점이 있다면 꼭 "plugin:react/recommended",뒤에 runtime 플러그인을 넣어줘야 한다.
  • 참고로 json 파일이 cjs 보다 우선순위가 낮기 때문에 같이 존재해도 문제가 되진 않는다. (우선 순위가 높은 1가지 설정파일만 적용된다.)
댓글