뷰의 장점 중 하나는 빠른 프로토 타이핑이 가능하다는 점이다.
뷰 CLI로 프로젝트를 생성하고 나면 npm으로 원하는 기능들을 빠르게 확장해 나갈 수 있다.
뷰 CLI 2.9 버전을 이용하여 webpack.simple 프로젝트를 아래와 같이 생성한다.
vue init webpack-simple folder-structure
프로젝트를 생성하고 나면 기본적인 폴더 구조는 아래와 같이 구성된다.
.
├─ README.md
├─ index.html
├─ webpack.config.js
├─ package.json
└─ src
├─ main.js
├─ App.vue
└─ assets
└─ logo.png
실무에서 개발할 때 필수로 사용되는 라우터, 사용 관리, 필터, 다국어, 플러그인 등을 이용하면 아래와 같이 폴더를 구분할 수 있다.
.
├─ README.md
├─ index.html
├─ webpack.config.js
├─ package.json
└─ src
├─ main.js
├─ App.vue
├─ components 컴포넌트
│ ├─ common
│ └─ ...
├─ router 라우터
│ ├─ index.js
│ └─ routes.js
├─ views 라우터 페이지
│ ├─ MainView.vue
│ └─ ...
├─ store 상태 관리
│ ├─ auth
│ ├─ index.js
│ └─ ...
├─ api api 함수
│ ├─ index.js
│ ├─ users.js
│ └─ ...
├─ utils 필터 등의 유틸리티 함수
│ ├─ filters.js
│ ├─ bus.js
│ └─ ...
├─ mixins 믹스인
│ ├─ index.js
│ └─ ...
├─ plugins 플러그인
│ ├─ ChartPlugin.js
│ └─ ...
├─ translations 다국어
│ ├─ index.js
│ ├─ en.json
│ └─ ...
└─ assets css 등의 웹 자원
├─ css
├─ images
└─ ...
코드 분할(Code Splitting)은 싱글 페이지 애플리케이션의 성능을 향상시키는 방법이다.
싱글 페이지 애플리케이션(Single Page Application)은 초기 실행시에 필요한 웹 자원을 모두 다운 받는 특징이 있다.
코드 분할을 활용하게 되면 초기 로딩시에 모든 웹 자원을 다운받지 않고 필요한 시점에 다운 받아 성능상의 이점이 생긴다.
참고로 뷰에서 코드 분할이 가능한 이유는 뷰의 비동기 컴포넌트 로딩과 웹팩의 코드 스플리팅 기술 덕택이다.
다만 지연된 로딩(Lazy Loading) 방법을 적용하기 위해서는 아래와 같은 개발 환경을 갖고 있어야 한다.
바벨 Syntax-dynamic-import 설치 방법
뷰 CLI로 생성한 경우에는 이미 1번과 2번을 만족하고 있겠지만 3번의 경우에는 별도의 설치가 필요하다.
바벨 Syntax-dynamic-import 플러그인 설치는 아래의 절차를 따른다.
1. syntax-dynamic-import 플러그인 설치npm install --save-dev babel-plugin-syntax-dynamic-import
.babelrc
파일에 아래와 같이 플러그인 설정 추가{ "plugin": ["syntax-dynamic-import"] }
싱글 페이지 애플리케이션에서 뷰 라우터를 사용할 때 라우팅 별로 코드를 분할하는 방법은 아래와 같다.
{
path: 'url 이름',
component: () => import('컴포넌트 이름')
}
위와 같은 방법은 지연된 로딩(Lazy Loading)이라고 한다.
이는 애플리케이션 규모가 커져 싱글 페이지 애플리케이션의 초기 화면 로딩 시간을 줄일 때 사용하는 방법이다.
왜냐면 화면이 10개인 웹 앱이 있는데 애플리케이션을 처음 시작했을 때 쓰지도 않을 나머지 화면 9개를 불러오는 것 보다는 특정 화면으로 이동할 때마다 해당 화면의 내용을 추가적으로 불러온느 것이 애플리케이션 로딩 속도 면에서 더 효율적이기 때문이다.
위 환경을 구성하고 나면 아래와 같이 특정 URL에 따른 코드 분할이 가능해진다.
const routes = [
{
path: '/login',
name: 'login',
component: () => import('./LoginPage.vue')
},
{
path: '/main',
name: 'main',
component: () => import('./MainPage.vue')
},
];
new VueRouter({
mode: 'history',
routes: routes,
})
네비게이션 가드(Navigation Guard
)는 특정 URL에 접근 (Navigation) 하기 전에 불려지는 훅(Hook)의 일종으로, 다른 페이지로 우회 하거나 접근 자체를 취소시킬 수 있기 때문에 네비게이션 가드라고 불린다.
사용자의 권한에 따라 페이지 접근을 막거나 페이지를 로딩하기 전에 데이터를 미리 불러올 때 사용하기 좋은 기술이다.
사실상 싱글 페이지 애플리케이션을 구현할 때는 거의 필수로 구현해야 한다.
네비게이션 가드의 종류는 적용되는 위치, 범위에 따라서 전역, 지역, 컴포넌트 3가지로 나뉜다.
전역 가드는 모든 라우팅에 적용되는 네이게이션 가드다.
라우터의 beforeEach
라는 메소드를 통해 전역가드의 로직을 설정할 수 있다.
아래는 전역 가드를 설정하는 예시 코드이다.
var router = new VueRouter();
router.beforeEach(function(to, from, next) {
// ...
});
뷰 라우터 인스턴스를 하나 생성하고 해당 인스턴스를 참조하는 변수에 beforeEach()
API를 호출한다.
인자로 받은 3개의 변수는 다음과 같은 역할을 한다.
TIP
next
함수의 인자에 따라서 라우팅 허용 여부가 달라진다.
next()
: 라우팅 승인
next(false)
: 라우팅 취소
next('/')
: 특정 라우트로 진입 (route.push
처럼 진입하고자 하는 경로 지정 가능. 참조)
WARNING
라우팅 허용 여부에 상관없이 반드시
next
를 호출해야한다.
호출되지 않을 경우 라우팅이 진행되지 않고 대기 상태에 빠진다.
지역 가드는 라우팅별로 적용되는 네비게이션 가드이다.
아래와 같이 특정 라우트의 beforeEnter
속성에 호출할 함수를 지정한다.
var router = new VueRouter({
routes: [
{
path: '/login',
component: Login,
beforeEnter: function(to, from, next) {
// 인증 값 검증 로직 추가
}
}
]
})
beforeEnter()
의 인자 3개는 앞에서 살펴본 내용과 동일하다.
컴포넌트 가드는 컴포넌트 인스턴스를 통해 라우팅을 제어하는 네비게이션 가드이다.
목적에 따라 다시 세 종류로 나뉘지만 인자들은 앞에서 살펴본 전역, 지역 가드와 동일하다.
beforeRouteEnter
는 컴포넌트 인스턴스가 생성되기 전에 호출된다.
인스턴스 생성 전이기 때문에 this
를 통한 인스턴스 접근은 불가능하다.
대신 인스턴스를 조작하는 콜백을 next
에 전달하면 인스턴스가 생성된 이후에 콜백이 호출된다.
export default {
data() {
return {
state: 'pending',
}
},
beforeRouteEnter(to, from, next) {
// 네비게이션 승인 후 state를 업데이트
next((vm) => (vm.state = "approved"));
}
}
beforeRouteUpdate
는 동일한 컴포넌트를 사용하지만 페이지 주소가 바뀔 경우 호출된다.
동적 라우팅을 통해서 페이지의 주소만 바뀌고 같은 컴포넌트를 재활용하는 경우를 예로 들 수 있다.
new VueRouter({
routes: [{ path: '/foo/:id', component: Foo }],
});
// 현재 URL: /foo/1
export default {
beforeRouteUpdate(to, from, next) {
console.log(this.$route.params.id); // 1
next();
},
methods: {
moveToNext() {
// 페이지를 이동 하기전에 beforeRouteUpdate를 호출한다.
this.$router.push('/foo/2');
},
},
};
beforeRouteLeave
는 해당 컴포넌트를 벗어나 새로운 페이지로 이동할 때 호출된다.
보통 사용자가 변경사항을 저장하지 않고 갑작스럽게 사이트를 벗어날 경우 사용된다.
next(false)
로 페이지 이동을 막을 수 있다.
beforeRouteLeave(to, from, next) {
const answer = window.confirm('사이트에서 나가시겠스니까? 변경사항이 저장되지 않을 수 있습니다.');
if (answer) {
next();
} else {
next(false);
}
beforeRouteLeave
호출beforeEach
호출beforeRouteUpdate
호출beforeEnter
호출beforeRouteEnter
호출beforeRouteEnter
의 next
에 넘겨진 콜백 함수네비게이션 가드가 가장 많이 쓰이는 곳은 사용자 인증 정보에 따라 접근을 막는 로직이다.
router.beforeEach(function(to, from, next) {
// to: 이동할 url에 해당하는 라우팅 객체
if (
to.matched.some(function(routeInfo) {
return routeInfo.meta.authRequired;
})
) {
// 이동할 페이지에 인증 정보가 필요하면 경고 창을 띄우고 페이지 전환은 하지 않음
alert("Login Please!");
} else {
console.log("routing success: '" + to.path + "'" );
next(); // 페이지 전환
})
참고 자료
뷰는 라이브러리 내부적으로 트랜지션, 애니메이션 기능을 갖고 있다.
그래서 간단한 규칙과 속성들만 알면 쉽고 멋진 애니메이션 효과를 추가할 수 있다.
뷰 트랜지션 코드를 간단히 살펴보자.
<div>
<button @click="showComment">show</button>
<transtion name="fade">
<p v-if="status">This is a comment</p>
</transition>
</div>
new Vue({
...
data: {
status: false
},
methods: {
showComment() {
this.status = true;
}
}
})
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
위 코드에서 show 버튼을 클릭하면 This is a comment 라는 텍스트가 부드럽게 살며시 표시된다.
여기서 주목할 코드는 <transition>
이라는 태그이다.
<transition>
태그는 name
속성을 갖고 있고, 해당 name
속성과 연관된 CSS 코드가 위에 정의되어 있다.
CSS 코드에 따라서 텍스트가 표시될 때 opacity의 값이 변화되고, 이에 따라 살며시 나타나는 효과를 볼 수 있다.
앞의 코드에서 트랜지션 효과가 나타날 수 있었던 것은 바로 트랜지션 태그의 name
속성 덕택이다.
name
속성에 맞춰 아래와 같이 CSS 코드를 구현했다.
<transition name="fade">
</transition>
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
fade-enter-active
, fade-leave-active
등으로 볼 수 있듯이 뷰의 트랜지션 CSS 코드는 일정한 규칙을 갖는다.
여기서 사용하는 CSS 클래스는 아래와 같이 6개가 있다.
일반적으로 v-enter
, v-leave-to
를 함께 사용하고, v-enter-to
, v-leave
를 함께 사용한다.
그림의 색깔을 보면 짝 지어져서 잘 구분되어 있다.