ESLint, Preitter 제대로 알고 사용하자

dyeon-dev·2025년 9월 3일
post-thumbnail

코드의 품질을 위해 ESLint와 Preitter를 보통 혼합해서 쓴다.
왜 그럴까? 하는 역할은 비슷해보이는데 어떤 게 달라서 둘 다 같이 써야하는지 알아보고 각각 어떤 설정이 어떤 역할을 하는건지 파악해보자.

VSCode가 코드의 Lint Error를 잡는 것부터, 저장 시 자동 수정하는 설정까지 복잡한 조건 설정 과정을 적용해보자!

ESLint

ESLint는 코드 품질을 개선하고 런타임에 버그가 발생하지 않도록 사전에 버그를 수정하는 데 도움이 되는 linter이다.

'Lint'는 실제로 보풀이라는 뜻이다. ESLint는 거슬리는 보풀 같은 코드를 깔끔하게 만들어준다는 뜻이라고 보면 된다.ㅎ

ESLint를 사용하는 이유

  • 코드 일관성 유지: 코드 스타일 가이드를 준수하여 일관성 있는 코드 작성 가능
  • 버그 및 오류 방지: 잠재적인 버그나 오류를 사전에 찾아내고 수정할 수 있다.
  • 팀 협업 강화: 팀원 간에 코드 품질을 통일시켜 협열 효율을 높일 수 있다.

v9.x 버전 마이그레이션 사항

  • eslintrc는 더 이상 사용되지 않는다. eslintrc 구성 형식을 사용해야 하는 경우 ESLINT_USE_FLAT_CONFIG 환경 변수를 false으로 설정해야 한다.

이 글에서는 v9.x 버전으로 다룬다.

플러그인 제공

ESLint 에서 많이 사용하는 plugin 으로는 기본인 plugin:@typescript-eslint/recommended 가 있다.
그리고 Airbnb, Google 등에서 본인들의 ESLint style 을 작성하여 npm 모듈로 제공하고 있다.

규칙

공식 문서의 Rules Reference를 확인해보면, 각 규칙에는 있는 이모지 표시로 규칙 활성화자동 수정 여부를 확인할 수가 있다.

  • ✅ recommendedconfig 설정 시 활성화 되는 규칙
  • 🔧 --fix 명령어로 자동으로 수정할 수 있는 규칙

세 가지 오류 수준을 통해 ESLint가 규칙을 적용하는 방식을 세부적으로 제어할 수 있다.

  1. "off" or "0"
  • 규칙을 해제, 해당 규칙을 사용하지 않음
  1. "warn" or "1"
  • 규칙을 경고로 설정, 규칙을 강제하지 않고 경고만 해줌
  1. "error" or "2"
  • 규칙을 에러로 설정, 통합 테스트, build, PR등의 경우에 에러 발생

설치

npm init @eslint/config@latest
  1. How would you like to use ESLint? // eslint를 어떤 방식으로 쓸거에요?
  • To check syntax only // 문법적 오류만 잡을거에요
  • To check syntax and find problems // 문법이랑 에러도 잡을거에요
  1. What type of modules does your project use? // 프로젝트에선 어떤 모듈화를 사용하나요?
  • JavaScript modules (import/export)
  • CommonJS (require/exports)
  • None of these
  1. Which framework does your project use? // 어떤 프레임워크를 사용하나요?
  • React
  • Vue.js
  • None of these // 안써요
  1. Does your project use TypeScript? // 프로젝트는 typescript를 사용하나요?
  • y/s로 대답
  1. Where does your code run? // 당신의 코드는 어디서 돌리나요?
  • browser
  • Node
  1. Which package manager do you want to use? // 패키지 매니저 선택
  • npm
  • yarn
  • pnpm

설치를 완료하면 eslint.config.mjs 파일이 생성된다. 생성된 파일에 설정들을 추가해보자.

export default defineConfig([

	{ files: ["app.js", "server/**/*.js"], languageOptions: { globals: globals.node } },
	{ files: ["features/**/*.js"], languageOptions: { globals: globals.browser }},
	js.configs.recommended,
	{
		rules: {
			"no-unused-vars": "warn",
			// "no-undef": "warn",
		},
	},

]);
  • "eslint:recommended": ESLint가 권장하는 규칙. 위에서 본 ✅ 표시 적용
  • rules: ESLint는 규칙이 있어야 그걸 보고 코드를 검사한다. 새 객체를 정의하여 규칙을 개별적으로 구성할 수 있다.
    • no-undef: 코드에서 선언되지 않은 식별자를 사용하면 오류를 표시하는 규칙이다. 하지만 globals 설정을 해주면 이런 오류를 잡아주기 때문에 따로 처리하지 않았다. 또한, TypeScript 계획이 있다면 no-undef는 TS가 잡아주므로 끄는 편(off)이 일반적이다.
  • browser 코드와 node 코드를 files 패턴으로 분리해 각각 globals를 적용해야 한다. globals.browser/globals.node를 languageOptions.globals에 넣어야 no-undef 오탐이 생기지 않는다.

    왜 globals 설정이 no-undef 오탐을 줄이나요?
    - 문제: 브라우저/노드 환경에는 미리 제공되는 전역 식별자들이 있는데, ESLint가 이를 모르면 no-undef로 오탐한다.
    - 브라우저 전역 예시: windowdocumentnavigatorlocation 등
    - 노드 전역 예시: processdirnameBufferglobal 등
    - 해결: globals 패키지의 globals.browserglobals.node를 ESLint 설정의 languageOptions.globals에 주입하면, 해당 식별자들을 “이미 전역에 존재하는 읽기전용 변수”로 인식해서 no-undef 오탐이 사라진다.

Preitter

Preitter는 포맷팅 역할을 해서 코드를 일관성 있게 만들어준다.
ESLint와 달리 규칙이 미리 세팅되어 있기 때문에 설정 없이도 npx prettier . --write 명령어로 바로 사용해볼 수 있는 간편함이 있다.

Preitter 설치

npm install --save-dev --save-exact prettier

.prettierrc 파일 추가

.prettierrc 파일을 추가해서 직접 커스텀을 해도 된다.

{
  ------------------------
  기본 포맷팅 설정
  ------------------------
  // 한 줄의 최대 길이를 설정 (기본값: 80)
  // 이 길이를 초과하면 자동으로 줄바꿈이 발생
  "printWidth": 80,
  
  // 들여쓰기 시 사용할 공백 문자 수 (기본값: 2)
  // useTabs가 false일 때만 적용됨
  "tabWidth": 2,
  
  // 들여쓰기에 탭 문자 사용 여부 (기본값: false)
  // true: 탭 문자 사용, false: 공백 문자 사용
  "useTabs": false,
  
  // 문장 끝 세미콜론 사용 여부 (기본값: true)
  // true: 모든 문장 끝에 세미콜론 추가
  // false: 필요한 경우에만 세미콜론 추가
  "semi": true,
  
  ------------------------
  따옴표 관련 설정
  ------------------------
  // 문자열에 작은따옴표 사용 여부 (기본값: false)
  // true: 'string', false: "string"
  "singleQuote": true,
  
  // 객체 속성에 따옴표 추가 방식 (기본값: "as-needed")
  "quoteProps": "as-needed",
  // - "as-needed": 필요한 경우에만 따옴표 추가
  // - "consistent": 하나라도 따옴표가 필요하면 모든 속성에 따옴표 추가
  // - "preserve": 입력된 따옴표 스타일 유지
  
  // JSX에서 작은따옴표 사용 여부 (기본값: false)
  // singleQuote 설정과 독립적으로 동작
  "jsxSingleQuote": true,
  
  ------------------------
  쉼표 및 괄호 설정
  ------------------------
  // 객체, 배열 등의 후행 쉼표 설정 (기본값: "es5")
  "trailingComma": "es5",
  // - "all": 모든 구문에서 후행 쉼표 사용 (함수 인자 포함)
  // - "es5": ES5에서 유효한 위치에만 후행 쉼표 추가
  // - "none": 후행 쉼표 사용 안 함
  
  // 객체 리터럴의 중괄호 주위 공백 추가 (기본값: true)
  // true: { foo: bar }, false: {foo: bar}
  "bracketSpacing": true,
  
  // JSX 요소의 > 위치 설정 (기본값: false)
  // true: 마지막 줄에 > 위치, false: 다음 줄에 > 위치
  "bracketSameLine": false,
  
  // 화살표 함수 매개변수 괄호 사용 방식 (기본값: "always")
  "arrowParens": "always",
  // - "always": (x) => x
  // - "avoid": x => x (매개변수가 하나일 때)
  
  ------------------------
  특수 포맷팅 설정
  ------------------------
  // 줄 끝 문자 설정 (기본값: "lf")
  "endOfLine": "lf",
  // - "lf": \n (Unix)
  // - "crlf": \r\n (Windows)
  // - "cr": \r (Mac OS)
  // - "auto": 첫 줄 끝 문자 유지
  
  // 마크다운 텍스트의 줄바꿈 방식 (기본값: "preserve")
  "proseWrap": "always",
  // - "always": 항상 printWidth에 따라 줄바꿈
  // - "never": 줄바꿈 하지 않음
  // - "preserve": 원본 텍스트 줄바꿈 유지
  
  // HTML 공백 처리 방식 (기본값: "css")
  "htmlWhitespaceSensitivity": "strict",
  // - "css": CSS display 속성 기준으로 처리
  // - "strict": 모든 공백을 유지
  // - "ignore": 모든 공백을 무시
}

하지만 Preitter는 단순히 코드를 예쁘게 만들어주는 역할만 하고, 코드 품질과 관련된 검사는 ESLint의 몫이다.
그래서 Preitter는 ESLint와 통합하는 방법을 제공한다.
eslint-plugin-prettier를 설치하면 된다.
공식문서에 설명된 것처럼 코드 포맷팅 관련 문제에는 Prettier를, 코드 품질 관련 문제에는 ESLint를 사용해보자.

"devDependencies": {
	"@eslint/js": "^9.34.0",
	"eslint": "^9.34.0",
	"eslint-config-prettier": "^10.1.8",
	"globals": "^16.3.0",
	"prettier": "3.6.2"
}

지금까지 설치한 각 패키지들의 핵심 기능을 설명하면 다음과 같다.

핵심 린팅 도구
• eslint: JavaScript/TypeScript 코드의 문제점을 검사하는 린터
• @eslint/js: ESLint의 JavaScript 관련 기본 설정

코드 스타일링
• prettier: 코드 포맷터
• eslint-config-prettier: 서로 충돌하는 옵션이 있으면 Preitter 규칙을 사용하여 충돌 방지

ESLint config에서 Preitter 설정

ESLint와 Preitter의 충돌을 설정해주기 위해 eslint.config.mjs에서 설정을 해줘야 한다.

import prettierConfig from "eslint-config-prettier";

export default defineConfig([
	{
		files: ["app.js", "server/**/*.js"],
		languageOptions: { globals: globals.node },
	},
	{
		files: ["features/**/*.js"],
		languageOptions: { globals: globals.browser }.
	},
	js.configs.recommended,
	prettierConfig, // Prettier와 충돌하는 규칙 비활성화
]);

🐛eslint-plugin-prettier 설정은 뺐어요.
이렇게 통합하는 과정에서 여러 블로그 글을 참고하다보면 eslint-config-prettier뿐만 아니라 eslint-plugin-prettier 플러그인을 추가로 사용하는 경우도 있다.
이건 Prettier가 ESLint 규칙으로 통합돼서 실행할 수 있도록 해주는 기능이다.

그런데,, 나도 처음에 eslint-plugin-prettier 플러그인으로 다음과 같이 통합해주는 과정을 거쳤는데 그렇게 하니까 몇가지 부분에서 통합이 제대로 이뤄지지 않는 문제상황을 겪었다.

import prettier from 'eslint-plugin-prettier';

...

{
		plugins: { prettier },
		rules: {
			"prettier/prettier": "error", // Prettier 규칙 위반 시 오류 표시
		},
	},

.prettierrc에서 분명 싱글 따옴표(') 규칙으로 설정을 했는데 ESLint로 통합해서 적용할 때 더블 따옴표(") 규칙으로 적용되면서 Prettier 규칙을 위반했다고 빨간줄이 생기는 오류가 발생했다.

이 부분에 대해서 왜 그런지 찾아보다가.. 처음에는 뭔말인지 잘 모르고 넘어갔던 공식문서에서 언급한 부분을 다시 한 번 보게 되었다.
이 플러그인은 특정 상황에서는 유용할 수 있지만 일반적으로 권장되지는 않는 방식이라고 하는데, 이렇게 통합이 잘 되지 않는 문제가 발생하기도 해서 권장되지 않는다고 설명한게 아닐까 생각이 든다..!

자동화 설정

매번 npm run lint를 돌리거나 빨간줄을 직접 수정하기에는 상당히 귀찮다. 이걸 해결해주기 위해 코드를 저장할 때 자동으로 코드포맷팅을 해주는 자동화 설정을 해주자.

폴더 상위 디렉토리에 .vscode/settings.json를 추가한다.

{
	// ESLint 확장 프로그램 활성화
	"eslint.enable": true,
	
	
	// 기본 코드 포맷터를 Prettier로 설정
	"editor.defaultFormatter": "esbenp.prettier-vscode",
	
	
	// 파일 저장 시 자동으로 코드를 포맷팅
	"editor.formatOnSave": true,
	"editor.codeActionsOnSave": {
		"source.fixAll.eslint": "explicit", // ESLint 오류 자동 수정
		"source.organizeImports": "explicit" // import 문 자동 정리
	},
	
	// ESLint가 검사할 파일 타입들을 지정
	"eslint.validate": [
		"javascript",
		"javascriptreact",
		"typescript",
		"typescriptreact"
	],
	
	"prettier.requireConfig": true, // .prettierrc 파일이 있을 때만 Prettier를 사용 (프로젝트별 설정 강제)
	
	// .mjs 파일을 JavaScript로 인식하도록 설정
	"files.associations": {
		"*.js": "javascript",
		"*.mjs": "javascript"
	},
	
	
	// 탭 크기를 2칸으로 설정하고, 탭 대신 스페이스 사용
	"editor.tabSize": 2,
	"editor.insertSpaces": true,
	
	
	// 파일 저장 시 빈 줄 제거
	"files.trimTrailingWhitespace": true,
	"files.insertFinalNewline": true
}

참고자료

0개의 댓글