Vue에서 컴포넌트 템플릿을 정의하는 7가지 방법

이 문서는 https://vuejsdevelopers.com/2017/03/24/vue-js-component-templates/의 내용을 변역한 문서입니다.

Vue에서는 컴포넌트 템플릿을 정의할 때 꽤 많은 선택권이 있습니다. 제가 알기로는 적어도 7가지 방법이 있습니다.

  • String
  • Template literal
  • X-Templates
  • Inline
  • Render functions
  • JSX
  • Single page components
  • 아마 몇개 더 있을거에요

이 글에서는 어느 상황에서 어느 방법이 가장 좋은지 알 수 있도록 각각의 경우에 대해서 장단점을 살펴보겠습니다.

1. Strings

템플릿은 JS 파일의 string으로 정의됩니다. 저는 string 템플릿은 가독성이 꽤 떨어진다고 생각하며, 아마 모두들 인정하는 부분일 겁니다. 이 방법은 많은 브라우저 지원 외에는 딱히 큰 장점은 없습니다.

Vue.component('my-checkbox', {
  template: `<div class="checkbox-wrapper" @click="check"><div :class="{ checkbox: true, checked: checked }"></div><div class="title"></div></div>`,
  data() {
    return { checked: false, title: 'Check me' }
  },
  methods: {
    check() { this.checked = !this.checked; }
  }
});

2. Template literals

ES6 템플릿 문자열(“백틱”)은 일반적인 자바스크립트 string과 달리 템플릿 문자열 내에서 줄바꿈을 사용하며 템플릿을 정의할 수 있습니다. 이 방법은 훨씬 가독성이 좋으며 최신 브라우저에서 대부분 지원하고 있지만, 그래도 ES5 문법으로 변환하는 게 안전합니다.

하지만 이 방법도 완벽하지는 않습니다. 대부분의 IDE에서 아직까지는 구문 강조, 탭이나 줄바꿈 등등 다양한 부분에 문제가 있기 때문에 빡침을 유발할 수 있습니다.

Vue.component('my-checkbox', {
  template: `<div class="checkbox-wrapper" @click="check">
               <div :class="{ checkbox: true, checked: checked }"></div>
               <div class="title"></div>
             </div>`,
  data() {
    return { checked: false, title: 'Check me' }
  },
  methods: {
    check() { this.checked = !this.checked; }
  }
});

3. X-Templates

이 방법을 사용하면 index.html파일의 <script>태그 안에 템플릿이 정의됩니다. <script> 태그는 text/x-template로 표시되고 컴포넌트 정의 부분에서 지정한 id로 참조됩니다.

이 방법은 템플릿을 HTML 마크업으로 작성하는 점에서는 좋으나, 템플릿과 컴포넌트의 나머지 부분이 분리된다는 단점이 있습니다.

Vue.component('my-checkbox', {
  template: '#checkbox-template',
  data() {
    return { checked: false, title: 'Check me' }
  },
  methods: {
    check() { this.checked = !this.checked; }
  }
});
<!-- index.html -->
<script type="text/x-template" id="checkbox-template">
  <div class="checkbox-wrapper" @click="check">
    <div :class="{ checkbox: true, checked: checked }"></div>
    <div class="title"></div>
  </div>
</script>

4. Inline Templates

컴포넌트에 inline-template 속성을 추가하면 Vue는 내부 콘텐츠를 템플릿으로 인식합니다. slot같은 분산된 콘텐츠와는 다르게 말이죠.

x-templates와 같은 단점이 있지만, HTML 템플릿 안의 내용이 정확한 위치에 있기 때문에 자바스크립트 실행을 기다리는 것보다 페이지 로드 단계에서 렌더링이 된다는 장점이 있습니다.

Vue.component('my-checkbox', {
  data() {
    return { checked: false, title: 'Check me' }
  },
  methods: {
    check() { this.checked = !this.checked; }
  }
});
<my-checkbox inline-template>
  <div class="checkbox-wrapper" @click="check">
    <div :class="{ checkbox: true, checked: checked }"></div>
    <div class="title"></div>
  </div>
</my-checkbox>

5. Render functions

Render 함수 방식을 사용하려면 템플릿을 자바스크립트 객체로 정의해주어야 합니다. 이 방법은 템플릿 옵션 중에서 가장 장황하고 추상적입니다.

그러나, 디렉티브(v-)에서 제공하는 기능만이 아닌, 자바스크립트의 전체적인 기능을 사용할 수 있다는 점과 컴파일러에 훨씬 더 가깝다는 점에서는 장점이라고 볼 수 있습니다.

Vue.component('my-checkbox', {
  data() {
    return { checked: false, title: 'Check me' }
  },
  methods: {
    check() { this.checked = !this.checked; }
  },
  render(createElement) {
    return createElement(
      'div',
        {
          attrs: {
            'class': 'checkbox-wrapper'
          },
          on: {
            click: this.check
          }
        },
        [
          createElement(
            'div',
	    {
              'class': {
                checkbox: true,
                checked: this.checked
              }
	    }
          ),
          createElement(
            'div',
            {
              attrs: {
                'class': 'title'
              }
	    },
	    [ this.title ]
          )
        ]
      );
    }
  }
);

6. JSX

Vue에서 가장 논란이 되는 템플릿 옵션인 JSX입니다. 몇몇 개발자는 JSX가 Vue의 정신에 반대된다며 극혐하고 있습니다. JSX는 브라우저에서 읽을 수 없어서 트랜스파일을 먼저 해야 합니다. 하지만 render 함수를 사용해야 하는 경우, JSX는 확실히 덜 추상적인 템플릿 정의 방법입니다.

Vue.component('my-checkbox', {
  data() {
    return { checked: false, title: 'Check me' }
  },
  methods: {
    check() { this.checked = !this.checked; }
  },
  render() {
    return <div class="checkbox-wrapper" onClick={ this.check }>
             <div class=></div>
             <div class="title">{ this.title }</div>
           </div>
  }
});

7. Single File Components

빌드 툴을 다루는데 익숙하다면 Single File Components가 진리입니다. 싱글 파일 컴포넌트는 컴포넌트 정의와 마크업을 한 파일 내에서 작성할 수 있다는 장점이 있습니다. 이 방법은 트랜스파일 과정을 거쳐야 하며 몇몇 IDE에서는 이 파일 타입에 대해서 구문 강조를 지원하지 않는다는 단점이 있긴 하지만 그래도 짱입니다.

<template>
  <div class="checkbox-wrapper" @click="check">
    <div :class="{ checkbox: true, checked: checked }"></div>
    <div class="title"></div>
  </div>
</template>
<script>
  export default {
    data() {
      return { checked: false, title: 'Check me' }
    },
    methods: {
      check() { this.checked = !this.checked; }
    }
  }
</script>

Pug 같은 템플릿 전처리기를 사용함으로써 템플릿 정의 가능성이 더욱 많아질 수 있을 것입니다.

어떤 방법이 짱인가?

물론 완벽한 방법은 없으며 각각의 사용되는 케이스를 잘 판단해야 합니다. 최고의 개발자라면 모든 경우를 인지하고 상황에 알맞은 템플릿 정의 방법을 사용할 것입니다.

Written on January 1, 2018