eslint 설정
개인 취향을 적어보자.
- 지성
- import/order : import 순서 조정 (자동으로 줄바꿈 진행)
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', 'import'], settings: { 'import/parsers': { '@typescript-eslint/parser': ['.ts', '.tsx'], }, 'import/resolver': { typescript: true, }, }, rules: { 'react-refresh/only-export-components': [ 'warn', { allowConstantExport: true }, ], 'import/order': [ 'error', { 'newlines-between': 'always', groups: [ 'builtin', 'external', 'internal', ['parent', 'sibling'], 'index', ], pathGroups: [ { pattern: 'react*', group: 'builtin', position: 'before', }, { pattern: '@/stores/*', group: 'internal', position: 'after', }, { pattern: '@/contexts/*', group: 'internal', position: 'after', }, { pattern: '@/hooks/*', group: 'internal', position: 'after', }, { pattern: '@/components/*', group: 'internal', position: 'after', }, { pattern: '@/assets/*', group: 'internal', position: 'after', }, { pattern: '@/public/*', group: 'internal', position: 'after', }, ], pathGroupsExcludedImportTypes: [], alphabetize: { order: 'asc', }, }, ], 'import/no-unresolved': ['error', { ignore: ['.svg'] }], }, };
- 희석
module.exports = { root: true, env: { browser: true, es2020: true }, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react-hooks/recommended', 'plugin:prettier/recommended', 'plugin:storybook/recommended', ], ignorePatterns: ['dist', '.eslintrc.cjs'], parser: '@typescript-eslint/parser', plugins: ['react-refresh'], rules: { 'react-refresh/only-export-components': [ 'warn', { allowConstantExport: true }, ], }, };
@typescript-eslint/naming-convention
: 변수, 함수, 클래스 등의 명명 규칙을 정의합니다.
@typescript-eslint/naming-convention
: ["error", { "format": ["camelCase"] }],@typescript-eslint/no-unnecessary-type-assertion
: 불필요한 타입 단언을 금지합니다.
- 유진
- 기본적인 것 말고도 참고하면 좋은 라이브러리들 목록
Simple-import-sort
:이 라이브러리는 자동으로 임포트 순서를 정렬해줍니다function-component-definition
: 함수 형식을 강제로 고정할 때 사용(화살표 함수 등)typescript-eslint/naming-convention
: 변수 함수 인터페이스 작성 등 네이밍 컨벤션 강제화react/jsx-curly-brace-presence
: props로 넘겨줄때 중괄호로 넘길건지 문자열로 넘길건지 결정react/no-unknown-property
: 올바르지 않은 프로퍼티가 넘어왔을 때 에러처리를 해줄 수 있습니다.import/newline-after-import
: import 아래에 엔터칠건지 안칠건지..unicorn/filename-case
: 파일명을 통일시켜줍니다. (대문자로 할건지 아닌지 등)
module.exports = { env: { browser: true, es2021: true, }, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended', 'plugin:react/recommended', 'prettier', ], plugins: ['react', 'prettier', '@typescript-eslint', 'simple-import-sort'], overrides: [ { env: { node: true, }, files: ['.eslintrc.{js,cjs}'], parserOptions: { sourceType: 'script', }, }, ], parserOptions: { ecmaVersion: 'latest', sourceType: 'module', }, rules: { 'linebreak-style': ['error', require('os').EOL === '\r\n' ? 'windows' : 'unix'], 'prettier/prettier': ['error', { endOfLine: 'auto' }], 'react/no-unknown-property': ['error', { ignore: ['css'] }], 'react/prop-types': 'off', 'no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': 'off', '@typescript-eslint/no-use-before-define': 'off', '@typescript-eslint/strict-boolean-expressions': 'off', '@typescript-eslint/explicit-function-return-type': 'off', 'simple-import-sort/imports': 'error', 'simple-import-sort/exports': 'error', 'react/react-in-jsx-scope': 'off', 'react/jsx-curly-brace-presence': ['error', { props: 'always', children: 'always' }], 'react/function-component-definition': [ 'error', { namedComponents: 'arrow-function', unnamedComponents: 'arrow-function', }, ], '@typescript-eslint/naming-convention': [ 'error', { format: ['camelCase', 'UPPER_CASE', 'PascalCase'], selector: 'variable', leadingUnderscore: 'allow', }, { format: ['camelCase', 'PascalCase'], selector: 'function', }, { format: ['PascalCase'], selector: 'interface', }, { format: ['PascalCase'], selector: 'typeAlias', }, ], }, parser: '@typescript-eslint/parser', }
- `function-component-definition` : 화살표 함수 - `typescript-eslint/naming-convention` : 변수 함수 인터페이스 작성 등 네이밍 컨벤션 강제화 - `react/jsx-curly-brace-presence` : props로 넘겨줄때 중괄호(확정❗️) - `react/no-unknown-property`: 올바르지 않은 프로퍼티가 넘어왔을 때 에러처리를 해줄 수 있습니다. - `import/newline-after-import`: import 아래에 엔터칠건지 안칠건지.. - `import/order` : import 순서 조정 (자동으로 줄바꿈 진행) - `unicorn/filename-case` : 파일명을 통일시켜줍니다. (대문자로 할건지 아닌지 등) - `@typescript-eslint/no-unnecessary-type-assertion`**: 불필요한 타입 단언을 경고❗️합니다
지성팀 eslint~ ^^ (최종본)
//기본적인 세팅 'prettier/prettier': ['error', { endOfLine: 'auto' }], 'react/no-unknown-property': ['error', { ignore: ['css'] }], 'react/prop-types': 'off', 'no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': 'warn', '@typescript-eslint/no-use-before-define': 'off', '@typescript-eslint/strict-boolean-expressions': 'off', '@typescript-eslint/explicit-function-return-type': 'off', ---- '@typescript-eslint/naming-convention': [ 'error', { format: ['camelCase', 'UPPER_CASE', 'PascalCase'], selector: 'variable', leadingUnderscore: 'allow', }, { format: ['camelCase', 'PascalCase'], selector: 'function', }, { format: ['PascalCase'], selector: 'interface', }, { format: ['PascalCase'], selector: 'typeAlias', }, 'react/jsx-curly-brace-presence': ['error', { props: 'always', children: 'always' }], { "import/order": [ "error", { "groups": [ "type", "builtin", "external", "internal", "parent", "sibling", "index", "unknown" ], "pathGroups": [ { "pattern": "react*", "group": "external", "position": "before" }, { "pattern": "@hooks/*", "group": "internal", "position": "after" }, { "pattern": "@pages/*", "group": "internal", "position": "after" }, { "pattern": "@components/*", "group": "internal", "position": "after" } ], "pathGroupsExcludedImportTypes": ["@tanstack*"], "alphabetize": { "order": "asc" } } ] }, "unicorn/filename-case": [ "error", { "cases": { "camelCase": true, "pascalCase": true } } ], - `@typescript-eslint/no-unnecessary-type-assertion`**: 불필요한 타입 단언을 금지합니다.
prettier 설정
- 지성
- “semi” : 무조건false….
- “Single Quote” : true, (’)
- Tab width : 2 or 4 아무거나 상관없습니다!
- Trailling Comma : none(에러가 자주 나더라구요…)
- printWidth : 80
- 희석
- "semi": true,
- "tabWidth": 4,
- "arrowParens": "always",
- "singleQuote": true,
- 유진
- Semi : false
- Tab width 2
- Single quote true
- Pritnwidth 80
semi : false "trailling Comma" : none(에러가 자주 나더라구요…) "arrowParens": "always", "singleQuote": true, "tab width" : 2, "printwidth" : 80
{ // prettier전체 옵션이라고하는데 혹시 빼먹은거 있으면 말씀해주세요! "arrowParens": "avoid", // 화살표 함수 괄호 사용 방식 "bracketSpacing": false, // 객체 리터럴에서 괄호에 공백 삽입 여부 "endOfLine": "auto", // EoF 방식, OS별로 처리 방식이 다름 "htmlWhitespaceSensitivity": "css", // HTML 공백 감도 설정 "jsxBracketSameLine": false, // JSX의 마지막 `>`를 다음 줄로 내릴지 여부 "jsxSingleQuote": false, // JSX에 singe 쿼테이션 사용 여부 "printWidth": 80, // 줄 바꿈 할 폭 길이 "proseWrap": "preserve", // markdown 텍스트의 줄바꿈 방식 (v1.8.2) "quoteProps": "as-needed" // 객체 속성에 쿼테이션 적용 방식 "semi": true, // 세미콜론 사용 여부 "singleQuote": true, // single 쿼테이션 사용 여부 "tabWidth": 2, // 탭 너비 "trailingComma": "all", // 여러 줄을 사용할 때, 후행 콤마 사용 방식 "useTabs": false, // 탭 사용 여부 "vueIndentScriptAndStyle": true, // Vue 파일의 script와 style 태그의 들여쓰기 여부 (v1.19.0) "parser": '', // 사용할 parser를 지정, 자동으로 지정됨 "filepath": '', // parser를 유추할 수 있는 파일을 지정 "rangeStart": 0, // 포맷팅을 부분 적용할 파일의 시작 라인 지정 "rangeEnd": Infinity, // 포맷팅 부분 적용할 파일의 끝 라인 지정, "requirePragma": false, // 파일 상단에 미리 정의된 주석을 작성하고 Pragma로 포맷팅 사용 여부 지정 (v1.8.0) "insertPragma": false, // 미리 정의된 @format marker의 사용 여부 (v1.8.0) "overrides": [ { "files": "*.json", "options": { "printWidth": 200 } } ], // 특정 파일별로 옵션을 다르게 지정함, ESLint 방식 사용 }
클린 코드를 위한 래퍼런스
변수명, 함수명, 일관적인 코드 작성을 위해 서로 고려했으면 하는 점
- 지성
- 저도 희석님과 같은 레퍼런스를 참고 했습니다
- 컴포넌트 이름 : 대문자 + 파일과 컴포넌트 이름 겹쳤으면 좋겠습니다
- ex) Header > Header.tsx( index.tsx ❌)
- 자주 쓰이는 접두사
- 함수
- 되도록이면 순수함수로… (사이드 이펙트는 최대한 없었으면 좋겠습니다)
- 저도 arrow function이었으면 좋겠습니다!
- 클린코드 문서를 좀 보다가.. 함수 파라미터로 boolean type은 지양해야한다는데 조금 더 실펴보겠습니다
- 희석
- 파일명 : camelCase
- 컴포넌트 파일명 : PascalCase
- 변수명 : 카멜 케이스
ex) getUser
- 상수명 : 대문자 + 스네이크 케이스
ex) SNAKE_CASE
- 함수
- 화살표 함수 사용
- 함수는 한 가지의 일만 수행하기
- 될 수 있으면 부정 조건문 사용하지 않기
ex) if(!data)
- 유진
- 함수
- 화살표 함수가 좋아요~~
- 함수는 되도록 리턴값이 존재하는 형식으로 작성하기!! (리턴값이 없으면 state 느낌으로 관리하도록 노력해주기)
- api작성
- 객체로 정리하여 api들이 한 곳에 모여 있을수 있도록 하기 (빨리 찾을 수 있음)
- Mutation 중복되는거는 커스텀 훅으로 만들수있으면 빼기 ⇒ ‘authmutation’
- 컴포넌트 분리
page.tsx
- 포스트 제목
- 포스트 사진
- 포스트 글
- 포스트 정보
- 포스트 댓글
- 댓글 작성하기
- 변수명 관련
- 희석님께서 너무 좋은 예시를 가져와주셔서
PostList.page ⇒ 300줄 넘어가는 경우가 ..
todo
husky 설치
기동팀 클린 코드 문서 작성
변수명
동일한 유형의 변수는 동일한 단어로 사용하기
//bad function getUserInfo(): User; function getUserDetails(): User; function getUserData(): User;
//good function getUser(): User; // 여러 개 가져올 때 vs 다 가져올 때 const = getusers() vs const getAllUsers() => {...}
배열 이름은 되도록 복수로 설정하기
// bad const fruit = ['apple', 'banana', 'cucumber']; // okay const fruitArr = ['apple', 'banana', 'cucumber']; // good const fruits = ['apple', 'banana', 'cucumber']; // great const fruitNames = ['apple', 'banana', 'cucumber']; const fruits = [ { name: 'apple', genus: 'malus' }, { name: 'banana', genus: 'musa' }, { name: 'cucumber', genus: 'cucumis' }, ];
Booleans
// bad const open = true; const write = true; const fruit = true; const equal = true; const visible = true; // good const isOpen = true; const canWrite = true; const hasFruit = true; const areEqual = true; const isVisible = trueBODY: $PR_BODY" ISSUE_NUMBER=$(echo $PR_BODY | grep -oE "close #[0-9]+" | tr -d 'close #') echo "ISSUE_NUMBER: $ISSUE_NUMBER" if [[ ! -z "$ISSUE_NUMBER" ]]; then curl -s -H "Authorization: token ${{ secrets.ACTION_TOKEN }}" -X PATCH "https://api.github.com/repos/${{ github.repository }}/issues/$ISSUE_NUMBER" -d '{"state": "closed"}' fi shell: bash
name: Close associated issue on: pull_request: branches: - dev types: - closed jobs: close-issue: runs-on: ubuntu-latest steps: - name: Close associated issue run: | PR_NUMBER=${{ github.event.pull_request.number }} PR_URL="https://api.github.com/repos/${{ github.repository }}/pulls/$PR_NUMBER" echo "PR_URL: $PR_URL" PR_BODY=$(curl -s -H "Authorization: token ${{ secrets.ACTION_TOKEN }}" $PR_URL | jq -r '.body') echo "PR_BODY: $PR_BODY" ISSUE_NUMBER=$(echo $PR_BODY | grep -oE "close #[0-9]+" | tr -d 'close #') echo "ISSUE_NUMBER: $ISSUE_NUMBER" if [[ ! -z "$ISSUE_NUMBER" ]]; then curl -s -H "Authorization: token ${{ secrets.ACTION_TOKEN }}" -X PATCH "https://api.github.com/repos/${{ github.repository }}/issues/$ISSUE_NUMBER" -d '{"state": "closed"}' fi shell: bash
접두사(최대한 여기 있는거 참고하기)
코드 스타일
etc
- 될 수 있으면 부정 조건문 사용하지 않기
ex) if(!data)
함수 작성방법
- 클린코드 문서를 좀 보다가.. 함수 파라미터로 boolean type은 지양해야한다는데 조금 더 실펴보겠습니다
- 화살표 함수 사용하기
- 함수의 매개변수는 2개 이하로 작성하기
- 하나의 함수는 한가지만 동작만 수행하기
변수 작성방
- 파일명 : camelCase
- 컴포넌트 파일명 : PascalCase
- 변수명 : 카멜 케이스
ex) getUser
- 상수명 : 대문자 + 스네이크 케이스
ex) SNAKE_CASE