Files
project-base/.claude/commands/vue3.md
T
ttipo f5a18a52f4 docs: 템플릿 규칙 정비 및 환경변수 예제·README 추가
- CLAUDE.md: 모노레포 개요·표준 응답 포맷·에러 코드 맵(구현 일치)·환경변수 위임 구조(SSOT) 정리
- nestjs/vue3/flutter 규칙을 실제 구현(클래스명, env키, 디렉터리)과 정합화
- 루트 .env 단일 진실 공급원 구조에 맞춰 docker-compose 변수명 정정(BACKEND_API_URL, DB/REDIS_DATA_DIR)
- backend/frontend/flutter 예제 env 추가(루트 위임 반영, 서비스 고유 값만 작성)
- README.md 신규 작성, command.md 범용화, .gitignore에 *.example 재포함 규칙 추가

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 11:14:42 +09:00

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_BASE_URL || '/api', // env.d.ts 에 타입 선언
  withCredentials: true, // HttpOnly 쿠키 전송
})

// 응답 인터셉터 — 표준 응답 언래핑 + 에러 코드 전역 처리
api.interceptors.response.use(
  (response) => response.data.data, // { success, data } → 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 등 기본 접근성 속성 포함