3.7 KiB
3.7 KiB
description
| description |
|---|
| Vue 3 프론트엔드 개발 규칙 |
이 파일은
.claude/commands/vue3.md에 위치한다. 사용법:/vue3 [요청 내용]
컴포넌트 작성 원칙
필수 구조
<script setup lang="ts">
// 1. import
// 2. Props / Emits 정의
// 3. Store / Composable 호출
// 4. 반응형 상태 (ref, reactive, computed)
// 5. 함수 정의
// 6. Lifecycle Hooks
// 7. watch
</script>
<template>
<!-- 시맨틱 HTML 태그 사용 -->
</template>
<style scoped>
/* rem 단위 사용, 인라인 스타일 금지 */
</style>
Options API사용 금지 →Composition API+<script setup>필수- 인라인 스타일(
style="") 사용 금지 →<style scoped>사용 - 모든 px 값은 rem으로 변환 (기준: 16px = 1rem)
Props / Emits 타입 정의
// Props
interface Props {
title: string
count?: number
items: string[]
}
const props = withDefaults(defineProps<Props>(), {
count: 0,
})
// Emits
interface Emits {
(e: 'update', value: string): void
(e: 'close'): void
}
const emit = defineEmits<Emits>()
상태 관리 (Pinia)
// stores/user.store.ts
export const useUserStore = defineStore('user', () => {
// 상태
const user = ref<User | null>(null)
const isLoggedIn = computed(() => !!user.value)
// 액션
async function fetchUser(id: number) {
// API 호출
}
return { user, isLoggedIn, fetchUser }
})
- 도메인별 Store 파일 분리 (
user.store.ts,auth.store.ts등) - Store 내 API 호출은 허용, 단 에러 처리는 인터셉터에 위임
API 호출 (Composables + Axios)
// composables/useApi.ts — 중앙 Axios 인스턴스
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL,
withCredentials: true, // HttpOnly 쿠키 전송
})
// 응답 인터셉터 — 에러 코드 전역 처리
api.interceptors.response.use(
(response) => response.data.data, // success: true → data 언래핑
(error) => {
const code = error.response?.data?.error?.code
// 에러 코드별 Toast 알림 처리 (CLAUDE.md 에러 맵 참조)
return Promise.reject(error)
},
)
// composables/useUser.ts — 도메인별 API Composable
export function useUser() {
const loading = ref(false)
const error = ref<string | null>(null)
async function getUser(id: number) {
loading.value = true
try {
return await api.get(`/users/${id}`)
} finally {
loading.value = false
}
}
return { loading, error, getUser }
}
- API 호출 로직은 반드시
composables/폴더에 분리 - 컴포넌트 내
axios.get()직접 호출 금지
라우터 (Vue Router)
// 코드 스플리팅 — 모든 페이지 컴포넌트는 lazy import
const routes = [
{
path: '/dashboard',
component: () => import('@/pages/DashboardPage.vue'),
meta: { requiresAuth: true },
},
]
// 네비게이션 가드 — 인증 처리
router.beforeEach((to) => {
const authStore = useAuthStore()
if (to.meta.requiresAuth && !authStore.isLoggedIn) {
return '/login'
}
})
성능 & 최신 트렌드 추가 규칙
- 컴포넌트 분리: 200줄 이상 컴포넌트는 분리 고려
defineAsyncComponent: 무거운 컴포넌트는 비동기 로딩 적용v-memo: 반복 렌더링 최적화 필요 시 활용<Suspense>: 비동기 컴포넌트 로딩 상태 처리에 활용- 환경변수: 모든 설정값은
import.meta.env.VITE_*형태로 관리 - 절대경로:
@/경로 alias 사용 (상대경로../../지양) - 접근성(a11y):
aria-label,role,tabindex등 기본 접근성 속성 포함