ESLint & Prettier

박정호·2022년 8월 31일
0

Portfolio

목록 보기
6/6
post-thumbnail
post-custom-banner

⭐️ Prettier

  • 정해진 규칙에 따라 자동으로 코드 스타일을 정리 해주는 도구
  • 코드를 읽어들여서 사용자 옵션에 따라 코드를 다시 포맷팅하는 코드 포맷터
  • 코드 스타일에 초점을 맞추고 있기 때문에, 코드 품질을 위해 사용하는 ESLint와는 성격이 다르다

설치

yarn add -dev prettier

상세내용:

💡 잠깐) npx?
npx를 통한 패키지 다운:
https://velog.io/@pjh1011409/npm-yarn

코드

루트 디렉토리에 .prettierrc 파일 생성 후 컨벤션 코드 작성

✏️ .prettierrc

{
  "singleQuote": true,     //  쌍따옴표가 아닌 홑따옴표를 사용
  "semi": true, 		   // statement 마지막에 세미콜론을 찍음
  "useTabs": false,		   // 탭을 사용하지 않고 스페이스를 사용
  "tabWidth": 2,		   // 탭을 할 경우 2 스페이스
  "trailingComma": "all",  // 선호되는 한 줄의 길이, 줄바꿈 한폭 길이
  "printWidth": 120,	   // 여러줄로 나뉘었을 때는 쉼표를 사용
  "arrowParens": "avoid",  // 화살표 함수에서 괄호 사용 의무화
  "endOfLine": "auto"      // 파일의 마지막에는 EOL을 보장
  }

실행

✏️ 직접 실행

npx prettier --write "파일.js"

✏️ 자동 실행

1. 설정에 prettier를 검색하고, setting.json을 연다.

2. setting.json 마지막에 다음과 같은 코드 추가

"[javascript]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "editor.formatOnSave": true

또는 직접 설정 창에서 다음과 같이 선택

코드 수정

앞서 설정한 과정으로 코드 작성 후 저장(command + S) 시 자동으로 prettier의 조건에 따라 코드 정렬이되는 것을 확인 가능

⭐️ ESLint

자바스크립트에서 문법적 에러를 표시해주는 도구

설치

yarn add -D eslint

추가 설치

  • eslint-plugin-import: ES2015+의 import/export 구문을 지원
  • eslint-config-airbnb-base: airbnb사의 코딩스타일
  • eslint-config-prettier, eslint-plugin-prettier: 앞선 prettier를 ESLint와 연결하기 위한 플러그인
yarn add -D eslint-plugin-import
yarn add -D eslint-config-airbnb-base
yarn add -D eslint-config-prettier eslint-plugin-prettier

간편하게 설치 : https://wookgu.tistory.com/31

💡 잠깐) npx?
npx를 통한 패키지 다운:
https://velog.io/@pjh1011409/npm-yarn

코드

✏️ .eslintrc.json

{
    "env": {
        "browser": true,
        "es2021": true,
        "node": true
    },
    "extends": [
        "plugin:react/recommended",
        "airbnb"
    ],
    "parserOptions": {
        "ecmaFeatures": {
            "jsx": true
        },
        "ecmaVersion": 12,
        "sourceType": "module"
    },
    "plugins": [
        "react"
    ],
    "rules": {
        "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }]
    }
}

코드 설명

  • env: 프로젝트의 사용 환경이다.
  • parserOptions: 자바스크립트 버전, 모듈 사용 여부 등을 설정할 수 있다.
  • extends: 확장 설정을 넣어준다. airbnb사의 코딩 스타일을 따르며 prettier을 반영하도록 설정했다.
  • rules extends와 plugins에 대한 세부 설정을 변경하는 코드를 넣을 수 있다. 값을 0으로 주면 에러 검출을 하지 않고, 1로 주면 경고, 2로 주면 에러를 표시한다. 상세한 룰은 문서 에 담겨져 있다.

상세내용 : https://www.daleseo.com/eslint-config/

실행

✏️ 직접 실행

npx eslint ./src/파일.js

✏️ 간편 실행

1. package.json의 scripts옵션에 eslint . 추가

"scripts": {
    ...
    "lint": "eslint ." // 프로젝트 전체 파일을 상대로 ESLint 실행
  },

2. lint가 불필요한 것들을 .eslintrc.json의 ignorePatterns에 추가
-> ex) node_modules 디렉터리의 경우 외부 라이브러리의 소스 코드를 담고 있기 때문에 린트를 해줄 필요가 없기 때문

{ 
	...
  "ignorePatterns": ["build", "dist", "public"]
}

✏️ 실행 시 다음과 같이 lint가 에러를 발생시킨다.

  • 이때 코드의 어느 부분에 에러가 발생하는지 확인하기 위해서는 ESLint라는 확장팩을 다운로드

코드 수정

✏️ -- fix 옵션을 붙여서 실행하면 자동으로 코드를 수정

 npx eslint src/pages/App.js --fix

✏️ import과 같은 코드에 대한 오류가 발생하면

💥 ESLint Prettier 충돌

ESLint는 코드의 에러와 문제점을 검사하였고, Prettier는 코드의 모습을 깔끔하고 가독성이 좋게 만든다.
ESLint는 코드의 구조을 바꿔주는 기능도 포함하지만, 오류 검출을 하는 것에 특화되어 사용해서 Prettier가 이를 해결한다. 하지만, 앞서 말한 것과 같이 ESLint에도 코드의 구조에 대한 기능도 포함되어있다보니 Prettier의 설정과 충돌이 일어날수 있다. 🥲

간단한 예로는 Prettier에서는 들여쓰기를 2칸으로 설정하였는데, ESLint의 포맷팅 기능으로는 들여쓰기 2칸이 오류라고 생각할 수도 있는 것이다.

따라서 이 둘을 통합하는 방법을 알아보자!😃

✚ ESLint Prettier 통합

✏️ 둘의 충돌을 막기 위한 패키지를 설치.

eslint-config-prettier

  • eslint에서 prettier와 충돌할 수 있는 rule을 꺼버린다.
  • 즉 자바스크립트 문법 및 코드 품질 검사는 ESLint가, 코드 포맷은 Prettier가 검사하도록 만들어주는 것이다.

eslint-plugin-prettier

  • prettier를 eslint의 rules로 동작하게 한다. (즉, ESLint 하나만 실행해도 문법검사와 formatting을 함께 실행 시킬 수 있다. )
  • 포맷팅 문제도 오류로 출력되어서 오류 메시지가 지나치게 많아지며 느리다는 단점 존재
    -> 하지만, 파일을 저장할 때 자동으로 prettier가 적용되는 설정을 하였으므로 포맷팅에 대한 속도지연 문제는 해결 가능
yarn add --dev eslint-config-prettier eslint-config-prettier

✏️ .eslintrc의 extends 옵션에 다음과 같은 코드 추가.

만약, 다른 값들이 존재할 경우 기존 설정보다 우선하기 위해서는 배열 내의 맨뒤에 위치시킨다.

[...,...,"plugin:prettier/recommended"]

✏️ 따라서, 파일 저장 시 prettier에 의한 formatting이 진행되고, eslint 실행 시 prettier의 rule을 감안하여 오류를 검출하게 된다.

💡 잠깐) prettier & ESLint의 실행 ~ 수정

현재 내가 formatter와 linter를 실행하는 방법은 다음과 같다.

  1. editor.formatOnSave의 true 설정으로 파일 저장 시 prettier가 실행 및 자동 수정
  2. npx eslint 파일명.js로 ESlint 실행.
  3. npx eslint 파일명.js --fix를 통해 오류가 있는 코드가 자동 수정.

이 방법의 경우 eslint-plugin-prettier를 사용하지 않은 경우다. 이 패키지는 ESLint 실행 시 자동으로 prettier의 formatting까지 진행되는 것이지만, 나는 파일 저장 시 formatting이 자동으로 수정되게 설정하였기 때문이다.

만약 위와 같은 순서의 방법이 귀찮다면 eslint-plugin-prettier를 사용할 수는 있다.
setting.json에 다음과 같이 코드를 작성한다.

 "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
  },
  "editor.formatOnSave": false,

즉, Prettier에 대한 formatting에 대한 자동수정은 false로 설정하고, ESLint에 대한 codeAction을 true로 하는 것이다. 앞서 말했듯이 ESLint 실행 시 Prettier도 자동 실행되기 때문에 가능한 설정이다. 하지만, 이럴 경우 Lint와 formatting에 대한 오류가 모두 발생하고 속도가 지연되는 단점이 있으므로 그냥 내가 하던 방법으로 사용하자! 😃

💾 ESLint + Commit

프로젝트 진행 시 앞서 설정한 lint를 수행하게 되는데, lint가 모두 완료되지 않은 상태로 commit을 할 수 있는 상황이 발생할 수 있다. 이는 협업을 할 경우에는 문제점이 될 수 있다.

따라서, commit을 할 경우 ESLint를 강제로 실행시켜 만약 문제가 있다면 repository에 유입되는 것을 차단하는 방법을 사용해보자.

설치

  • lint-staged는 스테이징 영역에 있는 파일을 상대로 린트를 해주는 도구
  • husky는 git command 실행시 특정 스크립트를 실행해주는 도구
yarn add -dev lint-staged husky

package.json에 다음과 같은 설정 추가

"lint-staged": {
    "*.js": [
      "eslint --fix",
      "git add"
    ]
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  }

❌ ESLint Error

Prettier의 경우 파일 저장 시 자동 수정이 되므로 해결되었고, ESLint의 경우도 --fix의 기능으로 코드 수정이 가능하다. 하지만 그래도 발생하는 에러들이 있다. 그 에러들에 알아보고, ESLint의 에러에는 어떤 것들이 있는지 알아보자!

✏️ error JSX not allowed in files with extension '.js'

➡️ js파일에 JSX를 작성하는 것에 대한 에러를 해결하기 위해 rules에 다음과 같은 코드 추가

  "rules": {
        "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }]
    }

✏️ error 'React' must be in scope when using JSX

➡️ JSX는 자바스크립트 문법의 확장으로 ECMA 표준이 아니다. 따라서 바벨과 같은 툴로 JSX를 자바스크립트로 변환해야 한다. 바벨이 JSX가 사용되었음을 알고 이를 변환하도록 하기 위해서는 React를 import해주어야 한다ㅣ

import React from 'react';

✏️ error Unable to resolve path to module

➡️ 다음과 같이 rules에 추가한다. 정확히는 import로 가져온 파일 혹은 모듈이 unresolved가 되지 않도록(no)하는 옵션이다. 절대경로를 사용하기 때문에 발생한 것 같은데 그에 대한 것을 off로 설정하면 에러가 사라진다.

 "rules": {
    ...
    "import/no-unresolved": "off"
  },

✏️ error img elements must have an alt prop, either with meaningful text, or an empty string for decorative images

➡️ img태그의 alt값을 작성하지 않아서 일어나는 에러

<img alt="추가"  src={...}/>

✏️ error ' can be escaped with &apos;, &lsquo;, &#39;, &rsquo;

➡️ HTML에 특수문자를 작성할 시 대체할 문자가 필요하다.

변경 전
site's personal blog

변경 후
site &#39 s personal blog

HTML 특수문자 리스트: http://kor.pe.kr/util/4/charmap2.htm

✏️ error Missing an explicit type attribute for button

➡️ button의 타입에는 세가지(submit,reset,button)가 존재한다. 만약 값을 지정하지 않으면 기본값으로 sumit이 설정된다. 따라서, form 태그로 감싸져 있는 button태그의 타입을 지정하지 않으면 자동적으로 submit 기능이 실행되버린다. 따라서, button태그라 하더라도 반드시 type을 작성해주자.

<button type="button" className={styles.signUpBtn}>버튼</button>

button 타입별 좋은 예시: https://nykim.work/96

✏️ error Arrow function should not return assignment

➡️ JS는 거의 모든 시점에서 할당이 가능하기 때문에, 특히 return문 사용 시 더 그렇다.
= 의미가 모호성을 가지기 때문에 ===을 작성하여 확실성을 준다.

변경 전
<div ref={el => (NavRef.current[0] = el)}>


변경 후
<div ref={el => NavRef.current[0] === el}>

no-return-assign: https://runebook.dev/ko/docs/eslint/rules/no-return-assign

✏️ error Missing radix parameter

➡️ 문자열을 정수로 변환할 때 parseInt의 두번째 파라미터에 radix(진수) 표시를 한다.

변경 전
const postId = parseInt(id);

변경 후
const postId = parseInt(id, 10);

✏️ warning Unexpected confirm, alert

➡️ 대력적 이유 : https://eslint.org/docs/latest/rules/no-alert

변경 전
 if (window.confirm('삭제하시겠습니까?')) dispatch(deletePost(data.id));

alert('삭제되었습니다');

변경 후
 // eslint-disable-next-line no-alert
 if (window.confirm('삭제하시겠습니까?')) dispatch(deletePost(data.id));
    
 // eslint-disable-next-line no-alert
    alert('삭제되었습니다');

ESLint 비활성화: https://ahnanne.tistory.com/18

✏️ assigned a value but never used

➡️ state 변수를 선언하였고 그 변수를 할당하는 코드는 있지만, setState는 선언만 되었고 사용되지 않았다. ESLint는 이 것을 보고 선언만 되고 사용되지 않고 있다는 에러를 보인다. 따라서, 해당 코드에 대해서만 에러를 없애는 코드를 작성할 수 있고, .eslintrc.json의 rules에 off값을 줄 수도 있다.

방법1)
   // eslint-disable-line no unused-vars
  const [limit, setLimit] = useState();
  
방법2)
  "rules": {
   		...
    "no-unused-vars": "off"
  },
 

✏️ error Default parameters should be last

➡️ ESLint에서 rule의 경우 두 매개 변수에 기본값을 지정하거나 특정 줄에 대한 규칙을 비활성화해야 함을 의미한다. rule에 따르면 ({type, payload}, state = initialState) 과 같이 기본 매개변수를 마지막에 넣으면 함수 호출에서 선택적 꼬리 인수를 생략할 수 있다고 한다.
하지만, 이 에러를 무시하고 싶다면 .enlintrc.json의 rules에 다음과 같이 추가자.

"default-param-last": 0

상세내용: https://eslint.org/docs/latest/rules/default-param-last

✏️ error Unexpected lexical declaration in case block

➡️ ESLint에서는 변수가 현재 범위 외부에 있기 때문에 권장하지 않으므로 {}를 통해 블록 범위를 만들면 해결이 가능하다.

	...
    case DELETE_POST: {
      const inputData = [...state.inputData];
      const dataIndex = inputData.findIndex(post => post.id === action.payload);
      inputData.splice(dataIndex, 1);
      return { ...state, inputData };
    }

✏️ error Identifier 'ㅁㅁㅁ' is not in camel case

➡️ 변수 이름 지정과 관련하여서는 camelCase로 작성하는 rule을 갖는다

변경전) import jwt_decode from 'jwt-decode';

변경전) import jwtDecode from 'jwt-decode';

✏️ error objectpassed as the value prop to the Context provider changes every render. To fix this consider wrapping it in a useMemo hook

➡️ context provider의 value로 전달될 object가 렌더링될때마다 변경됨으로 useMemo 후크로 래핑하면 해결

  const contextData = useMemo(
    {
      user,
      authTokens,
      setAuthTokens,
      setUser,
      loginUser,
      logoutUser,
    },
    [user, authTokens, loginUser, logoutUser],
  );

✏️error 'children' is missing in props validation

➡️ children에 대한 값이 어떤 타입을 가지는지 모르기 때문에 ESLint의 유효성검사를 통해 에러가 발생.
따라서, 두가지 방법으로 해결 가능.

1. prop-types라는 패키지를 설치하고 props의 타입을 명시해주느 것이다.

import {PropsTypes} from 'prop-types'

 const AuthContext = ({children}) => {
  return(<div>{children}</div>)
}

AuthContext.propsTypes = {
  children: PropTypes.node.isRequired,
};

Prop Type의 종류: https://haerim95.tistory.com/41

  1. .eslintrc.json의 rules에 에러 발생 off 하기 설정
"rules":{
	...
  "react/prop-types": "off"
}

✏️ error Visible, non-interactive elements with click handlers must have at least one keyboard listener
✏️ error Avoid non-native interactive elements. If using native HTML is not possible, add an appropriate role and support for tabbing, mouse, keyboard, and touch inputs to an interactive content element

➡️ HTML의 요소들에는 각각 고유한 역할이있다. a태그는 링크, img태그는 이미지를 삽입하는 것처럼 역할이 있는데 햄버거 토글바를 동적인 버튼으로 반들기 위해 각각 세개의 줄을 div태그로 만들어서 구현하였다. 따라서, div의 역할에 대한 맞지 않는 역할을 갖고 있어서 발생하는 에러인 것 같다. 따라서 그러한 마크엄 요소의 의미를 제거하고 내용만을 전달하는 속성(persentation)을 작성하여서 해결하였다.

  <div
       role="presentation"
       className={!menuToggle ? `${styles.burgerMenu}` : `${styles.xMenu}`}
       onClick={menuToggleHandler}
   >
   ...
   </div>

위의 에러코드를 해석하면 다음과 같다.

'클릭 핸들러가 있는 표시되는 비대화형 요소에는 하나 이상의 키보드 리스너가 있어야 합니다.'

'기본이 아닌 대화형 요소를 피하십시오. 기본 HTML을 사용할 수 없는 경우 대화형 콘텐츠 요소에 탭 이동, 마우스, 키보드 및 터치 입력에 대한 적절한 역할 및 지원을 추가합니다.'

presentation의 역할: https://heewon26.tistory.com/82
참고자료: https://inswave.com/confluence/pages/viewpage.action?pageId=19076563

✏️ error Must use destructuring props assignment

➡️ 반드시 props를 비구조화 할당하라는 뜻이다. 다른 컴포넌트로 받아온 props를 비구조화 할당하여 받아오는 것이다.

변경전)
function Header(props) {
	
    const onClickNav = i => {
    	props.handleIndexClick(i);
  };
 };
변경후)
function Header({handleIndexClick}) {
	
    const onClickNav = i => {
    	handleIndexClick(i);
  };
 };
 
또는

function Header(props) {
	const {handleIndexClick} =. props;
    const onClickNav = i => {
    	handleIndexClick(i);
  };
 };

구조분해할당: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

✏️ error Prop spreading is forbidden
➡️ props를 컴포넌트에 전달할 때 props 객체의 압축을 풀기 위해 spread 구문을 사용할 때 에러가 발생한다. 이 경우에는 에러를 비활성화하는 것이 제일 낫다.

rules: {
	...
    "react/jsx-props-no-spreading": "off",
  }

✏️ Because the unary ++ and -- operators are subject to automatic semicolon insertion, differences in whitespace can change semantics of source code.

➡️ 단항 ++ 및 -- 연산자는 자동 세미콜론 삽입의 대상이 되기 때문에 공백의 차이는 소스 코드의 의미를 변경할 수 있기 때문에 다음과 같이 변경.

 변경전)
 for (let i = 0; i < cookies.length; i ++) {
 변경후)
 for (let i = 0; i < cookies.length; i += 1) {

참조

profile
기록하여 기억하고, 계획하여 실천하자. will be a FE developer (HOME버튼을 클릭하여 Notion으로 놀러오세요!)
post-custom-banner

0개의 댓글