블로그 시리즈
이 블로그 포스트는 시리즈로 제작되었습니다. 다음은 블로그 시리즈 리스트입니다.
개요
ESLint란 ES(EcmaScript) + Lint(에러 코드 표식) 합성어로 Javascript 코드를 분석하고, 잠재적인 오류나 버그를 찾는데 도움을 주는 툴입니다.
- ESLint 공식 사이트: https://eslint.org/
이번 블로그 포스트에서는 create-react-app
으로 생성한 React 프로젝트에 ESLint를 적용하는 방법에 대해서 살펴보도록 하겠습니다.
프로젝트 준비
React에서 ESLint를 사용하기 위해, create-react-app
으로 간단하게 프로젝트를 생성하겠습니다. create-react-app
에 관해 잘 모르시는 분들은 아래의 링크를 참고하시기 바랍니다.
그럼 다음 명령어를 사용하여 ESLint를 사용할 React 프로젝트를 생성합니다.
npx create-react-app eslint_example --template=typescript
저는 주로 TypeScript
를 사용하여 React를 개발하므로 --template=typescript
옵션을 사용하여 React 프로젝트를 생성하였습니다.
ESLint 설치
React에서 ESLint를 사용하기 위해서는 ESLint 라이브러리를 설치할 필요가 있습니다. 다음 명령어를 사용하여 ESLint 라이브러리를 설치합니다.
# cd eslint_example
npm install eslint --save-dev
ESLint 설정
React에서 ESLint를 사용하기 위해서는 ESLint를 설정할 필요가 있습니다. 다음 명령어를 실행하여 ESLint를 설정합니다.
npx eslint --init
위에 명령어를 실행하면, 다음과 같은 질문을 확인할 수 있습니다.
? How would you like to use ESLint? …
To check syntax only
❯ To check syntax and find problems
To check syntax, find problems, and enforce code style
자신이 사용하고자 하는 옵션을 선택합니다. 저는 To check syntax and find problems
을 선택하였습니다. 그럼 다음과 같은 질문을 확인할 수 있습니다.
? What type of modules does your project use? …
❯ JavaScript modules (import/export)
CommonJS (require/exports)
None of these
React는 기본적으로 import/export
방식을 사용하므로 JavaScript modules (import/export)
을 선택하여 진행합니다. 그럼 다음과 같은 질문을 확인할 수 있습니다.
? Which framework does your project use? …
❯ React
Vue.js
None of these
우리는 ESLint를 React 프로젝트에서 사용할 예정이므로 React
를 선택하여 진행합니다. 그럼 다음과 같은 질문을 확인할 수 있습니다.
? Does your project use TypeScript? › No / Yes
저는 React를 개발할 때, 주로 TypeScript를 사용하므로 Yes
를 선택하여 진행하였습니다. TypeScript를 사용하지 않는다면 No
를 선택하고 진행하시기 바랍니다. 그럼 다음과 같은 질문을 확인할 수 있습니다.
? Where does your code run? … (Press <space> to select, <a> to toggle all, <i> to invert selection)
✔ Browser
✔ Node
React는 Browser에서 코드가 실행되므로 Browser
를 선택하여 진행합니다. 그럼 다음과 같은 질문을 확인할 수 있습니다.
? What format do you want your config file to be in? …
❯ JavaScript
YAML
JSON
지금까지 대답한 ESLint의 설정 내용을 저장할 파일 포맷을 선택하는 옵션입니다. 저는 JavaScript
포맷을 선호하므로, JavaScript
를 선택하여 진행하였습니다.
eslint-plugin-react@latest @typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest
? Would you like to install them now with npm? › No / Yes
마지막으로, 이렇게 설정한 내용을 바탕으로 필요한 라이브러리를 설치할지 물어봅니다. Yes
를 선택하여 필요한 라이브러리를 설치합니다.
ESLint 룰
ESLint의 공식 사이트와 TypeScript ESLint 공식 페이지에서 설정 가능한 다른 룰(Rule)들을 확인할 수 있습니다.
해당 룰들을 확인하고, 자신의 프로젝트에 맞게 룰을 설정할 수 있습니다. 하단은 제가 사용하고 있는 룰 설정 내용입니다.
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:storybook/recommended',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
sourceType: 'module',
project: './tsconfig.json',
},
plugins: ['react', '@typescript-eslint', 'functional', 'import'],
settings: {
react: {
version: 'detect',
},
},
rules: {
// General
'no-console': ['error', { allow: ['debug', 'warn', 'error'] }],
// TypeScript
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-member-accessibility': 'off',
'@typescript-eslint/indent': 'off',
'@typescript-eslint/member-delimiter-style': 'off',
'@typescript-eslint/no-confusing-void-expression': [
'error',
{
ignoreArrowShorthand: true,
ignoreVoidOperator: true,
},
],
'no-duplicate-imports': 'off',
'@typescript-eslint/no-duplicate-imports': 'error',
'@typescript-eslint/no-implicit-any-catch': 'error',
'no-invalid-this': 'off',
'@typescript-eslint/no-invalid-this': 'error',
'@typescript-eslint/no-invalid-void-type': 'error',
'no-loop-func': 'off',
'@typescript-eslint/no-loop-func': 'error',
'no-loss-of-precision': 'off',
'@typescript-eslint/no-loss-of-precision': 'error',
'@typescript-eslint/no-parameter-properties': 'off',
'no-redeclare': 'off',
'@typescript-eslint/no-redeclare': 'error',
'no-shadow': 'off',
'@typescript-eslint/no-shadow': 'error',
'no-throw-literal': 'off',
'@typescript-eslint/no-throw-literal': 'error',
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error',
'@typescript-eslint/no-unnecessary-condition': 'error',
'@typescript-eslint/no-unnecessary-type-arguments': 'error',
'no-unused-expressions': 'off',
'@typescript-eslint/no-unused-expressions': 'error',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-use-before-define': [
'error',
{
variables: false,
},
],
'@typescript-eslint/prefer-enum-initializers': 'error',
'@typescript-eslint/prefer-for-of': 'error',
'@typescript-eslint/prefer-includes': 'error',
'@typescript-eslint/prefer-nullish-coalescing': 'error',
'@typescript-eslint/prefer-optional-chain': 'error',
'@typescript-eslint/prefer-reduce-type-parameter': 'error',
'@typescript-eslint/prefer-string-starts-ends-with': 'error',
'@typescript-eslint/prefer-ts-expect-error': 'error',
'@typescript-eslint/promise-function-async': 'error',
'no-return-await': 'off',
'@typescript-eslint/return-await': 'error',
'@typescript-eslint/strict-boolean-expressions': 'error',
'@typescript-eslint/switch-exhaustiveness-check': 'error',
// React
'react/jsx-boolean-value': 'warn',
'react/jsx-curly-brace-presence': 'warn',
'react/jsx-fragments': 'warn',
'react/jsx-no-useless-fragment': 'warn',
'react/jsx-uses-react': 'off',
'react/prefer-stateless-function': 'warn',
'react/prop-types': 'off',
'react/react-in-jsx-scope': 'off',
// Functional
'functional/prefer-readonly-type': [
'error',
{
allowLocalMutation: true,
allowMutableReturnType: true,
ignoreClass: true,
},
],
'import/order': [
'error',
{
groups: ['builtin', 'external', 'internal'],
pathGroups: [
{
pattern: '{react,react-dom/**}',
group: 'external',
position: 'before',
},
],
pathGroupsExcludedImportTypes: ['react'],
'newlines-between': 'always',
alphabetize: {
order: 'asc',
caseInsensitive: true,
},
},
],
'react/react-in-jsx-scope': 'off',
'linebreak-style': ['error', 'unix'],
eqeqeq: ['error', 'always', { null: 'ignore' }],
camelcase: ['error', { properties: 'never' }],
quotes: ['error', 'single', { avoidEscape: true }],
},
};
위에 룰을 사용하려면 다음 명령어를 실행하여 eslint-plugin-functional
을 설치할 필요가 있습니다.
npm install --save-dev eslint-plugin-functional
ESLint 체크
다음 명령어를 사용하면 우리가 정의한 ESLint의 룰을 지키고 있지 않은 파일과 내용을 확인할 수 있습니다.
npx eslint ./src
명령어를 실행하면 다음과 같이 정의된 룰을 지키고 있지 않는 파일과 내용을 확인할 수 있습니다.
/eslint_test/src/App.tsx
5:1 warning Missing return type on function @typescript-eslint/explicit-module-boundary-types
/eslint_test/src/reportWebVitals.ts
1:1 error All imports in the declaration are only used as types. Use `import type` @typescript-eslint/consistent-type-imports
3:25 warning Missing return type on function @typescript-eslint/explicit-module-boundary-types
✖ 3 problems (1 error, 2 warnings)
1 error and 0 warnings potentially fixable with the `--fix` option.
ESLint로 코드 수정
다음 명령어를 사용하면 우리가 정의한 ESLint의 룰을 사용하여 코드를 수정합니다.
npx eslint --fix ./src
명령어를 실행하면 ESLint가 수정할 수 있는 파일은 수정하게 되고, 수정하지 못한 파일들은 다음과 같이 표시합니다.
/eslint_test/src/App.tsx
5:1 warning Missing return type on function @typescript-eslint/explicit-module-boundary-types
/eslint_test/src/reportWebVitals.ts
3:25 warning Missing return type on function @typescript-eslint/explicit-module-boundary-types
수정하지 못한 파일들은 파일을 열어 직접 수정해 줍니다.
// code ./src/App.tsx
function App(): JSX.Element {
// code ./src/reportWebVitals.tsx
const reportWebVitals = (onPerfEntry?: ReportHandler): void => {
이렇게 파일 수정한 후, 다시 다음 명령어를 실행하여 코드를 체크해 보면, 이전과는 다르게 아무 경고가 표시되지 않는 것을 확인할 수 있습니다.
npx eslint ./src
이로써 우리는 미리 정의한 ESLint 룰들을 잘 지키고 있음을 확인할 수 있습니다.
저는 ESLint가 코드를 자동으로 수정하는 --fix
옵션 사용을 선호하지 않습니다. 직접 코드를 보면서 이유를 알아가는 것도 중요하기 때문이고, 가끔 ESLint가 잘못 수정하는 경우도 있기 때문입니다.
package.json 설정
앞에서 살펴본 check
명령어와 fix
명령어를 점 더 쉽게 사용하기 위해 package.json
파일을 열고 다음과 같이 수정합니다.
"scripts": {
...
"lint": "eslint ./src",
"lint:fix": "eslint --fix ./src"
},
이렇게 package.json
파일을 수정하였다면, 이제 다음 명령어를 사용하여 ESLint를 사용할 수 있습니다
npm run lint
npm run lint:fix
완료
이것으로 React 프로젝트에서 ESLint를 설정하는 방법에 대해서 알아보았습니다. 지금부터 ESLint를 사용하여 잠재적인 오류와 버그들을 수정해 보시기 바랍니다.
제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!
앱 홍보
Deku
가 개발한 앱을 한번 사용해보세요.Deku
가 개발한 앱은 Flutter로 개발되었습니다.관심있으신 분들은 앱을 다운로드하여 사용해 주시면 정말 감사하겠습니다.