Frontend/Etc

Eslint와 Prettier 설정하기(React + Ts 사용)

이의찬 2023. 12. 31. 15:48

1. Why?

과제 테스트를 React와 TypeScript로 진행하는 중이다. 간만에 Eslint와 Prettier를 설정하다보니 기억도 가물가물한데, 그 김에 Eslint와 Prettier를 어떻게 설정했는지 설명하고 왜 이렇게 설정했는지에 대해서 적어보고자 한다.

 

아래의 설정은 React + TypeScript + pnpm 기준이다. 


2. Eslint init

잠깐!

일단 설명하기 전에, 나는 실수로 eslint를 정상적으로 적용시키지않고 과제를 제출했다...

eslint를 설치하고 나서 .eslintrc.json 파일도 정상적으로 설정해줬으니 알아서 잘 돌아가겠거니~ 했는데

'hi'

과제 제출 후 글을 작성하는 도중에 혹시나 하고 var를 코드에 입력해봤는데 에러가 출력되지 않았다...

뒤늦게 eslint init을 통해서 다시 eslint를 설정하고 .eslintrc.json파일과 프로젝트 코드를 수정했다.

물론 소 잃고 외양간 고친거긴 하지만,,, 다음부터 eslint 실수하는 일은 없겠지....😢

결론

여러분들은 이런 일 없게 그냥 처음부터 eslint init으로 설정하세요. 그러니까 eslint init 방법부터 설명하겠습니다.

설명

pnpm 기준으로 pnpm eslint --init 명령어를 입력하면 어떻게 eslint를 사용할지에 대해 물어보는 첫 선택지가 출력된다.

  • 문법 오류를 체크한다.
  • 문법 오류를 체크하고 문제점을 찾는다.
  • 문법 오류, 문제점을 찾고 지정한 코드 스타일을 강제한다.

eslint는 보편적인 선택지를 default값으로 주기에, 정 모르겠으면 그냥 default로 가는것도 괜찮다.

난 코드 스타일은 prettier로 관리할꺼니까 2번을 선택했다.

프로젝트에서 어떤 모듈 형식을 쓰니?

  • JavaScript module (import/export)
  • CommonJs (require/exports)
  • 둘 다 아님

node Js에서는 CommonJs를 default로 쓴다고 알고 있다. 하지만  React나 Vue에서는 Es module을 기본으로 쓰니까 1번 선택하면 된다. 

어떤 프레임워크 쓰니?

타입스크립트 쓰니?

뜬금없는데 타입스크립트 정말 좋다. 처음 사용할때는 좀 불편했는데 적응하고나니까 Js보다 100배는 편하다...
혹시 아직 안 써본 사람이라면 꼭 사용하길

코드 실행 환경에 대해서 물어본다. 하나만 선택할 수도, 둘 다 선택할 수도 있다.

  • 브라우저
  • Node

Next.js같은 풀스택 프레임워크라면 둘 다, Node.js로 백엔드를 만들거라면 Node를, React나 Vue로 웹 프론트엔드를 만들거라면 Browser를 선택하면 된다.

설정 파일은 뭘로 할래?

  • JavaScript
  • YAML
  • JSON

보통은 JS나 JSON으로 선택하는데, 난 익숙한 JSON으로 했다.

지금까지 선택한대로 설정하려면 위의 패키지들이 필요한데 설치해줘? 

Yes

 

어떤 패키지 매니저를 사용하니?

  • npm
  • yarn
  • pnpm

https://cksxkr5193.tistory.com/2

이 때 패키지매니저를 결정한 이후로 계속 pnpm을 사용하고 있다.

나는 위와 같이 선택했고, 결과는 다음과 같다.

{
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:react/recommended"
    ],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
    "plugins": [
        "@typescript-eslint",
        "react"
    ],
    "rules": {
    }
}

3. Eslint 결과물

하지만 eslint init만 해줬다고 끝이아니다. 추가적인 설정도 해줘야 한다. 사전과제에서는 다음과 같이 설정했다.

extends

 "extends": [
    "airbnb",
    "airbnb-typescript",
    "airbnb/hooks",
    "plugin:prettier/recommended",
    "prettier"
 ]

다른 eslint 설정을 상속받은 것. 가장 대중적이고 유명한 airbnb룰을 선택했다.

settings

 

  "settings": {
    "import/resolver": {
      "alias": {
        "map": [["@", "./src"]],
        "extensions": [".ts", ".tsx", ".js", ".jsx", ".json"]
      }
    }
  },

절대경로 설정 시 에러가 출력되지 않도록 import/resolver에 "@"로 시작되는 경로를 인식할 수 있게 했다.

rules

  "rules": {
    "linebreak-style": 0,
    "prettier/prettier": [
      "error",
      {
        "endOfLine": "auto"
      }
    ],
    "import/prefer-default-export": "off",
    "react/react-in-jsx-scope": "off",
    "import/no-extraneous-dependencies": [
      "error",
      {
        "devDependencies": true,
        "optionalDependencies": true,
        "peerDependencies": true
      }
    ],
    "react/require-default-props": "off",
    "import/extensions": [
      "error",
      "ignorePackages",
      {
        "js": "never",
        "jsx": "never",
        "ts": "never",
        "tsx": "never",
        "json": "never"
      }
    ],
    "import/order": [
      "error",
      {
        "groups": ["builtin", "external", "parent", "sibling", "index"],
        "pathGroups": [
          {
            "pattern": "react",
            "group": "external",
            "position": "before"
          },
          {
            "pattern": "react-router-dom",
            "group": "external",
            "position": "before"
          },
          {
            "pattern": "@/**/*",
            "group": "parent",
            "position": "before"
          }
        ],
        "pathGroupsExcludedImportTypes": ["builtin"],
        "newlines-between": "always",
        "alphabetize": {
          "order": "asc",
          "caseInsensitive": true
        }
      }
    ]
  }
}
  • "linebreak-style": 0,
  • "prettier/prettier"

eslint의 줄 바꿈 스타일에 대한 규칙을 비활성화하고, prettier에서 처리하도록 했다.

이런 스타일은 모두 prettier에서 처리하는쪽이 낫다고 생각한다.

  • "import/prefer-default-export": "off"

하나만 export할거면 default export로 처리하는 규칙인데, 처음 type 파일 생성해서 export할때는 default 달아주고 그 다음 추가할때는 삭제해주는게 불편해서 off.

  • "react/react-in-jsx-scope": "off"

최상단에 무조건 import react를 기입해야하는 규칙인데 React 17버전 이후로는 없어도 된다. 마찬가지로 불편해서 off

  • "react/require-default-props": "off"

optional한 props는 기본값을 가져야하는 규칙이다. 아직 크게 필요성을 느낀적 없어서 off했다.

  • "import/no-extraneous-dependencies": 

@vitejs/plugin-react패키지를 사용하기 위해 devDependencies, optionalDependencies, peerDependencies 등을 참조해서 사용할 수 있게 했다.

  • "import/extensions"

import 시 파일의 확장자를 모두 명시해야하는 rule이다. js, jsx, ts, tsx, json의 경우에는 굳이 명시하지 않는게 더 깔끔해보여서 ignorePackages로 설정했다.

  • "import/order"

import 순서를 정렬하는 rule이다. 원래는 Eslint에서 import order를 하기보단 formatter인 Prettier에서 설정하는게 원래의 역할에 더 가깝다고 생각해 Prettier에서 처리하도록 설정했다.

하지만 trivago의 import sort가 생각보다 불편한 점이 많았고 eslint와 충돌이 일어나는 부분도 있어 그냥 eslint로 설정했다. 

{
  "env": {
    "browser": true,
    "es2021": true
  },
  "extends": [
    "airbnb",
    "airbnb-typescript",
    "airbnb/hooks",
    "plugin:prettier/recommended",
    "prettier",
  ],
  "overrides": [
    {
      "env": {
        "node": true
      },
      "files": [".eslintrc.{js,cjs}"],
      "parserOptions": {
        "sourceType": "script"
      }
    }
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "project": "**/tsconfig.json",
    "ecmaVersion": "latest",
    "sourceType": "module"
  },
  "plugins": ["@typescript-eslint", "prettier", "import"],
  "ignorePatterns": ["node_modules/"],
  "settings": {
    "import/resolver": {
      "alias": {
        "map": [["@", "./src"]],
        "extensions": [".ts", ".tsx", ".js", ".jsx", ".json"]
      }
    }
  },
  "rules": {
    "linebreak-style": 0,
    "prettier/prettier": [
      "error",
      {
        "endOfLine": "auto"
      }
    ],
    "import/prefer-default-export": "off",
    "react/react-in-jsx-scope": "off",
    "import/no-extraneous-dependencies": [
      "error",
      {
        "devDependencies": true,
        "optionalDependencies": true,
        "peerDependencies": true
      }
    ],
    "react/require-default-props": "off",
    "import/extensions": [
      "error",
      "ignorePackages",
      {
        "js": "never",
        "jsx": "never",
        "ts": "never",
        "tsx": "never",
        "json": "never"
      }
    ],
    "import/order": [
      "error",
      {
        "groups": ["builtin", "external", "parent", "sibling", "index"],
        "pathGroups": [
          {
            "pattern": "react",
            "group": "external",
            "position": "before"
          },
          {
            "pattern": "react-router-dom",
            "group": "external",
            "position": "before"
          },
          {
            "pattern": "@/**/*",
            "group": "parent",
            "position": "before"
          }
        ],
        "pathGroupsExcludedImportTypes": ["builtin"],
        "newlines-between": "always",
        "alphabetize": {
          "order": "asc",
          "caseInsensitive": true
        }
      }
    ]
  }
}

결과적으로 위와 같은 설정이 완료되었다.

+ 추가

eslint-plugin-tailwindcss도 설치해주었다. Tailwind CSS 쓰는 사람에게 강력하게 추천하는 패키지다.

나름대로 혼자 신경써서 '크기가 맨 앞에, flex는 그 다음, 사용자 지정 스타일은 그 다음...' 하는 식으로 정렬해주고 있었는데 한 방에 고민을 해결해줬다.


4. Prettier

{
  "arrowParens": "always",
  "htmlWhitespaceSensitivity": "css",
  "bracketSameLine": false,
  "bracketSpacing": true,
  "printWidth": 80,
  "proseWrap": "preserve",
  "quoteProps": "as-needed",
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "useTabs": false
}

사실 대부분의 설정은 default 값과 비슷하다. singleQuote 정도만 다른데, 그냥 이건 개인 선호라 특별한 이유는 없다. 다만 광활한 대지를 달려나가는 코드들을 보면서 광개토대왕의 위엄을 느낄게 아니라면 tabWidth는 무조건 2를 쓰는게 좋다.

+ 추가

여기도 마찬가지로 자동 정렬을 위해 prettier-plugin-tailwindcss 패키지를 설치해주었다. 

자세한 내용은 https://tailwindcss.com/blog/automatic-class-sorting-with-prettier 여기를 참조하면 된다.

 


4. 래퍼런스

https://tech.kakao.com/2019/12/05/make-better-use-of-eslint/

 

ESLint 조금 더 잘 활용하기

들어가며 안녕하세요. 카카오 FE플랫폼팀의 Joah입니다. 최근에 팀에서 사용하는 JavaScript 스타일 가이드를 개선하는 업무에 참여했습니다. 업무를 하며 스타일 가이드에서 사용하고 있는 ESLint에

tech.kakao.com

https://xionwcfm.tistory.com/359

 

nextjs 13 typescript 환경에서 eslint airbnb 에 husky, gitmoji, lint-staged까지?

😡 왜그러시죠? 제가 화난 사람처럼 보이나요? 항상 그렇지만 환경설정이 제일 어려운 것 같습니다. 미래의 제가 또 같은 일을 해야할 상황이 빈번할 것 같아 미리 기록을 남겨둡니다. 윈도우환

xionwcfm.tistory.com

https://www.daleseo.com/eslint-config/

 

ESLint 상세 설정 가이드

Engineering Blog by Dale Seo

www.daleseo.com

https://www.daleseo.com/js-prettier-config/

 

Prettier 상세 설정 가이드

Engineering Blog by Dale Seo

www.daleseo.com

https://univdev.page/posts/eslint-prettier-installation/

 

ESlint와 Prettier 설치하기

ESLint ESLint는 코드를 보다 예쁘고 일관성있게 관리하기 위한 최소한의 제한사항입니다. VSCode 에디터를 사용하고 있다면 ‘저장 시 자동으로 포맷’ 기능을 활용하여 ESLint에 비준하지 않는 코드

univdev.page

https://tailwindcss.com/blog/automatic-class-sorting-with-prettier

 

Automatic Class Sorting with Prettier - Tailwind CSS

People have been talking about the best way to sort your utility classes in Tailwind projects for at least four years. Today we’re excited to announce that you can finally stop worrying about it with the release of our official Prettier plugin for Tailwi

tailwindcss.com