[VUE] SPA 웹 프론트앤드 개발을 위한 정리

일본어 번역본: [VUE]SPAウェブフロントエンド開発ためのまとめ


목표

본 포스팅에서는 SPASingle Page Application 개발에 앞서 SPA에 대한 이해 및 자바스크립트 프레임워크 Vue.js에 대한 기본적인 이해를 목표로 하고 있습니다. (MPA 웹 서비스 및 MVC 패턴에 대한 기본적인 이해를 바탕으로 작성하였습니다.)




목차

  1. JavaScript Framework의 사용 배경
  2. MPA 개발에서 SPA 개발까지
  3. SPA 라우팅에 대한 이해
    ①Link 방식
    ②Ajax 방식
    ③Hash 방식
  4. JavaScript Framework의 주 활용 요소
  5. VUE
  6. 주요 라이브러리
    ①VUE Router
    ②VUE CLI
    ③Vuex
     (1) State란
     (2) State 관리의 필요성
     (3) 구성 요소
     (4) State, Getters, Actions, Mutaitions
     (5) 렌더링 퍼포먼스에 대해서
  7. 정리




1. JavaScript Framework의 사용 배경


자바스크립트 프레임워크가 등장하기 전에는, 프론트 로직을 플레인 자바스크립트나 jQuery*1을 활용하여 구현하였습니다. JavaScript 프레임 워크는 프론트엔드의 개발이 복잡해지면서 등장하였습니다.

JavaScript 프레임 워크를 활용하면 SPA(Single Page Application)*2 등 고급 웹 애플리케이션을 개발하는 데 훨씬 용이합니다.

*1 jQuery: DOM을 쉽게 조작하기 위한 라이브러리
*2 SPA: 단일 페이지 어플리케이션(Single Page Application)의 형태로 웹을 개발하는 것을 의미, 자세한 내용은 2번 참고




2. MPA 개발에서 SPA 개발까지


기존의 MPA(multiple-page application)웹 서비스는, 클라이언트의 리퀘스트request가 있을 때마다 서버로부터 리소스resource들과 데이터를 받아와 화면에 새롭게 렌더링rendering을 하는 방식이었습니다. 링크 <a href="#">를 클릭하면 해당 페이지로 이동하게 되며, 명시 되어있는 자원을 서버로 요청하여 응답을 받아옵니다.
이처럼, MPA방식은 매 페이지마다 서버측으로 html 문서를 요청하기 때문에 중복되는 데이터를 받아올 수 밖에 없었습니다.

한편, SPA 웹 서비스는 위와 같은 기존 웹서비스의 한계를 보완합니다. 최초 로드 시, 전체 페이지를 로드 한 후부터는 기존의 페이지와 비교하여 갱신이 필요한 특정 부분만을 json형태로 데이터를 가져와 바인딩binding합니다.
따라서, SPA방식은 Ajax(3번 참고)로 데이터를 가져와 필요한 부분만을 갱신 하도록 자바스크립트를 작성합니다.




3. SPA 라우팅에 대한 이해


*라우팅(Routing)이란?
데이터를 보낼 최적의 경로를 선택하는 과정으로, 주어진 데이터를 최적화 된 형태로 주고받을 수 있는 경로를 선택하는 과정 입니다.


① 링크 방식(전통적 방식)


링크 방식은 아래의 과정을 포함하고 있습니다.

(1) link tag(<a href="#">) 클릭
(2) href 속성attribute값인 리소스의 경로가 URL의 path에 추가
(3) 브라우저의 주소창에 path값 표시
(4) 해당 리소스를 서버에 요청

클라이언트 측에서 (1)~(4)를 거치게 되면, 서버 측에서는 완전한 리소스를 html 형태로 응답합니다. 또한, 브라우저 측에서는 이 html을 받아 렌더링 합니다. 이전 페이지에서 새로 받아온 페이지로 전환하는 방식은, 전체 페이지를 다시 렌더링하는 방식으로, 새로고침reload이 발생하고 히스토리history가 남으며 뒤로가기를 사용할 수 있습니다. 이 때, 클라이언트의 리퀘스트마다 중복된 HTML과 JavaScript, CSS를 매번 받아와야 하므로 퍼포먼스 측면에서 손해를 봅니다.



출처: ASP.NET – Single-Page Applications / 전통적인 페이지 수명 주기



② AJAX 방식


이를 보완하기 위하여 자바스크립트에서 비동기Asynchronous로 서버와 브라우저가 데이터를 교환할 수 있는 통신 방식을 활용하게 되는데, 이 통신 방식이 AJAXAsynchronous JavaScript and XML입니다.

페이지에서 업데이트가 필요한 부분만을 로드하여 갱신하고, 새로고침 없이 불필요한 리소스의 중복 요청을 막기 때문에 퍼포먼스 측면에서 더 우수합니다. 데이터 부분이 비워져있는 html을 서버에서 받아오며, 페이지 로드 시 JavaScript로 데이터를 가져와서 채워 넣습니다.



출처: ASP.NET – Single-Page Applications / SPA 수명주기



이 때, AJAX는 URL을 변경 시키지 않으므로 주소창의 주소가 변경되지 않습니다. 이는 브라우저의 히스토리history 관리가 불가능하며, 뒤로가기를 사용할 수 없음을 의미합니다. (이 외에도 SEO에 대한 이슈도 있습니다.)


③ HASH 방식


위의 AJAX를 보완하기 위해 등장한 클라이언트 라우팅 방식이 Hash입니다.

Hash 방식은 앵커anchor를 사용하는 방식으로, link tag(<a href="#hash">등)의 href 속성에 hash(#)를 사용합니다. 클릭 시 문서에서 #뒤에 붙은 id를 가진 요소로 이동합니다.

동일한 URL에서 Hash가 변경 될 경우,
브라우저 측에서는 이를 URL이 바뀐 것으로 인식하나, 실제로 클라이언트 측에서 서버 측으로 리퀘스트를 보내거나 하지는 않습니다. 앵커로 웹 페이지 내부에서의 이동을 위한 것이기 때문입니다. 요청을 하지 않기 때문에 페이지의 갱신은 없으나, 페이지가 각각의 고유한 URL을 가지므로 히스토리history 관리가 가능합니다.

위에 언급한 3가지 방식 외에도 PJAX(html5 pushState + ajax)도 있습니다.




4. Javascript Framework의 주 활용 요소


  • 라우팅
    : 공식적인 라우팅 라이브러리를 제공합니다.

  • 템플릿
    : 렌더링 된 DOM을 기본 인스턴스의 데이터에 선언적으로 바인딩 할 수 있는 HTML 기반 템플릿 구문을 사용합니다.
    (이 부분은 dJango에서도 지원을 해 줬던 것 같다)

  • 컴포넌트 재사용
    Web 컴포넌트는 Web 페이지와 Web 어플리케이션 사이에서 캡슐화 된 재사용이 가능한 HTML 태그를 생성할 수 있습니다.




5. VUE

가상 DOM을 활용할 수 있으며, DOM을 통해 모든 요소를 실시간 반응형 컴포넌트로 제작할 수 있는 자바스크립트 프레임워크 입니다. 보통 프로젝트의 규모가 커질수록 다양한 형태의 컴포넌트가 생성되기 때문에, 이를 관리하는 데에 도움이 되는 라우팅 관리 및 글로벌 상태를 관리하는 라이브러리 등을 제공합니다.


6. 주요 라이브러리


① VUE Router

Vue을 이용하여 SPA 웹을 구축할 때, 라우팅 제어를 위한 공식 플러그인입니다.

  • VueRouter을 이용하여 URL 히스토리를 관리할 수 있습니다.
  • 브라우저에서 뒤로 가기앞으로 가기 동작을 가능하게끔 하며, 유저로 하여금 사용성을 향상 시킵니다.

[라우팅을 정의하는 형식]

// views/Home.vue (템플릿 구성요소)
<template>
  <div class="home">
    <h1>Home</h1>
  </div>
</template>

// src/router.js (라우팅 정의)
import  Vue  from  ' vue ' 
import  Router  from  ' vue-router ' 
import  Home  from  ' ./views/ '

Vue . use ( Router )

export  default  new  Router ({ 
  mode :  ' history ' , 
  routes :  [ 
    { 
      path :  ' / ' , 
      name :  ' home ' , 
      component :  Home 
    } 
  ] 
})

이후 링크로 정의할 시, 템플릿의 아래와 같은 구문을 삽입하여 사용할 수 있습니다.

  < router-link to = "/" > Home </ router-link > 



②VUE CLI Command Line Interface


Vue-cli로 명령어를 실행 시키면 cli가 자동으로 최적화 된, 프로젝트의 기본 골격을 생성 합니다.  뿐만 아니라, 아래와 같은 설정이 가능합니다.

  • Vue 프로젝트 생성 
  • Vue 라이브러리 관리 
  • Vue 배포 파일 설정 : 최적화된 Webpack*1 형태의 결과물을 생성 합니다.
  • Vue GUI 제공



*1Webpack: JS, CSS, 이미지를 하나의 JS파일로 묶어주는 모듈입니다. 개발자가 작성한 JS와 프로젝트 내 필요한 라이브러리를 로드하는 JS, 작성한 CSS파일 및 이미지 파일까지 정리할 수 있습니다. 이미지 파일의 경우 DataURI (Base64 형식)으로 변환하여 JS 파일에 정리 합니다.

*dJango에서 프로젝트를 생성하고, 라이브러리를 관리하고, 배포 시 정적 파일 관리를 제공했던 것들과 유사한 느낌



③Vuex

Vue 컴포넌트에서 활용 할 데이터를 관리하는 것을 목적으로 하는, 스테이트State 관리 라이브러리입니다.

1) State

*공식 문서에서 state 데이터를 상태 관리 패턴으로 번역을 하여 이래저래 헷갈렸던 부분 (디자인 패턴 중에 스테이트 패턴을 접목 시킨 줄)으로, mutation도 각 번역마다 말이 달라 개발을 어느 정도 진행한 후에야 확실히 정의할 수 있었습니다.

모든 클라이언트 쪽 컴포넌트에서 공통적으로 사용할 수 있도록 빼놓은 클라이언트 용 데이터를 말합니다. 일반적으로 클라이언트 쪽에 데이터를 뿌려주기 위해서는 서버로부터 데이터를 받아와야 한다는 번거로움이 있습니다. State를 사용할 경우, 최초에 서버에서 받아온 데이터를 State에 보관 후 필요한 부분에 대한 데이터만 꺼내 사용하게 됩니다.

2) State 관리의 필요성

MVC 패턴의 복잡한 데이터 흐름 문제는 대규모 어플리케이션 개발 시 MVC 패턴에서 발생하는 구조적 오류를 야기합니다. 복잡한 화면과 데이터의 구성이 필요할 시 Controller에 다수의 Model과 View가 얽히기 때문입니다. 따라서 기존의 MVC간의 의존성을 제거하기 힘들어지고, 이는 기능 추가 및 업데이트 시 생기는 문제점을 해결하기 복잡하게 만듭니다.

Vuex는 컴포넌트 간의 데이터 전달을 View, Action, State로 명시적으로 표현하여, 보다 데이터의 흐름을 단순하게 유지합니다.

3) 구성 요소

Vuex 구성요소는 View, Actions, State가 있습니다.

출처: https://vuex.vuejs.org/ (vuex 공식 문서)



(1) 유저가 View(Template)에서 버튼을 클릭
(2) Actions(Method)에서 메소드 호출 및 동작
(3) Actions 수행 후 State(data)를 변경

View는 클라이언트 쪽에 노출 될 탬플릿을 의미합니다. 클라이언트 측에서 View를 통해 데이터 저장 등의 동작을 요청하면, 요청에 따라 Actions에서는 백앤드 쪽과 요청 및 응답을 주고받게 됩니다.

State의 경우 클라이언트 조작에 필요한 데이터를 공유합니다. Actions를 통해 백앤드 API를 호출하여 요청에 맞는 데이터를 받아오면, 컴포넌트 간에서 해당 데이터를 모두 공유할 수 있도록 State에 저장합니다.

각 컴포넌트에서는 State에 프로젝트에서 공통으로 공유할 데이터를 저장해 둘 수 있으며, 최초 저장만으로 어느 컴포넌트에서든 해당 데이터를 조회할 수도, 수정할 수도 있습니다.

(4) State, Getters, Actions, Mutations
  • State
    모든 컴포넌트에서 동일한 데이터를 사용할 수 있도록 공통적인 변수를 선언합니다.
  • Getters
    컴포넌트 내에서 State에 특정 처리를 진행한 후 컴포넌트에 바인딩 하는 경우, Getters에 해당 로직을 정의한 후 각 컴포넌트에서 호출할 수 있습니다.
    예시) State에 포함되는 모든 데이터 중, 특정 데이터만 가져오는 경우
  • Actions
    응답을 받아오는 부분의 텀이 일정하지 않을 경우 등의 대기가 필요하지 않은 비동기 로직이 들어가는 처리를 작성합니다.
  • Mutations
    State에 존재하는 변경하는 로직들을 작성하며, State의 값을 변경시키는 것은 Mutations 안에서만 변경되어야 합니다.

    하지만, 개발자가 Mutation을 직접 호출하는 경우는 없으며, State를 변경하는 commit 등의 메소드를 사용하는 등의 방법으로 간접적으로 사용하게 됩니다.

    Mutation의 경우, 각 컴포넌트에서 State를 변경한 이력들을 확인할 수 있습니다. 각 변경 건에 대해 하나하나 동기적으로 처리 하여 모든 이력을 남기기 때문에, 서로 다른 컴포넌트에서 State를 변경하여도 충돌하지 않습니다.

(5) 렌더링 퍼포먼스에 대해서


Vue의 getters의 경우, 사용할 때 마다 매번 연산 처리가 들어가는 방식이기 때문에 많은 양의 데이터를 처리하는 경우 성능이 급격하게 저하되는 현상이 있었습니다. 한 컴포넌트에서 불러오는 데이터의 건 수(row 기준)가 3000건이 넘어갈 때, 평소 초당 60프레임의 성능을 보여주었다면, 많은 양의 데이터를 무작정 getters로 불러오면 초당 2프레임이 지속되다 멈추는 현상을 확인할 수 있었습니다.



프레임 저하 현상이 지속되는 구간


이러한 현상을 개선하기 위해, 첫 번째로는 state로 읽어오는 것이 아닌, 서버 쪽의 api를 이용하여 필요한 부분의 데이터만 직접 받아 오는 방식으로 작성했습니다. state를 통하지 않고 서버로부터 직접 받아와 뿌려주기 때문에 서버 쪽에서 받아오는 시간만이 들었고, 컴포넌트를 렌더링하는 데에는 많은 시간이 들지 않았습니다.

두 번째로는 해당 컴포넌트에 페이지네이션을 추가를 하였습니다. 최초 데이터는 모두 읽어온 후 클라이언트 쪽에서 페이징을 처리하는 방식이었기 때문에 프레임 저하에는 큰 도움이 안됐으나, 브라우저가 실행 중단이 되어버리는 현상이 사라졌습니다.


같은 페이지를 두 번 불렀을 때의 현상. 확실히 이전보다 프레임 저하 구간이 짧아지고 떨어지는 폭도 줄었다




7. 정리


Vue.js는 자바스크립트 프레임워크 중 하나로, SPA 개발에 특화되어 있습니다.

  • SPA
    SPA 웹은 최초 로드 시, 전체 페이지를 로드 한 후부터는 기존의 페이지와 비교하여 갱신이 필요한 특정 부분만을 json형태로 데이터를 가져와 바인딩binding합니다.

  • Vue.js로 웹을 개발할 시, 프로젝트 구축 및 기타 작업을 수행해 줄 Vue-Cli, 라우팅을 담당해 줄 Vue Router, 컴포넌트 간의 State 관리를 담당 할 Vuex를 사용합니다.

  • Routing
    SPA웹의 사용성 한계를 보완하기 위해서는, 라우팅을 담당해 줄 라이브러리를 이용하여 히스토리의 관리를 하는 것이 좋습니다.

  • State 관리
    각 컴포넌트에서는 State에 프로젝트에서 공통으로 공유할 데이터를 저장해 둘 수 있으며, 최초 저장만으로 어느 컴포넌트에서든 해당 데이터를 조회할 수도, 수정할 수도 있습니다.