Vue 기본 개념

이 문서는 vue에 대한 빠르고 개략적인 이해를 위해서 간략한 개념만을 정리하고 있다. 따라서 실제 프로젝트에 적용하기 위해서는 참고문서에 지정된 공식문서와 다른 분들이 정리해 놓은 자료들을 참고하도록 한다.
현재 진행 중인 프로젝트에 무사히(?) 적용을 끝내고 나면 그 과정을 기준으로 새로운 정리 문서들을 추가할 예정이다.

Vue?

Vue 가 무엇인가에 대한 것은 Vue 키 포인트 소개 (Gregg 소개 자료)를 참고하면 쉽게 이해할 수 있다.

현재 Top 3(Angular, React, Vue)에 해당하는 Javascript Framework으로 MVVM(Model-View-ViewModel) 패턴 기반의 UI 라이브러리

  • 데이터 바인딩과 화면 단위를 컴포넌트 형태로 제공하며, 관련된 API를 지원한다.
  • 양방향 데이터 바인딩 지원 (Component <-> Model)
  • 컴포넌트간의 통신은 React와 같이 단방향 데이터 흐름 (Parent -> Child) 사용
  • Angular, React 등과 비교해서 상대적으로 가볍고 빠름
  • 문법이 단순하고 간결해서 진입장벽이 낮고 쉽게 접근 가능
  • Virtual DOM 지원
  • Single file copmpoent 지원
  • View에 최적화되어 있어 jQuery등을 이용한 DOM 조작이 필요없다.
  • 많은 모듈들의 지원과 한글화된 정보들이 많이 존재한다.
    • Vuex : 중앙집중식 상태관리 저장소
    • vue-router : SPA를 위한 라우터
    • vue-resource : HTTP, Ajax, …
    • vue-devtools : Vue에 최적화된 개발자 모드

MVVM 패턴이란?

서버와 클라이언트의 UI 코드와 데이터를 분리하기 위한 기본적인 구조인 MVC (Model-View-Controller) 패턴에서 파생된 것으로 쉽게 생각하면 서버와 연계되는 데이터(Model)와 UI 코드 및 UI 동작 (View) 간의 분리와 데이터 연계를 위한 중간 매개체로의 역할 (ViewModel)을 담당하는 패턴을 의미한다.

MVVM 패턴
[ MVVM 패턴 ]

Vue Instance

모든 Vue 어플리케이션들은 Vue 함수를 이용해서 인스턴스를 만드는 것부터 시작된다.

아래의 예제는 아주 간단한 “Hello Vue”를 출력하는 기본 샘플이다.

 1<!DOCTYPE html>
 2<html>
 3  <head>
 4    <title>Vue First Sample</title>
 5  </head>
 6  <body>
 7    <div id="app">
 8      {{ message }}
 9    </div>
10
11    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
12    <script>
13      new Vue({
14        el: '#app',
15        data: {
16          message: 'Hello Vue.js!'
17        }
18      })
19    </script>
20  </body>
21</html>
  • 11번 라인에서 Vue.js 스크립트 지정
  • 13-18번 라인에서 Vue Instance 생성
  • 14번 el은 Vue 인스턴스가 마운트될 DOM 의 엘리먼트를 지정
  • 15번 data는 Model 데이터 지정
<script>
...
new Vue({
  // option properties
})
...
</script>

옵션으로 지정할 수 있는 속성들은 다음과 같다.

  • data : 뷰의 반응성(Reactivity)이 반영될 데이터 속성
  • template : 화면에 표시할 요소 (HTML, CSS 등)
  • el : vue 인스턴스가 연계될 HTML 엘리먼트
  • methods : 화면의 동작과 이벤트를 처리하기 위한 메서드
  • events (life cycle hooks) : Vue 라이프사이클에 맞는 이벤트 훅
  • watch: data에 정의한 속성이 변경 (양방향 Binding)되었을 떄 추가 동작을 수행할 수 있도록 정의하는 속성

옵션으로 지정 가능한 전체 목록은 Vue 공식사이트의 API문서를 참고하면 된다.

Vue 라이프 사이클

Vue는 아래와 같은 라이프 사이클을 가진다.

Vue lifecycle
[출처:Vue공식문서 - 라이프사이클 다이어그램]

위의 그림을 단순한 진행 스텝 단위로 정리하면 아래와 같고, 우리가 사용하게될 부분은 굵은 글씨로 표현된 이벤트 훅을 받아서 필요한 처리를 수행하면 된다.

  • Vue 인스턴스 생성
  • events and lifecycle 초기화
    • beforeCreate 이벤트 훅 발생
  • injections and reactivity 초기화
    • created 이벤트 훅 발생
  • Vue 인스턴스 연결 (el option 지정에 따라 vm.$mount(el) 호출)
  • 템플릿 구성 (템플릿 미지정시는 el의 outerHTML을 템플릿으로 처리)
    • beforeMount 이벤트 훅 발생
  • vm.$el 변수 생성 및 el 엘리먼트를 Vue 인스턴스로 대체
    • mounted 이벤트 훅 발생
  • 데이터 변경 발생시 Virtual DOM에 적용
    • 데이터 변경 전에 beforeUpdate 이벤트 훅 발생
    • 데이터 변경 후에 updated 이벤트 훅 발생
  • vm.$destroy() 메서드 호출되면 종료 진행
    • beforeDestroy 이벤트 훅 발생
    • watchers, child components, event listeners 들 종료
    • destroyed 이벤트 훅 발생

Vue Components

기본 HTML 엘리먼트를 확장해서 재 사용 가능한 코드로 캡슐화한 것으로 HTML + CSS + SCRIPT 의 구성으로 특정한 기능성을 제공하기 위한 것이다.

컴포넌트 구성
[출처:Cracking Vue.js - 컴포넌트 구성]

따라서 컴포넌트를 기반으로 화면을 개발하면 코드의 재 사용성이 올라가고 일관성 유지를 하면서 빠르게 개발이 가능하다.

Vue는 사용자 지정 태그 이름에 대한 W3C 규칙을 따르지 않고 아래의 규칙을 사용한다.
- 모두 소문자로 구성한다.
- ’-’ 을 포함해야 한다.

전역 컴포넌트

Vue 인스턴스에 직접 컴포넌트를 등록한다. Vue.component(tagName, options)

 1...
 2<div id="example">
 3  <my-component></my-component>
 4</div>
 5...
 6<script>
 7...
 8// 전역 컴포넌트 등록
 9Vue.component('my-compoent', {
10  // options
11  template: '<div>사용자 정의 컴포넌트!!</div>'
12})
13...
14// 인스턴스 생성
15new Vue({
16  // option properties
17  el: '#example'
18})
19
20...
21</script>

실행된 결과는 다음과 같다.

1// 렌더링 결과
2<div id="example">
3  <div>사용자 정의 컴포넌트!!</div>
4</div>

지역 컴포넌트

모든 컴포넌트를 전역으로 등록할 필요는 없다. 컴포넌트를 components 라는 인스턴스 옵션으로 등록해서 다른 인스턴스 또는 컴포넌트의 범위 내에서 사용하도록 할 수도 있다.

 1var Child = {
 2  template: '<div>사용자 정의 컴포넌트!!</div>'
 3}
 4
 5new Vue({
 6  // ...
 7  components: {
 8    // <my-component> 는 상위 템플릿에서만 사용할 수 있습니다.
 9    'my-component': Child
10  }
11})

컴포넌트 사용시 주의할 점

  • DOM 템플릿 구문 오류
    Vue는 템플릿 컨텐츠를 처리할 때 HTML이 동작하는 고유의 몇가지 제한 사항이 존재하며 브라우저가 구문 분석과 정규화한 후에 동작하기 때문에 <ul>, <ol>, <table>, <select>와 <option> 등과 같이 제한이 존재하는 경우는 오류가 발생하게 된다. 따라서 이런 문제를 해결하기 위해서는 is 라는 특수한 속성을 이용해야 한다.
    1  <table>
    2    <my-row>...</my-row>   <!-- <tr> 태그가 아닌 사용자 정의 컴포넌트가 존재하므로 오류 발생 -->
    3  </table>
    4
    5  <!-- 위의 문제를 해결하기 위해서는 아래와 같이 특수 속성을 사용해야 한다. -->
    6  <table>
    7    <tr is="my-row">...</my-row>   <!-- <tr> 에 "is" 속성으로 컴포넌트 연결 -->
    8  </table>
    9  
    물론 순수하게 DOM 파싱을 거치지 않는 경우는 예외적으로 사용할 수 있다.
    • <script type="text/x-template"> 에서 사용하는 경우
    • Javascript 인라인 템플릿 문자열
    • .vue 컴포넌트
  • data option은 반드시 함수여야 한다
    Vue 생성자에 사용할 수 있는 대부분의 옵션들은 컴포넌트에서도 사용할 수 있지만 data의 경우는 반드시 함수여야 한다.
    1  Vue.component('my-component', {
    2    template: '<span>{{ message }}</span>',
    3    data: {             // 함수가 아니므로 경고 표시됨.
    4      message: 'hello'
    5    }
    6  })
    7  
    아래와 같이 함수로 처리해서 사용하면 된다.
     1  ...
     2  <div id="example-2">
     3    <simple-counter></simple-counter>
     4    <simple-counter></simple-counter>
     5    <simple-counter></simple-counter>
     6  </div>
     7  ...
     8  <script>
     9    var data = { counter: 0 }
    10
    11    Vue.component('simple-counter', {
    12      template: '<button v-on:click="counter += 1">{{ counter }}</button>',
    13      // 데이터는 기술적으로 함수이므로 Vue는 따지지 않지만
    14      // 각 컴포넌트 인스턴스에 대해 같은 객체 참조를 반환합니다.
    15      data: function () {
    16        return data   // 객체 반환
    17      }
    18    })
    19
    20    new Vue({
    21      el: '#example-2'
    22    })
    23  </script>
    24  
    위의 예제는 정상적으로 잘 동작을 하지만 잘 보면 data란 객체를 생성하고 이를 반환하는 함수로 data 옵션을 구성했기 때문에 모든 컴포넌트가 동일한 객체를 바라보기 때문에 하나의 컴포넌트에서 값을 바꾸면 모든 컴포넌트가 변경되는 문제가 발생한다. 이를 해결하기 위해서는 아래와 같이 코드를 작성해야 한다.
     1  ...
     2  <div id="example-2">
     3    <simple-counter></simple-counter>
     4    <simple-counter></simple-counter>
     5    <simple-counter></simple-counter>
     6  </div>
     7  ...
     8  <script>
     9    Vue.component('simple-counter', {
    10      template: '<button v-on:click="counter += 1">{{ counter }}</button>',
    11      // 데이터는 기술적으로 함수이므로 Vue는 따지지 않지만
    12      // 각 컴포넌트 인스턴스에 대해 같은 객체 참조를 반환합니다.
    13      data: function () {
    14        return 0      // 객체마다 0 반환 (고유 값 배정됨)
    15      }
    16    })
    17
    18    new Vue({
    19      el: '#example-2'
    20    })
    21  </script>
    22  

컴포넌트간의 관계

컴포넌트는 주로 부모-자식 관계로 구성된다. 부모 컴포넌트의 템플릿에서 자식 컴포넌트를 지정해서 사용하는 방식이기 때문에 서로 간의 정보 소통이 필요하다.

컴포넌트 관계
[출처:Vue공식문서 - 컴포넌트 관계]

위의 그림과 같이 부모는 자식에서 속성 값을 전달하고, 자식은 부모에서 이벤트로 전달하는 방식을 취하기 때문에 각 컴포넌트의 코드가 격리된 상태로 운영되고 재 사용할 수 있다.

  • 부모에서 자식으로 데이터 전달

    • props 데이터 전달
      prop는 부모 컴포넌트의 정보를 전달하기 위한 사용지 지정 특성이며, 자식 컴포넌트는 props 옵션을 사용해서 받을 수 있다.
       1    <script>
       2      Vue.component('child', {
       3        // props 정의
       4        props: ['message'],
       5        // 데이터와 마찬가지로 prop은 템플릿 내부에서 사용할 수 있으며
       6        // vm의 this.message로 사용할 수 있습니다.
       7        template: '<span>{{ message }}</span>'
       8      })
       9    </script>
      10
      11    <child message="안녕하세요!"></child>   <!-- 부모 컴포넌트에서 message라는 props로 지정된 속성을 통해서 값 전달 -->
      12    
    • props 설정할 때의 camelCase, kebab-case 사용
      스크립트에서는 카멜케이스를 사용하지만 HTML에서는 대소문자를 구별하지 않기 때문에 템플릿에서 사용할 때는 케밥케이스를 사용해야 한다.
      1    <child my-message="안녕하세요!"></child>  <!-- HTML는 kebab-case를 사용해서 `my-message`로 표현 -->
      2
      3    <script>
      4      Vue.component('child', {
      5        props: ['myMessage'],      // JavaScript는 camelCase로 `myMessage`로 표현
      6        template: '<span>{{ myMessage }}</span>'
      7      })
      8    </script>
      9    
      문자열 템플릿을 이용하는 경우는 이 제한이 적용되지 않는다.
  • 자식 컴포넌트에서 부모 컴포넌트로 데이터 전달

    • 템플릿에 v-on:eventName을 지정해서 부모 자식간의 이벤트 전달 및 수신
    • 자식 컴포넌트에서 $emit(eventName)을 호출해서 부모로 전달할 이벤트 작동
       1  <div id="counter-event-example">
       2    <p>{{ total }}</p>      <!-- 자식 컴포넌트에서 잔달된 값을 누적해서 출력 -->
       3    <button-counter v-on:increment="incrementTotal"></button-counter>   <!-- v-on:increment 설정으로 자식에서 전달된 이벤트 수신하여 incrementTotal 메서드 호출 (부모 컴포넌트 입장의 이벤트 수신) -->
       4    <button-counter v-on:increment="incrementTotal"></button-counter>   <!-- v-on:increment 설정으로 자식에서 전달된 이벤트 수신하여 incrementTotal 메서드 호출 (부모 컴포넌트 입장의 이벤트 수신) -->
       5  </div>
       6
       7  <script>
       8    Vue.component('button-counter', {
       9      template: '<button v-on:click="incrementCounter">{{ counter }}</button>', // 자식 컴포넌트의 click 이벤트 처리
      10      data: function () {
      11        return {
      12          counter: 0
      13        }
      14      },
      15      methods: {
      16        incrementCounter: function () {
      17          this.counter += 1
      18          this.$emit('increment')   // 부모로 전달될 수 있도록 'increment' 이벤트 호출
      19        }
      20      },
      21    })
      22
      23    new Vue({
      24      el: '#counter-event-example',
      25      data: {
      26        total: 0
      27      },
      28      methods: {
      29        incrementTotal: function () {
      30          this.total += 1
      31        }
      32      }
      33    })
      34  </script>
      35  

동일 레벨 컴포넌트간의 통신

동일 컴포넌트간의 직접적인 통신 방법은 제공되지 않는다.

  • 동일한 Parent를 가지는 Child 간의 통신은 Child > Parent > Child 방식으로 통신을 해야 한다.
  • 상/하위 관계가 아닌 경우는 Event Bus 를 활용해야 한다. 이 때는 화면과 연동되는 Vue 인스턴스가 아닌 빈 인스턴스를 하나 더 만들어서 Event Bus 용도로 사용하면 된다.
     1  <script>
     2  var eventBus = new Vue();   // Event Bus로 활용하기 위한 별도의 Vue 인스턴스 생성
     3
     4  // 화면 처리용 Vue 인스턴스
     5  new Vue({
     6    // ...
     7  })
     8  ...
     9  // 데이터를 보낼 컴포넌트에서 `$emit` 사용
    10  eventBus.$emit('refresh', 10);
    11  ...
    12  // 데이터를 받는 컴포넌트에서 `$on` 사용, 단 Event Bus의 이벤트 수신은 라이프사이클 함수에서 처리
    13  new Vue({
    14    created: function() {
    15      // Vue created event hook에서 Event Bus 수신 처리 정의
    16      eventBus.$on('refresh', function(data) {
    17        console.log(data); // 10
    18      });
    19    }
    20  })
    21  </script>
    22  
  • 만일 Event Bus의 콜백 함수 내에서 해당 메서드를 참고할 경우는 vm사용
     1  <script>
     2    new Vue({
     3      methods: {
     4        callAnyMethod() {       // Event Bus에서 호출할 Vue 인스턴스내의 메서드
     5          // ...
     6        }
     7      },
     8      created() {
     9        var vm = this;       // Vue 인스턴스를 vm에 설정
    10        eventBus.$on('refresh', function(data) {
    11          console.log(this); // 여기서의 this는 이벤트 버스용 인스턴스를 가리킴
    12          vm.callAnyMethod() // vm은 현재 인스턴스를 가리킴
    13        });
    14      }
    15    })
    16  </script>
    17  

자바스크립트에서의 this는 상황에 따라서 다른 문맥객체로 동작한다. 위의 예제에서도 굳이 this를 vm이라는 변수로 설정해 놓는 이유도 외부 메서드와 내부 메서드의 문맥객체가 다르기 때문이다.
일반적으로 this는 아래와 같은 상황들에서 다른 문맥객체로 처리된다.
- 함수 실행 : this는 전역 객체 문맥을 가진다. (브라우저라면 아마도 window 객체일 것이다)
- 엄격모드에서의 함수 실행 : this는 undefined가 된다.
- 메서드 실행 : this는 메서드를 소유하고 있는 객체로서의 문맥을 가진다.
- 생성자 실행 : this는 새롭게 인스턴싱된 객체로서의 문맥을 가진다.
- …
실행되는 상태에 따라서 this는 의미가 다른 문맥을 가르키게 되므로 항상 이 부분을 조심해야 한다.

Vue Routers

Vue Router는 Vue 코어 라이브러리와 함께 공식 라이브러리로 제공되고 있다. 주로 Vue를 이용해서 SPA (Single Page Application) 어플리케이션을 작성할 때 사용된다.

설치는 CDN과 NPM 모두 지원한다.

  • CDN 설치
      <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
      
  • NPM 설치
      npm install vue-router --save
      

Vue 라우터는 기본적으로 'Root URL'/#/'Router name' 구조를 가진다.

example.com/#/user

위의 구조에서 기본 사용되고 있는 “#“을 제거하고 싶은 경우는 아래와 같이 속성을 지정하면 된다.

new VueRouter({
  mode: 'history'
})
  • Nested Router 라우터를 기준으로 화면을 이동할 때 Nested Router를 이용해서 지정된 하위 컴포넌트를 표시할 수 있다. 물론 컴포넌트의 구조는 Parent - Child 구조여야 한다.

     1  ...
     2  <!-- localhost:5000 -->
     3  <div id="app">
     4    <router-view></router-view>
     5  </div>
     6
     7  <!-- localhost:5000/home -->
     8  <div>
     9    <p>Main Component rendered</p>
    10    <app-header></app-header>
    11  </div>
    12  ...
    13  <script>
    14  ...
    15  // 'localhost:5000/home'에 접근하면 Main과 Header 컴포넌트 둘다 표시된다.
    16  {
    17    path : '/home',
    18    component: Main,
    19    children: [
    20      {
    21        path: '/',
    22        component: AppHeader
    23      },
    24      {
    25        path: '/list',
    26        component: List
    27      },
    28    ]
    29  }
    30  ...
    31  </script>
    32  

  • Named Views 특정 URL로 이동했을 때 여러 개의 컴포넌트를 동시에 표현할 수 있는 방법이다.

     1  ...
     2  <div id="app">
     3    <router-view name="appHeader"></router-view>
     4    <router-view></router-view>
     5    <router-view name="appFooter"></router-view>
     6  </div>
     7  ...
     8  {
     9    path : '/home',
    10    // Named Router
    11    components {
    12      appHeader: AppHeader,
    13      default: Body,
    14      appFooter: AppFooter
    15    }
    16  }
    17  ...
    18  </script>
    19  

  • Nested Router vs. Named Views

    • 특정 URL에 지정된 1개 이상의 컴포넌트가 여러 개의 하위 컴포넌트를 갖는 것을 Nested Router라고 한다.
    • 특정 URL에 여러 개의 컴포넌트를 영역 별로 지정해서 렌더링하는 것을 Named View라고 한다.
Nested Routers vs. Named Views
[ Nested Routers vs. Named Views ]

HTTP 통신

Vue에서 HTTP 통신을 위해서 가장 많이 사용하는 라이브러리는 Axios로 CDN과 NPM 설치 방식을 모두 지원하며 사용하기 편리한 API와 속성들이 많다. 기본적으로 Promise 기반이기 때문에 코드를 간결하게 작성할 수 있다.

  • CDN 설치
      <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
      
  • NPM 설치
      npm install axios
      

실제 사용 방법은 다음과 같다.

...
methods: {
  fetchData: function() {
    axios.get('URL 주소')
      .then(res => {
        console.log(res.data)
      })
  }
}
...

좀 더 자세한 설명과 샘플은 아래의 참고자료 참고

Vue Template

템플릿은 Vue에서 화면을 표현하기 위해서 제공되는 문법으로 Vue 인스턴스에서 관리하는 데이터와 화면과의 연계를 위한 데이터 바인딩(Data Binding)과 화면의 조작을 위한 지시자(Directive)로 나뉜다.

  • Data Binding
    "{{ ... }}"를 활용해서 인스턴스의 data, computed, props 속성들을 연결할 수 있다. 또한 간단한 자바스크립트 표현식도 사용할 수 있다.
      <div>{{ str }}</div>
      <div>{{ number + 1 }}</div>
      <div>{{ message.split('').reverse().join('') }}</div>
      
  • Directive
    HTML 태그의 속성에 v- 접두사가 붙은 특별한 속성으로 화면의 DOM 조작을 쉽게할 수 있는 문법들을 제공한다.
      <!-- 조건문 처리 : seen의 true/false에 따라 p 태그의 표시여부 결정 -->
      <p v-if="seen">Now you see me</p>
      <!-- 화면에 a 태그가 표시되는 시점에 Vue 인스턴스에서 관리하는 url 데이터 값을 href 속성 값으로 바인딩 처리 -->
      <a v-bind:href="url"></a>
      <!-- button의 클릭 이벤트로 doSomething이라는 메서드를 실행 -->
      <button v-on:click="doSomething"></button>
      
  • Filters
    화면에 표시되는 텍스트의 형식을 편하게 설정할 수 있도록 하는 기능으로 파이프 문자(|)를 이용해서 여러 개의 필터를 적용할 수 있다.
     1  <!-- message 값에 capitalize 필터를 적용하여 첫 글자를 대문자로 변경 -->
     2  {{ message | capitalize }}
     3  ...
     4  <script>
     5    new Vue({
     6      filters: {
     7        capitalize: function(value) {
     8          if (!value) return '';
     9          value = value.toString();
    10          return value.charAt(0).toUpperCase() + value.slice(1);
    11        }
    12      }
    13    })
    14  </script>
    15  
    위의 샘플은 “message” 데이터를 출력하는데 “capitalize”라는 Vue 인스턴스에 정의된 Filters 메서드를 호출해서 첫 글자를 대문자로 변경한 후에 이 결과를 출력하도록 처리하는 방식이다.

Single File Component

UI에 대해서 특정 기능을 제공하는 컴포넌트로 하나의 파일 내에서 HTML, CSS, JS 코드를 모두 지원한다. 확장자는 .vue를 사용하고 HTML 파일 내에서 Vue 개발을 진행했을 때의 한계를 극복할 수 있는 방법이다.

HTML 파일 내에서 개발할 때의 한계점들은 다음과 같다.

  • 모든 컴포넌트의 유일한 식별을 위해서 공유의 이름을 지정해야 한다.
  • js 파일에서 template 안의 HTML 문법 강조가 되지 않는다.
  • js 파일에서 css 스타일 작업이 거의 불가능하다.
  • ES5를 이용해서 계속 앱을 작성할 경우 Babel 빌드가 지원되지 않는다.

기본적인 골격은 다음과 같다.

<template>
  <!-- HTML -->
</template>

<script>
  // Javascript
</script>

<style>
  /* CSS */
</style>

Vue Loader

Single File Component로 작성된 컴포넌트를 브라우저에서 실행가능한 자바스크립트 파일로 변환해 주는 Webpack Loader로 Vue Loader를 사용하면 다음과 같은 장점이 있다.

  • ES6 지원
  • <style>, <template>에 대한 각각의 Webpack Loader 지원 (eg. sass, jade, …)
  • .vue 컴포넌트의 범위(scope)로 대상으로 하는 css 스타일 지원
  • Webpack 모듈 번들링에 대한 지원과 의존성 관리 제공
  • 개발 시에 HMR (Hot Module Replacement) 지원

Vue CLI

Vue CLI3는 Vue.js 개발을 위한 시스템으로 Vue.js Core에서 공식으로 제공하는 CLI (Command Line Interface)로 Vue 어플리케이션 개발에 집중할 수 있도록 프로젝트 생성을 위한 명령어 도구로 Node 기반에서 동작하므로 당연히 Node가 사전 설치가 되어 있어야 한다.

또한 Vue 생태계에서 표준 툴을 목표로 하고 있다. 프로젝트를 구성하고 스캐폴딩에 도움을 주는 것이기 때문에 반드시 필요한 것은 아니지만 Vue.js와 관련된 오픈소스들은 대부분 Vue CLI를 통해서 설치가 가능하기 때문에 사용하는 것이 좋다.

주요 사용은 다음과 같다.

  • vue 명령어
    • $ vue create : 프로젝트 생성
    • $ vue ui : 제공되는 ui를 통해서 프로젝트 관리
  • CLI Service : webpack, webpack-dev-server 위에 구축되며 CLI Plugin을 실행하는 핵심 서비스와 webpack에 대한 설정을 포함하고 있다. 즉, webpack을 기반으로 어플리케이션의 개발, 빌드, 실행을 처리한다.
  • CLI Plugin : Babel, Typescript, ESLint, e2d Test 등과 같은 선택적으로 설치가 필요한 Plugin을 말하며, 프로젝트 생성 시점에 포함하거나 이후에 포함시킬 수 있다.

자세한 내용은 아래의 참고자료를 참고하면 된다.

Virtual DOM

React처럼 Vue도 Virtual DOM을 사용한다. Virtual DOM은 화면을 위한 기반 기술로 화면의 DOM에 추가/삭제 등의 변경이 발생하면 화면을 다시 그리는 것이 아니라 자바스크립 상에 객체로 DOM의 구조를 설정해 놓고, 실제 변경이 발생한 경우에 그 부분만 화면을 그릴 수 있도록 해서 브라우저가 화면을 다시 그리는 부하를 줄이는 기법이다.

동작하는 방법은 아래와 같이 추상적으로 예상해 볼 수 있다.

  1. DOM이 Load되면 DOM의 Tag들을 Javascript JSON 객체로 복제한다.
  2. Vue의 변경에 대한 작업은 모두 복제된 JSON 객체를 대상을 이루어진다.
  3. JSON 객체에서 Diff 정보를 추출한다.
  4. Diff 정보를 기준으로 실제 DOM의 어떤 부분이 변경되었는지를 확인하고 해당 부분만 갱신한다.

자세한 샘플은 아래의 참고자료를 참고하면 된다.

참고자료