ESLint 적용 및 자동화
코드를 일관성 있는 형식으로 유지하는 것은 중요하다. 일관성 있는 코드는 가독성을 올려주며, 이는 협업 및 유지보수에 큰 도움을 준다.
코드를 일관성있게 유지하는 방법은 많이 있겠지만, (React Native 환경에서) 가장 쉽게 적용할 수 있는 방법 중 하나가 ESLint 적용이라고 생각한다. ESLint 는 설정된 규칙에 어긋나는 코드를 리포팅해주는 도구이다. 설치 및 설정이 간단하기 때문에 누구나 쉽게 사용할 수 있다.
1. 설치
yarn add --dev eslint
위 명령어를 통해 설치할 수 있다.
ESLint 는 설치한 뒤, 설정 파일을 작성해야 한다. 방법은 두 가지가 있다. 하나는 ESLint 에서 제공하는 명령어를 통해 자동 생성하는 것이고, 다른 하나는 프리셋을 사용하는 것이다. (물론 직접 작성하는 방법도 있지만 이 글에서는 다루지 않는다.)
1.1. eslint --init
./node_modules/.bin/eslint --init
위 명령어를 입력하면 아래처럼 터미널에 몇 가지 문항이 뜨는데 자신에게 알맞는 답을 선택하면 자동으로 설정 파일을 생성해주고 필요한 디펜던시까지 설치해준다.
✔ How would you like to use ESLint?
✔ What type of modules does your project use?
✔ Which framework does your project use?
✔ Does your project use TypeScript?
✔ Where does your code run?
✔ What format do you want your config file to be in?
The config that you've selected requires the following dependencies:
eslint-plugin-react@latest @typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest
✔ Would you like to install them now with npm?
Installing eslint-plugin-react@latest, @typescript-eslint/eslint-plugin@latest, @typescript-eslint/parser@latest
1.2. react-native-community 의 프리셋 사용
또다른 방법은 React Native Community 에서 제공하는 설정 프리셋을 사용하는 것이다. 해당 프리셋은 아래 명령어로 설치할 수 있다.
yarn add --dev @react-native-community/eslint-config
이 프리셋에는 TypeScript 관련 설정이 포함되어 있다.
라이브러리가 설치되면 설정 파일을 작성해주어야 한다.
// {ROOT}/.eslintrc.js
module.exports = {
root: true,
extends: ["@react-native-community"],
};
@react-native-community/eslint-config 패키지에 설정이 미리 되어 있으므로, 이 이상 더 해 줄 것은 없다.
1.2.1. 프리셋 설정 수정
React Native Community 의 프리셋이 일부 마음에 들지 않을 수 있다. 그렇다면 설정 파일을 수정하면 된다.
마음에 들지 않을 수 있는 대표적은 설정으로는 prettier 설정이 있다. React Native Community 의 프리셋에는 prettier 옵션이 설정되어 있고, 이 옵션에 의한 코드 스타일은 개발자의 호불호가 크게 갈릴 수 있다. 만약 해당 설정을 끄고 싶다면 아래처럼 설정 파일을 수정하면 된다.
// {ROOT}/.eslintrc.js
module.exports = {
root: true,
extends: [
"@react-native-community",
// eslint-config-prettier 는
// @react-native-community/eslint-config 의 디펜던시에
// 포함된 패키지이므로, 추가로 설치해 줄 필요는 없다.
"eslint-config-prettier",
],
rules: {
// prettier 설정을 끈다.
"prettier/prettier": 0,
},
};
단 위처럼 prettier를 꺼버리면 comma-dangle
, quotes
등 prettier 를 통해 적용되고 있던 일부 lint 옵션들이 꺼질 수 있다. 그러면 rules
필드에 원하는 룰을 추가해주면 된다.
// {ROOT}/.eslintrc.js
module.exports = {
// ...
rules: {
// ...
"comma-dangle": ["error", "always-multiline"],
quotes: ["error", "single"],
semi: ["error", "always"],
},
};
설정에 관한 자세한 내용은 공식 문서를 참고하자.
2. 자동화
ESLint 를 적용했지만, 이 툴은 설치한 것만으로 자동으로 코드를 검사를 해주지 않는다. eslint
명령어를 실행해야지만 코드를 검사해준다. 하지만 명령어를 일일이 쳐주는 것은 번거로울 뿐더러 까먹기도 쉽다. 까먹고 커밋하고 푸시하면 결국 설치한 것이 의미가 없어진다. 까먹지 않는 가장 좋은 방법은 툴이 자동으로 알아서 실행되게끔 자동화를 해주는 것이다.
자동화 방법에는 여러가지가 있을 수 있겠지만, 여기서는 git 의 pre-commit 훅을 사용한다.
2.1. pre-commit
pre-commit 훅은 커밋 직전에 실행되는 스크립트다. 스크립트 결과에 따라 커밋을 막을 수도 있다. 즉 우리는 pre-commit 으로 eslint
명령어를 실행하고, 룰셋에 맞지 않는 코드가 있으면 커밋을 하지 못하게 할 것이다.
pre-commit 훅은 .git/hooks/pre-commit
파일에 작성하면 된다. 아래는 간략화한 pre-commit 코드다.
# eslint 가 설치되어 있는지 확인하고 설치되어있지 않다면 커밋을 막는다.
ESLINT="node_modules/.bin/eslint"
if [[ ! -x "$ESLINT" ]]; then
printf "Please install ESlint\n"
exit 1
fi
# staged 된 파일들에 대해서만 eslint --fix 명령어를 실행한다.
STAGED_FILES=($(git diff --cached --name-only --diff-filter=ACM | grep ".[jt]sx\{0,1\}$"))
$ESLINT "${STAGED_FILES[@]}" --fix
ESLINT_EXIT="$?"
# eslint --fix 결과에 따라 커밋을 진행한다.
if [[ "${ESLINT_EXIT}" == 0 ]]; then
printf "COMMIT SUCCEEDED"
else
printf "COMMIT FAILED"
exit 1
fi
exit $?
(스크립트 원문)
3. 결과
이제 코드를 커밋할 때마다 git 스테이지에 포함된 파일에 대해 자동으로 eslint 명령어가 실행될 것이다. 작업 다 끝났다고 생각했는데 pre-commit 에 의해 커밋이 막히면 기분이 나쁠 수도 있지만, 장기적으로 봤을 때 작업의 효율성이 개선될 것이다.
4. 개선점?
ESLint 는 기본적으로 일관된 코드를 강제하는 것에 초점을 두기 보다는 나쁜 코드를 막는 것에 초점을 둔다. 규칙에 맞지 않는 코드를 찾아주지만 그것을 자동으로 고쳐주지는 않고 (--fix
옵션을 통해 몇몇 옵션들은 코드를 자동으로 고쳐주기도 하지만 모든 옵션이 다 그렇지는 않다), 규칙 자체도 상황에 따라서는 느슨하다고 느낄 수 있다.
그렇다면 일관된 코드를 강제하기 위한 대안은 어떤 게 있을까?
Prettier 라이브러리를 사용하는 방법이 있다. Prettier 는 말 그대로 일관된 코드를 강제하는, 일관되지 않은 부분을 강제로 고쳐주는 툴이다. (1.2.1. 프리셋 설정 수정 에서 비활성화했던 prettier 옵션이 이 Prettier 라이브러리의 ESLint 플러그인 버전이다.) 다만 이 툴은 강제성이 크기 때문에 사용자에 따라 호불호가 갈릴 수 있다. 사용해보고 더 맞는 쪽을 선택하는 것이 좋을 것 같다.