4.0 KiB
4.0 KiB
name, description
| name | description |
|---|---|
| nuxt-component-create | 새로운 Vue 3 컴포넌트를 팀 컨벤션에 맞게 생성할 때 사용합니다. "컴포넌트 만들어줘", "새 컴포넌트", "UI 컴포넌트 추가", "버튼 만들어줘", "카드 컴포넌트" 등을 요청하면 트리거됩니다. (기존 컴포넌트 리뷰는 vue-component-review 스킬을 사용하세요.) |
Vue 컴포넌트 신규 생성
이 skill은 팀 컨벤션에 맞는 새로운 Vue 3 컴포넌트를 생성합니다.
기존 컴포넌트의 리뷰/점검은 vue-component-review skill을 사용합니다.
작업 순서
-
요구사항 확인
- 컴포넌트의 목적, 필요한 props, emits, 사용 위치를 파악
- 불명확한 부분은 사용자에게 질문
-
기존 컴포넌트 탐색
components/디렉토리에서 유사/재사용 가능한 컴포넌트 확인.claude/project/conventions.md에서 프로젝트별 컴포넌트 규칙 확인
-
파일 위치 결정
- 프로젝트의 기존 디렉토리 구조 패턴을 따름
- 일반적 구조:
components/base/(Atoms),components/common/(Molecules),components/domain/(Organisms)
-
인터페이스 우선 설계
defineProps<T>()제네릭 형태로 props 타입 정의defineEmits<{}>()제네릭 형태로 events 선언- 필요 시
defineSlots로 슬롯 타입 정의
-
구현
<script setup lang="ts">사용- 로직이 30줄을 넘으면 composable 추출 검토
- 템플릿의 가독성 유지
-
스타일링
- Tailwind 유틸리티 클래스 우선
- 조건부 클래스는
clsx또는cn유틸리티 사용 @apply는 꼭 필요한 경우에만
-
검증
- TypeScript 오류 확인
- 파일 길이 200줄 이내 확인
컴포넌트 템플릿
<script setup lang="ts">
interface Props {
/** 버튼 라벨 */
label: string;
isDisabled?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
isDisabled: false,
});
const emit = defineEmits<{
click: [event: MouseEvent];
}>();
function handleClick(event: MouseEvent) {
if (!props.isDisabled) {
emit('click', event);
}
}
</script>
<template>
<button
:disabled="isDisabled"
class="rounded-lg bg-blue-600 px-4 py-2 text-white hover:bg-blue-700 disabled:opacity-50"
@click="handleClick"
>
{{ label }}
</button>
</template>
슬롯이 있는 컴포넌트 템플릿
<script setup lang="ts">
interface Props {
title: string;
isCollapsible?: boolean;
}
withDefaults(defineProps<Props>(), {
isCollapsible: false,
});
const isOpen = ref(true);
function handleToggle() {
isOpen.value = !isOpen.value;
}
</script>
<template>
<div class="rounded-lg border border-gray-200 p-4">
<div class="flex items-center justify-between">
<h3 class="text-lg font-semibold">{{ title }}</h3>
<button v-if="isCollapsible" @click="handleToggle">
{{ isOpen ? '접기' : '펼치기' }}
</button>
</div>
<div v-show="isOpen" class="mt-4">
<slot />
</div>
</div>
</template>
분리 기준 가이드
| 상황 | 조치 |
|---|---|
| 파일 200줄 초과 | 하위 컴포넌트로 분리 |
| script 로직 30줄 초과 | composable로 추출 |
| Props 5개 초과 | 객체 prop으로 그룹핑 검토 |
| 동일 패턴 3회 이상 반복 | 공통 컴포넌트로 추출 |
네이밍 규칙
- 파일명:
PascalCase.vue(예:UserCard.vue) - 이벤트 핸들러:
handle*또는on*접두사 - 불리언 props:
is*,has*,can*,should*접두사 - 상수:
UPPER_SNAKE_CASE
주의사항
- Options API 사용 금지. 반드시
<script setup lang="ts"> any타입 사용 금지. 불가피 시 주석으로 사유 기재,unknown우선 고려- 직접
fetch/$fetch호출 금지. composable 또는 API wrapper 사용 - 새 컴포넌트 생성 전 기존 컴포넌트 재사용 가능 여부를 반드시 먼저 확인
- 사용자가 리팩토링을 요청하지 않은 경우 기존 코드를 수정하지 않음