Skip to content

SFC 작성 규칙

10.4.1. 블록 순서

SFC(Single File Component) 내 블록은 다음 순서를 따릅니다.

  1. <script setup lang="ts"> — 로직
  2. <template> — 마크업
  3. <style scoped> — 스타일
vue
<script setup lang="ts">
import { ref } from 'vue'

const message = ref('Hello')
</script>

<template>
  <p>{{ message }}</p>
</template>

<style scoped>
p {
  color: inherit;
}
</style>

필수

ESLint vue/block-order 규칙이 이 순서를 강제합니다. 위반 시 린트 에러가 발생합니다.


10.4.2. template 작성 규칙

  • v-html사용하지 않습니다. XSS 공격에 취약합니다. 불가피한 경우 DOMPurify로 새니타이즈한 후 사용합니다.
  • v-for에는 반드시 :key를 바인딩합니다. index를 key로 사용하지 않습니다.
  • v-ifv-for를 같은 요소에 동시에 사용하지 않습니다. <template> 태그로 분리합니다.
vue
<!-- 올바른 예 -->
<template v-for="item in items" :key="item.id">
  <div v-if="item.isActive">
    {{ item.name }}
  </div>
</template>

<!-- 잘못된 예 -->
<div v-for="item in items" v-if="item.isActive" :key="item.id">
  {{ item.name }}
</div>

10.4.3. 속성 바인딩 규칙

  • 정적 속성은 일반 HTML 속성으로, 동적 속성은 v-bind(:) 약어로 작성합니다.
  • boolean 속성은 값 없이 선언하여 true를 전달합니다.
  • 속성이 3개 이상이면 한 줄에 하나씩 배치합니다.
vue
<!-- 속성이 3개 이상 — 한 줄에 하나씩 -->
<UserCard
  :user="currentUser"
  :editable="isAdmin"
  :loading="isLoading"
  @update="handleUpdate"
/>

<!-- boolean 속성 -->
<BaseButton
  primary
  disabled
  @click="handleClick"
/>

10.4.4. 이벤트 핸들링

  • 이벤트 핸들러는 @ 약어를 사용합니다. v-on은 사용하지 않습니다.
  • 인라인 핸들러는 단순 표현식(1줄)에만 허용합니다.
  • 복잡한 로직은 별도 함수로 분리합니다.
vue
<script setup lang="ts">
function handleSubmit() {
  // 복잡한 로직
}
</script>

<template>
  <!-- 올바른 예: 단순 표현식 -->
  <button @click="count++">증가</button>

  <!-- 올바른 예: 함수 참조 -->
  <form @submit.prevent="handleSubmit">
    <!-- ... -->
  </form>
</template>

10.4.5. style 규칙

  • <style> 태그에는 반드시 scoped 를 사용합니다. 글로벌 스타일은 src/styles/ 디렉토리에서 관리합니다.
  • :deep() 선택자는 자식 컴포넌트 스타일 오버라이드 시에만 제한적으로 사용합니다.
  • Tailwind CSS 유틸리티 클래스를 우선 사용하며, 커스텀 CSS는 최소화합니다.
vue
<style scoped>
/* scoped 스타일 */
.container {
  @apply flex items-center gap-4;
}

/* 자식 컴포넌트 스타일 오버라이드 (제한적 허용) */
:deep(.child-class) {
  color: inherit;
}
</style>

TIENIPIA QUALIFIED STANDARD