이번 주 수정사항
- 폴더 구조 변경 완료 → 호민
- api/axios 추상화 코드 추가 + Get API 타입 선언 및 Model 타입 선언 → 호민
다음주 요구 수정사항
- Tanstack 도입
- Styled Lint 도입
- 기존 컨벤션 수정
기존 컨벤션
Code Naming
종류 | 형식 | 예시 |
상수 | UPPER, snack_case | API_KEY |
함수 | 동사, 명확한 네이밍, camelCase | fetchPostData |
파일 | .tsx, 명확한 네이밍, PascalCase | LoginPage |
컴포넌트 | PascalCase | Input |
type, interface | PascalCase | Users |
hooks | use__형식, camelCase | useAxios |
utils | camelCase | validatePassword |
API | camelCase | getPostList |
- 여기서
postPost
이렇게 진행되어야 할 것 같은데 얘네들은CreatePost
이런식으로 가면 어떨까요
Code Style
규칙 | 비고 |
약어 사용 금지 | const btn → const button |
커밋 파일 내 주석, console 금지 | console 및 //, /* */ 삭제 요망 |
함수 표현식 (화살표 함수) 우선 사용 | 함수 선언식은 this 바인딩이 필요할 경우 사용 |
배열의 이름은 반드시 ___Array 형태로 명시적 사용 | chat, chats, chatList → chatArray |
boolean값은 is___ 형태로 명시적 사용 | isCompleted |
var 사용 금지, let보다 const를 권장 | 값이 변하지 않으면 const만 사용할 것 |
const는 let보다 상단에 위치 | const constantName = 0;
let variableName = 0; |
비동기 처리는 async await 사용 | const promise = new Promise().then().then() →
const fetchData = async (url) ⇒ { … } |
문자열 조합은 템플릿 리터럴 작성 | return ` 문자열: ${stringABC} ` |
전역 상수는 src/constants/index.ts 파일에서 관리 | ㅤ |
타입스크립트는 interface를 기본으로 사용한다. | 모든 타입은 types 폴더에서 별도 관리 |
css단위는 rem단위를 기본으로 적용 | ㅤ |
src 경로는 @로 단축한다. | import Header from @/components/Header |
내부 정의 이벤트는 handle__,
props로 전달 받은 이벤트는 on___형식으로 작성한다. | handleClick과 onClick 두 가지를 구분하기 위함 |
블록 구문 내 한 줄 코드 역시 중괄호로 묶어준다. | if (true) {
return 1;
} |
객체 프로퍼티는 Destructuring로 접근한다. | const {name, age} = userData |
return문은 메인코드 한 줄 아래 작성,
또한 early return을 권장함. | 코드 길이로 인한 가독성 측면에서 if-else문 사용 예정 시 팀원 간 공유할 것 |
- 개인적으로 간단한 주석은 처리해주는게 오히려 도움될 것 같다는 의견입니다. 리팩토링 과정에서 재작업 해야될 부분들이 계속 공유되면 좋겠는데 주석이 아예 없으면 오잉.. 하는 부분들이 있을 것 같아요.
- 배열의 이름은 가능하면 모두 -s , 로 잡아보는것도 좋을 것 같아요
- CSS단위는 rem단위에 맞게 4, 8, 12, 16 이렇게 재정의해야할것같아요
- interface를 기본으로한다는 뭔가 어색한 느낌이에요 객체라면 interface, 그외라면 type으로 가는게 맞는것 같아요
- 상대경로와 절대경로를 적절하게 섞어써야 할 것 같아요. 같은 컴포넌트 내에서도 절대경로를 써버리니까 import문이 많이 더러워지네요,,
ESLint
module.exports = { root: true, env: { browser: true, es2020: true, node: true }, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react-hooks/recommended', 'plugin:prettier/recommended', ], ignorePatterns: ['dist', '.eslintrc.cjs', 'vite.config.ts'], parser: '@typescript-eslint/parser', plugins: ['react', 'prettier', '@typescript-eslint', "import", "unused-imports"], rules: { 'no-console': 'error', 'no-var': 'error', 'prefer-template': 'error', 'arrow-spacing': 'error', 'no-duplicate-imports': 'error', 'dot-notation': 'error', 'no-useless-concat': 'error', 'react/react-in-jsx-scope': 'off', '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', }, ], "import/order": [ "warn", { groups: [ "index", "sibling", "parent", "internal", "external", "builtin", "object", "type", ], }, ], "unused-imports/no-unused-imports": "error", "import/newline-after-import": ["error", { count: 1 }], "padding-line-between-statements": [ "error", { blankLine: "always", prev: "const", next: "return" }, ], }, }; // npm i -D eslint-plugin-react // npm i -D eslint-plugin-import eslint-plugin-unused-imports /* "no-unused-vars": "error", // 미사용 변수 금지 "react/jsx-key": "error", // 반복문 내 key값 강제화 */ // 호민 '@typescript-eslint/naming-convention': [ 'error', { selector: 'interface', format: ['PascalCase'], }, { selector: 'typeAlias', format: ['PascalCase'], }, { selector: 'variable', format: ['PascalCase', 'camelCase', 'UPPER_CASE'], }, { selector: 'variable', types: ['function'], format: ['PascalCase', 'camelCase'], }, { selector: 'variable', types: ['boolean'], format: ['PascalCase'], prefix: ['is', 'has'], }, ],
- import관련 ESLint는 지워도 될 것 같습니다.
- recommended로 선언해도 대부분 잡히는 것 같아서 거의 지워도 될 것 같아요
- typescript부분은 더 빡세게 정제해도 될 것 같아요 가령 boolean에는 is키워드가 포함되어야 한다던지
- 해당 내용 예시는 코드로 첨부했습니다.
Prettier
{ "singleQuote": true, "trailingComma": "all", "endOfLine": "auto", "bracketSameLine": true, "semi": true, "arrowParens": "always", "vueIndentScriptAndStyle": false, "jsxSingleQuote": true, "quoteProps": "as-needed", "embeddedLanguageFormatting" : "auto", } // 호민팀 => trivago 사용해서 import강제하고 ESLint에서 import관련내용 제거했어요 // tailwindCss는 무시해도 될 것 같아요 { "singleQuote": true, "semi": true, "useTabs": false, "tabWidth": 2, "trailingComma": "all", "printWidth": 80, "arrowParens": "avoid", "endOfLine": "auto", "jsxSingleQuote": true, "importOrderSeparation": true, "importOrderSortSpecifiers": true, "embeddedLanguageFormatting": "auto", "importOrder": [ "^(react/(.*)$)|^(react$)", "<THIRD_PARTY_MODULES>", "^(@/(.*)$)", "^[./]" ], "tailwindFunctions": ["clsx", "cn", "twmerge", "cva"], "plugins": [ "@trivago/prettier-plugin-sort-imports", "prettier-plugin-tailwindcss" ] }
4/5일까지 할일
- 일요일까지 호민님 PR 리뷰 후 Merge
- 본인이 맡은 페이지의 api 요청 Tanstack 사용하는 형태로 변경
- tantack query 사용은 석현의 컨벤션을 따름