좋은 코드를 작성할 수 있는 환경을 구축하는 것이 코드 작성만큼 중요하다.
예기치 못한 작동을 방지하기 위해서 가장 먼저 시도해 볼 수있는 방법이 정적 코드 분석이다. 정적 코드 분석이란, 코드의 실행과는 별개로 코드 그 자체만으로 코드 스멜을 찾아내어 문제의 소지가 있는 코드를 사전에 수정하는 것을 의미한다.
그리고 자바스크립트에서 가장 많이 사용되는 정적 코드 분석 도구는 ESLint이다.
ESLint는 어떻게 코드를 분석할까?
ESLint는 자바스크립트 코드를 정적 분석해 잠재적인 문제를 해결하고 나아가 수정까지 도와주는 도구이다. 그렇다면 ESLint는 어떻게 자바스크립트 코드를 읽어서 분석할까?
여기서 중요한 것은 1번과정에서 읽은 코드를 구조화하는 과정인 2번이다.
ESLint는 기본값으로 espree를 사용한다. 다음은 function hello(str) {}코드를 espree로 분석한 결과이다.
{
"type": "Program",
"start": 0,
"end": 22,
"range": [0,22],
"body": [
{
"type": "FunctionDeclaration",
"start":0,
"end": 22,
"id": {
"type": "Identifier",
"start": 9,
"end": 14,
"name": "hello"
},
"expression": false,
"generator": false,
"async": false,
"params": [
{
"type": "Identifier",
"start": 15,
"end": 18,
"name": "str"
}
],
"body": {
"type": "BlockStatement",
"start": 20,
"end": 22,
"body": []
}
}
],
"sourceType": "module"
}
단순히 변수인지, 함수인지 등을 파악하는 것이 아니라 코드의 정확한 위치와 같은 아주 세세한 정보도 분석해 알려준다. 타입스크립트의 경우도 마찬가지로 @typescript-eslint/typescript-estree 라고 하는 espree 기반 파서가 있으며 이를 통해 타입스크립트 코드를 분석해 구조화한다.
ESLint가 espree로 코드를 분석한 결과를 바탕으로, 어떤 코드가 잘못된 코드이며 어떻게 수정해야 할지도 정해야하는데 이를 ESLint 규칙이라고 한다. 특정한 규칙의 모음을 plugins라고 한다.
eslint-plugin
eslint-plugin이라는 접두사로 시작하는 플러그인은 앞서 언급했던 규칙을 모아놓은 패키지다. eslint-plugin-import, eslint-plugin-react 등이 존재한다.
eslint-config
eslint-plugin을 한데 묶어서 완벽하게 한 세트로 제공하는 패키지이다. eslint-config를 만드는 것은 굉장히 번거로운 일이기 때문에 개인 개발자가 만드는 일은 드물고, 일부 IT 기업들에서 공개한 잘 만들어진 eslint-config를 설치해서 사용하는 것이 일반적이다.
ESLint을 생성해 관리하면 개발자가 일일이 수정하는 것보다 훨씬 더 빠르고 쉽게 수정할 . 수 있고, 이후에 반복되는 실수 또한 방지할 수 있어 매우 유용하다.
이미 존재하는 규칙을 커스터마이징해서 적용하기 : Import React를 제거하기 위한 ESLint 규칙 만들기
React 17버전부터는 import React from 'react' 구문이 필요없어졌다.
불필요한 코드를 삭제하면 번들러의 크기를 줄일 수 있기 때문에 제거하는 것이 유용하다. 비록 웹팩이 제공하는 트리쉐이킹 기능이 사용하지 않는 코드를 모두 삭제하지만, 트리쉐이킹이 진행되는데 걸리는 시간을 줄일 수 있기 때문에 삭제하는 것이 더 이득이다.

다음은 import React에 대해 리포트할 수 있는 ESLint 규칙이다.
module.exports = {
rules: {
'no-restricted-imports' : [
'error',
{
paths : [
{
name: 'react',
importNames: ['default'],
message: "import React from react는 react 17부터 필요하지 않습니다."
},
],
},
],
},
}
실행하면 다음과 같은 에러가 발생하고, 코드 에디터에서도 해당 규칙이 적용되어 에러가나는 것을 확인할 수 있다.

완전히 새로운 규칙 만들기 : new Date를 금지시키는 규칙
type이 NewExpression이며, callee.name이 Date이고 ExpressionStatement.expression.arguments가 빈배열일 경우 금지해주면 된다.
module.exports = {
meta: {
type : 'suggestion',
docs : {
description : 'disallow use of the new Date()',
recommended : false,
},
fixable: 'code',
schema: [],
messages: {
message: "new Date()는 클라이언트에서 실행 시 해당기기의 시간에 의존적이라 정확하지 않습니다."
},
},
create: function(context) {
return {
NewExpression : function(node) {
if(node.callee.name == 'Date' && node.arguments.length ===0){
context.report({
node: node,
messageId : 'message',
fix : function(fixer) {
return fixer.replaceText(node,'ServerDate()')
},
})
}
},
}
},
}
Prettier와의 충돌
Prettier는 포매팅과 관련된 작업 (줄바꿈, 들여쓰기, 작은 따옴표와 큰따옴표 등)을 담당한다면, ESLint는 잠재적인 문제가 될 수 있는 부분을 분석해준다. 그러나 ESLint에서도 Prettier에서 처리하는 작업들을 처리할 수 있기 때문에 두 가지 모두를 실행한다면 서로 충돌하는 규칙으로 인해 에러가 발생할 수 있다.
서로 규칙이 충돌되지 않게끔 규칙들 잘 선언하거나, 자바스크립트-타입스크립트는 ESLint에 그 외의 파일은 Prettier에 맡기는 방법이 있다.
규칙에 대한 예외 처리, 그리고 react-hooks/no-exhasutive-deps
일부 코드에서 특정 규칙을 임시로 제외시키고 싶다면 eslint-disable- 주석을 사용하면 된다.
ESLint 버전 충돌
설치하고자 하는 eslint-config, eslint-plugin이 지원하는 ESLint 버전을 확인하고, 또 설치하고자 하는 프로젝트에서 ESLint 버전을 어떻게 지원하고 있는지 살펴봐야 한다.