---
title: "Prettier와 ESLint로 코드 일관성·품질 향상하기"
description: "개발 업무에서 코드 스타일 일관성과 코드 품질을 유지하는 건 매우 중요합니다. 이는 개발팀 협업과 팀 생산성을 향상하는 데 큰 역할을 합니다. Prettier와 ESLint는 코드 스타일 일관성과 코드 품질 관리를 돕는 도구입니다. 이 글은 코드 스타일 일관성과 코드 품질을 유지하기 위해 Next.js 프로젝트에서 Prettier와 ESLint를 사용하는 방법을 다뤘습니다."
url: https://insight.infograb.net/blog/2024/09/20/prettier-eslint/
source: content/generated/blog/2024-09-20-prettier-eslint.md
---

개발 업무에서 코드 스타일 일관성과 코드 품질을 유지하는 건 매우 중요합니다. 협업 프로젝트나 대규모 코드베이스에 일관되지 않은 코드 스타일과 실수가 쌓이면, 코드 가독성과 유지보수성이 저하됩니다.  이는 개발팀 협업에 방해가 되고, 팀 생산성까지 떨어뜨릴 수 있습니다.

Prettier와 ESLint를 사용하면 이러한 문제를 해결하는 데 도움이 됩니다. Prettier는 JavaScript, TypeScript, HTML, CSS 등 다양한 언어의 코드를 일관된 스타일로 자동 포맷팅하는 도구입니다. ESLint는 JavaScript, TypeScript 코드의 잠재 오류를 사전 감지하고, 정해진 코드 스타일을 강제해 일관성을 유지하도록 돕는 도구입니다.

이 글에서는 코드 스타일 일관성과 코드 품질을 유지하기 위해 Next.js 프로젝트에서 Prettier와 ESLint를 사용하는 방법을 살펴보겠습니다.

## 1. 도구 설치

### ESLint

다음 명령을 입력해 Next.js 프로젝트, ESLint, Tailwind CSS를 설치합니다.

```bash
npx create-next-app@latest

✔ What is your project named? … nextjs-prettier-eslint
✔ Would you like to use TypeScript? … No / 
Yes

✔ Would you like to use ESLint? … No / 
Yes

✔ Would you like to use Tailwind CSS? … No / 
Yes

✔ Would you like to use `src/` directory? … No / 
Yes

✔ Would you like to use App Router? (recommended) … No / 
Yes

✔ Would you like to customize the default import alias (@/*)? … 
No
 / Yes
```

### Prettier

1. **설치**

    다음 명령을 입력해 Prettier를 설치합니다.

    ```bash
    npm install -D prettier
    ```

    또는

    ```bash
    yarn add -D prettier
    ```

2. **설정**

    프로젝트 루트에 `.prettierrc` 파일을 생성하고, 아래 예시와 같이 설정합니다.

    ```json
    {
        "printWidth": 120,
        "trailingComma": "es5",
        "tabWidth": 4,
        "semi": true,
        "singleQuote": true,
        "endOfLine": "auto",
        "useTabs": false,
        "arrowParens": "always",
        "tailwindConfig": "./tailwind.config.ts"
    }
    ```

    - `"printWidth"`: 한 줄의 최대 길이를 설정합니다.
    - `"trailingComma"`
        - `"none"`: 마지막 요소 뒤에 쉼표를 추가하지 않습니다.
        - `"es5"`: ES5에서 허용될 때만 마지막 요소 뒤에 쉼표를 추가합니다. 배열, 객체, 함수 인자 등에서 마지막 요소 뒤에 쉼표가 추가됩니다.
        - `"all"`: 가능한 모든 곳에서 마지막 요소 뒤에 쉼표를 추가합니다. TypeScript나 Flow와 같은 언어의 함수 인자나 제네릭 타입 등에도 쉼표가 추가됩니다.
    - `"tabWidth"`: 탭의 크기를 설정합니다.
    - `"singleQuote"`: 문자열에 홑따옴표(')를 사용할지 겹따옴표(")를 사용할지 설정합니다. true면 홑따옴표를 사용합니다.
    - `"endOfLine"`
        - `"auto"`: Prettier가 현재 파일에서 사용 중인 줄 바꿈 문자를 자동으로 감지하고 이를 유지합니다.
    - `"useTabs"`: 탭을 사용할지 공백을 사용할지 설정합니다. false면 공백, true면 탭을 사용합니다.
    - `"arrowParens"`: 화살표 함수에서 인자가 하나일 때 괄호를 사용할지 설정합니다. `"avoid"`(생략) 또는 `"always"`(항상 사용) 중 선택할 수 있습니다.

## 2. prettier-plugin-tailwindcss로 Prettier 활용

prettier-plugin-tailwindcss는 Prettier와 Tailwind CSS를 함께 사용하는 플러그인입니다. 이는 Prettier가 코드를 포맷팅할 때 Tailwind CSS 유틸리티 클래스를 지정된 기준에 따라 알파벳 순서로 자동 정렬합니다. 이로써 코드 스타일의 일관성을 유지하고 가독성을 높입니다.

### 플러그인 설치

다음 명령을 입력해 prettier-plugin-tailwindcss를 설치합니다.

```bash
npm install -D prettier-plugin-tailwindcss
```

또는

```bash
yarn add -D prettier-plugin-tailwindcss
```

:::note 참고

1. 클래스는 Tailwind 아키텍처에 따라 아래 순서로 정렬됩니다.
    1. 기본(Base) 레이어 클래스(예: container)
    2. 컴포넌트(Component) 레이어 클래스
    3. 유틸리티(Utility) 레이어 클래스(예: text-center, bg-red-500)
2. 유틸리티 레이어에서 클래스는 기능에 따라 아래 순서로 추가 정렬됩니다.
    1. 레이아웃과 구조에 영향을 미치는 클래스
    2. 시각적 스타일과 관련된 클래스

:::

### 설정

`.prettierrc` 파일에 다음과 같이 설정합니다.

```bash
{
    .
    .
    .
    //이전 설정들...
    
    "plugins": ["prettier-plugin-tailwindcss"]
}
```

:::note 참고

설정이 적용되지 않을 때,

1. settings.json 설정을 확인합니다.

    "editor.formatOnSave": true,
    "editor.defaultFormatter": "esbenp.prettier-vscode"

2. VS Code를 재시작합니다.

:::

## 3. eslint-plugin-tailwindcss로 ESLint 활용

eslint-plugin-tailwindcss는 Tailwind CSS와 ESLint를 함께 사용하는 플러그인입니다. 이는 JSX 또는 일반 HTML에서 사용된 Tailwind CSS 클래스명을 검사하고, 올바른 Tailwind CSS 클래스명을 사용하는지 확인합니다. 이로써 코드 스타일의 일관성을 유지하도록 지원합니다.

### 플러그인 설치

다음 명령을 입력해 eslint-plugin-tailwindcss를 설치합니다.

```bash
npm install -D eslint-plugin-tailwindcss
```

또는

```bash
yarn add -D eslint-plugin-tailwindcss
```

### 설정

아래와 같이 설정합니다.

```json
{
  "plugins": ["tailwindcss"],
  "extends": ["next/core-web-vitals", "plugin:tailwindcss/recommended"],
  "rules": {
    "tailwindcss/no-custom-classname": "off",
    "tailwindcss/classnames-order": "off"
  }
}
```

- `"tailwindcss/no-custom-classname"`: JSX 또는 HTML에서 Tailwind CSS로 정의되지 않은 사용자 정의 클래스명을 사용할 때 경고 또는 오류를 발생시키는 규칙입니다. 커스텀 클래스가 있으면 오류가 생기므로, 이 예시에서는 `“off”` 로 설정합니다.
- `"tailwindcss/classnames-order"`: Tailwind CSS 클래스명을 알파벳 순서로 정렬하도록 요구하는 규칙입니다. `“prettier-plugin-tailwindcss”` plugin으로 Tailwind CSS 클래스명을 정렬하기에 이 예시에서는 `“off”`로 설정합니다.

## 4. @tanstack/eslint-plugin-query로 ESLint 활용

@tanstack/eslint-plugin-query는 프론트엔드 애플리케이션의 데이터 관리, 상태 관리를 최적화하는 ESLint 플러그인입니다. 이는 TanStack Query를 사용할 때 발생하는 오류와 성능 문제를 방지하고, 최적의 코드 품질을 유지하도록 규칙과 권장 사항을 제공합니다. 이로써 코드 스타일의 일관성을 유지하고, 가독성을 향상하도록 돕습니다.

### 플러그인 설치

다음 명령을 입력해 @tanstack/eslint-plugin-query를 설치합니다.

```bash
npm i -D @tanstack/eslint-plugin-query
```

또는

```bash
yarn add -D @tanstack/eslint-plugin-query
```

### 설정

아래와 같이 설정합니다.

```json
{
  "plugins": ["@tanstack/query"],
  "extends": ["plugin:@tanstack/query/recommended"],
  "rules": {
    // "@tanstack/query/exhaustive-deps": "error",
    // "@tanstack/query/stable-query-client": "error",
    // "@tanstack/query/no-rest-destructuring": "warn",
    // "@tanstack/query/no-unstable-deps": "warn"
  }
}
```

- `"@tanstack/query/exhaustive-deps"`: Query function 내부에서 사용하는 모든 변수를 Query key에 포함합니다.

    ✅ **올바른 예**

    ```javascript
    useQuery({
      queryKey: ['todo', todoId],
      queryFn: () => api.getTodo(todoId),
    })
    
    const todoQueries = {
      detail: (id) => ({ queryKey: ['todo', id], queryFn: () => api.getTodo(id) }),
    }
    ```

- `"@tanstack/query/stable-query-client"`: 애플리케이션의 전체 라이프사이클 동안 하나의 QueryClient 인스턴스만 생성합니다.

    ✅ **올바른 예**

    ```javascript
    const queryClient = new QueryClient()
    function App() {
      return (
        <QueryClientProvider client={queryClient}>
          <Home />
        </QueryClientProvider>
      )
    }
    ```

    ```javascript
    function App() {
      const [queryClient] = useState(() => new QueryClient())
      return (
        <QueryClientProvider client={queryClient}>
          <Home />
        </QueryClientProvider>
      )
    }
    ```

- `"@tanstack/query/no-rest-destructuring"`: Query 결과에서 실제 필요한 필드에만 구독을 걸도록 설정합니다.

    ✅ **올바른 예**

    ```javascript
    const todosQuery = useQuery({
      queryKey: ['todos'],
      queryFn: () => api.getTodos(),
    })
    
    // normal object destructuring is fine
    const { data: todos } = todosQuery
    ```

- `"@tanstack/query/no-unstable-deps"`:  아래 Query hook의 반환값을 구조 분해해 얻은 개별값을 React hook의 의존성 배열에 전달합니다.
    - useQuery
    - useSuspenseQuery
    - useQueries
    - useSuspenseQueries
    - useInfiniteQuery
    - useSuspenseInfiniteQuery
    - useMutation

    ✅ **올바른 예**

    ```javascript
    /* eslint "@tanstack/query/no-unstable-deps": "warn" */
    import { useCallback } from 'React'
    import { useMutation } from '@tanstack/react-query'
    
    function Component() {
      const { mutate } = useMutation({ mutationFn: (value: string) => value })
      const callback = useCallback(() => {
        mutate('hello')
      }, [mutate])
      return null
    }
    ```

## 5. **eslint-plugin-import로 ESLint 활용**

eslint-plugin-import는 JavaScript, TypeScript 프로젝트의 import/export 문법을 위한 ESLint 플러그인입니다. 이는 코드에서 모듈을 가져오고 내보내는 방식의 규칙을 제공합니다. 이로써 코드 스타일의 일관성과 코드 품질을 유지하도록 지원합니다.

### 플러그인 설치

다음 명령을 입력해 eslint-plugin-import를 설치합니다.

```bash
npm install -D eslint-plugin-import
```

또는

```bash
yarn add -D eslint-plugin-import
```

### 설정

아래와 같이 설정합니다.

```json
{
  "plugins": ["import"],
  "rules": {
    "import/order": [
      "warn",
      {
        "groups": [
          "builtin", // Node.js 기본 모듈
          "external", // 외부 라이브러리 모듈
          ["internal", "parent", "sibling"], // 프로젝트 내부 모듈
          "index", // 인덱스 파일
          "object", // import 객체 (e.g., import * as _ from 'lodash')
          "type" // 타입 import (TypeScript에서)
        ],
        "pathGroups": [
          {
            "pattern": "react",
            "group": "external",
            "position": "before"
          },
          {
            "pattern": "{react-query,**/query}",
            "group": "external",
            "position": "after"
          },
          {
            "pattern": "{app/components/**,app/**/components/**}",
            "group": "internal",
            "position": "after"
          },
          {
            "pattern": "hooks/**",
            "group": "internal",
            "position": "after"
          },
          {
            "pattern": "utils/**",
            "group": "internal",
            "position": "after"
          },
          {
            "pattern": "{styles/**,images/**}",
            "group": "internal",
            "position": "after"
          }
        ],
        "pathGroupsExcludedImportTypes": ["builtin"],
        "alphabetize": {
          "order": "asc",
          "caseInsensitive": true
        },
        "newlines-between": "always"
      }
    ]
  }
}
```

- `“groups”`: import 문을 그룹으로 나눠 정렬하는 기준을 정의합니다.
    - `“builtin”`: Node.js의 기본 모듈(fs, path 등)
    - `“external”`: 외부 라이브러리 모듈(react, lodash 등)
    - `“internal”`: 프로젝트 내부에서 정의한 모듈
    - `“parent"`: 부모 디렉터리에서 가져온 모듈
    - `“sibling”`: 형제 디렉터리에서 가져온 모듈
    - `“index”`: 디렉터리의 index.js나 index.ts 파일
    - `“object”`: 객체로 가져오는 import 문(예: import * as _ from 'lodash').
    - `“type”`: TypeScript에서 사용하는 타입을 가져오는 import 문(예: `import type { MyType } from './types'`).
- `“pathGroups”`: 특정 패턴의 경로에 import 순서를 세밀하게 제어합니다.
    - `“pattern”`: 특정 패턴에 맞는 import 문을 지정합니다.
    - `“group”`: 이 import 문이 속할 그룹을 지정합니다(external, internal 등).
    - `“position”`: 해당 그룹에서 위치를 지정합니다(before, after).
- `“pathGroupsExcludedImportTypes”`: 여기 나열된 타입의 import 문은 pathGroups에서 지정된 그룹으로 구분되지 않습니다. 이때 Node.js의 기본 모듈(builtin)은 pathGroups 영향을 받지 않습니다.
- `“alphabetize”`: import 문을 알파벳순으로 정렬하는 옵션
    - `“order”`: `"asc"`로 설정되면, 오름차순으로 정렬합니다.
    - `“caseInsensitive”`: `true`로 설정되면, 대소문자를 구분하지 않고 정렬합니다.
- `“newlines-between”`: 서로 다른 import 그룹 사이에 항상 빈 줄을 추가합니다.

## 맺음말

지금까지 일관된 코드 스타일과 코드 품질을 유지하기 위해 Next.js 프로젝트에서 Prettier와 ESLint를 사용하는 방법을 살펴봤습니다. 이때 Tailwind CSS와 TanStack Query도 활용하면 코드를 더 효율적으로 작성하고, 코드 유지보수성도 향상할 수 있습니다.

프로젝트 초기부터 Prettier와 ESLint 설정을 잘 구성하면, 개발자 간 스타일 충돌을 최소화할 수 있습니다. 아울러 코드 리뷰에서 불필요한 논쟁도 방지할 수 있습니다. 이는 개발팀의 생산성을 높이고, 장기적으로 안정적이며 유지 보수하기 쉬운 코드베이스를 구축하는 데 도움이 됩니다.

여러분도 Prettier와 ESLint로 코드 스타일과 코드 품질을 잘 관리해 업무 효율을 향상하고, 개발팀 동료와 원활히 협업하시길 바랍니다.

::cta::

## 참고 자료

1. Jonathan Reinink·Adam Wathan, “Automatic Class Sorting with Prettier”, Tailwindcss, 2022.1.25, [https://tailwindcss.com/blog/automatic-class-sorting-with-prettier](https://tailwindcss.com/blog/automatic-class-sorting-with-prettier)
2. “eslint-plugin-tailwindcss”, NPM, [https://www.npmjs.com/package/eslint-plugin-tailwindcss](https://www.npmjs.com/package/eslint-plugin-tailwindcss)
3. “ESLint Plugin Query”, TanStack Query, [https://tanstack.com/query/latest/docs/eslint/eslint-plugin-query](https://tanstack.com/query/latest/docs/eslint/eslint-plugin-query)
4. “Exhaustive dependencies for query keys”, TanStack Query, [https://tanstack.com/query/latest/docs/eslint/exhaustive-deps](https://tanstack.com/query/latest/docs/eslint/exhaustive-deps)
5. “Stable Query Client”, TanStack Query, [https://tanstack.com/query/latest/docs/eslint/stable-query-client](https://tanstack.com/query/latest/docs/eslint/stable-query-client)
6. “Disallow object rest destructuring on query results”, TanStack Query, [https://tanstack.com/query/latest/docs/eslint/no-unstable-deps](https://tanstack.com/query/latest/docs/eslint/no-unstable-deps)
7. “Disallow putting the result of query hooks directly in a React hook dependency array”, TanStack Query, [https://tanstack.com/query/latest/docs/eslint/no-unstable-deps](https://tanstack.com/query/latest/docs/eslint/no-unstable-deps)

::faq::

- q: Prettier와 ESLint는 각각 무엇을 하나요?

    a: Prettier는 JavaScript, TypeScript, HTML, CSS 등 여러 언어의 코드를 일관된 스타일로 자동 포맷팅하는 도구입니다. ESLint는 JavaScript와 TypeScript 코드의 잠재 오류를 미리 감지하고, 정해진 코드 스타일을 강제해 일관성을 유지하도록 돕는 도구입니다. 협업 프로젝트에 일관되지 않은 스타일과 실수가 쌓이면 가독성과 유지보수성이 떨어지므로, 프로젝트 초기부터 두 도구를 설정하면 스타일 충돌과 코드 리뷰의 불필요한 논쟁을 줄일 수 있습니다.

- q: Next.js 프로젝트에 Prettier는 어떻게 설정하나요?

    a: create-next-app으로 프로젝트를 만들 때 TypeScript, ESLint, Tailwind CSS 사용 여부를 선택하고, npm install -D prettier 또는 yarn add -D prettier로 Prettier를 설치합니다. 그다음 프로젝트 루트에 .prettierrc 파일을 만들어 한 줄 최대 길이(printWidth), 마지막 요소 뒤 쉼표(trailingComma), 탭 크기(tabWidth), 홑따옴표 사용(singleQuote), 줄 바꿈 문자(endOfLine), 화살표 함수 괄호(arrowParens) 같은 규칙을 정합니다. 2024년 9월 기준 예시에서는 printWidth 120, trailingComma es5, tabWidth 4, singleQuote true로 설정했습니다.

- q: prettier-plugin-tailwindcss는 무엇을 하나요?

    a: prettier-plugin-tailwindcss는 Prettier가 코드를 포맷팅할 때 Tailwind CSS 유틸리티 클래스를 정해진 기준에 따라 자동 정렬해 주는 플러그인입니다. 클래스는 Tailwind 아키텍처에 따라 기본 레이어, 컴포넌트 레이어, 유틸리티 레이어 순으로 정렬되고, 유틸리티 레이어 안에서는 레이아웃·구조 클래스가 시각적 스타일 클래스보다 앞에 옵니다. 플러그인을 설치하고 .prettierrc의 plugins에 추가하면 되며, 적용되지 않으면 VS Code의 formatOnSave와 기본 포매터 설정을 확인하고 재시작합니다.

- q: Tailwind CSS와 TanStack Query를 쓸 때 어떤 ESLint 플러그인을 쓰면 좋나요?

    a: eslint-plugin-tailwindcss는 JSX나 HTML에서 쓴 Tailwind CSS 클래스명이 올바른지 검사하며, 2024년 9월 기준 예시에서는 커스텀 클래스 오류를 막으려 no-custom-classname을, Prettier 플러그인이 정렬을 맡으므로 classnames-order를 꺼 두었습니다. @tanstack/eslint-plugin-query는 TanStack Query 사용 시 오류와 성능 문제를 막는 규칙을 제공합니다. 대표 규칙은 Query 함수에서 쓰는 모든 변수를 Query key에 넣는 exhaustive-deps, 앱 생애주기 동안 QueryClient를 하나만 만드는 stable-query-client, 필요한 필드만 구독하게 하는 no-rest-destructuring, 그리고 no-unstable-deps입니다.

- q: eslint-plugin-import로 import 순서는 어떻게 정리하나요?

    a: eslint-plugin-import의 import/order 규칙으로 import 문을 그룹별로 정렬합니다. groups에 builtin(Node.js 기본 모듈), external(외부 라이브러리), internal(내부 모듈), parent, sibling, index, object, type 같은 그룹 순서를 정하고, pathGroups로 특정 경로 패턴의 위치를 세밀하게 지정합니다. alphabetize의 order를 asc로, caseInsensitive를 true로 두면 대소문자 구분 없이 오름차순 정렬되고, newlines-between으로 그룹 사이에 빈 줄을 넣을 수 있습니다.

::faq-end::

::button::[코드 품질 기준을 리뷰 단계에서 일관되게 지키고 싶으신가요? DevOps 전문가, 인포그랩과 상담하세요!](https://insight.infograb.net/contact/)::
