본문 바로가기
관리자

Programming-[Frontend]/Vue.js

Vue.js / 기초 / 6. 파일, 컴포넌트 및 router 구조

728x90
반응형

1. 파일구조

이제 지엽적으로 Vue 문법만 공부하는 것이 아니라, 전체적인 파일구조를 살펴보자. 기본 구조는 아래와 같다. 전체적인 파악 후, header 만들기를 따라하면서 각 컴포넌트들이 어떻게 구성되어지는가를 살펴보자.

 

이미 실행해봤지만, 초기 파일에서 console창을 열어서(intelliJ, windows이면 [Alt + F12]), 'npm run serve' 명령어를 입력해보자. localhost:8080/에 접속하면 아래와 같은 화면이 나온다. 이 화면은 public 폴더의 index.html을 표현한 것이며, 여기에 components 폴더의 HelloWorld.vue 컴포넌트를 삽입한 것이다. 정확히 어떤 경로를 거쳐서 이 컴포넌트가 화면에 출력된 것인지 알아보자.


2. index.html - main.js - App.vue의 흐름파악

 

public 폴더 - index.html : 컴포넌트들을 마운팅 해준다.

내가 만든 결과물(컴포넌트)은 public 폴더의 index.html에 의해 페이지로 표현되게 된다. 이때까지 여러 html을 만들었는데, 이 파일들은 개념 이해를 위한 것들이였다. 각 html 파일에서 id="app"인 엘리먼트에 인스턴스의 "el" 값을 대입했었다. 그러나 실제로 vue는 개발자가 컴포넌트들을 만들고, 해당 컴포넌트들은 이 public - index.html 파일에 모아진다고 생각하면 된다. index.html 내부에 14번줄에 해당하는 <div id="app"></div>로 표시된 부분을 볼 수 있는데, 여기에 main.js에서 지정하는 컴포넌트들이 마운팅 된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>
cs

 

main.js : 인스턴스를 생성하고 index.html 파일과 연결해준다.

 

1
2
3
4
5
6
7
8
9
import Vue from 'vue'
import App from './App.vue'
 
Vue.config.productionTip = false
 
new Vue({
  render: h => h(App),
}).$mount('#app')
 
cs

 

main.js의 하단에 인스턴스를 생성하는 new Vue({ ... }) 구문이 있다. render, $mount 등으로 작성되어 있는데 이것은 아래에 따로 표기한 코드와 같은 방식으로, app 이라는 id를 가진 태그에 해당 인스턴스를 적용하겠다는 것이다. 즉 index.html의 <div id="app"></div> 태그를 해당 인스턴스로 꾸며주게 된다.

 

이외에도 main.js 부분에 BootstrapVue 등 필요한 라이브러리들을 import 해오기도 한다.

 

main.js
위와 같은 의미로 표현된 인스턴스. 이전 글들에서 배운 방식과 같은 것을 알 수 있다.

 

App.vue : 실제 컴포넌트 파일

위 사진의 23~24번 줄에서 <App /> 컴포넌트를 호출하는 것을 볼 수 있다. 즉 App.vue 파일은 하나의 컴포넌트이고, 여기에 여러 컴포넌트들을 불러와서 main.js로 넘겨주는 통합 컴포넌트라고 볼 수 있다. 컴포넌트 파일은 1. 파일구조에서 살펴본 바와 같이 <template>, <script>, <style> 부분으로 나누어져 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
 
<script>
import HelloWorld from './components/HelloWorld.vue'
 
export default {
  name'App',
  components: {
    HelloWorld
  }
}
</script>
 
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
 
cs

<template> 부분에서는 HTML로 내가 화면상에 표시할 요소들을 작성한다. 현재는 app 이라는 요소 안에 이미지와 HelloWorld라는 컴포넌트가 있다.

 

<script> 부분에는 import와 export가 있다. import 구문을 통해서 <template>에서 사용할 HelloWorld 컴포넌트를 불러온다. export default 구문에서는 당 <App> 컴포넌트가 다른 곳(지금은 main.js 파일)에서 불러와지도록 내용을 작성해준다. 여기서도 components로 import해 온 HelloWorld가 포함되어 있음을 유의하자.

 

<script> 부분에서 <template>의 id="app" 요소를 꾸며줄 css 구문들을 작성해준다.

 

 

※ IntelliJ 에서 [Ctrl+J]를 입력하면 자동완성 기능 목록을 볼 수 있다. 이 중에 vbase라고 되있는 항목을 선택하면, .Vue 파일의 기본 템플릿이 추가된다.(또는 vbase 입력후 [tab]키)


 

3. App.vue에 다른 컴포넌트 불러오기

 

App.vue 작성해보기

직접 App.vue 파일을 편집해보자. 아래 코드와 같이 직접 작성해본다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<template>
  <div id="app">
    <Header></Header>
    <h3>안녕하세요</h3>
    <router-link to="/">Home</router-link>
    <router-link to="/about">   About</router-link>
    <router-view></router-view>
  </div>
</template>
 
<script>
import Header from '@/components/layout/Header.vue'
 
export default {
  name'App',
  components: {
    Header
  }
}
</script>
 
<style scoped>
h3 {
  color: red;
}
</style>
 
cs

 

App.vue에 <Header> 컴포넌트를 불러오고, router-link를 통해 SPA 페이지를 위한 링크도 작성하였다.

 

import 시에는 경로 입력 시 @는 src 폴더를 의미함을 기억하자.

 

아직 작성되지 않은 Header와 Router에 대해서는 아래에서 좀 더 자세히 다뤄보자.

 

 

<Header> 컴포넌트

경로에 작성했던대로, components 디렉토리에 layout 디렉토리를 만들고, Header.vue 파일을 만든다.

 

<template> 내부에 person이라는 변수를 적용하였다. 그리고 <script>에서 export default { } 부분 안에 data() 함수를 적용해서 객체값을 지정해주었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
  <div id="greeting">
    {{ person }}의 홈페이지입니다.
  </div>
</template>
 
<script>
export default {
  name"Header",
  data() {
    return {person: "charlie"}
  }
}
 
</script>
 
<style scoped>
 
</style>
cs

 

작성이 완료됬으면 npm run serve로 실행해보자. 아래 그림과 같은 페이지가 출력될 것이다.

 

 


 

4. router 및 스타일 적용

 

 

vue-router

Router에 대해서 알아보자. Vue가 단일 페이지로 작동(SPA)하기 때문에, 페이지에 요청이 올 때마다 서버에 요청을 보내서 페이지를 받아오는게 아니라, 미리 페이지들을 로딩해서 갖고 있다. 이런 각 페이지들로 이동할 수 있게 해주는 것이 Router이다. 

 

※Vue에서 제공하는 공식 플러그인인 vue-router가 설치되어 있어야 한다. 혹시 CDN 구문만을 이용해 진행하고 있었다면, 이제 명령어를 통해 vue를 관리할 수 있는 vue-cli를 설치하고 vue-router를 설치하자. 콘솔창에 다음 명령어를 입력한다.

vue-cli 설치
npm install -g @vue/cli
vue-router 설치
npm install vue-router --save

 

 

router.js

이제 페이지를 이동할 수 있는 Router 컴포넌트를 만들 차례다. src 디렉토리 아래에 views라는 폴더를 만들고, 그 아래에 Home.vue, About.vue 파일을 만들자.

그리고 src 디렉토리 아래에 router.js라는 자바스크립트 파일을 만든다. 이후 아래 코드와 같이 작성한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from "./views/Home"
import About from "./views/About"
 
Vue.use(VueRouter)
 
const router = new VueRouter({
    mode:"history",
    routes: [
        {path: "/"name"home", component: Home},
        {path: "/about"name"about", component: About}
    ]
})
 
export default router
cs

 

Vue.use(VueRouter)로 vue-router 인스턴스를 생성하였다. 그리고 mode와 routes 속성 설정을 해주었다. 

 

mode에는 "hash"와 "history"가 있는데, Vue는 기본적으로 hash로 설정된다. Hash 모드는 URL 상에 "#"이 들어간다. 이것은 mode를 직접 "hash"로 해서 실행하면 확인할 수 있다. 이 모드는 SPA 방식이라서 페이지가 바뀔 때마다 서버에 페이지에 대한 정보들을 다시 요청하지 않는다. history 모드는 페이지가 바뀔 때마다 서버에 요청을 하므로 통신 부하가 있으나, 정보가 갱신되고, URL 상 "#" 표시가 안들어간다는 장점이 있다.(참조 2)

 

routes에서는 URL 주소가 될 path, name 그리고 실제 참조할 컴포넌트 파일의 이름인 component를 설정해주었다. 

 

router가 작동하기 위해, main.js 파일에 router를 명시해주어야 한다. 다음과 같이 작성한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
import Vue from 'vue'
import App from './App.vue'
 
Vue.config.productionTip = false
 
import router from './router.js';
 
new Vue({
  render: h => h(App),
  router
}).$mount('#app')
 
cs

 

이제 실행해보면, Home, About 부분에 링크가 걸리고 URL 이동이 가능함을 확인할 수 있다.

 

추가내용

 

Lazy Load와 Prefetch

router의 routes를 입력하는 부분에서, component 부분을 콜백 형태로 작성하여 Lazy Load를 구현할 수도 있다.

(기존에 About 컴포넌트를 import 하는 구문은 삭제 필요)

1
2
3
4
5
6
7
const router = new VueRouter({
    mode:"history",
    routes: [
        {path: "/"name"home", component: Home},
        {path: "/about"name"about", component: () => import('./views/About.vue')}
    ]
})
cs

이렇게 작성하면, About 컴포넌트에 Lazy Load가 적용되어 해당 컴포넌트는 사용자의 요청이 있을 때 불러오게 된다. Lazy Load는 VUE CLI 3부터 적용된 prefetch 기능을 기반으로 하는데, About 처럼 콜백을 이용해서 비동기 호출을 적용한 컴포넌트를 미리 캐시에 저장하는 기능이다. 

 

원래 모든 컴포넌트를 chunk 라는 파일에 담아서 한 번에 렌더링 해야되는데, Lazy Load - prefetch 기능이 적용된 컴포넌트는 따로 분리되어 캐시에 저장된다. 원래 하나의 chunk 파일이 분리되어 용량이 적어져서 웹 페이지 전체의 렌더링에 소요되는 시간이 적게 들 수 있으나, 분리된 About 컴포넌트에 대해 따로 chunk 파일을 요청(request)하게 되므로 오히려 로딩 시간이 길어질 수 있다. 아래 Network 탭 사진을 보면, 분리된 컴포넌트에 대해 요청이 따로 간 것을 알 수 있다.

 

-기존처럼 바로 import 했을 경우

-About 컴포넌트를 Lazy Load한 경우

prefetch 기능을 적용하면, 분리된 chunk 파일들을 먼저 로딩하고 첫 화면에 대한 파일을 나중에 로딩하므로 첫 화면의 로딩이 느려질 수 있다. 그러나 분리된 chunk 파일들에 해당하는 페이지로 이동하는 것은 빨라질 수 있다. router 기능을 적용해서 이동하는 페이지의 소스 크기가 작으면 prefetch를 적용해도 문제가 없으나, 크기가 큰 경우에는 prefetch 기능을 적용하면 첫 페이지 로딩이 느려지는 문제가 발생할 수 있다.

 

router-view 태그

App.vue 컴포넌트에 <router-view> 태그를 작성하였는데, 이 태그가 없어도 routes.path로 화면 전환은 되지만 해당 태그가 없으면 실제 컴포넌트의 내용 이 출력되지 않으므로 꼭 써주어야 한다.

 

style scoped 태그

style 태그 뒤에 scoped 를 써주어야 해당 컴포넌트의 요소들에만 스타일이 적용된다. scoped를 써주지 않으면 프로젝트 전체의 요소에 스타일을 적용하므로 유의해야한다.

 


참조

 

1) [유튜브] 코지코더 - '뷰js 2 기초익히기 시리즈'

www.youtube.com/channel/UCI4tTBupvhMX1aWDSm-HAXw

 

2) [블로그] Human Above the code

https://happy-coding-day.tistory.com/128

 

3) [서적] Vue.js 프로젝트 투입 일주일 전 - 고승원 지음

728x90
반응형