프로젝트를 시작할 때 eslint와 prettier를 함께 맞추고 시작한다. 하지만 모든 룰을 다 맞추더라도 vscode 설정에 따라 사람마다 다르게 적용되는 문제가 발생한다.
나는 여태 eslint로는 오류를 찾고, prettier로는 포맷팅을 하며, 이 둘 사이의 충돌을 막기 위해 eslint-config-prettier와 eslint-plugin-prettier를 모두 필요한 줄 알았다. 하지만 2개의 패키지는 별도의 패키지이고, 2개를 설치하여 1개만 사용하고 있었다 😭. 이미 설정되어 있다면 vscode 설정을 변경하고, 새로 프로젝트를 시작한다면 eslint-config-prettier
를 사용하는 것을 권장한다. 기존에 쓰고 있는 것이 안되는 경우 이 글을 읽고, vscode 설정을 처음 설치하여 설정한다면 이전 글을 참고하면 좋을 것 같다.
eslint-config-prettier
: eslint에서 prettier와 충돌할 수 있는 rule 제거
코드 오류를 잡는데는 eslint, 코드 포맷팅에는 prettier 사용
eslint-plugin-prettier
: prettier를 eslint의 rules로 동작하게 함
포맷팅 문제도 오류로 출력되고 느리다.
prettier-eslint
: prettier를 실행하고 나서 eslint —fix 실행
prettier만 실행하는 것보다 훨씬 느리다.
cmd
+ ,
로 설정창을 열어 default formatter를 prettier로 설정하고 eslint-config-prettier 사용
// .eslintrc.cjs
module.exports = {
extends: [
...,
'prettier',
],
...
}
cmd
+ ,
로 설정창을 열어 default formatter를 eslint로 설정하고 eslint-plugin-prettier 사용
// .eslintrc.cjs
module.exports = {
extends: [
...,
'plugin:prettier/recommended',
],
...
}
react + typescript + vite 환경에서의 프로젝트 세팅
[ typescript 설정 ]
@typescript-eslint/eslint-plugin
: TypeScript 코드에 대한 ESLint 규칙을 적용하는 데 도움을 주는 플러그인
@typescript-eslint/parser
: ESLint가 TypeScript문법을 이해할 수 있도록 parser에 설정
[ eslint + prettier 충돌 방지 설정 ]
eslint-config-prettier
: eslint 설정과 prettier 포맷팅 충돌 방지
[ typescript import문 설정 ]
eslint-import-resolver-typescript
: ESLint가 타입스크립트에서 import하는 모듈의 경로를 해석하고 찾을 수 있게 도와주는 라이브러리
eslint-plugin-import
: import문 순서 지정
[ react 설정 ]
eslint-plugin-react-hooks
: 리액트 훅 관련 lint rule
eslint-plugin-react-refresh
: 코드 변경 사항을 빠르게 적용하여 개발자가 애플리케이션을 새로 고치지 않고도 변경 사항을 볼 수 있음
굳이 cjs 확장자로 사용할 필요 없고, 사용한 이유도 크게 없다. 처음 lint가 잘 적용되었을 때 cjs로 했어서 그냥 계속 하고 있다. js는 eslint가 esm을 지원안해서 오류나고, .eslintrc나 json으로 바꾸면 따옴표를 다 붙여야 되서 그냥 쓰는 느낌이라고 보면 된다.
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
'plugin:import/recommended',
'prettier',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
'import/order': [
'error',
{
groups: ['builtin', 'external', ['parent', 'sibling'], 'index'],
pathGroups: [
{
pattern: 'react*',
group: 'builtin',
position: 'before',
},
{
pattern: '@/pages/*',
group: 'internal',
position: 'after',
},
{
pattern: '@/components/*',
group: 'internal',
position: 'after',
},
{
pattern: '@/hooks/*',
group: 'internal',
position: 'after',
},
{
pattern: 'src/**',
group: 'internal',
},
],
alphabetize: {
order: 'asc',
caseInsensitive: true,
},
'newlines-between': 'always',
},
],
},
settings: {
'import/resolver': {
typescript: {},
node: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
},
},
},
};
{
"singleQuote": true,
"semi": true,
"useTabs": false,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 100,
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "auto"
}
{
...
"devDependencies": {
...,
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6",,
},
}
{
"javascript.format.enable": false,
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "always"
},
"eslint.format.enable": true,
...
}