ESLint + Prettier + Husky로 안정화된 개발 환경 구축하기

Tooling_Setup

2025년 8월 10일

·

10 min read

들어가며

팀 프로젝트에서 중요한 것 중 하나는 일관된 코드 스타일품질 관리입니다. 개발자마다 다른 코딩 스타일이나 사소한 실수로 인한 버그는 프로젝트가 커질수록 누적되어 큰 문제가 될 수 있습니다.

제가 진행하고 있는 프로젝트는 현재 모노레포(Monorepo) 구조로 디자인 시스템을 관리하고 있습니다. 여러 패키지가 하나의 저장소에 공존하다 보니, 각기 다른 설정 때문에 관리가 복잡해지는 문제가 발생했습니다.

이번 글에서는 ESLint, Prettier, Husky를 활용해 모노레포 환경에서 안정적인 개발 환경을 구축한 경험을 공유하고, 과정 중 마주했던 문제와 해결 방법을 정리해보겠습니다.


도구 소개

우선 본격적인 설명에 앞서, 각 도구가 해결하는 문제와 역할을 간단히 정리해봤습니다.

ESLint - 코드 품질 검사

ESLint는 JavaScript/TypeScript 코드를 정적 분석해 잠재적인 오류나 규칙 위반을 찾아내는 도구입니다.

// ESLint가 잡아낼 수 있는 문제들
const unusedVariable = "hello"; // ❌ 사용하지 않는 변수
let name = "john";
name = 123; // ❌ 타입 불일치 (TypeScript)
if ((user.name = "admin")) {
  // ❌ 할당(=) vs 비교(===) 실수
  // ...
}

Prettier - 코드 포맷팅

Prettier는 코드 포맷터로, 개발자가 스타일을 고민하지 않아도 일관된 규칙에 따라 코드를 정리해줍니다.

// Before: 들여쓰기, 공백이 제각각
const user = { name: "john", age: 25, city: "seoul" };
 
// After: 일관된 스타일 적용
const user = {
  name: "john",
  age: 25,
  city: "seoul",
};

Husky + lint-staged - 자동화

HuskyGit Hook을 관리하는 도구로, 커밋/푸시 전에 자동으로 검사나 스크립트를 실행할 수 있습니다.

lint-staged는 Git에 staged된 파일들만 선별적으로 검사하여 성능을 최적화해줍니다.

# 커밋 시도
git commit -m "fix: button component"
 
# Husky가 자동 실행
 ESLint 검사 실행...
 Prettier 검사 실행...
 모든 검사 통과 시에만 커밋 완료

실제로 문제가 있는 파일을 커밋하면 아래와 같이 차단되며 오류가 표시됩니다.

lint-staged
lint-staged

왜 도입해야할까?

앞선 도구들을 간략하게 설명드렸습니다. 그렇다면 저는 왜 프로젝트에서 해당 도구들을 도입하게 되었는지 배경을 간략하게 정리해봤습니다.

  1. 코드 스타일 불일치: 개발자마다 다른 들여쓰기, 따옴표 사용 등으로 인한 가독성 저하
  2. 잠재적 버그: 타입 에러, 사용하지 않는 변수 등 런타임 에러로 이어질 수 있는 문제들
  3. 리뷰 시간 낭비: 코드 스타일이나 간단한 실수에 시간을 쓰느라 핵심 로직 리뷰에 집중하지 못함
  4. 모노레포 복잡성: 여러 패키지에 각각 다른 설정이 있어 관리 부담 증가

따라서 아래와 같이 목표를 설정했습니다.

  • Root 중심의 통합 설정으로 모노레포 전체에 일관된 규칙 적용
  • 커밋 전 자동 검사로 품질이 낮은 코드의 저장소 유입 방지
  • 효율적인 검사로 개발 속도 저하 최소화
  • 팀원 간 설정 공유로 개발 환경 통일

해결 과정: 단계별 구현

그렇다면 각 도구를 어떻게 적용했는지를 살펴봅시다.

ESLint 설정 - 코드 품질 검사

TypeScript + React 환경에 맞는 ESLint 설정을 구성했습니다.

// eslint.config.ts
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";
 
export default tseslint.config(
  { ignores: ["dist"] },
  {
    extends: [js.configs.recommended, ...tseslint.configs.recommended],
    files: ["**/*.{ts,tsx}"],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
    },
    plugins: {
      "react-hooks": reactHooks,
      "react-refresh": reactRefresh,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      "react-refresh/only-export-components": [
        "warn",
        { allowConstantExport: true },
      ],
    },
  }
);

핵심 포인트:

  • 모듈형 설정: 플러그인별로 명확하게 분리하여 유지보수성 향상
  • typescript-eslint로 타입 안전성 확보
  • React Hooks 및 Fast Refresh 지원
  • eslint-config-prettier로 ESLint와 Prettier 간 규칙 충돌 방지

Prettier 설정 - 코드 스타일 통일

코드 스타일 통일을 위한 Prettier 설정을 추가했습니다.

// .prettierrc
{
  "semi": false,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 80
}

.prettierignore를 활용해 빌드 산출물, 로그 파일, lock 파일 등은 검사 대상에서 제외했습니다.

// .prettierignore
# Build output
dist/
build/
storybook-static/

# Dependencies
node_modules/
.pnpm/

# Tooling
.turbo/
coverage/
*.tsbuildinfo

# Logs and temp files
*.log
.DS_Store

# Lock file
pnpm-lock.yaml

# eslint config
eslint.config.js

plopfile.js
plop-templates/

Husky + lint-staged - 커밋 시점 자동화

가장 핵심적인 부분인 Git Hook을 통한 자동화를 구현했습니다.

// package.json 일부
{
  "scripts": {
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives",
    "format:check": "prettier --check .",
    "quality:check": "pnpm lint && pnpm format:check"
  },
  "lint-staged": {
    "*.{ts,tsx}": [
      "eslint --max-warnings 0",
      "prettier --check"
    ],
    "*.{js,jsx,json,css,md}": [
      "prettier --check"
    ]
  }
}

모노레포 구조와 통합 관리

저희 프로젝트는 다음과 같은 모노레포 구조를 가지고 있습니다:

design-system/
├── eslint.config.js     # 전체 프로젝트 ESLint 규칙
├── .prettierrc          # 전체 포맷팅 규칙
├── .vscode/settings.json # VSCode 통합 설정
├── package.json         # 통합 스크립트 및 Husky 설정
├── packages/
│   ├── design-system/   # 디자인 시스템 패키지
│   ├── playground/      # 테스트 및 데모 환경
│   ├── tokens/          # 디자인 토큰
│   └── themes/          # 테마 설정
└── .husky/              # Git hooks
    └── pre-commit

각 패키지별로 따로 설정하지 않고 Root 디렉토리에서 통합 관리하는 방식을 선택했습니다.

마주한 문제점들과 해결책

구현 과정에서 몇 가지 문제점들을 마주했는데, 이를 어떻게 해결했는지 공유하겠습니다.

ESLint와 Prettier 규칙 충돌

초기에는 ESLint의 포맷팅 규칙과 Prettier가 충돌하는 문제가 발생했습니다.
해결책: eslint-config-prettier 패키지를 설치하여 충돌하는 ESLint 규칙을 비활성화했습니다.

pnpm add -D eslint-config-prettier

성능 이슈 - 전체 파일 검사로 인한 느린 커밋

처음에는 커밋 시 프로젝트 전체를 검사하여 커밋 시간이 매우 오래 걸렸습니다.
해결책: lint-staged를 도입하여 변경된 파일만 검사하도록 최적화했습니다.


마무리

ESLint, Prettier, Husky를 통한 개발 환경 구축은 단순히 코드를 정리하는 수준을 넘어, 팀 전체의 생산성과 협업 효율성을 높이는 기반이 됩니다.

저희 팀에서는 실제로 코드 리뷰 시 스타일 관련 코멘트가 크게 줄어들었으며 협업 효율성도 크게 향상되었습니다.

처음에는 규칙과 설정이 번거롭게 느껴질 수 있습니다. 그러나 한 번 구축해두면 시간이 지날수록 이점이 누적되어, 특히 모노레포처럼 복잡한 구조에서는 필수적인 품질 관리 수단이 됩니다.

  • ESLint
  • Prettier
  • Husky