본문으로 바로가기

Vue Router

category JavaScript/Vue.js 2021. 7. 16. 18:23

라우팅

 - 사용자가 접속한 주소에 따라 페이지가 달리지는 것

 

샘플파일로 vue-router 살펴보기

// scr/App.vue
<template>
  <div id="app">
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
  </div>
  <router-view />
</template>

 - 코드에 router-link to="/", router-link to="/about" 부분이 있다. 해당 부분의 링크를 클릭하고 브라우저 URL을 보면 Home을 클릭하면 localhost:8080, About을 클릭하면 localhost:8080/about으로 바뀌는 것을 확인할 수 있다.

 (크롬에서 개발자 모드로 확인을 하면 router-link to="/" 코드가 a href="/"로 변경되는 것으로 보아 같은 기능을 수행하는것 같다.)

 

 - 개발한 페이지에서 화면이 어떻게 브라우저의 주소가 바뀔 때마다 바뀌어 보이도록 설정되는지 알아보자

// 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 chuck (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: ()=> import(/* webpackChunkName: "about" */ '../views/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 파일을 잠조한다.

 

 - routes 배열의 두 번째 값에 path와 name 밑에 주석 처리된 부분이 있다.

// route level code-splitting
라우트 레벨에서 코드를 분할하는 방법입니다.

// this generates a separate chuck (about.[hash].js) for this route
이 라우트에 대한 chunk 파일이 분리되어 생성됩니다.

// which is lazy-loaded when the route is visited.
이 라우트에 방문했을 때 lazy-load(지연 로드) 됩니다.

component: ()=> import(/* webpackChunkName: "about" */ '../views/About.vue')
주석처럼 라우트 레벨에서 코드를 분할한 후 별도의 chunk 파일을 생성하고, 실제 이 라우트를 방문했을 때 
리소스를 로드하게 됩니다. 여기서 chunk 파일은 about이라는 이름으로 생성됩니다.
컴포넌트 import시 /* webpackChunkName: "about" */ 라는 주석으로 chunk 파일이름을 정의했기 떄문입니다.

 - 첫 번째 등록된 라우터와 두 번째 등록된 라우터의 가장 큰 차이는 첫 번쨰는 사용자가 해당 path에 접근하지 않더라도 이미 vue 파일을 import 하는 것이고, 두 번쨰 방법은 path에 접근하기 전까지는 vue 파일에 대한 import가 일어나지 않는다.

 

Lazy Load 적용하기 (비동기 컴포넌트)

 - Lazy Load는 리소스를 컴포넌트 단위로 분리하여 컴포넌트 혹은 라우터 단위로 필요한 것들만 그때 그때 다운받을 수 있게 하는 방법

 - 라우터에서 Lazy Load로 컴포넌트를 import 한 것은 내부적으로 Vue CLI의 prefetch 기능이 사용되는 것이다.

 - Vue CLI3부터 prefetch 기능이 추가되었다. prefetch 기능은 미래에 사용될 수 있는 리소스를 캐시에 저장함으로써, 사용자가 접속했을 떄 굉장히 빠르게 리소스를 내려줄 수 있다. 굉장히 유용한 기능이지만, 비동기 컴포넌트로 정의된 모든 리소스를 당장 사용하지 않더라도 캐시에 담는 비용이 발생한다.

 - 즉, 별도로 분리된 chunk 파일 각각에 대한 request가 일어나고, 각각의 파일을 다운로드 받아서 캐시에 저장하게 되는 것이다.

 - prefetch 기능을 사용하는 이유는 랜더링 시간을 줄이기 위해서인데, 잘못 사용하면 오히려 랜더링 시간이 늘어나게 된다.

 

- Vue CLI에서 prefetch 기능은 기본값으로 true가 설정되어 있기 떄문에, Lazy Load가 적용된 컴포넌트는 모두 prefetch 기능이 적용되어 캐시에 저장된다.

 - prefetch 기능은 당므과 같은 부분을 반드시 고려해서 사용해야한다. prefetch 기능을 사용하면 request 요청 수가 증가한다. 비동기 컴포넌트로 정의된 모든 리소스를 캐시에 담기 때문에 request 요청 수가 많아지게 된다.

 

 - prefetch 기능을 사용하지 않으면 요청 수가 훨씬 줄어든다. 요청 수가 많다는 것은 서버와의 통신 수가 증가한다는 것이고, 내려받는 리소스 크키도 크다는 것이다.

 - prefetch 기능을 사용하지 않으면 라우터가 이동될 때마다 해당 라우터에서 필요한 리소스를 그때 그떄 가져오게 된다. 물론 한번 가져온 리소스는 다시 요청하지 않는다.

 

 - prefetch 기능을 사용하면 애플리케이션의 첫 화면 접속 시 랜더링 속도가 느려질 수 있다. 첫 화면에서 사용되는 리소스를 가장 나중에 다운받게 되어 있다. 이 말은 아직 사용하지 않고 있는 화면에 대한 리소스를 모두 내려받고 나서야 첫 화면에서 사용되는 리소르르 내려받는다는 것이다.

 - 오히려 초기 랜더링은 prefetch 기능을 사용하지 않아야 더 빨리 로딩이 된다. prefetch 기능은 다른 화면에서 사용될 리소스를 미리 내려 받아서, 애플리케이션에서 화면 전환 시 빠른 성능을 가져온다는 장점을 이용하기 위해서 사용되는 것이다.

 - 그래서 정말 필요한 컴포넌트에 대해서 prefetch 기능을 적용하는 것이 좋다.

 

 - 라우터를 통해 이동되는 컴포넌트에서 사용되는 리소스가 크기 않다면 prefetch 기능을 사용하지 않더라도 사용자 접속 시점에 다운 받아도 충분히 매끄럽게 동작할 수 있다. 물론 이동하는 컴포넌트에서 사용되는 리소스가 매우 크다면 prefetch 기능을 사용하지 않으면 라우터 이동 시 화면 전환이 늦게 진행된다는 문제가 발생한다.

 - 그래서 prefetch 기능을 적절한 곳에 적용하는 고민이 반드시 필요하고, 프로젝트 팅에서는 이 부분을 반드시 고려해야 좋은 애플리케이션을 서비스 할 수 있다.

 

 - 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 */ 부분이 있다. 이와 같이 컴포넌트 impor시 주석 /* webpackPrefetch: true */을 넣어주면 해당 컴포넌트에 대해서는 prefetch가 적용된다.

Vue 애플리케이션 개발 시 기본적으로 prefetch 기능은 끄는 것을 권장합니다.

 

Vue에서 prefetch 기능을 사용해서 비동기 방식으로 컴포넌트를 로드하는 것은 매우 중요한 부분입니다.
어떤 컴포넌트는 하나의 파일로 내려받을지, 그리고 어떤 컴포넌트는 prefetch를 적용해서 캐시에 넣어서 사용할지, 그리고 어떤 컴포넌트는 prefetch 없이 사용자의 접속 시점에 내려줄지를 어떻게 설계하느냐에 따라 전체 애플리케이션을 효율적으로 사용할 수 있게 되는 것입니다. 이 부분은 분명 사용자 경험에도 중요한 요소일 것입니다.
사용자가 접속할 가능이 높은 컴포넌트는 한 번에 다운로드 할 수 있게 설정하고, 사용자의 접속 빈도가 낮은 컴포넌트는 prefetch를 적용하거나, 사용자 접속 시점에 리소스를 다운로드 받게 해서 전체 애플리케이션에 대한 리소스를 내려받는 시점을 분리합니다. 물론 초기 설계 시 적용한 방법을 그대로 유지하기보다는, 시스템 운영을 통해 사용자가 접속하는 페이지 및 빈도에 대한 현황 조사를 통해 지속적으로 라우터 설정을 개선해 나갑니다.

 

 

 - 다시 본론으로 돌아와서 routes/index.js의 첫 번쨰 줄을 보면 vue에서 라우팅을 처리하기 위해서 vue-router를 import 하는 것을 확인할 수 있다. 이렇게 정의된 router는 main.js에 등록을 해줘야 실제 적용이 되어서 사용할 수 있게 된다.

 

 - main.js 를 살펴보자

// src/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에 마운트 시키게 된다.

 

 

router 함수 정리

html 코드 javscript 코드 설명
<router-link to="/"></router-link> $router.push("/") 현재 라우트를 변경
<router-link to="/" replace></router-link> $router.replace("/") history에 현재 라우트를 남기지 않고 이동
  $router.go(1)
$router.go(-1)

앞으로 가기
뒤로 가기
(history에 이동한 라우트가 있어야 가능)

 - router는 jsp/java에서의 Controller라고 생각하고 공부하였다.

 - $router.push는 jsp에서의 forward이나 컨트롤러를 통해서 변경해주는 느낌인것 같다.

 - $router.replace는 jsp에서의 redirect이라고 생각한다.

 - $router.go()는 jsp에서의 history.go()라고 생각한다.

 

NavigationDuplicated: Avoided redundant navigation to current location: "/". 에러

 - 경로 주소가 겹칠 경우에 발생하는 에러이다.

 - 해결한 방법

methods: {
  changePage(page) {
  	// 현재 라우터 주소와 이동하려는 페이지 주소 비교
    if(this.$router.currentRoute.path !== page) {
      this.$router.push(page)	// 페이지 이동
    }
    else {
      this.$router.go(page)	// 새로고침 같은 역할
    }
  }
}
반응형

'JavaScript > Vue.js' 카테고리의 다른 글

Vuex (v4.x)  (0) 2021.07.19
Reusability & Compostion  (0) 2021.07.19
컴포넌트 심화 학습 (Provide/Inject, Template refs)  (0) 2021.07.16
컴포넌트 심화 학습 (Slot)  (0) 2021.07.16
컴포넌트 심화 학습(Props, $refs, $emit)  (2) 2021.07.16