bandal.dev

프로젝트 ESLint 설정 in VSCode

코드 컨벤션을 유지하기 위한 ESLint 설정 방법

9
ESLint
VSCode
React

ESLint 설정 방법에 대해 정리한 글입니다.
제가 React 프로젝트를 진행할 때 주로 사용했던 ESLint 설정 기반으로 작성되었습니다.

정의

ESLint

240220-205457

Javascript, JSX의 코드를 분석하여 문법 오류나 안티 패턴을 찾아주거나 일괄된 코드 스타일로 작성하도록 코드 포맷을 만들 수 있는 라이브러리 입니다.
그 중 외부에 오픈되어 있는 코딩 규칙도 사용이 가능한데 유명한 Airbnb, Google 등의 Style을 제공합니다.

Prettier

240220-210647

Prettier는 코드를 읽고 다시 작성하여 코드 스타일을 일관성 있게 맞춰주는 도구입니다.
ESLint와 함께 사용할 경우 코드 스타일 관련된 ESLint 규칙을 비활성화하고 Prettier에 맡기는 방식으로 사용합니다.

왜 Prettier는 다루지 않나요?

Linters는 코드를 분석하여 문제점을 찾아내는 것이 주 할이고, Formatters는 코드를 정리하는 것이 주 역할입니다.

Linters로 코드 작성 규칙 정리 과정은 코드 분석 및 문제점을 찾아내는 과정으로 인해 Formatters 대비 느린 속도를 보입니다. 그래서 코드작성규칙은 Prettier로 작성하길 권장하는 글을 종종 볼 수 있습니다.

하지만 Prettier는 코드를 읽고 다시 작성하기에 그 과정에서 소스 코드에서 모든 스타일 정보를 버려버립니다. 그 과정에서 개발자가 원하는 스타일을 보존할 수 없게 만듭니다.

가장 큰 예시로 printWidth 옵션을 들 수 있습니다. 아래 예시를 통해 오히려 시각적으로 더 읽기 어려운 코드가 되는 것을 확인할 수 있습니다.

240220-212618

ESLint의 포매팅 규칙 deprecate

2023.12.16 추가

ESLint v8.53.0부터 포매팅 규칙을 deprecate 처리하였고, 이후 v10부터 완전히 제거할 계획을 발표했습니다.

주된 이유로는 언어적 발전에 따른 구문들의 변화와 프레임워크(주로 React)의 사용이 폭발적으로 증가함에 따라 스타일 규칙을 동결해 관리하고자 했지만, 더 이상 변화들과 사용자 요구를 따라잡기 어려워졌기 때문이라고 합니다.

대신 코드 형식을 관리하고자 한다면 코드 포메터인 Prettier를 사용할 것을 권장합니다.

설정 방법

IDE에 ESLint 설치

240222-004856

VSCode의 확장탭에서 ESLint를 검색하여 설치합니다.

.eslintrc 파일을 이용한 ESLint 설정

1. ESLint 패키지중 필요한 패키지를 설치합니다.

  • eslint: ESLint의 코어 패키지
  • eslint-plugin-react: JSX 및 React 컴포넌트 관련 규칙
  • eslint-plugin-react-hooks: React Hooks 관련 규칙
  • eslint-plugin-import: import / export 관련 규칙
  • eslint-plugin-jsx-a11y: JSX 요소의 접근성 관련 규칙
  • @typescript-eslint/eslint-plugin: TypeScript 관련 규칙
  • @typescript-eslint/parser: TypeScript 코드를 분석하기 위한 parser
  • eslint-plugin-tailwindcss: Tailwind CSS 관련 규칙 // Tailwind CSS 를 사용할 경우
  • eslint-config-next: Next.js 프로젝트에서 사용하는 ESLint 설정 // Next.js 프로젝트일 경우

eslint-config-next는 Next CLI로 구성했을 경우 기본 설치되어 있으므로 아래 명령어에 포함하지 않았습니다.

npm
npm install --save-dev eslint eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-tailwindcss @typescript-eslint/eslint-plugin @typescript-eslint/parser
yarn
yarn add --dev eslint eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-tailwindcss @typescript-eslint/eslint-plugin @typescript-eslint/parser
pnpm
pnpm i -D eslint eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-tailwindcss @typescript-eslint/eslint-plugin @typescript-eslint/parser

2. .eslintrc.json 파일을 생성하고 아래와 같이 설정합니다.

패키지 목록을 전부 설치했을 경우 샘플 설정입니다.

.eslintrc.json
{
  // 플러그인 문서
  // https://github.com/jsx-eslint/eslint-plugin-react
  // https://typescript-eslint.io/
  // https://www.npmjs.com/package/eslint-plugin-jsx-a11y
  // https://www.npmjs.com/package/eslint-plugin-tailwindcss
  "extends": [
    "next/core-web-vitals", // Next.js 프로젝트일 경우
    "plugin:react/recommended",
    "plugin:react-hooks/recommended",
    "plugin:jsx-a11y/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:tailwindcss/recommended" // tailwindcss 사용 시
  ],
  "plugins": [
    "import",
    "@typescript-eslint",
    "tailwindcss", // tailwindcss 사용 시
    "jsx-a11y",
    "react"
  ],
  "parser": "@typescript-eslint/parser",
  "settings": {
    "tailwindcss": {
      // Tailwind를 사용하는 className override 함수를 지정합니다.
      "callees": ["cn"],
      "config": "tailwind.config.js"
    },
    "next": { // Next.js 프로젝트일 경우
      "rootDir": ["./src/"]
    },
    // React 버전을 지정합니다.
    // 지정하지 않을 경우, React 라이브러리 전체를 탐색하므로 린트 속도가 느려질 수 있습니다. ( 기본값: "detect" )
    "react": {
      "version": "18.3.1"
    },
    // typescript, node 모듈 설정
    "import/resolver": {
      "typescript": {
        "alwaysTryTypes": true,
        "project": "./tsconfig.json"
      },
      "node": {
        "extensions": [".js", ".jsx", ".ts", ".tsx"]
      }
    }
  },
  "rules": {
    "indent": ["error", 2],
    "quotes": ["error", "double"],
    "semi": ["error", "always"],
    "comma-dangle": ["error", "always-multiline"],
    "no-trailing-spaces": "error",
    "comma-spacing": ["error", { "before": false, "after": true }],
    "block-spacing": ["error", "always"],
    "semi-spacing": "error",
    "key-spacing": ["error", {
      "afterColon": true,
      "beforeColon": false
    }],
    "arrow-parens": ["warn", "always"],
    "arrow-spacing": ["error", { "before": true, "after": true }],
 
    // <img> 엘리먼트에 유의미한 대체 텍스트가 있는지 체크
    "jsx-a11y/alt-text": [
      "warn",
      {
        "elements": ["img"]
      }
    ],
    // 유효한 aria-* 속성만 사용
    "jsx-a11y/aria-props": "warn",
    // 유효한 aria-* 상태/값만 사용
    "jsx-a11y/aria-proptypes": "warn",
    // DOM에서 지원되는 role, ARIA만 사용
    "jsx-a11y/aria-unsupported-elements": "warn",
    // 필수 ARIA 속성이 빠져있는지 체크
    "jsx-a11y/role-has-required-aria-props": "warn",
    // ARIA 속성은 지원되는 role에서만 사용
    "jsx-a11y/role-supports-aria-props": "warn",
 
    // import React from 'react'; 를 사용하지 않아도 되도록 설정
    "react/react-in-jsx-scope": 0,
    // children이 없는 경우 self-closing 태그로 설정
    "react/self-closing-comp": ["error", {
      "component": true,
      "html": true
      }],
    // DOM에 정의되지 않은 속성 사용 체크
    "react/no-unknown-property": ["error", {
      "ignore": ["cmdk-input-wrapper"]
    }],
    // JSX가 여러줄로 이루어진 경우, 괄호로 감싸도록 설정
    "react/jsx-wrap-multilines": [
      "error",
      {
        "declaration": "parens-new-line",
        "assignment": "parens-new-line",
        "return": "parens-new-line",
        "arrow": "parens-new-line",
        "condition": "parens-new-line",
        "logical": "parens-new-line",
        "prop": "parens-new-line"
      }
    ],
    // 정의되지 않은 prop 사용 체크 ( 기본적으로 typescript에서 체크하므로 off )
    "react/prop-types": "off", // @see https://github.com/shadcn-ui/ui/issues/120
 
    // console.warn, console.error만 허용
    "no-console": ["error", {
      "allow": ["warn", "error"]
    }],
 
    // Tailwind 사용시 커스텀 클래스명 사용 체크
    "tailwindcss/no-custom-classname": "off",
 
    // import 순서 정렬
    "import/order": [
      "error",
      {
        "groups": ["builtin", "external", "internal", ["parent", "sibling", "index"]], // 그룹핑 순서
        "newlines-between": "always" // 그룹 사이에 빈 줄 추가 여부
      }
    ],
    
    // 사용하지 않는 변수 체크
    "@typescript-eslint/no-unused-vars": [
      "warn",
      {
        "varsIgnorePattern": "_.*",
        "argsIgnorePattern": "_.*",
        "args": "none"
      }
    ]
  }
}

VSCode 설정

소스코드를 내려받은 사용자가 VSCode에 ESLint를 기본 Formatter로 사용할 수 있도록 공통 설정을 추가합니다.
.vscode/settings.json 파일을 생성하고 아래와 같이 설정합니다.

.vscode/settings.json
{
    "eslint.format.enable": true,
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "dbaeumer.vscode-eslint",
    "css.lint.unknownAtRules": "ignore", // Tailwind CSS 사용 시
    "typescript.preferences.importModuleSpecifier": "non-relative", // tsconfig의 path alias 사용 시
}
.vscode/extensions.json
{
  "recommendations": [
    "dbaeumer.vscode-eslint"
  ]
}

.eslintignore

ESLint 규칙 제외 대상을 지정할 수 있습니다.
Project의 최상위에 .eslintignore 파일을 생성하거나 .eslintrc 의 "ignorePatterns" 에 추가하여 설정할 수 있습니다.

.eslintignore
dist
.cache
public
node_modules
*.esm.js