본문 바로가기

3.구현/HTML5&Javascript

[vue2] Vue.js 프로젝트 기본 구성

초기 소스코드를 구성할 경우 해야할 일이 많다. 최근 프레임워크는 많이 간소화되어서 해야할 작업이 매우 많이 줄어들었지만 그래도 해야할 일이 좀 있다. 사용할 목적에 따라 달라질 수 있지만, 웹 어플리케이션을 만든다고 가정해서 가장 기본적인 환경 구성을 정리해보았다.

작성자: ospace114@empal.com, http://ospace.tistory.com/

들어가기

Vue.js을 몇번 사용하면서 반복적으로 구성하면서 필요로 하는 작업이 있다. 그때마다 검색하면서 똑같은 작업하기가 번거롭기 때문에 한번 정리해보았다. Vue.js는 버전 3까지 나왔지만, 여기서는 버전 2에 대한 환경 구성을 다룰려고 한다.
Vue.js 프로젝트 구성은 vue cli을 사용해서 초기 구성을 할 수 있다. vue cli도 버전이 2.x와 3.x가 있는데 3.x을 추천한다. 좀거 프로젝트 구성이 깔끔해졌다.
GUI 사용이 좋다고 하시는 분은 "vue ui" 명령으로 GUI를 통해 구성도 가능해졌다.

초기화

먼저 vue cli 설치가 필요하다.

npm install -g @vue/cli-init

vue.js 프로젝트 초기화해보자. 프로젝트 이름은 foo로 하겠다. 자신이 생성하고 싶은 프로젝트 이름을 사용하면 된다.

vue create foo

실행하면 아래 화면이 표시된다. 방향키로 원하는 vue.js 버전을 선택하면 된다. 여기서는 Vue 2를 선택한다.

? Please pick a preset: (Use arrow keys)
> Default ([Vue 2] babel, eslint)
  Default (Vue 3) ([Vue 3] babel, eslint)
  Manually select features

생성되었다면 버전에 따라 달라질 수 있지만 아래 형태의 폴더 구조와 파일이 생성될 것이다.

foo/
+ node_modules/
* public/
  + favicon.ico
  * index.html
+ src/
  + assets/
    + logo.png
  + components/
    + HelloWorld.vue
  + App.vue
  + main.js

간단하게 실행해서 테스트해보자.

yarn serve

아래처럼 보이면 된다. "x.x.x.x"은 자신 컴퓨터 IP주소이다.

  App running at:
  - Local:   http://localhost:8080/
  - Network: http://x.x.x.x:8080/

  Note that the development build is not optimized.
  To create a production build, run yarn build.

Note: 빌드할 경우 vue-cli 2.x로 생성된 프로젝트는 publicPath가 "/dist"로 인식되서 빌드된 파일과 섞이게 된다. vue-cli 3.x가 되면서 "/public" 폴더가 별도로 존재하며 "/dist"와 분리된 구조로 더 좋아졌다.

Route 구성

링크를 선택했을 때에 페이지 이동하기 위한 내용이다. 이 부분도 vue.js 초기화에는 포함되어 있지 않다. 웹 어플리케이션에서는 당연히 필요하다.

설치

먼저 필요한 패키지를 설치하자.

yarn add vue-router

index.js 파일 추가

간단한 router을 생성해보자. 먼저 프로젝트 최상위 폴더에 있는 src 폴더에 routes 폴더를 생성하자. 그리고 아래 index.js 파일을 routes 폴더에 생성한다.

import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const router = new VueRouter({
    mode: 'history',
    routes: [
        {
            path: '/',
            name: 'home',
            component: ()=> import('@/Home.vue'),
        },
        {
            path: '/bar',
            name: 'bar',
            component: ()=> import('@/components/Bar.vue'),
        },
    ],
});
export default router;

main.js 파일에 라우터 등록

route 폴더에 생성된 index.js을 활성화하기 위해서는 main.js 파일에 아래 내용을 추가해야 한다.

import router from './routes'

...
new Vue({
    ...
    router,
}).$mount('#app')

주의할 부분은 router 이름을 변경할 수 없다.

App.vue 파일 변경

기존 페이지를 홈페이지로 만들고 링크 클릭했을 때에 화면 전환하도록 만들어보자. 앞에 라우터 설정에서 "/" 경로에 대한 component을 Home.vue로 지정했다. 이는 루트 페이지로 Home.vue을 불러오겠다는 의미이다.
먼저 기존 App.vue을 Home.vue로 파일명을 변경해보자. 다음으로 간단한 링크 테스트를 위해서 App.vue 파일을 새로 생성해보자.

<template>
    <p>
      <router-link to="/">Home</router-link> / 
      <router-link to="/bar">Go to Bar</router-link>
      <router-view></router-view>
    </p>
</template>

router-view 부분이 라우터의 component내용으로 대처되는 부분이다. 즉, 최상단 App.vue가 기본으로 로딩되며 컴포넌트가 배치되고 라우터 설정에 따라 App.vue에 로딩될 컴포넌트가 지정되며 해당 컴포넌트는 router-view에 표시된다.
router-link은 navigator역활로 a 태그와 동일한 기능이다. router-link은 현재 라우터($router)와 경로가 일치할 경우 router-link-active 클래스가 활성화된다.

Bar.vue 파일 추가

마지막으로 테스트용 Bar.vue 파일을 src/components/ 폴더에 추가해보자.

<template>
    <h1>Bar Page</h1>
</template>

실행해보면, 화면 상단에 "Home / Go to Bar" 네비게이션이 보인다. 해당 링크를 클릭하면 Home.vue 또는 Bar.vue에 만들어진 페이지가 표시된다. 페이지를 구성할 때에 Header, Side, Body, GNB(Global Navigation Bar), LNB(Local Navigation Bar) 등 구성으로 레이아웃을 만들기도 한다. 이런 레이아웃을 현재 작업된 라우터 기능을 활용하면 가능하다.

Proxy 구성

로컬에서 개발을 할 경우 API 서버로 호출이 필요하다. 이때 활용할 수 있는 기능으로 Proxy가 있다. 특정 경로에 대한 요청을 지정된 API 서버로 전달해주는 기능이다. 작업은 프로젝트 루트에 vue.config.js파일을 생성하고 아래 내용을 추가한다.

module.exports = {
    devServer: {
        proxy: {
            '/api': {
                target: 'API서버 주소',
                changeOrigin: true,
                exposedHeaders: ['Content-Disposition'],
            },
        },
    },
};

"/api"가 시작하는 모든 요청은 target으로 보내게 된다. 해당 부분은 추후 웹서버로 구성해서 페이지를 구동할 경우 Proxy 설정에 적용될 내용이다.

Axio 사용하여 API 호출

axio는 vue.js에서 API 서버로 호출 때에 사용하는 라이브러리이다.
src 폴더에 api폴더를 생성하고 그 안에 index.js 파일을 생성하자.

import axios from 'axios';

const instance = axios.create();


instance.defaults.timeout = 2500; // 기본 타임아웃
instance.get('/foo', { timeout: 5000 }); // 특정 API에 대한 타임아웃

instance.defaults.headers.common['Authorization'] = process.env.VUE_APP_AUTH; // 공통 인증 코드
instance.interceptors.request.use(
    config => {
        // 요청 성공 직전 호출됩니다.
        // config.headers['파라미터명'] = 값;
        return config;
    },
    error => {
        // 요청 에러 직전 호출됩니다.
        return Promise.reject(error);
    },
);
// 응답 인터셉터
instance.interceptors.response.use(
    response => {
        let resData = response.data;
        //if (!isSuccess(resData)) {
        //    return Promise.reject({ status: 520, error: resData.error, message: resData.message });
        //}
        return resData;
    },
    error => {
        return Promise.reject(error);
    },
);

export default instance;

interceptors에 의해서 요청과 응답 중간에 메시지 처리를 할 수 있다. 요청시 인증에 대한 처리, 응답시 응답 결과에 대한 처리 등을 실행한다. 물론 필요 없다면 interceptors부분은 제외해도 된다.
사용하는 법은 간단하다.

import api from '@/src/api';

...

let res = await api.get('/api/foo');
console.log(res);

프로파일 구성

개발하다 보면 최종적으로 운영에 배포를 해야한다. 물론 중간에 테스트도 진행해야 한다. 최종 운영 배포할 경우는 빌드 과정을 통해서 웹팩으로 파일이 생성되는 과정이 있으며 이 과정을 통해 개발환경에 설정이 아닌 운영환경에 맞는 설정 적용이 필요하다. 이 때 사용하는게 프로파일이다. 개발 환경에서는 개발 프로파일, 운영 환경에서는 운영 프로파일를 선택하다는 의미이다.

vue cli에서는 환경에 따라 다를 수 있지만 기본 3개 모드가 있다.

  • development : serve 실행할 경우
  • production : build 실행할 경우
  • test : test 실행할 경우

각 프로파일은 "process.env.NODE_ENV"에서 선택된 프로파일을 식별할 수 있다. 물론 사용자 정의도 가능하고, 특정 프로파일을 지정해서 실행할 수도 있다.
각 프로파일 별로 환경 설정은 프로젝트 루트에 환경변수 파일을 생성 규칙이 있다. 파일 명 규칙은 아래와 같다.

  • .env: 모든 프로파일에 적용됨
  • .env.local: 모든 프로파일에 적용됨(원격은 제외)
  • .env.프로파일명: 특정 프로파일에 적용 (예. 운영이라면 .env.production )
  • .env.프로파일명.local: 특정 프로파일에 적용(원격은 제외)

참고로 local은 각자 본인 환경에 적용되는 환경설정 파일이기 때문에 git을 사용하는 경우 공유하지 말아야 한다. 그렇기 때문에 .gitignore 추가를 권장한다.

각 환경설정 파일에 환경설정변수 설정형식이다. VUE_APP_{변수명} = {값} 형식으로 설정 값을 부여한다.

NODE_ENV = development
VUE_APP_PORT = 8000

NODE_ENV은 기본 프로파일들은 이미 제공되고 있기 때문에 별다른 설정은 필요없지만, 변경하고 싶다면 수정할 수 있다.
실제로 환경변수를 vue.config.js 파일에 적용하는 예를 보자.

module.exports = {
    devServer: {
        port: process.env.VUE_APP_PORT || 8080
    }
}

설정에 있는 값이 있으면 사용하고 없으면 기본으로 8080 포트를 사용하도록 구성되어 있다.

쿠키 사용

쿠키를 사용하기 위해서는 vue-cookies 모듈 설치가 필요하다.

yarn add vue-cookies

쿠키를 사용하는 예제이다. 사용법은 간단하다.

import VueCookies from "vue-cookies";

// 가져오기
let foo = VueCookies.get('foo');

// 저장하기
VueCookies,set('foo', 'foo value', '10s');

기타 추가설정

npm repository 변경

nexus를 사용해서 새로운 repository을 구성할 경우 접속할 주소를 변경해야 한다. 프로젝트 루트에 .npmrc 파일을 생성하고 아래 내용을 추가한다.

registry=https://foo.com/repository/npm-foo-proxy/
_auth=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

인증에 관련된 추가 설정은 repository 서버 구성에 맞게 수정하면 된다.

빌드시 index.html 파일 이름 변경

현재 개발 중에는 index.html 파일 사용이 문제 없지만, 운영환경에서는 문제가 생길 가능성이 있다. 이때 빌드할 때에 index.html 파일명이 아닌 다른 파일 명으로 생성된 빌드파일을 생성하도록 변경할 수 있다.
vue.config.js 파일에 아래 내용을 추가한다.

module.exports = {
    ...
    indexPath: 'main.html',
};

index.html 파일이 아닌 main.html 파일로 빌드되도록 설정을 변경하였다.

Troubleshoot

'<' 토큰 에러

index.html 파일에 base 태그 및 기타 태그를 추가한다.

<head>
    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Expires" content="0">
    <base href="/">
</head>

그리고 package.json 파일에 homepage 속성도 추가한다.

{ "homepage": "." …}

브라우저 캐시로 배포 문제

운영에 배포했는데 브라우저로는 변경된 내용이 반영되지 않은 경우가 있다. 물론 강제로 전체 리로딩하면 된다. 이는 브라우저 캐시 문제로 서버 환경과 네트워크 환경에 따라 달라질 수 있는 부분이다. 일단 vue.js에서 해결할 수 있는 방법은 다음과 같다.

  • 로딩되는 파일이 있는 경우 버전관리를 해주자
  • 빌드시 파일명을 변경해주자

첫번째 방법은 의외로 간단핟. 본인이 사용하는 방법은 버전을 시퀀스 처럼 관리한다. 매번 수정될 때마다 1씩 증가한다.

<link rel="stylesheet" href="/assets/css/common.css?v=1" type="text/css" />

새로 변경된 내용이 있다면,

<link rel="stylesheet" href="/assets/css/common.css?v=2" type="text/css" />

이 벙법은 별도 분리된 파일이 배포되는 경우 유용하지만, vue 자체 패키징되는 파일은 제어할 수 없다. 그래서 다음 방법이 필요하다.

두번째 방법으로 웹팩에 의해서 파일이 패키징되는 경우 파일명에 해시값을 붙여서 다른 파일로 인식하도록 한다.
vue.config.js 파일에 아래 내용을 추가한다.

module.exports = {
    ....
    configureWebpack: config => {
        if (process.env.NODE_ENV === 'production') {
            config.output.filename = 'js/[name].[chunkhash:8]].js';
        }
    },
}

"chunkhash:8" 대신에 "hash"를 적용할 수 있다. 아마도 이미 vue.js에 chunkhash 형태로 빌드되도록 적용되어 있을 것이다.

관련자료

참고

[1] https://cli.vuejs.org/guide/creating-a-project.html#vue-create
[2] https://router.vuejs.org/kr/guide
[3] https://cli.vuejs.org/config/

반응형