cover

이미 이전 글들을 봐왔다면 이미 익숙하다고 할 수 있는 Single-File Components(SFC)에 대해 간략하게 잠시 다뤄보고자 합니다.


Single-File Componts

Single-File Components(SFC)라고 불리지만 사실 Vue 컴포넌트 *.vue 파일을 말합니다. Single-File이라 표현한 이유는 View(HTML), Logic(Javascript), Styling(CSS)이 하나의 파일에 모여있기 때문이죠. 결국 HTML, CSS, JS를 하나의 파일에 모은 컴포넌트 파일이라고 할 수 있습니다.

html
      <script setup>
import { ref } from 'vue'
const greeting = ref('Hello World!')
</script>

<template>
  <p class="greeting">{{ greeting }}</p>
</template>

<style>
.greeting {
  color: red;
  font-weight: bold;
}
</style>
    

왜 사용해야하는가?

SFC 파일 자체로는 브라우저에서 볼 수 없습니다. 별도의 빌드 단계가 필요한데 그럼에도 불구하고 장점들이 많이 있습니다.

친숙한 HTML, CSS, JS 문법을 사용한다.
해결해야할 문제에 맞게 필요한 것들끼리 모여있다.
사전 컴파일된 template 덕에 런타임 컴파일 비용이 줄어든다.
scoped CSS 지원한다.
사람이 사용하기 편한 문법인 Composition API 지원한다.
template과 script를 교차분석해서 컴파일 시간을 최적화한다.
IDE에서 자동 완성, 유형 검사를 지원한다.
설치할 필요없이 편하게 쓸 수 있는 Hot-Module Replacement (HMR) 지원한다.
info
      HMR은 개발할 때 브라우저를 새로고침하지 않고도 웹팩으로 빌드한 결과물이 바로 반영되는 기능입니다.
    

SFC는 다음과 같은 경우에 사용되는 것이 좋습니다.

Single-Page Application (SPA)
Static Site Generation (SSG)
DX(Development Experience)를 위해 빌드 단계가 있는 약간 복잡한 프론트엔드 개발 프로젝트

SFC를 사용하기에는 좀 간단한 경우이고 상호작용도 적은 HTML 파일이 많다면, petite-vue를 사용하는 것도 좋습니다.

어떻게 동작하는가?

SFC는 Vue를 위한 프레임워크 파일 포맷이기 때문에 @vue/compiler-sfc로 표준 JS, CSS로 미리 컴파일 되어야 합니다.

이렇게 컴파일된 SFC는 표준 JS 모듈이 되기 때문에 설정만 잘 되어있다면 SFC를 모듈처럼 가져올 수 있습니다.

javascript
      import MyComponent from './MyComponent.vue'

export default {
  components: {
    MyComponent
  }
}
    

CSS의 경우에는 개발 중에는 <style> 태그를 만들어 삽입하고 개발완료하고 배포한 것은 모든 컴포넌트들에서 추출해서 하나의 CSS 파일에 병합합니다.

HTML과 CSS, JS를 모으는 것에 대하여

일부러 각 기능에 맞게 HTML, CSS, JS로 분리된 것을 다시 SFC로 합치는게 혼란스럽고 합리적인지 의심이 들 수 있습니다. 이에 대해 답하자면, SFC가 구분하고자 하는 것은 사용 목적입니다.

예를 들어, 하나의 버튼을 만들기 위해 HTML, CSS, JS는 각각 파일에 따로 구현해야 합니다. 하지만 SFC는 이를 한 파일에 모아서 구현할 수 있습니다. 버튼이라는 사용 목적을 위해 서로 다른 파일로 있는 것보다 하나의 컴포넌트로 관리되는 것이 코드 유지 관리면에서 더 효율적입니다.

그럼에도 불구하고 분리하고 싶다면 src 속성을 이용해서 분리하실 수 있습니다.

html
      <template src="./template.html"></template>
<style src="./style.css"></style>
<script src="./script.js"></script>
    

SFC 문법

HTML과 비슷한 문법을 가지고 있지만, 몇 가지 다른 점들이 있습니다. 그 중 하나가 언어 블록(Language Block)이 있다는 겁니다.

<template>
*.vue 파일마다 하나만 있을 수 있습니다.
이 안의 내용은 @vue/compiler-dom에 전달되서, 자바스크립트 render함수에 의해 컴파일(pre-compiled)되어 컴포넌트의 render 옵션 값에 들어갑니다.
<script>
*.vue 파일마다 하나만 있을 수 있습니다.
ES 모듈로 실행됩니다.
default export 뒤에 들어갈 값은 컴포넌트 객체여야 합니다. 여기서 말하는 컴포넌트 객체는 컴포넌트 옵션들이 들어간 일반 객체일 수도 있고, defineComponent의 반환값일 수도 있습니다.
setup 옵션을 추가할 수 있으며, 이는 script 내부를 setup() 함수처럼 사용할 수 있습니다. 보통은 변수나 함수등을 return해야 template에 노출(expose)되어 사용할 수 있습니다. 하지만 이 경우 하위 스코프가 아닌 최상단(top-level)에서 변수나 함수를 정의했다면 return한 것처럼 자동으로 노출되어 사용할 수 있습니다.
<style>
*.vue 파일마다 여러 개 있을 수 있습니다.
module, scoped 속성을 이용해 다른 컴포넌트에 영향 주지 않고 현재 컴포넌트에만 스타일이 적용되도록 할 수 있습니다.
script에서 만든 변수값을 v-bind를 이용해 넣어줄 수 있습니다. 예) color: v-bind('myVal');

그 외에도 라이브러리에 따라 다른 블록들을 넣을 수 있습니다.

커스텀 블록도 만들 수 있는데 이는 다음 글에서 다뤄보도록 하겠습니다.

lang 속성

HTML, CSS, JS 뿐만 아니라 Pug, SASS, TS 등 다른 언어들도 많이 있습니다. lang 속성을 넣어주면 편하게 해당 언어의 문법을 사용해 구현할 수 있습니다.

html
      <script lang="ts">
  // use TypeScript
</script>

<template lang="pug">
p {{ msg }}
</template>

<style lang="scss">
  $primary-color: #333;
  body {
    color: $primary-color;
  }
</style>
    

주석

HTML과 유사한 문법을 쓰기 때문에 template, script, style과 같은 곳에서 주석을 써야 한다면 HTML과 동일한 <!-- 주석 --> 방식을 사용합니다. script 내에서는 /* */, // 를, style 내에서는 /* */ 를 사용하시면 됩니다.

html
      <!-- 바깥 주석 -->
<template>
<!-- HTML 주석 -->
</template>

<script>
// JS 주석
/* JS 주석 */
</script>

<style>
/* CSS 주석 */
</style>