Vue 3 + Nuxt 3 코딩 컨벤션
Raw1. 프로젝트 디렉터리 구조
Section titled “1. 프로젝트 디렉터리 구조”Nuxt 3는 다수의 폴더를 자동 스캔하여 기능을 제공합니다. 폴더명은 kebab-case를 권장합니다.
1.1 디렉터리 트리 예시
Section titled “1.1 디렉터리 트리 예시”Directorymy-app
- app.vue # 최상위 앱 컴포넌트
- nuxt.config.ts # Nuxt 설정 파일
Directoryassets/ # 스타일·폰트·이미지 등(빌드 도구가 처리)
- …
Directorycomponents/ # 재사용 가능한 Vue 컴포넌트 (자동 임포트)
- …
Directorycomposables/ # 재사용 가능한 composition 함수 (자동 임포트)
- …
Directorylayouts/ # 페이지 레이아웃 (비동기 로드)
- …
Directorymiddleware/ # 클라이언트 라우트 미들웨어
- …
Directorypages/ # 파일 기반 라우팅 페이지 컴포넌트
- …
Directoryplugins/ # Nuxt 플러그인 (자동 등록)
- …
Directorystores/ # Pinia 상태 관리 스토어 (자동 임포트)
- …
Directoryserver/ # 서버 API / routes / middleware / plugins
- …
Directoryutils/ # 일반 유틸리티 (자동 임포트)
- …
Directorypublic/ # 빌드 미처리 정적 파일 (robots.txt 등)
- …
Directorytypes/ # TypeScript 타입 정의 (선택)
- …
1.2 폴더별 상세 가이드
Section titled “1.2 폴더별 상세 가이드”assets/
Section titled “assets/”빌드 도구가 처리하는 정적 자산을 저장합니다.
- CSS, Sass, 이미지, 폰트 등
- 코드에서 직접 임포트
- Vite/Webpack에 의해 최적화됨
components/
Section titled “components/”Vue 컴포넌트를 저장하며 자동으로 임포트됩니다.
네이밍 규칙:
- 하위 폴더 구조가 컴포넌트 이름을 결정
- 예:
components/base/foo/Button.vue→<BaseFooButton />
특수 기능:
- 전역 컴포넌트:
.global.vue접미사 (과용 금지) - 지연 로딩:
Lazy접두사 사용 →<LazyFooBar /> - 클라이언트 전용:
.client.vue접미사 - 서버 전용:
.server.vue접미사
composables/
Section titled “composables/”Composition API 기반 재사용 가능한 로직을 저장합니다.
규칙:
- 파일명:
useSomething.ts형태 권장 - 기본적으로 최상위 파일만 스캔
- 하위 폴더 사용 시
nuxt.config.ts에서 설정 필요
layouts/
Section titled “layouts/”페이지의 공통 레이아웃을 정의합니다.
중요사항:
- 비동기 로드됨
- 이름은 kebab-case로 변환
- 단일 루트 요소 필수 (루트가
<slot />이면 안 됨)
middleware/
Section titled “middleware/”라우트 네비게이션 가드를 정의합니다.
세 가지 유형:
- 익명 미들웨어: 페이지 내부에서 직접 정의
- 명명 미들웨어: 파일명으로 참조
- 전역 미들웨어:
.global.ts접미사
pages/
Section titled “pages/”파일 기반 라우팅 시스템을 사용합니다.
라우팅 패턴:
| 파일 | 라우트 |
|---|---|
pages/index.vue | / |
pages/about.vue | /about |
pages/posts/[id].vue | /posts/:id (동적) |
pages/posts/[[id]].vue | /posts/:id? (선택적) |
pages/[...slug].vue | /* (캐치올) |
pages/(marketing)/about.vue | /about (그룹화) |
단일 루트 요소 필수
stores/
Section titled “stores/”Pinia를 사용한 상태 관리 스토어입니다.
Setup 스토어 (권장)
Options 스토어
useState vs Pinia 선택 가이드
| 상황 | 권장 솔루션 |
|---|---|
| 단순 전역 상태 (테마, 로케일 등) | useState |
| 컴포넌트 간 공유되는 단일 값 | useState |
| 복잡한 상태 + 여러 액션 | Pinia |
| 상태 지속성 (localStorage 등) | Pinia |
| DevTools 디버깅 필요 | Pinia |
server/
Section titled “server/”서버 사이드 API와 로직을 정의합니다.
구조:
server/api/→/api/*엔드포인트server/routes/→/api없는 라우트server/middleware/→ 서버 미들웨어server/utils/→ 서버 유틸리티
utils/
Section titled “utils/”일반 유틸리티 함수를 저장하며 자동 임포트됩니다.
public/
Section titled “public/”빌드 처리 없이 그대로 제공되는 정적 파일입니다.
public/robots.txt→/robots.txtpublic/favicon.ico→/favicon.ico
2. 파일 및 컴포넌트 명명 규칙
Section titled “2. 파일 및 컴포넌트 명명 규칙”2.1 컴포넌트 파일 명
Section titled “2.1 컴포넌트 파일 명”- PascalCase 또는 kebab-case 중 하나를 선택해 일관성 있게.
- 베이스 컴포넌트:
Base,App,V접두사 사용(예:BaseButton.vue,BaseTable.vue).- HTML 요소/다른 베이스 컴포넌트/외부 UI만 포함, 글로벌 상태 금지.
- 접두사 정렬로 에디터 탐색 효율 ↑
- 부모-자식 관계가 강한 경우, 부모 이름을 접두사로(예:
TodoListItemButton.vue). - 일반 규칙: 상위 개념 → 하위 개념 순(예:
SearchButtonClear.vue). - HTML 요소 충돌 방지를 위해 두 단어 이상으로 명명.
2.2 페이지 파일 명
Section titled “2.2 페이지 파일 명”pages/index.vue→/루트. 하위 폴더의index.vue는 해당 디렉터리의 기본 경로.- 동적 라우트:
[id].vue/ 선택적 파라미터:[[param]].vue - 혼합 세그먼트:
users-[group]/[id].vue - 캐치올:
[...slug].vue - 라우트 그룹:
pages/(group)/...(URL 영향 없음) - 페이지는 단일 루트 요소 필수.
2.3 레이아웃 파일 명
Section titled “2.3 레이아웃 파일 명”- 레이아웃 이름은 kebab-case로 변환. 파일명과 일치.
- 예:
layouts/custom.vue→custom레이아웃
- 예:
- 중첩 폴더는 경로 기반 이름 부여
- 예:
~/layouts/desktop/default.vue→desktop-default
- 예:
- 단일 루트 요소 필요(루트
<slot />금지).
2.4 컴포저블·유틸리티·스토어 파일 명
Section titled “2.4 컴포저블·유틸리티·스토어 파일 명”- 컴포저블:
composables/useSomething.ts(함수명useSomething). camelCase/kebab-case 파일명 허용하나 노출 함수는 camelCase. - 유틸리티:
utils/random-entry.ts→randomEntry(). - Pinia 스토어:
stores/user.ts+defineStore('user', ...)→ 내보내기 함수useUserStore.- 각 파일 1 스토어 권장. 여러 스토어 사용 가능.
2.5 서버 API·미들웨어·플러그인 파일 명
Section titled “2.5 서버 API·미들웨어·플러그인 파일 명”- API:
server/api/hello.ts→/api/hello- 동적:
[name].ts, 메서드별:.get.ts,.post.ts, …
- 동적:
- server routes:
/api접두사 제거 필요 시server/routes/* - server middleware:
server/middleware/log.ts(모든 요청 전 실행) - server plugins:
server/plugins/myPlugin.ts(Nitro 플러그인) - 클라이언트 미들웨어:
app/middleware/*.ts(kebab-case, 전역은.global)
3. 함수·변수·컴포저블 네이밍 규칙
Section titled “3. 함수·변수·컴포저블 네이밍 규칙”3.1 일반 규칙
Section titled “3.1 일반 규칙”- camelCase 사용(JS/TS 함수·변수·반응형 상태 포함).
- 불린 변수:
is*,has*,should*접두사(예:isAuthenticated,hasPermission). - 이벤트 핸들러:
handle*,on*(예:handleSubmit,onClick). - 비동기/데이터 패칭:
fetch*,load*,get*(예:fetchUserProfile,loadPosts). - 컴포저블:
use*(예:useAuth,useFetchData). - Pinia 스토어:
use*Store(예:useUserStore).
3.2 Vue 컴포넌트 스크립트 작성
Section titled “3.2 Vue 컴포넌트 스크립트 작성”- 기본적으로
<script setup>사용(간결/타입 추론 우수). - 각 파일 하나의 컴포넌트,
export default사용. - 화살표 함수 선호, 불필요한 중괄호·세미콜론 지양.
예제: 기본 컴포넌트 구조
defineModel을 활용한 양방향 바인딩 (Vue 3.4+)
Section titled “defineModel을 활용한 양방향 바인딩 (Vue 3.4+)”Vue 3.4부터 도입된 defineModel() 매크로는 v-model 양방향 바인딩을 간편하게 구현합니다.
기본 사용법
Named Model (v-model:name)
부모 컴포넌트에서 사용
Modifiers 접근
참고:
defineModel()은 이전의defineProps+defineEmits조합을 대체하여 더 간결한 양방향 바인딩을 제공합니다.
3.3 컴포저블 및 유틸리티 작성
Section titled “3.3 컴포저블 및 유틸리티 작성”컴포저블 작성 가이드
Section titled “컴포저블 작성 가이드”컴포저블은 Vue의 Composition API를 활용하여 재사용 가능한 상태 로직을 캡슐화합니다.
예제: 기본 컴포저블
예제: 비동기 데이터 페칭 컴포저블
유틸리티 작성 가이드
Section titled “유틸리티 작성 가이드”유틸리티는 순수 함수로 작성하며, Vue의 반응성 시스템과 독립적입니다.
예제: 유틸리티 함수
- 컴포저블:
ref,reactive,computed등으로 상태 구성 후 필요한 값 반환 - 파일명 = 함수명 일치 권장 (예:
useAuth.ts→useAuth()) - 유틸리티: 순수 함수 지향, 부수 효과 회피
- 스토어와 컴포저블 역할 분리: 컴포저블 내부에서 스토어를 직접 생성/의존하지 않도록 설계
- Nuxt auto-import 적극 활용
3.4 기타 네이밍 컨벤션
Section titled “3.4 기타 네이밍 컨벤션”타입 및 인터페이스
Section titled “타입 및 인터페이스”PascalCase를 사용하며, I 접두사는 지양합니다.
enum 대신 상수 객체를 사용하여 타입 안전성과 유연성을 확보합니다.
4. 코드 스타일 및 모범 사례
Section titled “4. 코드 스타일 및 모범 사례”4.1 포매팅 및 린팅
Section titled “4.1 포매팅 및 린팅”ESLint + Prettier를 사용하여 일관된 코드 스타일을 유지합니다.
4.2 반응성 관리
Section titled “4.2 반응성 관리”Pinia 스토어 사용 시 주의사항
Section titled “Pinia 스토어 사용 시 주의사항”구조 분해 시 반응성을 잃지 않도록 storeToRefs()를 사용합니다.
Reactive 객체 구조 분해
Section titled “Reactive 객체 구조 분해”4.3 데이터 패칭
Section titled “4.3 데이터 패칭”서버 사이드 렌더링과 통합
Section titled “서버 사이드 렌더링과 통합”참고:
signal옵션은 요청 취소(abort)를 지원하며, 컴포넌트 언마운트 시 자동으로 요청을 취소합니다.
데이터 패칭 모범 사례
Section titled “데이터 패칭 모범 사례”병렬 데이터 페칭
Section titled “병렬 데이터 페칭”여러 API를 동시에 호출할 때는 Promise.all과 signal을 활용합니다.
4.4 컴포넌트 설계 원칙
Section titled “4.4 컴포넌트 설계 원칙”단일 책임 원칙
Section titled “단일 책임 원칙”각 컴포넌트는 하나의 명확한 책임만 가져야 합니다.
Props 전달 규칙
Section titled “Props 전달 규칙”Vue 공식 스타일 가이드에 따라 Props 케이싱을 일관되게 사용합니다.
- Props 선언: camelCase 사용
- 템플릿에서 전달: kebab-case 사용
Scoped 스타일 사용
Section titled “Scoped 스타일 사용”모든 컴포넌트는 scoped 스타일 또는 CSS Modules를 사용해야 합니다. 전역 스타일은 App.vue와 레이아웃 컴포넌트에서만 허용합니다.
4.5 접근성 및 국제화
Section titled “4.5 접근성 및 국제화”ARIA 속성 사용
Section titled “ARIA 속성 사용”국제화 (i18n)
Section titled “국제화 (i18n)”요약 체크리스트
- 폴더/파일명 규칙(PascalCase vs kebab-case) 팀 합의
- 베이스 컴포넌트 접두사(
Base|App|V) 사용- 페이지/레이아웃 단일 루트 요소 보장
- 동적 라우트/캐치올/그룹 구조 명확화
- 컴포저블
use*/스토어use*Store일관성- ESLint/Prettier 설정 및 CI 체크
- Pinia 반응성(
storeToRefs) 준수
5. 마무리
Section titled “5. 마무리”본 가이드는 Vue 3 + Nuxt 3 프로젝트의 구조, 명명, 코드 스타일을 정리한 실무 템플릿입니다. 팀 합의와 리뷰 문화를 통해 지속적으로 개선하고, 공식 문서/스타일 가이드 업데이트를 주기적으로 반영하세요.