목표
본 포스팅에서는 SPASingle Page Application 개발에 앞서 SPA에 대한 이해 및 자바스크립트 프레임워크 Vue.js에 대한 기본적인 이해를 목표로 하고 있습니다. (MPA 웹 서비스 및 MVC 패턴에 대한 기본적인 이해를 바탕으로 작성하였습니다.)
목차
- JavaScript Framework의 사용 배경
- MPA 개발에서 SPA 개발까지
- SPA 라우팅에 대한 이해
①Link 방식
②Ajax 방식
③Hash 방식 - JavaScript Framework의 주 활용 요소
- VUE
- 주요 라이브러리
①VUE Router
②VUE CLI
③Vuex
(1) State란
(2) State 관리의 필요성
(3) 구성 요소
(4) State, Getters, Actions, Mutaitions
(5) 렌더링 퍼포먼스에 대해서 - 정리
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를 매번 받아와야 하므로 퍼포먼스 측면에서 손해를 봅니다.

② AJAX 방식
이를 보완하기 위하여 자바스크립트에서 비동기Asynchronous로 서버와 브라우저가 데이터를 교환할 수 있는 통신 방식을 활용하게 되는데, 이 통신 방식이 AJAXAsynchronous JavaScript and XML입니다.
페이지에서 업데이트가 필요한 부분만을 로드하여 갱신하고, 새로고침 없이 불필요한 리소스의 중복 요청을 막기 때문에 퍼포먼스 측면에서 더 우수합니다. 데이터 부분이 비워져있는 html을 서버에서 받아오며, 페이지 로드 시 JavaScript로 데이터를 가져와서 채워 넣습니다.

이 때, 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
가 있습니다.

(1) 유저가 View(Template)
에서 버튼을 클릭
(2) Actions(Method)
에서 메소드 호출 및 동작
(3) Action
s 수행 후 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
에 프로젝트에서 공통으로 공유할 데이터를 저장해 둘 수 있으며, 최초 저장만으로 어느 컴포넌트에서든 해당 데이터를 조회할 수도, 수정할 수도 있습니다.