LHJ

I'm a FE developer.

ESLint

02 Oct 2020 » node_webpack2

ESLint

이번엔 주제를 바꿔서 린트에 대해 알아보도록 하겠습니다.

1. 배경

오래된 스웨터의 보푸라기 같은 것을 린트(Lint)라고 부른다.
보푸라기가 많으면 옷이 보기 좋지 않은데 코드에서도 이런 보푸라기가 있다.
들여쓰기를 맞추지 않은 경우, 선언한 변수를 사용하지 않은 경우…

보푸라기가 있는 옷을 입을 수는 있듯이 이러한 코드로 만든 어플리케이션도 동작은 한다.
그러나 코드의 가독성이 떨어지고 점점 유지보수하기 어려운 애물단지가 되어버리기 일쑤다.

1.1 린트가 필요한 상황

아래 코드를 유심히 보자.
console.log() 함수를 실행하고 다음 줄에서 즉시 실행함수를 실행하려는 코드이다.

console.log()
(function () {

})()

하지만 이 코드를 브라우저에서 실행하다보면 TypeError가 발생한다.
브라우저는 코드에 세미콜론을 자동으로 넣는 과정(ASI)을 수행하는데, 위와 같은 경우는 우리의 의도대로 해석하지 못하고 아래 코드로 해석한다.

console.log()
(function () {

})();

즉, 우리가 기대하는 대로 브라우저에서 자동으로 세미콜론을

console.log();
(function () {

})();

이렇게 넣어주는 것이 아니라

console.log()
(function () {

})();

이렇게 인식한다. 즉, console.log() 값은 undefined인데, 함수호출을 아래처럼 시도하려고 하니까

undefined(function () {

})()

이런식으로 인식되니까 타입에러가 발생하는 것이다.
console.log() 이거의 결과값은 ‘함수가 아니다!’라는 것이다.

이러한 것들은 개발자가 개발할 때 찾기 어렵고 브라우저에 올라가서 실제 실행될 때만 발생하는 런타임 에러다.
그렇기 때문에 사전에 체크할 필요가 있는데, 그때 사용하는 것이 린트이다.

console.log()가 반환하는 값이 함수가 아닌데 함수 호출을 시도했기 때문에 타입에러가 발생할 것이다.
모든 문장에 세미콜론을 붙였다면, 혹은 즉시 함수호출 앞에 세미콜론을 붙였다면 예방할 수 있는 버그이다.

린트는 코드의 가독성을 높이는 것 뿐만 아니라 동적 언어의 특성인 런타임 버그를 예방하는 역할도 한다.

2. ESLint

린트 중에 가장 많이 사용하는 것이 ESLint이다.

2.1 기본 개념

ESLint는 ECMAScript 코드에서 문제점을 검사하고 일부는 더 나은 코드로 정정하는 린트 도구 중의 하나이다.
코드의 가독성을 높이고 잠재적인 오류와 버그를 제거해 단단한 코드를 만드는 것이 목적이다.
과거 JSLint, JSHint에 이어서 최근에는 ESLint를 많이 사용하는 편이다.

코드에서 검사하는 항목을 크게 분류하면 아래 두 가지이다.

  1. 포멧팅
  2. 코드 품질

포멧팅은 일관된 코드 스타일을 유지하도록 하고 개발자로 하여금 쉽게 읽히는 코드를 만들어 준다.
이를테면 “들여쓰기 규칙”, “코드 라인의 최대 너비 규칙”을 따르는 코드가 가독성이 더 좋다.

한편, 코드 품질은 어플리케이션의 잠재적인 오류나 버그를 예방하기 위함이다.
(위에서 본 예시와 같은 역할이다.)
사용하지 않는 변수 쓰지않기, 글로벌 스코프 함부로 다루지 않기 등이 오류 발생 확률을 줄여준다.

린트 도구를 사용해서 코드를 검사하고 더 나아가 단단하고 읽기 좋은 코드를 만드는 방법을 알아보자.

3. 설치 및 사용방법

npm i -D eslint
// app2.js
console.log()
(function () {})()

위와 같이 코드를 작성하고 eslint가 이를 어떻게 검사하는지 알아보도록 하자.

npx eslint app2.js

위와 같이 실행하면 에러가 날 것이다.

eslint는 기본적으로 configuration 파일이 있어야된다.
.eslintrc.js라는 파일을 하나 생성한다.

위 파일을 생성하면 eslint.eslintrc.js 설정파일을 읽고 실행이 된다.

// .eslintrc.js
module.exports = {
    
}

일단은 위와 같이만 작성한다.
아직 아무런 설정을 안하고 빈 객체만 전달하는 상태이다.

npx eslint app2.js

아까처럼 오류 메시지는 안 나오는데 실행은 되긴 했다.

eslint 규칙(Rules)

ESLint는 검사 규칙을 미리 정해 놓았다.
문서의 Rules 메뉴에서 규칙 목록을 확인할 수 있다.
그래서 이 Rules 를 환경설정에 추가해야만 우리가 원하는 검사를 할 수 있다.

Rules는 위 홈페이지 들어가시면 볼 수 있다.
해당 eslint 페이지에 규칙 목록을 나열해놓은 걸 확인해보실 수 있다.

우리가 우려했던 문제와 관련된 규칙은 no-unexpected-multiline이다.
설정 파일의 rules 객체에 이 규칙을 추가한다.

// .eslintrc.js
module.exports = {
    rules : {
        "no-unexpected-multiline": "error"
    }
}

이렇게하면 eslint가 해당 설정 파일의 rules를 보고 해당 규칙들에 어긋난게 있으면 오류를 반환한다.

npx eslint app2.js

이렇게하면 app2.js에 오류가 있다는 메시지가 뜬다.
해석해보면 function과 ( 괄호 사이에 기대하지 않은 줄바꿈이 있다. 라고 이야기하고 있다.
그럼 이를 다음과 같이 수정하면 된다.

// app2.js
console.log(); // 세미콜론을 여기에 붙여주던지
(function () {})()
// app2.js
console.log()
;(function () {})() // 가끔 이렇게 앞에다 세미콜론을 붙여주는 개발자도 있다.
// 즉시실행함수로 작성된 코드를 보면 가끔 위와 같이 즉시실행함수 앞에 ; 세미콜론이 붙어있는 경우가 있다.
// 이러한 이유 때문에 그렇게 작성했던 것이다.
// 하지만 보통 아래처럼 각각 ; 세미콜론을 붙여주는 것이 일반적이다.
// app2.js
console.log();
(function () {})();

위와 같이 수정하고 다시 검사해보자.

npx eslint app2.js

이번에는 아래와 같이 작성해보자.

// app2.js
console.log();;
(function () {})();

console.log() 뒤에 ; 세미콜론을 2개 붙이면 어떻게될까?
자바스크립트에서 ; 세미콜론을 여려개 붙이는 것은 오류가 안난다.
그저 공문이 많이들어가는 것일 뿐이다.
하지만 이러한 코드는 보기에 좋지 않다.
이런 것을 eslint가 어떻게 처리하는지 한번 보자.

보시는 바와같이 아무런 에러도 잡지 않는다.
이러한 세미콜론 관련 규칙을 잡기 위해선 no-extra-semi 규칙을 추가해줘야한다.

// .eslintrc.js
module.exports = {
    rules : {
        "no-unexpected-multiline": "error",
        "no-extra-semi": "error"
    }
}

위와 같이 추가해주고 검사해보자.

그럼 위와 같이 불필요한 세미콜론이 있다는 메시지가 주르륵 뜬다.
그런데 아까와는 다르게 탐재적으로 고칠 수 있는 오류라면서 --fix 옵션을 주라고 되어있다.

npx eslint app2.js --fix

위와 같이 app2.js 파일이 자동으로 수정된 것을 확인할 수 있다.
이렇게 eslint는 자동으로 수정할 수 있는 규칙들이 있다.

위 사이트에 뻰찌? 뭐라하지.. 저 표시가 있는 규칙들은 다 자동으로 수정할 수 있는 목로들이다.
아까 위에서 사용했던 no-unexpected-multiline 규칙은 자동으로 고칠 수 없는 규칙들이다.
이런 규칙들은 그 코드를 개발한 개발자에게 ‘어떻게든 고쳐놔라’라고 해야되는 것이다.

그런데 이런 규칙들을 일일이 설정하는 것은 귀찮다.
바벨 프리셋과 마찬가지로 이러한 규칙들을 하나의 세트로 만들어놓은 것이 있다.
그것을 Extensible Config라고 한다.

2.5 Extensible Config

이러한 규칙을 여러개 미리 정해놓은 것이 eslint:recommended 설정이다.
규칙 목록 중에 왼쪽에 체크 표시되어 있는 것이 이 설정에서 활성화 되어있는 규칙이다.

이것을 사용하려면 extends 설정을 추가한다.

// .eslintrc.js
module.exports = {
    extends: [
        "eslint:recommended"
    ]
}

이렇게하면 rules 목록에 있는 목록들 중 왼쪽에 체크표시된 목록들이 다 들어가게된다.
보시면 아까 우리가 사용했던 no-extra-semi에도 체크표시가 되어있고 no-unexpected-multiline에도 체크표시가 되어있다.

그럼 똑같이 동작하는지 보자.

// app2.js
console.log();;;;;;;
(function () {})();

이렇게 다시 작성하고

npx eslint app2.js --fix

다수의 세미콜론이 자동으로 삭제된 것을 확인할 수 있다.


ESLint에서 기본으로 제공하는 설정 외에 자주 사용하는 두 가지가 있다.

  1. airbnb
  2. standard

airbnb 설정은 airbnb 스타일 가이드를 따르는 규칙 모음이다.
eslint-config-airbnb-base 패키지로 제공된다.

standard 설정은 자바스크립트 스탠다드 스타일을 사용한다.
elint-config-standard 패키지로 제공된다.

2.6 초기화

사실 eslint 설정파일은 .eslintrc.js 파일을 직접 만들어서 설정하기 보다는 명령어를 통해 사용한다.
그것이 훨씬 더 수월하다.

npx eslint --init

# 1
How would you like to use ESLint? ...
1. To check syntax only (문법검사만)
2. To check syntax and find problems (문법검사 + 코드품질검사, code style을 prettier를 사용할거면 3번선택 X)
3. To check syntax, find problems, and enforce code style (문법검사 + 코드품질검사 + 코딩스타일)
   즉 airbnb 스타일 또는 standard 스타일..

# 2
what type of modules does your project use? ...
1. JavaScript modules (import/export)
2. CommonJS (require/exports)
3. None of these

# 3
Which framework does your project use? ...
1. React
2. Vue.js
3. None of these

# 4
Does your project use TypeScript? No / Yes

# 5
Where does your code run? ... (Press <space< to select, <a> to toggle all, <i> to invert selection)
1. Browser
2. Node

# 6
What format do you want your config file to be in? ...
1. JavaScript
2. YAML
3. JSON

# 7
eslint@latest
Would you like to install them now with npm? Yes
// .eslintrc.js
module.exports = {
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": "eslint:recommended",
    "parserOptions": {
        "ecmaVersion": 12,
        "sourceType": "module"
    },
    "rules": {
    }
};

이렇게하면 .eslintrc.js가 새로운 코드로 덮여씌워진 것을 볼 수 있다.
보통은 이렇게 자동으로 생성되는 .eslintrc.js를 사용한다.