eslint.config와 eslint.plugin의 역할 및 설정

2025년 10월 4일

ESLint 기본 개념

ESLint란 "Linter"라는 도구입니다. Linter는 코드를 실행하기 전에 미리 검사해서 잠재적인 버그나 코딩 스타일 문제를 찾아주는 프로그램입니다.

eslint.config 파일 완벽 분석

eslint.config란?

eslint가 어떻게 동작할지 설정을 해두는 파일입니다. (a.k.a 설계도)
과거에는 .estlintrc이름의 파일로써 JSON/YAML 형식이었지만, 현재는 eslint.config.js파일의 형태로써, Javascript 모듈을 사용하고 유연한 프로그래밍이 가능합니다.


Config 파일 구조 상세 분석

그럼 eslint.config.js 파일 안을 자세히 보겠습니다. 이 파일은 기본적으로 설정 객체의 배열을 export합니다.

// eslint.config.js (Flat Config - ESLint 9.0+)

export default [
  {
    // 1️⃣ 파일 매칭 설정
    files: ['**/*.js', '**/*.jsx'],
    
    // 2️⃣ 무시할 파일
    ignores: ['node_modules/**', 'dist/**'],
    
    // 3️⃣ 언어 옵션 (파싱 설정)
    languageOptions: {
      ecmaVersion: 2024,           // JavaScript 버전
      sourceType: 'module',         // ES 모듈 사용
      globals: {
        window: 'readonly',         // 브라우저 전역 변수
        document: 'readonly',
      },
      parser: '@typescript-eslint/parser', // TypeScript 파서
      parserOptions: {
        ecmaFeatures: {
          jsx: true                 // JSX 지원
        }
      }
    },
    
    // 4️⃣ 플러그인 등록
    plugins: {
      react: reactPlugin,
      '@typescript-eslint': tsPlugin
    },
    
    // 5️⃣ 규칙 설정
    rules: {
      'no-console': 'warn',         // console 사용 시 경고
      'no-unused-vars': 'error',    // 미사용 변수 에러
      'react/prop-types': 'off'     // PropTypes 체크 끄기
    },
    
    // 6️⃣ 공유 설정
    settings: {
      react: {
        version: 'detect'           // React 버전 자동 감지
      }
    }
  }
];

배열인 이유는 프로젝트의 다른 부분에 다른 규칙을 적용하고 싶을 수 있기 때문입니다. 예를 들어, 일반 소스 코드에는 엄격한 규칙을 적용하지만, 개발 시에는 좀 더 느슨한 규칙을 적용하고 싶을 수 있습니다.

files: 어떤 파일을 검사할까?

첫 번째로 중요한 속성은 files입니다. 이것은 "이 설정을 어떤 파일들에 적용할지"를 정하는 패턴입니다.

{
  files: ['**/*.js', '**/*.jsx']
}

이 예시를 풀이해보면, **/*.js는 "어떤 경로에 있든 .js로 끝나는 모든 파일"을 의미합니다. **는 "모든 하위 디렉토리"를 뜻하고, *는 "어떤 이름이든"을 뜻합니다. 따라서 src/components/Button.js도 매칭되고, utils/helper.js도 매칭됩니다.

ignores: 검사하지 않을 파일

반대로 ignores는 검사에서 제외할 파일을 지정합니다.

{
  ignores: ['node_modules/**', 'dist/**', 'build/**']
}

node_modules 폴더 안의 파일들은 외부 라이브러리이므로 우리가 검사할 필요가 없습니다. distbuild 폴더는 빌드된 결과물이 들어가는 곳이므로 역시 검사할 필요가 없죠. 이런 폴더들을 ignores에 지정하면 ESLint가 건너뜁니다.

languageOptions: 언어 설정

languageOptions는 JavaScript라는 언어를 어떻게 해석할지 결정하는 설정입니다. JavaScript는 계속 발전하는 언어라서 어떤 버전의 문법을 사용할지 명시해야 합니다.

{
  languageOptions: {
    ecmaVersion: 2025,
    sourceType: 'module',
    globals: {
      window: 'readonly',
      document: 'readonly'
    }
  }
}

ecmaVersion: 2025는 2025년 기준의 JavaScript 문법을 사용한다는 뜻입니다. 예를 들어, 2020년에 도입된 Optional Chaining(user?.name) 같은 문법을 쓸 수 있다는 거죠.

sourceType: 'module'은 ES 모듈 방식을 사용한다는 뜻입니다. 즉, importexport 키워드를 사용할 수 있다는 의미입니다. 만약 이것을 'script'로 설정하면 옛날 방식인 requiremodule.exports를 사용해야 합니다.

ESLint는 "이런 전역 변수들이 있다"고 알려줘야 ESLint가 "정의되지 않은 변수를 사용했다"는 오류를 내지 않습니다. readonly는 이 변수를 읽기만 할 수 있고 수정하면 안 된다는 뜻입니다.

parser와 parserOptions: 코드를 이해하는 방법

때로는 JavaScript를 확장한 언어를 사용할 때가 있습니다. TypeScript나 JSX 같은 것들이죠. 이런 경우 ESLint가 기본적으로 제공하는 파서(Parser)로는 코드를 이해할 수 없습니다.

파서란 무엇일까요? 프로그램이 코드를 읽어서 의미를 이해하는 과정을 "파싱(Parsing)"이라고 합니다.

{
  languageOptions: {
    parser: '@typescript-eslint/parser',
    parserOptions: {
      project: './tsconfig.json',
      ecmaFeatures: {
        jsx: true
      }
    }
  }
}

TypeScript를 사용하는 프로젝트라면 TypeScript 전용 파서를 지정해야 합니다. @typescript-eslint/parser가 바로 그것이죠. parserOptionsproject는 TypeScript 설정 파일의 위치를 알려줍니다. TypeScript 파서는 타입 정보를 이해하기 위해 tsconfig.json을 참조해야 하거든요.

ecmaFeaturesjsx: true는 JSX 문법을 이해하라는 뜻입니다.일반 JavaScript 파서는 JSX 문법을 보면 오류로 간주하지만, JSX 기능을 켜면 정상적으로 이해합니다.

plugins: 규칙 모음 불러오기

plugins 속성은 외부의 규칙 모음을 불러오는 역할을 합니다. 이 부분이 바로 Plugin과 연결되는 지점이에요. Plugin에 대해서는 조금 뒤에 자세히 설명하겠지만, 일단 여기서는 "외부에서 만든 규칙들을 가져오는 것"이라고 이해하시면 됩니다.

{
  plugins: {
    react: reactPlugin,
    '@typescript-eslint': typescriptPlugin
  }
}

이 예시에서는 React 관련 규칙들을 담은 Plugin과 TypeScript 관련 규칙들을 담은 Plugin을 불러왔습니다. 각 Plugin에는 이름을 붙여줍니다. react라는 이름, @typescript-eslint라는 이름으로요. 이 이름은 나중에 규칙을 사용할 때 필요합니다.

rules: 실제 규칙 설정

드디어 가장 중요한 부분인 rules에 도달했습니다. 여기서 실제로 어떤 규칙들을 적용할지 정합니다.

{
  rules: {
    'no-console': 'warn',
    'no-unused-vars': 'error',
    'max-len': ['error', { code: 100 }]
  }
}

각 규칙은 "규칙 이름"과 "설정값"의 쌍으로 이루어져 있습니다. 설정값은 세 가지 형태가 가능합니다.

여기서 사용할 수 있는 문자열은 세 가지입니다:

  • 'off' 또는 숫자 0: 이 규칙을 사용하지 않습니다

  • 'warn' 또는 숫자 1: 이 규칙을 위반하면 경고를 표시합니다

  • 'error' 또는 숫자 2: 이 규칙을 위반하면 에러를 표시합니다

경고와 에러의 차이가 뭘까요? 경고는 "이거 좀 고치는 게 좋겠어요"라는 느낌입니다. CI/CD 파이프라인에서 빌드가 실패하지는 않습니다. 반면 에러는 "이건 반드시 고쳐야 해요"라는 강제사항입니다. 에러가 있으면 빌드가 실패할 수 있습니다.

실제 동작 예시로 이해하기

// 개발자가 작성한 코드
const name = 'John';
const age = 30;

console.log(name);
// age 변수는 사용하지 않음

이 코드에 대해 ESLint가 다음과 같은 설정으로 검사한다고 가정해봅시다:

{
  rules: {
    'no-unused-vars': 'error',
    'no-console': 'warn'
  }
}

ESLint는 코드를 분석하면서 두 가지 문제를 발견합니다:

  1. age 변수가 선언되었지만 사용되지 않았습니다 → no-unused-vars 규칙 위반 → 에러

  2. console.log를 사용했습니다 → no-console 규칙 위반 → 경고

에디터나 터미널에는 이런 메시지가 표시됩니다:

error: 'age' is defined but never used (no-unused-vars)
warning: Unexpected console statement (no-console)

개발자는 이 메시지를 보고 사용하지 않는 변수를 삭제하거나, 혹은 실제로 사용해야 합니다. console.log에 대해서는 경고만 나오므로 급하게 고치지 않아도 되지만, 배포 전에는 삭제하는 것이 좋겠죠.

settings: 추가 설정

마지막으로 settings 속성이 있습니다. 이것은 Plugin들이 참고할 수 있는 공유 정보를 담는 곳입니다.

{
  settings: {
    react: {
      version: 'detect'
    }
  }
}

예를 들어, React Plugin은 React의 버전에 따라 다른 규칙을 적용해야 할 수 있습니다. React 16과 React 18은 일부 기능이 다르거든요. version: 'detect'는 "프로젝트에 설치된 React 버전을 자동으로 감지해서 사용하라"는 뜻입니다.

Plugin 파일 완벽 분석

Plugin은 ESLint에 새로운 규칙들을 추가하는 패키지입니다.

ESLint는 기본적으로 JavaScript 언어 자체에 대한 규칙들만 제공합니다. 예를 들어 "선언되지 않은 변수를 사용하면 안 돼", "사용하지 않는 변수를 선언하면 안 돼", "같은 변수를 두 번 선언하면 안 돼" 같은 것들이죠.

그런데 실제 개발에서는 더 많은 규칙이 필요합니다. React를 사용한다면 React에 특화된 규칙들이 필요하고, TypeScript를 사용한다면 TypeScript에 특화된 규칙들이 필요합니다. 이런 특화된 규칙들을 제공하는 것이 바로 Plugin입니다.

Plugin의 구조

Plugin은 npm 패키지 형태로 배포됩니다. 보통 eslint-plugin-* 형식의 이름을 가집니다. 예를 들어:

  • eslint-plugin-react: React 관련 규칙들

  • eslint-plugin-vue: Vue.js 관련 규칙들

  • @typescript-eslint/eslint-plugin: TypeScript 관련 규칙들

Plugin 패키지 안을 들여다보면 크게 세 가지 요소가 있습니다.

첫째, 규칙(rules)의 구현입니다. Plugin은 여러 개의 규칙을 포함하고 있는데, 각 규칙은 실제로 어떻게 코드를 검사할지에 대한 로직을 담고 있습니다.

예를 들어, React Plugin의 jsx-uses-vars 규칙을 생각해봅시다. 이 규칙은 "JSX에서 사용된 컴포넌트가 실제로 import되었는지" 확인합니다.

import Button from './Button';

function App() {
  return <Button />; // Button이 사용됨
}

이 코드에서 Button이라는 변수는 JSX 안에서 사용되고 있습니다. 하지만 ESLint의 기본 no-unused-vars 규칙은 JSX 문법을 이해하지 못하기 때문에, Button을 "사용되지 않은 변수"로 잘못 판단할 수 있습니다. jsx-uses-vars 규칙은 이런 상황을 올바르게 처리하도록 도와줍니다.

Plugin 안에서 이 규칙은 대략 이렇게 구현되어 있습니다 (실제 코드는 훨씬 복잡하지만 개념만 보면):

rules: {
  'jsx-uses-vars': {
    create(context) {
      return {
        JSXIdentifier(node) {
          // JSX에서 식별자를 발견하면
          // "이 변수가 사용되었다"고 표시
          context.markVariableAsUsed(node.name);
        }
      };
    }
  }
}

이 코드는 AST(Abstract Syntax Tree, 추상 구문 트리)를 탐색하면서 JSX 안의 식별자를 찾습니다. AST는 코드를 트리 구조로 표현한 것인데, 컴파일러나 린터가 코드를 분석할 때 사용하는 방법입니다. 자세한 설명은 복잡하니 "코드의 구조를 나타내는 데이터"라고 이해하시면 됩니다.

둘째, Plugin은 추천 설정(configs)을 제공합니다. 규칙이 수십, 수백 개나 되는데 하나하나 설정하기는 번거롭겠죠? 그래서 Plugin 제작자들은 "이 정도 설정이면 대부분의 경우 괜찮을 거예요"라는 추천 설정을 미리 만들어줍니다.

configs: {
  recommended: {
    rules: {
      'react/jsx-uses-vars': 'error',
      'react/jsx-uses-react': 'error',
      'react/prop-types': 'warn',
      // ... 더 많은 규칙들
    }
  }
}

이 추천 설정을 사용하면 일일이 규칙을 지정하지 않아도 됩니다. Config 파일에서 이렇게 불러오면 되죠:

import react from 'eslint-plugin-react';

export default [
  react.configs.recommended
];

이렇게 하면 React Plugin이 추천하는 모든 규칙이 자동으로 적용됩니다.

셋째, Plugin은 환경(environments) 설정을 제공할 수 있습니다. 환경 설정은 특정 실행 환경에서 사용 가능한 전역 변수들을 정의합니다. 예를 들어, 브라우저 환경에서는 window, document 같은 전역 변수가 있고, Node.js 환경에서는 process, __dirname 같은 전역 변수가 있습니다.

Plugin 사용하는 과정

Plugin을 사용하는 과정을 단계별로 자세히 살펴봅시다.

1단계: 설치

먼저 npm이나 yarn을 통해 Plugin 패키지를 설치합니다.

npm install eslint-plugin-react --save-dev

--save-dev 옵션은 이 패키지를 개발 의존성(devDependencies)으로 설치한다는 뜻입니다. ESLint는 개발할 때만 필요하고 실제 프로덕션 코드에는 포함되지 않으므로 개발 의존성으로 설치합니다.

2단계: Import

Config 파일에서 Plugin을 import합니다.

import react from 'eslint-plugin-react';

여기서 주의할 점이 있습니다. ESLint가 자동으로 eslint-plugin- 접두사를 인식하기 때문에, import 할 때는 접두사를 생략하고 그냥 패키지 이름만 써도 됩니다. 하지만 명확하게 전체 이름을 쓰는 것도 가능합니다.

3단계: 등록

Plugin을 Config의 plugins 속성에 등록합니다.

export default [
  {
    plugins: {
      react: react
    }
  }
];

여기서 객체의 키(react)는 Plugin에 붙일 네임스페이스입니다. 이 이름은 나중에 규칙을 참조할 때 사용됩니다. 실제로는 키와 값이 같으므로 JavaScript의 단축 속성 문법을 사용해서 { react }라고만 써도 됩니다.

4단계: 규칙 사용

이제 Plugin이 제공하는 규칙을 사용할 수 있습니다.

export default [
  {
    plugins: {
      react: react
    },
    rules: {
      'react/jsx-uses-vars': 'error',
      'react/prop-types': 'warn',
      'react/react-in-jsx-scope': 'off'
    }
  }
];

규칙 이름 앞에 react/가 붙는 것은 3단계에서 지정한 네임스페이스입니다. "이 규칙은 react라는 이름으로 등록된 Plugin에서 가져온 거야"라는 의미입니다.

대표적인 Plugin들

실무에서 자주 사용되는 Plugin들을 소개하겠습니다.

eslint-plugin-react

React 프로젝트에서 거의 필수적으로 사용하는 Plugin입니다. React 컴포넌트를 작성할 때 지켜야 할 베스트 프랙티스를 검사합니다. 예를 들어:

  • 배열을 렌더링할 때 각 요소에 key prop을 제공했는지 확인

  • 이벤트 핸들러를 올바르게 바인딩했는지 확인

  • Hooks의 규칙을 지켰는지 확인

@typescript-eslint/eslint-plugin

TypeScript 프로젝트에서 사용하는 Plugin입니다. TypeScript 특유의 문제들을 잡아줍니다:

  • 타입 주석이 불필요한 곳에서 사용되지 않았는지 확인

  • any 타입의 남용을 방지

  • 함수의 반환 타입이 명시되어 있는지 확인

이 Plugin은 TypeScript 컴파일러와 협력해서 더 정교한 검사를 수행합니다. 그래서 parserOptionstsconfig.json의 경로를 지정해야 합니다.

eslint-plugin-import

import 문에 관련된 규칙들을 제공합니다:

  • import 경로가 실제로 존재하는 파일을 가리키는지 확인

  • 순환 참조(circular dependency)를 감지

  • import 문의 순서를 일관되게 유지

eslint-plugin-jsx-a11y

웹 접근성(accessibility)을 검사하는 Plugin입니다. 장애인 사용자를 포함한 모든 사용자가 웹사이트를 사용할 수 있도록 도와줍니다:

  • 이미지에 alt 속성이 있는지 확인

  • 클릭 가능한 요소가 키보드로도 접근 가능한지 확인

  • ARIA 속성이 올바르게 사용되었는지 확인

예를 들어, 이런 코드는 접근성 문제가 있습니다:

<img src="photo.jpg" />  // alt 속성 없음

jsx-a11y Plugin은 이를 감지하고 다음과 같이 수정하도록 제안합니다:

<img src="photo.jpg" alt="프로필 사진" />

eslint-plugin-promise

JavaScript의 Promise를 다룰 때 흔히 하는 실수들을 방지합니다:

  • Promise를 반환하는 함수에서 return을 빼먹지 않았는지

  • .catch()를 빠뜨려서 에러 처리를 안 한 건 아닌지

  • async 함수 안에서 불필요하게 await을 여러 번 사용하지 않았는지

eslint-plugin-security

보안 취약점을 찾아주는 Plugin입니다:

  • eval() 같은 위험한 함수 사용을 경고

  • 정규표현식 DoS 공격에 취약한 패턴을 감지

  • XSS 공격에 취약할 수 있는 코드를 경고

Shared Config의 개념

실무에서는 여러 프로젝트가 비슷한 ESLint 설정을 사용하는 경우가 많습니다. 예를 들어, 한 회사에서 여러 React 프로젝트를 진행한다면 모든 프로젝트가 동일한 코딩 스타일을 따르는 것이 좋겠죠.

이럴 때 각 프로젝트마다 똑같은 Config 파일을 복사-붙여넣기 하는 것은 비효율적입니다. 나중에 설정을 변경하고 싶을 때 모든 프로젝트를 일일이 수정해야 하니까요.

이 문제를 해결하는 것이 Shared Config입니다. 공통 설정을 별도의 npm 패키지로 만들어서 배포하고, 각 프로젝트에서 그것을 import해서 사용하는 방식입니다.

// 회사 내부 패키지: @company/eslint-config
export default [
  {
    plugins: {
      react: reactPlugin
    },
    rules: {
      'react/jsx-uses-vars': 'error',
      'react/prop-types': 'warn',
      // ... 회사 표준 규칙들
    }
  }
];

// 프로젝트 A의 eslint.config.js
import companyConfig from '@company/eslint-config';

export default [
  ...companyConfig,
  {
    // 프로젝트 A만의 추가 설정
    rules: {
      'no-console': 'warn'
    }
  }
];

// 프로젝트 B의 eslint.config.js
import companyConfig from '@company/eslint-config';

export default [
  ...companyConfig,
  {
    // 프로젝트 B만의 추가 설정
    rules: {
      'max-len': ['error', { code: 120 }]
    }
  }
];

이렇게 하면 회사 표준 설정은 @company/eslint-config 패키지 하나만 수정하면 되고, 각 프로젝트는 그것을 가져다 쓰면서 필요한 부분만 추가하거나 오버라이드할 수 있습니다.

Plugin의 Recommended Config 활용

대부분의 Plugin은 "추천 설정"을 제공합니다. Plugin 제작자가 "이 정도 설정이면 대부분의 사용자에게 적합할 거예요"라고 미리 만들어둔 설정이죠.

import react from 'eslint-plugin-react';

export default [
  react.configs.recommended
];

이 한 줄로 React Plugin이 제공하는 수십 개의 규칙 중에서 중요한 것들이 자동으로 활성화됩니다. 일일이 어떤 규칙을 켤지 고민할 필요가 없어지는 거죠.

하지만 추천 설정이 항상 완벽한 것은 아닙니다. 프로젝트의 특성에 따라 일부 규칙은 너무 엄격하거나 반대로 너무 느슨할 수 있습니다. 이럴 때는 추천 설정을 기반으로 하되, 특정 규칙만 오버라이드할 수 있습니다:

export default [
  react.configs.recommended,
  {
    rules: {
      // 추천 설정의 규칙을 오버라이드
      'react/prop-types': 'off'  // TypeScript 사용하므로 끄기
    }
  }
];

배열의 뒷부분에 있는 설정이 앞부분의 설정을 덮어쓰므로, 추천 설정 다음에 오는 규칙이 최종적으로 적용됩니다.

정리: 핵심 개념 요약

ESLint Config (eslint.config.js)

  • "어떻게" 검사할지를 정의하는 설정 파일

  • JavaScript 파일이므로 프로그래밍이 가능

  • 파일 매칭, 파서 설정, Plugin 등록, 규칙 활성화 등을 담당

  • 프로젝트의 "지휘자" 역할

ESLint Plugin (eslint-plugin-*)

  • "무엇을" 검사할지에 대한 규칙들의 모음

  • npm 패키지 형태로 배포

  • React, TypeScript, Vue 등 특정 기술에 특화된 규칙 제공

  • Config에 등록되어야 사용 가능

  • 프로젝트의 "도구 상자" 역할

둘의 관계

  • Plugin은 규칙을 제공만 하고, Config가 실제로 활성화

  • Plugin 없이 Config만으로도 기본 규칙 사용 가능

  • 하나의 Plugin을 여러 Config에서 공유 가능

  • Config는 여러 개의 Plugin을 조합해서 사용

참고 자료

이 글은 다음 공식 문서들을 참고하여 작성되었습니다:

최신 정보는 각 공식 문서에서 확인하시기 바랍니다. ESLint는 활발하게 업데이트되는 도구이므로, 이 글 작성 시점(2025년 10월) 이후 변경사항이 있을 수 있습니다.