HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🤎
프론트엔드 데브코스 5기 교육생
/
🦁
이희진팀
/
🤝
컨벤션
/
개발 컨벤션
개발 컨벤션
/
사프 컨벤션

사프 컨벤션

  • 디렉토리 네이밍: 복수형
  • 파일 네이밍: 단수형
  • component 파일을 제외한 다른 파일 및 폴더들: kebab-case
 
  • (auth)
    • todo (투두 페이지)
      • page.tsx
    • article (아티클 페이지)
      • page.tsx
    • layout.tsx
  • page.tsx (랜딩 페이지)
  • layout.tsx

2. 개발 컨벤션

  1. 줄임말은 쓰지않는다. (ex. event => e)
  1. 함수 export 방식 선언과 동시에 export (e.g. export const useTimeout = () ⇒ { … })
  1. 페이지와 컴포넌트는 function 키워드를 사용해서 선언한다.
  1. 핸들러 함수는 컴포넌트 내부에서 선언을 하고 const 키워드를 사용한다.
  1. 🐞  핸들러를 제외한 계산식이 들어가는 함수 같은 경우는 컴포넌트 바깥에서 function 키워드를 사용하여 선언(코드리뷰를 통해 다시 컨벤션 확립하기)
컴포넌트를 제외한 함수 선언 방식은 const 를 사용합니다.
  1. 세미콜론을 필수적으로 작성 (prettier로 관리)
  1. 리터럴 값은 상수로 만들어서 사용합니다. 상수는 Snake_Case를 사용합니다. ex) BASE_URL
  1. 변수명은 camelCase로 작성합니다.
  1. 라우트(폴더)명은 kebab-case를 사용합니다. ex) todo, user-info
  1. 컴포넌트명은 PascalCase를 사용합니다. ex) TodoList.tsx
  1. alias를 이용해서 파일 절대 경로로 import, export 사용합니다
  1. export 할때 barrel export 방식을 사용하지 않습니다.
  1. 타입을 분리할 경우(여러 곳에서 타입이 생성될 경우(2군데 이상)) types 디렉토리에 관리한다.
      • 컴포넌트 Props → 컴포넌트에서
      • Request / Response type → route handler에 추가해서 사용
        • 그래서 api랑 가까웠음 좋겠다
        • api/schema → response / request type
        • api handler → response / request type
  1. 최대한 코드에 대한 설명 주석은 적지 않습니다. 이름만 읽어도 무슨 일을 하는 함수인지 알 수 있어야합니다.
  1. 이벤트 핸들러를 정의할때 handle + 이벤트명 + 대상로 정의합니다. ex. handleCopyLink
  1. on 접두사가 붙은 경우, 이 Prop에 실제 이벤트가 연결되어 있다는 걸 뜻하고, handle 접두사가 붙은 경우, 이벤트가 발생했을 때 호출되는 실제 Function을 의미합니다.
  1. 컴포넌트 props 지정 방식
  1. 컴포넌트 props 네이밍
  1. asset 파일(image, svg)은 케밥 케이스를 사용하여 네이밍합니다.(ex. erase-check.svg)
      • kebab-case
 
├─ app │  ├─ api │  ├─ main │  │ ├─ page.tsx │  │ └─ _components # 메인 페이지에서만 사용되는 컴포넌트 │  └─ mypage │   ├─ page.tsx │   └─ _components ├— page.tsx ├— layout.tsx ├— providers.tsx ├— globals.css ├— components # 여기는 공통 컴포넌트 ├─ hooks │ ├─ queries │ ├─ mutations │ └─ useTimeout.ts ├─ constants ├─ types ├─ utils / libs └─ public
export default function ListItem() { const [age, setAge] = useState(100); const handleClick = () => { ... } return <div>asdf</div> } // 화살표 함수를 쓰지 않은 이유는 컨벤션 통일 function a() { ... }
import a from './a'; ✅ 단일 레벨(뎁스)까지만 상대경로 가능 & 모두 동의 ✅
~/api/todo.ts fetch(https://baseurl/todo).then(res=>) ~/api/todo/route.ts ~~~ componets fetch(api/todo)
handle + 이벤트명 + 대상 - Button - handler -> handleClickButton - Link - handler -> handleClickLink
function DateTypeToggleButton ({ onClick }) { return <button onClick={onClick} /> } function ModalButton ({ onClick }) { return <button onClick={onClick} /> } function Calendar () { const handleClickDateType = () => {} const handleModalOpen = () => {} /* 주의!! 컴포넌트의 props로 핸들러를 넘길때도 handle 접두사를 사용해야 합니다. */ return ( <> <DateTypeToggleButton onClick={handleClickDateType} /> <ModalButton onClick={handleModalOpen} /> </> ) }
interface CommentListItemProps {...} const CommentListItem = ({ id, author, loginId, createdAt, comment, isMyComment }: CommentListItemProps) => { ... }
interface Props { ... } const ListItem = () => {} const CommentListItem = ({ id, author, loginId, createdAt, comment, isMyComment }: CommentListItemProps) => { ... } interface CommentProps extends ComponentProps<typeof ListItem> { comment: string; } 다른 컴포넌트에서 Props를 전달받고 이걸 감싼 컴포넌트 - ComponentProps<typeof CommentListItem> - HTMLAttributes<HTMLInputElement>