Vue.js 고급 기술 (Vue Framework Advanced Technics)

Minho Yoo·2022년 12월 21일
2

Vue.js

목록 보기
8/12
post-thumbnail

뷰 프로젝트 폴더 구조

뷰의 장점 중 하나는 빠른 프로토 타이핑이 가능하다는 점이다.
뷰 CLI로 프로젝트를 생성하고 나면 npm으로 원하는 기능들을 빠르게 확장해 나갈 수 있다.

뷰 CLI로 생성한 기본 폴더 구조

뷰 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) 방법을 적용하기 위해서는 아래와 같은 개발 환경을 갖고 있어야 한다.

  1. 싱글 파일 컴포넌트 체계 (.vue)
  2. 웹팩 - 모듈 번들러 (2.x 이상)
  3. 바벨 Syntax-dynamic-import 플러그인

바벨 Syntax-dynamic-import 설치 방법

뷰 CLI로 생성한 경우에는 이미 1번과 2번을 만족하고 있겠지만 3번의 경우에는 별도의 설치가 필요하다.
바벨 Syntax-dynamic-import 플러그인 설치는 아래의 절차를 따른다.
1. syntax-dynamic-import 플러그인 설치

npm install --save-dev babel-plugin-syntax-dynamic-import
  1. .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개의 변수는 다음과 같은 역할을 한다.

  • to: 이동할 url
  • from: 현재 url
  • next: to에서 지정한 url로 이동하기 위해 꼭 호출해야 하는 함수

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

beforeRouteEnter는 컴포넌트 인스턴스가 생성되기 전에 호출된다.
인스턴스 생성 전이기 때문에 this를 통한 인스턴스 접근은 불가능하다.
대신 인스턴스를 조작하는 콜백을 next 에 전달하면 인스턴스가 생성된 이후에 콜백이 호출된다.

export default {
  data() {
    return {
      state: 'pending',
    }
  },
  beforeRouteEnter(to, from, next) {
    // 네비게이션 승인 후 state를 업데이트
    next((vm) => (vm.state = "approved"));
  }
}

beforeRouteUpdate

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

beforeRouteLeave는 해당 컴포넌트를 벗어나 새로운 페이지로 이동할 때 호출된다.
보통 사용자가 변경사항을 저장하지 않고 갑작스럽게 사이트를 벗어날 경우 사용된다.
next(false)로 페이지 이동을 막을 수 있다.

beforeRouteLeave(to, from, next) {
  const answer = window.confirm('사이트에서 나가시겠스니까? 변경사항이 저장되지 않을 수 있습니다.');
  if (answer) {
    next();
  } else {
    next(false);
}

네비게이션 가드 호출 순서(flow)

  1. 비활성화되는 컴포넌트에서 beforeRouteLeave 호출
  2. 전역 가드 beforeEach 호출
  3. 재사용되는 컴포넌트라면 beforeRouteUpdate 호출
  4. 지역 가드 beforeEnter 호출
  5. 활성화되는 컴포넌트 beforeRouteEnter 호출
  6. beforeRouteEnternext에 넘겨진 콜백 함수

네비게이션 가드로 인증 정보 확인

네비게이션 가드가 가장 많이 쓰이는 곳은 사용자 인증 정보에 따라 접근을 막는 로직이다.

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(); // 페이지 전환
})

참고 자료

Transition & Animation

뷰는 라이브러리 내부적으로 트랜지션, 애니메이션 기능을 갖고 있다.
그래서 간단한 규칙과 속성들만 알면 쉽고 멋진 애니메이션 효과를 추가할 수 있다.

트랜지션 예시

뷰 트랜지션 코드를 간단히 살펴보자.

<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를 함께 사용한다.
그림의 색깔을 보면 짝 지어져서 잘 구분되어 있다.

profile
Always happy coding 😊

0개의 댓글