2 뷰 라우터 설정
source: categories/study/vue-project/vue-project_2.md
2 뷰 라우터 설정
- 사용자가 접속한 주소에 따라 페이지(컴포넌트)가 달라지는 것을 라우팅이라고 합니다.
- 이번 챕터에서는 라우팅이 무엇인지 이해하고, Vue에서 라우팅 처리를 위해 사용하는 플러그인인
vue-router
에 대한 설치 및 사용 방법에 대해서 알아봅니다. - 또한
Vue CLI
의prefetch
기능에 대해서 정확히 이해하고, 컴포넌트의 로딩 시점을 설계하는 방법에 대해서 익히게 됩니다.
2.1 라우팅이란?
- 여러분이 특정 웹 페이지에 접속했을 때, 메뉴 혹은 특정 링크를 클릭하면 화면이 전환되는 것을 보았을 것입니다.
-
이때 브라우저 주소란을 보시면 페이지가 이동될 때마다 url 주소가 달라지는 것을 확인할 수 있습니다.
-
Vue와 같은 단일 페이지 어플리케이션의 경우 페이지를 이동할 때마다 서버에 요청해서 페이지를 새로 갱신하는 것이 아니라 클라이언트에서 미리 가지고 있던 페이지를 라우팅을 이용해서 화면을 갱신하게 됩니다.
- 라우팅이란 클라이언트에서 url 주소에 따라 페이지가 전환되는 것으로 이해하시면 됩니다.
- Vue 프로젝트 내부에서는 미리 url 주소를 정의하고, 각 주소마다 Vue 페이지를 연결해 놓습니다.
-
사용자가 메뉴를 클릭하거나, 브라우저 주소를 직접 갱신했을 때 미리 정의된 url 주소에 해당하는 Vue 페이지로 화면을 전환시킵니다.
- Vue는 vue에서 제공하는 공식 플러그인인 vue-router를 이용해서 라우팅을 쉽게 구현할 수 있습니다.
2.2 Vue-Router 설치
- 터미널에 다음 명령어를 입력하여 vue-router 설치 및 기본 설정을 모두 완료할 수 있습니다.
vue add router
@vue/cli-plugin-router
가 설치됩니다.
설치가 끝나면 src
폴더에 router
, views
폴더와 파일이 생성됩니다.
이 상태에서 다음 명령어를 입력하여 서버를 재시작합니다.
npm run serve
브라우저에 http://localhost:8080
을 입력합니다.
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
const routes = [
{
path: '/',
name: 'Home',
component: Home,
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../vies/About.vue')
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
})
export default router
routes
배열에는 2개의 라우트가 등록되어 있습니다.- 첫 번째는 Home 컴포넌트이고, 두 번째는 About 컴포넌트에 대한 라우트입니다.
{
path: '/',
name: 'Home',
component: Home
}
- path: 브라우저에서 접속하는 url 주소를 정의합니다.
- component: 지정된 path로 들어왔을 때 보여줄 vue 컴포넌트, 앞으로 구현할 vue 파일을 연결하고, 해당 파일을 실행시킵니다.
index.js 파일 두번째 줄에 있는 import Home from '../views/Home.vue'
가 실제 src -> views
폴더에 있는 Home.vue
파일을 참조합니다.
앞으로 개발할 화면에 해당하는 vue
파일을 이렇게 import
하고, routes
안에 특정 path
와 맵핑을 해주면 사용자가 접속하는 브라우저 url 주소에 따라 원하는 vue 파일을 보여줄 수 있습니다.
- routes 배열의 두 번째 값에 path와 name 밑에 주석 처리된 부분이 있습니다.
- // route level code-splitting
- 라우트 레벨에서 코드를 분할하는 방법입니다.
- // this generates a separate chunk (about.[hash].js) for this route
- 이 라우트에 대한 chunk 파일이 분리되어 생성됩니다.
- // which is lazy-loaded when the route is vixited.
- 이 라우트에 방문했을 때 lazy-load(지연 로드) 됩니다.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
- 주석처럼 라우트 레벨에서 코드를 분할한 후 별도의 chunk 파일을 생성하고, 실제 이 라우트를 방문했을 때 리소스를 로드하게 됩니다.
- 여기서 chunk 파일은 about이라는 이름으로 생성됩니다.
- 컴포넌트
import
시/* webpackChunkName: "about" */
라는 주석으로 chunk 파일 이름을 정의했기 때문입니다.
- 첫 번째 등록된 라우트와 두 번째 등록된 라우트의 가장 큰 차이는 첫 번째는 사용자가 해당 path에 접근하지 않더라도 이미 vue 파일을 import 하는 것이고,
- 두 번째 방법은 path에 접근하기 전까지는 vue 파일에 대한 import가 일어나지 않습니다.
2.3 Lazy Load 적용하기 (비동기 컴포넌트)
Vue CLI를 통해 빌드하면 소스 코드가 하나의 파일로 합쳐지는데, 큰 프로젝트에서는 전체 소스 코드가 하나로 합쳐지면서 파일 용량이 매우 커집니다.
이 때문에 사용자가 웹사이트에 처음 접속했을 때 한 번에 큰 파일을 다운로드 받느라 초기 랜더링 시간이 오래 걸리게 되며 랜더링 속도가 너무 늦어져서 사용자가 좋지 않은 경험을 가질 수 있습니다.
물론 페이지가 한번 로드되고 나서는 페이지 전환이 매우 빠르기 때문에 굉장한 이점을 가질 수 있습니다.
하지만 만약에 사용자가 이용하는 페이지가 별로 없다면, 사용하지도 않을 전체 페이지 코드를 다운로드 받음으로써 생기는 이점이 없습니다.
Lazy Load는 리소스를 컴포넌트 단위로 분리하여 컴포넌트 혹은 라우터 단위로 필요한 것들만 그때그때 다운받을 수 있게 하는 방법입니다.
Vue에서 Lazy Load를 사용할 때 한 가지 주의해야할 것이 있습니다.
앞서 우리가 살펴본 라우터에서 Lazy Load로 컴포넌트를 import한 것은 내부적으로 Vue CLI의 prefetch 기능이 사용되는 것입니다.
Vue CLI3부터 prefetch
기능이 추가가 되었습니다.
prefetch
기능은 미래에 사용될 수 있는 리소스(about과 같은 비동기 컴포넌트)를 캐시에 저장함으로써, 사용자가 접속했을 때 굉장히 빠르게 리소스를 내려줄 수 있습니다.
굉장히 유용한 기능이지만, 비동기 컴포넌트로 정의된 모든 리소스를 당장 사용하지 않더라도 캐시에 담는 비용이 발생합니다.
즉, 별도로 분리된 chunk 파일 각각에 대한 request가 일어나고, 각각의 파일을 다운로드 받아서 캐시에 저장하게 되는 것입니다.
prefetch 기능을 사용하는 이유는 랜더링 시간을 줄이기 위해서인데, 잘못 사용하면 오히려 랜더링 시간이 늘어나게 됩니다.
Vue CLI에서 prefetch 기능은 기본값으로 true가 설정되어 있기 때문에, Lazy Load가 적용된 컴포넌트는 모두 prefetch 기능이 적용되어 캐시에 저장됩니다.
prefetch 기능은 다음과 같은 부분을 반드시 고려해서 사용해야 합니다.
prefetch 기능을 사용하면 request 요청 수가 증가합니다.
비동기 컴포넌트로 정의된 모든 리소스를 캐시에 담기 때문에 Request 수가 많아지게 됩니다.
- prefetch 기능이 적용된 경우: 요청 수 11 requests, Load 타입 311ms
- prefetch 기 사용하지 않는 경우: 요청 수 8 requests, Load 타입 253ms
- prefetch 기능을 사용하지 않으면 요청 수가 훨씬 줄어듭니다.
- 요청 수가 많다는 것은 서버와의 통신 수가 증가한다는 것이고, 내려받는 리소스 크기도 크다는 것입니다.
- prefetch 기능을 사용하지 않으면 라우터가 이동될 때마다 해당 라우터에서 필요한 리소스를 그때그때 가져오게 됩니다.
- 물론 한번 가져온 리소스는 다시 요청하지는 않습니다.
- prefetch 기능을 사용하면 애플리케이션의 첫 화면 접속 시 랜더링 속도가 느려질 수 있습니다.
- 첫 화면에서 사용되는 리소스를 가장 나중에 다운받게 되어 있습니다.
- 이 말은 아직 사용하지 않고 있는 화면에 대한 리소스를 모두 내려받고 나서야 첫 화면에서 사용되는 리소스를 내려받는다는 것입니다.
- 오히려 초기 랜더링은 prefetch 기능을 사용하지 않아야 더 빨리 로딩이 됩니다.
- prefetch 기능은 다른 화면에서 사용될 리소스를 미리 내려받아서, 애플리케이션에서 화면 전환 시 빠른 성능을 가져온다는 장점을 이용하기 위해서 사용되는 것입니다.
- 그래서 정말 필요한 컴포넌트에 대해서 prefetch 기능을 적용하는 것이 좋습니다.
- 라우터를 통해 이동되는 컴포넌트에서 사용되는 리소스가 크지 않다면 prefetch 기능을 사용하지 않더라도 사용자 접속 시점에 다운받아도 충분히 매끄럽게 동작할 수 있습니다.
- 물론 이동하는 컴포넌트에서 사용되는 리소스가 매우 크다면 prefetch 기능을 사용하지 않으면 라우터 이동 시 화면전환이 늦게 진행된다는 문제가 발생합니다.
- 그래서 prefetch 기능을 적절한 곳에 적용하는 고민이 반드시 필요하고, 프로젝트팀에서는 이 부분을 반드시 고려해야 좋은 애플리케이션을 서비스할 수 있습니다.
- 앞서 Vue CLI에서는 prefetch 기능이 기본적으로 true로 설정되어 있다고 했습니다.
-
prefetch 기능을 끄는 방법을 알아봅시다.
vue.config.js
파일을 생성하고 다음 코드를 추가합니다.
// vue.config.js
module.exports = {
chainWebpack: config => {
config.plugins.delete('prefetch'); // prefetch 삭제
}
}
prefetch 기능을 삭제해도, 우리는 비동기 컴포넌트 즉, Lazy Load로 컴포넌트를 사용할 수 있습니다.
컴포넌트 import 시 다음과 같이 처리하면 됩니다.
import (/* webpackPrefetch: true */ './views/About.vue');
- import 코드를 보면 주석으로 처리된
/* webpackPrefetch: true */
부분이 있습니다. - 이와 같이 컴포넌트 import 시 주석
/* webpackPrefetch: true */
을 넣어주면 해당 컴포넌트에 대해서는prefetch
가 적용됩니다. - Vue 애플리케이션 개발 시 기본적으로 prefetch 기능을 끄는 것을 권장합니다.
- Vue에서 prefetch 기능을 사용해서 비동기 방식으로 컴포넌트를 로드하는 것은 매우 중요한 부분입니다.
- 어떤 컴포넌트는 하나의 파일로 내려받을지,
- 그리고 어떤 컴포넌트는 prefetch를 적용해서 캐시에 넣어서 사용할지,
- 그리고 어떤 컴포넌트는 prefetch 없이 사용자의 접속 시점에 내려줄지를
- 어떻게 설계하느냐에 따라 전체 애플리케이션을 효율적으로 사용할 수 있게 되는 것입니다.
-
이 부분은 분명 사용자 경험에도 중요한 요소일 것입니다.
- 사용자가 접속할 가능성이 높은 컴포넌트는 한 번에 다운로드할 수 있게 설정하고,
- 사용자의 접속 빈도가 낮은 컴포넌트는 prefetch를 적용하거나, 사용자 접속 시점에 리소스를 다운로드 받게 해서 전체 애플리케이션에 대한 리소스를 내려받는 시점을 분리합니다.
- 물론 초기 설계 시 적용한 방법을 그대로 유지하기보다는, 시스템 운영을 통해 사용자가 접속하는 페이지 및 빈도에 대한 현황 조사를 통해 지속적으로 라우터 설정을 개선해 나갑니다.
- 다시 본론으로 돌아와서
routes/index.js
의 첫 번째 줄을 보시면vue
에서 라우팅을 처리하기 위해서vue-router
를import
하는 것을 확인할 수 있습니다. - 이렇게 정의된
router
는main.js
에 등록을 해줘야 실제 적용이 되어서 사용할 수 있게 됩니다. - main.js 파일을 살펴보겠습니다.
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
createApp(App).use(router).mount('#app')
import router from './router'
를 통해router
폴더의index.js
가import
되게 됩니다.- 마지막 줄을 보면
createApp(App)
최상위 컴포넌트인App.vue
로app
을 생성하고, use(router)
코드를 추가하여App.vue
에서router
가 사용될 수 있도록 추가했습니다.- 그리고
App.vue
를public
폴더의index.html
에 정의되어 있는id="app"
인html element
에 마운트 시키게 됩니다.
- 앞에서 라우터를 살펴보았습니다.
- 우리는
Home
,About
을 클릭할 때마다 연결되어 있는vue
파일이 호출이 되고, 해당 파일의 코드가 실행되어서 화면에 나타나는 것을 확인했습니다. - 이렇게
.vue
작성된 파일을 컴포넌트라고 부릅니다.