임의로 작성하고 있는 것이기 때문에 자유롭게 수정해주셔도 됩니다! (창욱)
프로젝트 설정
- 코드 포맷팅 + 규칙
- import / order를 추가하자
- commitlint (https://commitlint.js.org/#/)
- 링크 타고 들어가서 Install, Configure 설정해주면 된다!
- 커밋 컨벤션을 체크해주는 기능 (ex. feat, fix, chore...)
npm install -g @commitlint/cli @commitlint/config-conventional
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlintrc.json
husky
랑commitlint
랑 연결해줘야함 (https://tech-marineplay.tistory.com/10)- husky, lint-staged
pre-commit
,pre-push
모두 설정하기.- (lint-staged 설치 전에 eslint, prettier 설정을 완료해야 한다.)
pre-commit
때는tsc
체크pre-push
때는build
체크- husky로 git hook 하자. (https://library.gabia.com/contents/8492/)
- Husky, Lint-staged를 이용한 Pre-commit Hook 구현 (https://one-armed-boy.tistory.com/entry/Husky-Lint-staged를-이용한-Pre-commit-Hook-구현)
npx husky-init -y && npm install
npx husky add .husky/pre-commit "echo 'Hello, Husky!'"
npm i -D lint-staged
"lint-staged": {"*.{cjs,js,jsx,ts,tsx}": ["eslint --fix --max-warnings=0"]}
- Issue, Pull Request 템플릿
- Github Project
- Merge할 때 빌드 테스트 기능을 추가!
(예시) eslintrc
{ "root": true, "env": { "browser": true, "es2020": true }, "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:react-hooks/recommended", "plugin:storybook/recommended", "plugin:react/recommended" ], "ignorePatterns": ["dist", "!.storybook", "!.config"], "parser": "@typescript-eslint/parser", "plugins": ["react-refresh", "import"], "settings": { "react": { "version": "detect" } }, "rules": { "no-console": "warn", "react/self-closing-comp": "warn", "react/react-in-jsx-scope": "off", "curly": ["error"], "react-refresh/only-export-components": ["warn", { "allowConstantExport": true }], "import/order": [ "error", { "groups": [ "type", "builtin", "external", "internal", "parent", "sibling", "index", "unknown" ], "pathGroups": [ { "pattern": "react*", "group": "external", "position": "before" }, { "pattern": "@/", "group": "internal" }, { "pattern": "@components/", "group": "internal" }, { "pattern": "@constants/", "group": "internal" }, { "pattern": "@api/", "group": "internal" }, { "pattern": "@context/", "group": "internal" }, { "pattern": "@hooks/", "group": "internal" }, { "pattern": "@pages/", "group": "internal" }, { "pattern": "@stories/", "group": "internal" }, { "pattern": "@types/", "group": "internal" }, { "pattern": "@utils/", "group": "internal" } ], "pathGroupsExcludedImportTypes": ["@tanstack*"], "alphabetize": { "order": "asc", "caseInsensitive": true } } ] } }
(예시) prettier
{ "semi": true, "singleQuote": false, "tabWidth": 2, "useTabs": false, "printWidth": 80, "endOfLine": "auto", "trailingComma": "none", "arrowParens": "always", "bracketSameLine": true, "plugins": ["@trivago/prettier-plugin-sort-imports"], "importOrder": [ "^react(.)", "<THIRD_PARTY_MODULES>", "^@apis/(.)$", "^@pages/(.)$", "^@components/(.)$", "^@hooks/(.)$", "^@styles/(.)$", "^@stores/(.)$", "^@contexts/(.)$", "^@type/(.)$", "^@constants/(.)$", "^@utils/(.)$", "^@assets/(.)$", "^[./]" ], "importOrderSeparation": true, "importOrderSortSpecifiers": true }
module.exports = { printWidth: 100, jsxBracketSameLine: false, semi: true, singleQuote: true, trailingComma: 'all', useTabs: false, bracketSpacing: true, arrowParens: 'always', endOfLine: 'auto', singleAttributePerLine: false, }
(예시)
{ "extends": ["@commitlint/config-conventional"], "rules": { "type-enum": [ 2, "always", [ "feat", "fix", "refactor", "design", "comment", "style", "test", "chore", "init", "rename", "remove", "docs" ] ] } }
코드 컨벤션
Common
- 한 줄 짜리 if 문도 블럭처리
- 컴포넌트 파일명
PascalCase
- 컴포넌트가 비대해지면
PascalCase
폴더명에index.tsx
- 컴포넌트는
화살표 함수
로 작성
- 상수화
- 따로 상수 폴더에 파일 작성해서 분리하기 (ex. constants/api.ts, constants/theme.ts, constants/regex.ts)
export
할 때- 컴포넌트만
default export
- 그 이외는
named export
- 주석이 필요하다면 (ex. props)
JSDoc(TSDoc)
으로 주석적기
- (복사가 필요하다면) 중첩된 객체에만
structuredClone
사용
- 변수명 길어지더라도 아예 생략없이 작성하기!(단, 자주쓰는 줄임말은 가능)
- 이벤트 핸들러명은
handle
prefix
const handleModalOpen = () => { ... }
- props로 넘길 때는
on
prefix를 사용한다.
<Modal onModalOpen={handleModalOpen} />
Typescript
- 인터페이스 or 타입
- api 응답과 관련된 것만
인터페이스
, 나머지는 다타입
으로 작성하기
- 변경되지 않는 객체는
enum
대신as const
붙이기!
- 타입스크립트
prefix
적지않기 (ex. I, T)
- Props
suffix
붙이기 (ex. ButtonProps)
- 타입스크립트 타입 선언에서 코드 반복을 줄이려고 노력하기!
Utility Type
적극 활용Union(|), Intersection(&)
적극 활용
기술 스택

- 유저 정보, 테마 등 스토리지로 관리해야할 것 같은 데이터는 zustand, jotai와 같은 상태관리 라이브러리를 사용해도 괜찮지 않을까 하는 고민이 있습니다… ⇒ jotai가 좋을 거 같습니다
스토리북을 꼭 써야할까??? 멘토님께 질문을 드려봅시다.
- ex) 스토리북을 꼭 써야할까요? 이전 2차팀 때 프로젝트를 하면서 스토리북을 운용하긴 했었습니다만 그 효용성에 대해서는 조금 의문이 듭니다. 현재의 프로젝트는 프론트, 백엔드만 있는 프로젝트이기도 하고 기획자나 디자이너들이 없기 때문에 저희들끼리는 스토리북보다는 작동하는 애플리케이션을 보면서 더 소통할 수 있지 않나 하는 생각이 듭니다... (스토리북을 잘 사용하지 못해서 이런 고민이 드는 것 같기도 합니다 ...)
- 멘토님 답변
- 스토리북을 통해 공통적으로 사용하는 컴포넌트들의 활용 방법 등에 대해 커뮤니케이션 할 수 있는 것은 좋지만... 현재 프로젝트 수준에서는 문서화로도 충분하지 않을까 싶어요! 시간이 혹시 생기면 good to have 정도로 생각하고 진행해주시면 어떨까 합니다.
폴더 구조
├── src/ │ ├── apis │ ├── assets │ ├── components │ ├── constants │ ├── hooks │ ├── pages │ ├── router (Route안에 Suspense 둬서 Skeleton처리) │ ├── stores? │ ├── stories? (스토리북이 필요할까??) │ ├── styles? (공통 스타일들은 styles 폴더에 두기) │ └── utils


프론트엔드 배포
- vercel 사용하기?
{ "rewrites": [{ "source": "/(.*)", "destination": "/" }] }
- 아니면 백엔드를 AWS EC2(또는 서버리스)로 배포할 테니 CloudFront를 사용해야 할 수도 있을 것 같다.
디자인 레퍼런스(다현)
1. 아임민






4. 현대카드 DIVE
https://wwit.design/2021/02/25/dive/

