Web Component
Web Components는 프레임워크에 종속되지 않는 표준 웹 기술입니다. Vue 컴포넌트를 Web Component로 변환하면 React, Angular, 바닐라 JS 등 어디서든 사용할 수 있습니다.
면접에서 "프레임워크에 독립적인 UI 컴포넌트를 만들려면 어떻게 하나요?"라고 물으면 Web Components를 언급할 수 있어야 합니다.
Vue 컴포넌트를 Web Component로 변환
// defineCustomElement — Vue 3.2+
import { defineCustomElement } from 'vue'
// 일반 Vue SFC를 Custom Element로 변환
import MyButton from './MyButton.ce.vue' // .ce.vue 확장자 권장
const MyButtonElement = defineCustomElement(MyButton)
// 브라우저에 등록
customElements.define('my-button', MyButtonElement)
<!-- MyButton.ce.vue -->
<script setup lang="ts">
const props = defineProps<{
label: string
variant?: 'primary' | 'secondary'
}>()
const emit = defineEmits<{
click: [event: MouseEvent]
}>()
</script>
<template>
<button :class="variant" @click="emit('click', $event)">
{{ label }}
</button>
</template>
<!-- Custom Element에서는 scoped가 아닌 일반 style 사용 -->
<!-- Shadow DOM이 스타일을 격리함 -->
<style>
button {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.primary { background: #42b883; color: white; }
.secondary { background: #e0e0e0; color: #333; }
</style>
<!-- 어디서든 사용 가능 -->
<my-button label="클릭" variant="primary"></my-button>
<script>
document.querySelector('my-button').addEventListener('click', (e) => {
console.log('클릭됨!')
})
</script>
외부 Web Component를 Vue에서 사용
// vite.config.ts — 커스텀 엘리먼트 인식 설정
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
// 특정 태그를 커스텀 엘리먼트로 인식
isCustomElement: (tag) => tag.startsWith('ion-') || tag.startsWith('sl-')
}
}
})
]
})
<template>
<!-- Shoelace Web Components 예시 -->
<sl-button variant="primary" @sl-click="handleClick">
버튼
</sl-button>
<sl-dialog :open="isOpen" @sl-after-hide="isOpen = false">
<span slot="label">다이얼로그 제목</span>
<p>내용입니다.</p>
</sl-dialog>
</template>
Props와 Events 매핑
Vue Props → HTML Attributes / DOM Properties
Vue Emit → Custom Events (CustomEvent)
주의사항:
- HTML 속성은 문자열만 가능 → 복잡한 데이터는 DOM property로
- 이벤트 이름은 kebab-case
- v-model은 직접 구현 필요
Shadow DOM과 스타일
Custom Element는 기본적으로 Shadow DOM을 사용하여 스타일이 격리됩니다.
<!-- 스타일이 Shadow DOM 내부에 캡슐화됨 -->
<style>
/* 이 스타일은 Custom Element 외부에 영향을 주지 않음 */
button { color: red; }
</style>
Shadow DOM을 비활성화하려면:
const MyElement = defineCustomElement(MyComponent, {
shadowRoot: false // Shadow DOM 비활성화
})
면접 팁
- Web Components는 표준 기술 이므로 프레임워크 업데이트에 영향받지 않습니다
- Vue의
defineCustomElement는 SFC의 모든 기능(props, emit, slots, 스타일)을 지원합니다 - Shadow DOM의 스타일 격리가 장점이자 단점이 될 수 있다는 것을 이해하고 있어야 합니다
요약
Vue 컴포넌트를 defineCustomElement로 Web Component로 변환하면 프레임워크에 독립적으로 사용할 수 있습니다. 외부 Web Component는 isCustomElement 설정으로 Vue에서 인식하게 하면 됩니다. Shadow DOM이 스타일을 격리하므로 CSS 충돌 걱정 없이 사용할 수 있습니다.
댓글 로딩 중...