Frontend/Vue

Make Your Components Easier to Think About (μ»΄ν¬λ„ŒνŠΈμ— λŒ€ν•΄ 더 μ‰½κ²Œ μƒκ°ν•˜κΈ°)

Seyun(Marco) 2024. 9. 15. 21:20
728x90

πŸ’‘μ›λ³ΈκΈ€ : https://michaelnthiessen.com/make-your-components-easier-to-think-about

 

Make Your Components Easier to Think About

I hate thinking. Well, actually, I *love* thinking, but only when I’m able to solve problems or make progress with it. But often our code gets in the way of this.

michaelnthiessen.com

 

λ‚˜λŠ” μƒκ°ν•˜λŠ”κ±Έ μ‹«μ–΄ν•œλ‹€.

사싀 μ €λŠ” μƒκ°ν•˜λŠ” 것을 μ’‹μ•„ν•˜μ§€λ§Œ, 문제λ₯Ό ν•΄κ²°ν•˜κ±°λ‚˜ 진전을 이룰수 μžˆμ„λ•Œλ§Œ 생각을 ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ’…μ’… μ½”λ“œκ°€ 이λ₯Ό λ°©ν•΄ν•  λ•Œκ°€ μžˆμŠ΅λ‹ˆλ‹€. ν•œ μ›Œν¬μˆ μ°Έμ„μžκ°€ μ½”λ“œ 읽기에 λŒ€ν•΄ λ§ν–ˆλ“―μ΄ “λ§Œμ•½ ν˜Όλž€μŠ€λŸ½λ‹€λ©΄ λ„ˆμ˜ 잘λͺ»μ΄ μ•„λ‹™λ‹ˆλ‹€.” λ‹€μŒμ˜ μ½”λ“œλ₯Ό 더 μ‰½κ²Œ μƒκ°ν•˜μ—¬ ν˜Όλž€μ„ 쀄이고 μ‹€μ œ μž‘μ—…μ„ μ™„λ£Œν•  수 μžˆλŠ” λͺ‡ 가지 λ°©λ²•μž…λ‹ˆλ‹€.

가독성을 μœ„ν•œ μ»΄ν¬λ„ŒνŠΈλ₯Ό μΆ”μΆœν•˜κΈ°

μ‚¬λžŒμ΄ μ΄ν•΄ν•˜κΈ° 쉽도둝 μ»΄ν¬λ„ŒνŠΈλ₯Ό μ΅œμ ν™”ν•˜λŠ” ν•œ 가지 방법은 μ˜λ„(intention)와 κ΅¬ν˜„(implementation)을 λΆ„λ¦¬ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. μ΄λŠ” μƒˆλ‘œμš΄ μ»΄ν¬λ„ŒνŠΈλ₯Ό λ§Œλ“€μ–΄μ•Ό ν•˜λŠ” κ°€μž₯ μ€‘μš”ν•œ 이유 쀑 ν•˜λ‚˜μ΄λ©°, μ½”λ“œμ˜ 일뢀뢄을 ν•΄λ‹Ή μ½”λ“œμ˜ κΈ°λŠ₯을 μ„€λͺ…ν•˜λŠ” μ½”λ“œλ‘œ λŒ€μ²΄ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ‹€μŒμ€ μ‹€μ œ 기본적인 μ»΄ν¬λ„ŒνŠΈμž…λ‹ˆλ‹€.

<template>
  <div>
    <p>{{ user.name }} ({{ user.age }})</p>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const user = ref({
  name: 'John Doe',
  age: 28,
});
</script>

UserInfo μ»΄ν¬λ„ŒνŠΈλ₯Ό μΆ”μΆœν•˜λ©΄ 이 ν•œ 쀄이 ν•˜λŠ” 일인 μ‚¬μš©μž 정보λ₯Ό ν‘œμ‹œν•˜λŠ” 것이 맀우 λͺ…ν™•ν•΄μ§‘λ‹ˆλ‹€.

<template>
  <div>
    <UserInfo :user="user" />
  </div>
</template>

<script setup>
import { ref } from 'vue';
import UserInfo from './UserInfo.vue';

const user = ref({
  name: 'John Doe',
  age: 28,
});
</script>

이 μ»΄ν¬λ„ŒνŠΈλ₯Ό λ§Œλ“€κΈ° μœ„ν•΄μ„œλŠ” λͺ‡ 가지 보일러 ν”Œλ ˆμ΄νŠΈλ₯Ό ꡬ성해야 ν•©λ‹ˆλ‹€.

<template>
  <p>{{ user.name }} ({{ user.age }})</p>
</template>

<script setup>
import { defineProps } from 'vue';

const props = defineProps({
  user: Object,
});
</script>

λ¦¬νŒ©ν† λ§ν•œ μ½”λ“œμ—μ„œλŠ” μ‚¬μš©μž 정보λ₯Ό UserInfo μ»΄ν¬λ„ŒνŠΈλ‘œ μΆ”μΆœν–ˆμŠ΅λ‹ˆλ‹€. μ΄λ ‡κ²Œ λΆ„λ¦¬ν•˜λ©΄ μ½”λ“œκ°€ λͺ¨λ“ˆν™”κ°€ λ©λ‹ˆλ‹€. 이제 우리 μ½”λ“œλŠ” 쒀더 읽기 μ‰¬μ›Œμ§‘λ‹ˆλ‹€. 이것은 κ°„λ‹¨ν•œ μ˜ˆμ‹œμ΄λ©°, 이점은 μ μŠ΅λ‹ˆλ‹€. 더 κΈΈκ³  λ³΅μž‘ν•œ μ»΄ν¬λ„ŒνŠΈμ—μ„œλŠ” μ΄λŸ¬ν•œ λ°©μ‹μœΌλ‘œ μ»΄ν¬λ„ŒνŠΈλ₯Ό μΆ”μΆœν•˜λ©΄ 훨씬 더 λ§Žμ€ 이점을 얻을 수 μžˆμŠ΅λ‹ˆλ‹€. 이것은 λ˜ν•œ self-documenting code(슀슀둜 λ¬Έμ„œν™”λœ μ½”λ“œ)λ₯Ό μž‘μ„±ν•˜λŠ” λ°©λ²•μ˜ ν•œ μ˜ˆμ‹œμ΄κΈ°λ„ ν•©λ‹ˆλ‹€. 이것이 λ°”λ‘œ Clean Components Toolkit의 핡심 λΆ€λΆ„μž…λ‹ˆλ‹€. λͺ¨λ“  νŒ¨ν„΄, 기술 및 원칙은 “μ–΄λ–»κ²Œ ν•˜λ©΄ μ½”λ“œλ₯Ό 더 μ„€λͺ…μ μœΌλ‘œ λ§Œλ“€μˆ˜ μžˆμ„κΉŒ?”λΌλŠ” μ§ˆλ¬Έμ„ λ˜μ§‘λ‹ˆλ‹€. λ§Œμ•½ μ½”λ“œλ₯Ό 덜 μ„€λͺ…μ μœΌλ‘œ λ§Œλ“œλŠ” νŒ¨ν„΄μ„ λ”°λ₯΄κ³  μžˆλ‹€λ©΄ 쒋은 νŒ¨ν„΄μ΄ 아닐 κ°€λŠ₯성이 λ†’μŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ self-documenting code(슀슀둜 λ¬Έμ„œν™”λœ μ½”λ“œ)λŠ” μ»΄ν¬λ„ŒνŠΈ μ΄λ¦„λΏλ§Œ μ•„λ‹ˆλΌ 더 μ„ΈλΆ„ν™”ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ’€ 더 self-documenting code(슀슀둜 λ¬Έμ„œν™”λœ μ½”λ“œ)λ₯Ό μž‘μ„±ν•˜κΈ°

Vue μ»΄ν¬λ„ŒνŠΈμ—λŠ” props, data, computed 속성, methods, λΌμ΄λΈŒμ‚¬μ΄ν΄ hooks 등등에 λŒ€ν•΄ λͺ…ν™•ν•˜κ³  μ˜λ―ΈμžˆλŠ” 이름이 μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€. λ˜ν•œ ν…œν”Œλ¦Ώ μ½”λ“œκ°€ μ μ ˆν•œ λ“€μ—¬μ“°κΈ°, μ„œμ‹(formatting), λ“œλ¬Έ 주석을 μ‚¬μš©ν•˜μ—¬ 체계적이고 가독성이 μ’‹μ•„μ•Ό ν•©λ‹ˆλ‹€. λ„ˆμ˜ μ½”λ“œκ°€ self-documenting(슀슀둜 λ¬Έμ„œν™”λœ μ½”λ“œ) λ˜μ–΄ μžˆλ‹€λ©΄ ν•΄λ‹Ή μ½”λ“œκ°€ μˆ˜ν–‰ν•˜λŠ” μž‘μ—…μ˜ μ˜λ„λ₯Ό μ•Œλ¦¬λŠ”λ° λ„μ›€λ©λ‹ˆλ‹€. ν„°λ¬΄λ‹ˆμ—†λŠ” μ˜ˆμ‹œμΌ μˆ˜λ„ μžˆμ§€λ§Œ(λˆ„κ°€ 이런 μ½”λ“œλ₯Ό μž‘μ„±ν•˜κ² μ–΄μš”?) μ½”λ“œμ—μ„œ 무슨 일이 μΌμ–΄λ‚˜κ³  μžˆλŠ”μ§€ νŒŒμ•…ν•˜λ €λ©΄ μ•½κ°„μ˜ λ…Έλ ₯이 ν•„μš”ν•˜μ£ .

<template>
  <div>
    <button @click="c">Increment</button>
    <p>{{ a }}</p>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const a = ref(0);

function c() {
  a.value++;
}
</script>

λ§žμŠ΅λ‹ˆλ‹€. counter μž…λ‹ˆλ‹€. ν•˜μ§€λ§Œ λ‹€μŒ μ˜ˆμ‹œλ₯Ό 보면 보자마자 무엇인지 μ¦‰μ‹œ μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

<template>
  <div>
    <button @click="incrementCounter">Increment</button>
    <p>{{ counterValue }}</p>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const counterValue = ref(0);

function incrementCounter() {
  counterValue.value++;
}
</script>

λ¦¬νŒ©ν† λ§λœ μ½”λ“œμ—μ„œλŠ” λ³€μˆ˜μ™€ λ©”μ„œλ“œμ˜ 이름을 더 잘 μ„€λͺ…ν•  수 μžˆλ„λ‘ κ°œμ„ ν–ˆμŠ΅λ‹ˆλ‹€. 이제 이 μ»΄ν¬λ„ŒνŠΈλ‘œ λŒμ•„μ˜¬ λ•Œλ§ˆλ‹€ μ‹œκ°„κ³Ό 정신적 μ—λ„ˆμ§€λ₯Ό λ‚­λΉ„ν•  ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€.

λ„ˆλ¬΄ κΈ΄ μ»΄ν¬λ„ŒνŠΈ λΆ„ν• ν•˜κΈ°

μ»΄ν¬λ„ŒνŠΈκ°€ λ„ˆλ¬΄ λ§Žμ€ 일을 ν•˜κ³  λ„ˆλ¬΄ 길어지면 μ΄ν•΄ν•˜κ³  μœ μ§€ 보수 κ΄€λ¦¬ν•˜κΈ°κ°€ μ–΄λ €μšΈ 수 μžˆμŠ΅λ‹ˆλ‹€. κΈ΄ μ»΄ν¬λ„ŒνŠΈ 원칙에 λ”°λ₯΄λ©΄ κΈ΄ μ»΄ν¬λ„ŒνŠΈλ₯Ό 더 μž‘κ³  μ§‘μ€‘λœ μ»΄ν¬λ„ŒνŠΈλ‘œ λ‚˜λˆ„λ©΄ 가독성, μž¬μ‚¬μš©μ„± 및 ν…ŒμŠ€νŠΈ κ°€λŠ₯성을 κ°œμ„ ν•˜λŠ” 데 도움이 λ©λ‹ˆλ‹€. λ‹€μŒμ€ 이 λͺ¨λ“ κ²ƒμ„ μ‹œλ„ν•˜λŠ” μ „μžμƒκ±°λž˜ μƒμ μ˜ μ»΄ν¬λ„ŒνŠΈμž…λ‹ˆλ‹€.

<template>
  <div>
    <h1>{{ title }}</h1>
    <p>{{ description }}</p>
    <ul>
      <li v-for="item in items" :key="item.id">
        {{ item.name }} - {{ item.price }}
        <button @click="addToCart(item)">Add to cart</button>
      </li>
    </ul>
    <div>
      <h2>Cart</h2>
      <ul>
        <li v-for="item in cart" :key="item.id">
          {{ item.name }} - {{ item.price }}
          <button @click="removeFromCart(item)">Remove</button>
        </li>
      </ul>
      <p>Total: {{ totalPrice }}</p>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue';

const title = ref('My Store');
const description = ref('Welcome to my store!');

const items = ref([
  { id: 1, name: 'Item A', price: 10 },
  { id: 2, name: 'Item B', price: 20 },
]);

const cart = ref([]);

function addToCart(item) {
  cart.value.push(item);
}

function removeFromCart(item) {
  const index = cart.value.indexOf(item);
  if (index !== -1) {
    cart.value.splice(index, 1);
  }
}

const totalPrice = computed(() => {
  return cart.value.reduce((sum, item) => sum + item.price, 0);
});
</script>

이λ₯Ό λΆ„ν• ν•˜λŠ” 데 도움이 λ˜λŠ” Clean Components Toolkit의 μ»΄ν¬λ„ŒνŠΈ 경계 νŒ¨ν„΄μ„ μ‚¬μš©ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€. 이 νŒ¨ν„΄μ€ 일반적으둜 μ½”λ“œμ— 이미 μ •μ˜λœ 경계가 μžˆμ–΄ μ»΄ν¬λ„ŒνŠΈλ₯Ό λΆ„ν• ν•˜λŠ” 데 μ‚¬μš©ν•  수 μžˆμŒμ„ μ•Œλ €μ€λ‹ˆλ‹€. μ΄λŸ¬ν•œ 경계λ₯Ό μ°ΎλŠ” κ°€μž₯ μ‰¬μš΄ 방법은 ν…œν”Œλ¦Ώμ„ μ‚΄νŽ΄λ³΄λŠ” κ²ƒμž…λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ μΆ”μΆœν•  수 μžˆλŠ” μ„Έ 가지 κ°œλ³„ ꡬ성 μš”μ†Œλ₯Ό 찾을 수 μžˆμŠ΅λ‹ˆλ‹€.

  • StoreHeader
  • ItemList
  • Cart
<template>
  <div>
    <!-- StoreHeader -->
    <h1>{{ title }}</h1>
    <p>{{ description }}</p>

    <!-- ItemList -->
    <ul>
      <li v-for="item in items" :key="item.id">
        {{ item.name }} - {{ item.price }}
        <button @click="addToCart(item)">Add to cart</button>
      </li>
    </ul>

    <!-- Cart -->
    <div>
      <h2>Cart</h2>
      <ul>
        <li v-for="item in cart" :key="item.id">
          {{ item.name }} - {{ item.price }}
          <button @click="removeFromCart(item)">Remove</button>
        </li>
      </ul>
      <p>Total: {{ totalPrice }}</p>
    </div>
  </div>
</template>

μƒˆλ‘­κ³  κ°„μ†Œν™”λœ ꡬ성 μš”μ†ŒλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€. 이제 무슨 일이 μΌμ–΄λ‚˜κ³  μžˆλŠ”μ§€ 훨씬 더 μ‰½κ²Œ 이해할 수 μžˆμŠ΅λ‹ˆλ‹€.

<template>
  <div>
    <StoreHeader :title="title" :description="description" />
    <ItemList :items="items" @addToCart="addToCart" />
    <Cart :cart="cart" @removeFromCart="removeFromCart" />
  </div>
</template>

<script setup>
import { ref } from 'vue';
import StoreHeader from './StoreHeader.vue';
import ItemList from './ItemList.vue';
import Cart from './Cart.vue';

const title = ref('My Store');
const description = ref('Welcome to my store!');

const items = ref([
  { id: 1, name: 'Item A', price: 10 },
  { id: 2, name: 'Item B', price: 20 },
]);

const cart = ref([]);

function addToCart(item) {
  cart.value.push(item);
}

function removeFromCart(item) {
  const index = cart.value.indexOf(item);
  if (index !== -1) {
    cart.value.splice(index, 1);
  }
}
</script>

 

StoreHeader μ»΄ν¬λ„ŒνŠΈμž…λ‹ˆλ‹€.

<template>
  <div>
    <h1>{{ title }}</h1>
    <p>{{ description }}</p>
  </div>
</template>

<script setup>
const props = defineProps({
  title: String,
  description: String,
});
</script>

ItemList μ»΄ν¬λ„ŒνŠΈμž…λ‹ˆλ‹€.

<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      {{ item.name }} - {{ item.price }}
      <button @click="$emit('addToCart', item)">Add to cart</button>
    </li>
  </ul>
</template>
<script setup>
const props = defineProps({
  items: Array,
});
</script>

Cart μ»΄ν¬λ„ŒνŠΈμž…λ‹ˆλ‹€.

<template>
  <div>
    <h2>Cart</h2>
    <ul>
      <li v-for="item in cart" :key="item.id">
        {{ item.name }} - {{ item.price }}
        <button @click="$emit('removeFromCart', item)">Remove</button>
      </li>
    </ul>
    <p>Total: {{ totalPrice }}</p>
  </div>
</template>

<script setup>
import { defineProps, computed } from 'vue';

const props = defineProps({
  cart: Array,
});

const totalPrice = computed(() => {
  return props.cart.reduce((sum, item) => sum + item.price, 0);
});
</script>

μ—¬κΈ°μ„œ νŠΈλ ˆμ΄λ“œμ˜€ν”„λ₯Ό λ°œκ²¬ν–ˆμ„μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. ν•˜λ‚˜μ˜ λ³΅μž‘ν•œ μ»΄ν¬λ„ŒνŠΈλ₯Ό μ—¬λŸ¬ 개의 κ°„λ‹¨ν•œ μ»΄ν¬λ„ŒνŠΈλ‘œ λ°”κΎΈλŠ” κ²ƒμž…λ‹ˆλ‹€. μ½”λ“œκ°€ 쑰금 더 λ§Žμ•„μ§€κΈ΄ ν•˜μ§€λ§Œ μ΄ν•΄ν•˜κΈ° 훨씬 쉽고 μœ μ§€ 관리 및 μˆ˜μ •ν•˜κΈ° μ‰¬μš΄ μ½”λ“œκ°€ λ©λ‹ˆλ‹€. μ œκ°€ λ³΄μ—¬λ“œλ¦° μ˜ˆμ‹œλ“€ μ‚¬μ΄μ—λŠ” ν†΅μΌλœ 원칙이 μžˆμŠ΅λ‹ˆλ‹€.

κ°€μž₯ λ©μ²­ν•˜κ³ , κ°€μž₯ μ’Œμ ˆν•˜κ³ , κ°€μž₯ ν”Όκ³€ν•œ μžκΈ°μžμ‹ μ„ μœ„ν•΄. μ΅œμ ν™” ν•˜μ„Έμš”.

μ €λŠ” μ˜λ¦¬ν•œ μ½”λ“œλ₯Ό μž‘μ„±ν•˜λŠ” κ²½ν–₯이 μžˆμŠ΅λ‹ˆλ‹€.(적어도 μ œκ°€ λ˜‘λ˜‘ν•˜λ‹€κ³  λŠκ»΄μ§€λ„λ‘ λ§Œλ“€μ£ .) ν•˜μ§€λ§Œ λ‹€μŒλ‚  μ˜μš•μ΄ λ–¨μ–΄μ§€κ±°λ‚˜ μ—λ„ˆμ§€κ°€ 쀄어든 μƒνƒœλ‘œ λŒμ•„μ˜€λ©΄ 무슨 일이 μΌμ–΄λ‚˜κ³  μžˆλŠ”μ§€ νŒŒμ•…ν•˜κΈ° μ–΄λ ΅μŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” μ΅œμ•…μ˜ 날에도 이해할 수 있고 μƒμ‚°μ μœΌλ‘œ μž‘μ—…ν•  수 μžˆλŠ” λͺ…ν™•ν•œ μ½”λ“œλ₯Ό μž‘μ„±ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€. μ΄λŠ” 쒋은 이름 지정과 정리, λͺ…ν™•ν•˜κ³  κ°„κ²°ν•œ λ¬Έμ„œμ™€ 예제λ₯Ό μ‘°ν•©ν•˜μ—¬ 달성할 수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ μΌκ΄€λœ νŒ¨ν„΄κ³Ό κ·œμΉ™μ„ μ‚¬μš©ν•˜λ©΄ 인지적 λΆ€ν•˜λ₯Ό 쀄이고 νœ΄μ‹μ΄λ‚˜ 쀑단 후에도 ν”„λ‘œμ νŠΈ μž‘μ—…μ„ κ³„μ†ν•˜κΈ°κ°€ μ‰¬μ›Œμ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€.

κ²°λ‘ 

μ‚¬λžŒμ΄ 이해할 수 μžˆλ„λ‘ μ»΄ν¬λ„ŒνŠΈλ₯Ό μ΅œμ ν™”ν•˜λŠ” 것은 μœ μ§€λ³΄μˆ˜μ„±, 가독성 및 μ „λ°˜μ μΈ ν”„λ‘œμ νŠΈ 성곡을 μœ„ν•΄ 맀우 μ€‘μš”ν•©λ‹ˆλ‹€. μ˜¬λ°”λ₯Έ λͺ…λͺ… κ·œμΉ™μ„ μ‚¬μš©ν•˜κ³ , μ»΄ν¬λ„ŒνŠΈ λ©”μ„œλ“œλ₯Ό μΆ”μΆœν•˜κ³ , μ½”λ“œλ₯Ό μ •λ¦¬ν•˜κ³ , λͺ¨λ²” 사둀λ₯Ό λ”°λ₯΄λ©΄ Vue μ»΄ν¬λ„ŒνŠΈμ— 더 μ‰½κ²Œ μ ‘κ·Όν•˜κ³  μž‘μ—…ν•˜κΈ° μ‰½κ²Œ λ§Œλ“€μˆ˜ μžˆμŠ΅λ‹ˆλ‹€. 이 λ¬Έμ„œμ—λŠ” λͺ‡ 가지 방법을 μ†Œκ°œν–ˆμ§€λ§Œ, κ·Έ 외에도 λ‹€μ–‘ν•œ 방법이 μžˆμŠ΅λ‹ˆλ‹€. Clean Component Toolkitμ—λŠ” 더 λ‚˜μ€ Vue μ»΄ν¬λ„ŒνŠΈλ₯Ό μž‘μ„±ν•˜λŠ” 데 λ„μ›€λ˜λŠ” νŒ¨ν„΄, 기술 및 κ°œλ…κ³Ό 같은 21가지 도ꡬ가 ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. 각각은 μ‹€μ œ μ½”λ“œ μ˜ˆμ œμ— 도ꡬλ₯Ό μ μš©ν•˜λŠ” 방법을 λ³΄μ—¬μ£ΌλŠ” 단계별 λ¦¬νŒ©ν„°λ§ 예제λ₯Ό ν¬ν•¨ν•˜μ—¬ 맀우 μƒμ„Έν•˜κ²Œ λ‹€λ£Ήλ‹ˆλ‹€. λ”°λΌμ„œ Vue μ½”λ“œλ₯Ό κ°œμ„ ν•˜λŠ” 방법에 λŒ€ν•΄ μžμ„Ένžˆ μ•Œμ•„λ³΄κ³  μ‹Άλ‹€λ©΄ Clean Components Toolkit을 μ‚¬μš©ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

728x90
728x90