Skip to main content

VanillaJS로 SPA 환경 구축하기 - Step4: Lint

· 10 min read

정적인 코드 스타일 체크를 위하여 Lint, Prettier, CommitLint 등을 설정하였다.

Configure Lint

Installation

eslint를 설치한다.

yarn add -D eslint

기본적인 eslint 설정 파일 생성을 위해 다음과 같이 커맨드를 실행한다.

npx eslint --init
# or
./node_modules/.bin/eslint --init

해당 config 파일 생성을 위한 과정 예시는 아래와 같다.

❯ npx eslint --init                                                      08:59:56
Need to install the following packages:
eslint
Ok to proceed? (y) y
You can also run this command directly using 'npm init @eslint/config'.
Need to install the following packages:
@eslint/create-config
Ok to proceed? (y) y
✔ How would you like to use ESLint? · style
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · none
✔ Does your project use TypeScript? · No / Yes
✔ Where does your code run? · browser
✔ How would you like to define a style for your project? · guide
✔ Which style guide do you want to follow? · airbnb
✔ What format do you want your config file to be in? · JavaScript
Checking peerDependencies of eslint-config-airbnb-base@latest
The config that you\'ve selected requires the following dependencies:

@typescript-eslint/eslint-plugin@latest eslint-config-airbnb-base@latest eslint@^7.32.0 || ^8.2.0 eslint-plugin-import@^2.25.2 @typescript-eslint/parser@latest
✔ Would you like to install them now? · No / Yes
✔ Which package manager do you want to use? · yarn
Installing @typescript-eslint/eslint-plugin@latest, eslint-config-airbnb-base@latest, eslint@^7.32.0 || ^8.2.0, eslint-plugin-import@^2.25.2, @typescript-eslint/parser@latest

해당 과정에서 추가로 설치가 된 플러그인들은 아래와 같다.

  • eslint-config-airbnb-base : 기본적으로 많이 사용하는 airbnb 에서 정의한 규칙을 적용. vanilla javascript 환경이므로 기본적인 규칙이 적용된 플러그인만 설치하면 됨
  • eslint-plugin-import : ES6의 import, export 구문을 지원해주는 플러그인
  • @typescript-eslint/eslint-plugin, @typescript-eslint/parser : typescript를 위한 플러그인

위와 같이 진행 후에 <project_root_dir>/.eslintrc.js 파일을 확인해보면 다음과 같이 작성되어있다.

module.exports = {
env: {
browser: true,
es2021: true,
},
extends: ['airbnb-base'],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: ['@typescript-eslint'],
rules: {},
};

이제 lint를 수행해보기 위해 package.json에 다음과 같이 script를 정의해준다.

"lint": "eslint src --ext .js,.jsx,.ts,.tsx"

그리고 아래와 같이 prelint 스크립트를 추가하여 lint 수행하기 전에 type check를 하도록 하기 위해 아래와 같이 최종적으로 수정하였다.

"tslint": "tsc -p tsconfig.json --skipLibCheck --noEmit --emitDeclarationOnly false",
"eslint": "eslint src --ext .js,.jsx,.ts,.tsx",
"lint": "yarn tslint && yarn eslint"

yarn3 (=yarn berry)에서는 사용자 정의 스크립트에 대하여서 pre, post를 지원하지 않는다고 한다.

Configuration Lint-staged & husky

코드를 수정하고 매번 lint를 수행하여 체크하는 것은 번거로울 수도 있는 일이고, 사람이 하는 일이다보니 놓쳐서 알지 못하게 불필요한 bug를 repository에 반영해버릴 수도 있다. 이러한 부분을 예방하기 위해 lint-stagedhusky를 이용하여 git으로 commit & push를 하는 시점에 정의한 lint가 수행되도록 설정한다.

  • lint-stageㅑ : git stage에 있는 파일들에 대해 lint를 수행하도록 해주는 도구이다.
  • husky : git hook을 편하게 사용할 수 있도록 해주는 도구이다.

Installation lint-staged

lint-staged를 설치한다.

yarn add lint-staged --dev

.lintstagedrc.js 파일을 생성하고 아래와 같이 정의한다.

module.exports = {
'*.{js,jsx}': ['yarn eslint --fix', 'git add'],
'*.{ts,tsx}': [() => 'yarn tslint', 'yarn eslint --fix', 'git add'],
};

Installation husky

앞에서 정의한 lint-staged가 git commit 시점에 동작하도록 hook을 걸어주기 위해 husky를 설치하여 구성해준다. yarn3를 사용하고 있으므로 husky doc > Usage > yarn 2에 작성된 가이드를 따라서 설치를 진행한다.

package.json에 해당 과정을 진행하기 전에 아래와 같은 설정을 추가해주었다.

private: true,

private 설정은 실수로 패키지가 publish가 되는 것을 예방해준다고 한다. 해당 프로젝트는 개인적이기도 하고, publish를 할 예정이 없기에 설정해주었다. 하지만, 배포 예정인 프로젝트라고 사전에는 true로 설정해두었다가 배포 시점에 수정하여 사용하는 것이 실수로 인한 배포를 예방할 수 있다고도 한다.

yarn add husky --dev

package.json에 아래의 스크립트를 추가해준다.

  //...SKIP
"license": "MIT",
"private": true,
"scripts": {
"postinstall": "husky install",
//...SKIP

여기까지 진행한 뒤에 아래의 명령어를 수행한다.

yarn install

해당 명령이 정상적으로 수행이 되었다면, <project_root_dir>/.husky 폴더가 다음과 같은 구조로 생성이 된다.

.husky
└── _
└── husky.sh

Create a hook

아래와 같이 명령어를 수행하여, pre-commit 스크립트를 추가한다.

npx husky add .husky/pre-commit "yarn lint-staged"

위와 같이 정의 후에 git commit을 수행하면 아래와 같이 lint-staged와 husky가 동작하는 것을 확인할 수 있다.

~/Documents/mio/cocoa-clone master* ❯ git ci -m "chore: configure eslint"                                    12:10:50
(node:13633) ExperimentalWarning: Custom ESM Loaders is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
⚠ Some of your tasks use `git add` command. Please remove it from the config since all modifications made by tasks will be automatically added to the git commit index.

[STARTED] Preparing lint-staged...
[SUCCESS] Preparing lint-staged...
[STARTED] Running tasks for staged files...
[STARTED] .lintstagedrc.js — 8 files
[STARTED] *.{js,jsx}2 files
[STARTED] *.{ts,tsx}1 file
[STARTED] eslint --fix
[STARTED] yarn tslint
[FAILED] yarn tslint [FAILED]
[FAILED] yarn tslint [FAILED]
[SUCCESS] Running tasks for staged files...
[STARTED] Applying modifications from tasks...
[SKIPPED] Skipped because of errors from tasks.
[STARTED] Reverting to original state because of errors...
[FAILED] eslint --fix [FAILED]
[FAILED] eslint --fix [FAILED]
[SUCCESS] Reverting to original state because of errors...
[STARTED] Cleaning up temporary files...
[SUCCESS] Cleaning up temporary files...

#...SKIP

해당 과정에서 lint 과정의 오류가 발생하면 수정해준다.

Configure Prettier

tab을 몇 칸으로 정의할 지, 한 줄에 몇 라인까지 허용할지 등에 대한 코드 스타일을 정의하고, 해당 규칙을 따르도록 변환해주기 위해 Code Formatter인 Prettier를 설정한다.

먼저 prettier를 설치해준다.

yarn add --dev --exact prettier

prettier 설정 파일을 아래와 같이 생성하여 정의해준다.

# .prettierrc
{
"endOfLine": "lf",
"printWidth": 80,
"singleQuote": true,
"semi": true,
"tabWidth": 2,
"useTabs": false,
"trailingComma": "all",
"arrowParens": "always",
"bracketSpacing": true,
"jsxSingleQuote": false,
"jsxBracketSameLine": false,
"newline-before-return": true,
"no-duplicate-variable": [true, "check-parameters"],
"no-var-keyword": true
}

prettier를 적용하지 않기 위한 파일들을 설정하기 위해 .prettierignore 파일을 추가한다.

# .prettierignore
# Ignore artifacts:
dist

ESLint

eslint를 이용하여 prettier를 같이 체크할 수 있도록 설정한다.

yarn add -D eslint-plugin-prettier eslint-config-prettier

eslintrc.js 파일에 해당 설정을 추가해준다.

  extends: [
'airbnb-base',
'plugin:prettier/recommended',
],
//...SKIP
plugins: ["@typescript-eslint", 'prettier'],

lint-staged

git hook을 이용하여 commit 시점에 prettier를 체크하기 위해 lint-staged에 추가해준다.

module.exports = {
"*.{js,jsx,ts,tsx,json,css,md}": ["prettier --write", "git add"],
// ...SKIP

Commitlint

통일된 commit message 관리를 위해 git hook을 이용하여 commit message를 체크하기 위한 commitlint를 설정하였다.

yarn add -D @commitlint/cli @commitlint/config-conventional

.commitlintrc.js 파일을 생성해서 아래와 같이 설정해준다.

module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'build',
'ci',
'chore',
'docs',
'feat',
'fix',
'perf',
'refactor',
'revert',
'style',
'test',
],
],
'type-case': [2, 'always', 'lowerCase'],
'type-empty': [2, 'never'],
'subject-empty': [2, 'never'],
'header-max-length': [2, 'always', 100],
},
};

git hook을 통해 comit message에 대해 검사하기 위해 아래와 같이 husky를 이용하여 hook을 생성해준다.

npx husky add .husky/commit-msg "yarn commitlint --edit $1"

위와 같이 설정 후에 아래와 같이 commit message를 작성하여 시도를 하면 정의된 규칙에 맞지 않아 commit이 되지 않고 에러가 발생하는 것을 확인할 수 있다.

git ci -m "xxx"
#....SKIP
(Use `node --trace-warnings ...` to show where the warning was created)
⧗ input: xxx
✖ subject may not be empty [subject-empty]
type may not be empty [type-empty]

✖ found 2 problems, 0 warnings
ⓘ Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint

husky - commit-msg hook exited with code 1 (error)