나의 공부방

[Frontend] VueJS 프로젝트 생성 및 설정하기

망나니개발자 2021. 2. 1. 14:48
반응형

본 포스팅은 과거에 Vue JS를 공부하며 정리했던 내용입니다. 개인적으로 참고하기 위해 올려놓은 내용이고, 더 이상 프론트엔드 프로그래밍을 진행하지 않아 부정확한 내용이 있을 수 있습니다.

 

1. VueJS 프로젝트 생성


[ VueJS 프로젝트 생성 ]

VueJS로 프로젝트를 실행하기 위해서는 vue-cli를 사용해야 한다. vue-cli는 npm 모듈로 제작되어 있기 때문에, node.js가 필수적으로 설치되어 있어야 한다. Node JS가 설치되어 있지 않다면 설치한 후에 아래의 내용을 진행하기 바란다.

 

  1. Node JS 콘솔 열기
  2. vue-cli 설치(npm install -g @vue/cli)
  3. 원하는 위치로 이동 후 Vue 프로젝트 생성(vue init <템플릿 이름> <프로젝트 이름>, ex) vue init webpack frontend)

위에서 vue-clie를 설치할 때 사용했던 g 옵션은 global을 의미하여, 어디에서든지 이용할 수 있도록 g 옵션을 추가하였다. 또한 template-name에는 여러 가지 방법이 올 수 있지만 webpack으로 진행하는게 가장 대중적인 방법이다. template-name에 사용할 수 있는 2가지의 webpack 방법 중 webpack-simple은 실제 서비스 운영을 위해서는 적합하지 않으므로, 그냥 webpack을 이용하도록 하자.

설치 명령어를 실행하면 환경 설정을 위한 입력이 진행된다. 이와 관련된 내용은 아래에 정의되어 있으니, 참고하여 작성하면 된다.

# 프로젝트 이름
? Project name (vue-example-project):

# 프로젝트 설명
? Project description (A Vue.js project):

# 작성자
? Author (MangKyu <whalsrb1226@gmail.com>):

# Vue 빌드 선택, 기본 선택은 Runtime + Compiler로 대부분 사용자에게 권장
? Vue build

# vue-router사용여부, 사용 시 자동으로 설정 
? Install vue-router? (Y/n)

# ESLint 적용여부, 사용 시  코드작성 스타일을 강제화함 
? Use ESLint to lint your code? (Y/n)

# ESLint 적용하면 나오는 질문으로, 어떤 스타일을 사용할 것인지 물어봄 
? Pick an ESLint preset 

# 3개의 선택지가 나오며 기본은 Standard로 설정 되어 있음
- Standard (https://github.com/feross/standard) 
- Airbnb (https://github.com/airbnb/javascript) 
- none (configure it yourself) 

# Unit Test 사용여부
? Set up unit tests (Y/n)

# Unit Test에 대해 3개의 선택지가 나옴
- Jest
- Karma and Mocha
- none (configure it yourself) 

# Test Runner를 선택해야 함
? Pick a test runner

# UI테스트 툴 Nightwatch 적용 여부 
? Setup e2e tests with Nightwatch? (Y/n)

# Should we run `npm install` for you after the project has been created? (recommended) (Use arrow keys)
- Yes, use NPM
- Yes, use Yarn
- No, I will handle that myself 

 

[ VueJS 프로젝트 설치 및 구동 ]

프로젝트의 생성이 완료되었으면, 해당 프로젝트 폴더로 이용하여 의존성 관련 모듈들을 먼저 설치해주어야 한다. 그리고 나면 프로젝트를 구동할 수 있다.

// 프로젝트 폴더로 이동
cd frontend

// 프로젝트 의존성 모듈 설치
npm install

// 프로젝트 실행
npm run dev

 

2. Bootstrap 연동하기


[ Bootstrap 연동하기 ]

이번에 사용할 Bootstrap은 https://mdbootstrap.com/docs/vue/getting-started/quick-start/ 이다. Vue 프로젝트에 연동하기 위해서는 먼저 해당 Bootstrap을 설치해주어야 한다.

// mdb를 전역적으로 설치한다.
npm install -g mdb-cli

// mdb 계정으로 로그인을 한다.
mdn login
? Enter your MDB username <계정명>
? Enter your MDB password <비밀번호 입력>

// 로그인한 mdb 계정으로 사용가능한 Bootstrap 목록을 확인한다.
mdn list

// vue 프로젝트로 이동 후에 mdb를 추가한다.
npm install --save mdbvue

 

그리고 main.js에 아래와 같이 bootstrap을 import해준다.

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import 'bootstrap-css-only/css/bootstrap.min.css'
import 'mdbvue/build/css/mdb.css'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

 

bootstrap이 잘 추가되었나 확인하기 위해 /src/components/HelloWorld.vue 를 수정해준다. 수정하는 항목들은 해당 컴포턴트를 임포트하고 template안에 추가하는 것이다.

<template>
  <div>
    <!-- Secondary button -->
    <mdb-btn color="secondary">Secondary</mdb-btn>

    <!-- Indicates a successful or positive action -->
    <mdb-btn color="success">Success</mdb-btn>

    <!-- Contextual button for informational alert messages -->
    <mdb-btn color="info">Info</mdb-btn>

    <!-- Indicates caution should be taken with this action -->
    <mdb-btn color="warning">Warning</mdb-btn>

    <!-- Indicates a dangerous or potentially negative action -->
    <mdb-btn color="danger">Danger</mdb-btn>
  </div>
</template>

<script>
import { mdbBtn } from 'mdbvue'

export default {
  name: 'HelloWorld',
  components: {
    mdbBtn
  },
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

 

하지만 위에서 추가한 mdb-bootstrap의 무료 버젼에서는 지원하지 않는 컴포넌트가 많으므로 기본 bootstrap도 추가해준다. 기본 부트스트랩의 링크는 https://bootstrap-vue.js.org/docs 이다.

// Bootstrap을 설치한다.
npm install vue bootstrap-vue bootstrap

 

/components/utils/bootstrapUtils.js를 생성하고 아래의 코드를 붙여넣는다.

import Vue from 'vue'

import bAlert from 'bootstrap-vue/es/components/alert/alert'
import bBadge from 'bootstrap-vue/es/components/badge/badge'
import bBreadcrumb from 'bootstrap-vue/es/components/breadcrumb/breadcrumb'
import bBreadcrumbItem from 'bootstrap-vue/es/components/breadcrumb/breadcrumb-item'
import bBreadcrumbLink from 'bootstrap-vue/es/components/breadcrumb/breadcrumb-link'
import bButton from 'bootstrap-vue/es/components/button/button'
import bButtonClose from 'bootstrap-vue/es/components/button/button-close'
import bButtonGroup from 'bootstrap-vue/es/components/button-group/button-group'
import bButtonToolbar from 'bootstrap-vue/es/components/button-toolbar/button-toolbar'
import bCard from 'bootstrap-vue/es/components/card/card'
import bCardBody from 'bootstrap-vue/es/components/card/card-body'
import bCardFooter from 'bootstrap-vue/es/components/card/card-footer'
import bCardGroup from 'bootstrap-vue/es/components/card/card-group'
import bCardHeader from 'bootstrap-vue/es/components/card/card-header'
import bCardImage from 'bootstrap-vue/es/components/card/card-img'
import bCarousel from 'bootstrap-vue/es/components/carousel/carousel'
import bCarouselSlide from 'bootstrap-vue/es/components/carousel/carousel-slide'
import bCol from 'bootstrap-vue/es/components/layout/col'
import bCollapse from 'bootstrap-vue/es/components/collapse/collapse'
import bContainer from 'bootstrap-vue/es/components/layout/container'
import bDropdown from 'bootstrap-vue/es/components/dropdown/dropdown'
import bDropdownDivider from 'bootstrap-vue/es/components/dropdown/dropdown-divider'
import bDropdownHeader from 'bootstrap-vue/es/components/dropdown/dropdown-header'
import bDropdownItem from 'bootstrap-vue/es/components/dropdown/dropdown-item'
import bDropdownItemButton from 'bootstrap-vue/es/components/dropdown/dropdown-item-button'
import bEmbed from 'bootstrap-vue/es/components/embed/embed'
import bForm from 'bootstrap-vue/es/components/form/form'
import bFormCheckbox from 'bootstrap-vue/es/components/form-checkbox/form-checkbox'
import bFormCheckboxGroup from 'bootstrap-vue/es/components/form-checkbox/form-checkbox-group'
import bFormFile from 'bootstrap-vue/es/components/form-file/form-file'
import bFormGroup from 'bootstrap-vue/es/components/form-group/form-group'
import bFormInput from 'bootstrap-vue/es/components/form-input/form-input'
import bFormInvalidFeedback from 'bootstrap-vue/es/components/form/form-invalid-feedback'
import bFormRadio from 'bootstrap-vue/es/components/form-radio/form-radio'
import bFormRadioGroup from 'bootstrap-vue/es/components/form-radio/form-radio-group'
import bFormRow from 'bootstrap-vue/es/components/layout/form-row'
import bFormSelect from 'bootstrap-vue/es/components/form-select/form-select'
import bFormText from 'bootstrap-vue/es/components/form/form-text'
import bFormTextarea from 'bootstrap-vue/es/components/form-textarea/form-textarea'
import bFormValidFeedback from 'bootstrap-vue/es/components/form/form-valid-feedback'
import bImage from 'bootstrap-vue/es/components/image/img'
import bImageLazy from 'bootstrap-vue/es/components/image/img-lazy'
import bInputGroup from 'bootstrap-vue/es/components/input-group/input-group'
import bInputGroupAddon from 'bootstrap-vue/es/components/input-group/input-group-addon'
import bInputGroupAppend from 'bootstrap-vue/es/components/input-group/input-group-append'
import bInputGroupPrepend from 'bootstrap-vue/es/components/input-group/input-group-prepend'
import bInputGroupText from 'bootstrap-vue/es/components/input-group/input-group-text'
import bJumbotron from 'bootstrap-vue/es/components/jumbotron/jumbotron'
import bLink from 'bootstrap-vue/es/components/link/link'
import bListGroup from 'bootstrap-vue/es/components/list-group/list-group'
import bListGroupItem from 'bootstrap-vue/es/components/list-group/list-group-item'
import bMedia from 'bootstrap-vue/es/components/media/media'
import bMediaAside from 'bootstrap-vue/es/components/media/media-aside'
import bMediaBody from 'bootstrap-vue/es/components/media/media-body'
import bModal from 'bootstrap-vue/es/components/modal/modal'
import bNav from 'bootstrap-vue/es/components/nav/nav'
import bNavbar from 'bootstrap-vue/es/components/navbar/navbar'
import bNavbarBrand from 'bootstrap-vue/es/components/navbar/navbar-brand'
import bNavbarNav from 'bootstrap-vue/es/components/navbar/navbar-nav'
import bNavbarToggle from 'bootstrap-vue/es/components/navbar/navbar-toggle'
import bNavForm from 'bootstrap-vue/es/components/nav/nav-form'
import bNavItem from 'bootstrap-vue/es/components/nav/nav-item'
import bNavItemDropdown from 'bootstrap-vue/es/components/nav/nav-item-dropdown'
import bNavText from 'bootstrap-vue/es/components/nav/nav-text'
import bPagination from 'bootstrap-vue/es/components/pagination/pagination'
import bPaginationNav from 'bootstrap-vue/es/components/pagination-nav/pagination-nav'
import bPopover from 'bootstrap-vue/es/components/popover/popover'
import bProgress from 'bootstrap-vue/es/components/progress/progress'
import bProgressBar from 'bootstrap-vue/es/components/progress/progress-bar'
import bRow from 'bootstrap-vue/es/components/layout/row'
import bTab from 'bootstrap-vue/es/components/tabs/tab'
import bTable from 'bootstrap-vue/es/components/table/table'
import bTabs from 'bootstrap-vue/es/components/tabs/tabs'
import bTooltip from 'bootstrap-vue/es/components/tooltip/tooltip'

Vue.component('b-alert', bAlert)
Vue.component('b-badge', bBadge)
Vue.component('b-breadcrumb', bBreadcrumb)
Vue.component('b-breadcrumb-item', bBreadcrumbItem)
Vue.component('b-breadcrumb-link', bBreadcrumbLink)
Vue.component('b-button', bButton)
Vue.component('b-button-close', bButtonClose)
Vue.component('b-button-group', bButtonGroup)
Vue.component('b-button-toolbar', bButtonToolbar)
Vue.component('b-card', bCard)
Vue.component('b-card-body', bCardBody)
Vue.component('b-card-footer', bCardFooter)
Vue.component('b-card-group', bCardGroup)
Vue.component('b-card-header', bCardHeader)
Vue.component('b-card-image', bCardImage)
Vue.component('b-carousel', bCarousel)
Vue.component('b-carousel-slide', bCarouselSlide)
Vue.component('b-col', bCol)
Vue.component('b-collapse', bCollapse)
Vue.component('b-container', bContainer)
Vue.component('b-dropdown', bDropdown)
Vue.component('b-dropdown-divider', bDropdownDivider)
Vue.component('b-dropdown-header', bDropdownHeader)
Vue.component('b-dropdown-item', bDropdownItem)
Vue.component('b-dropdown-item-button', bDropdownItemButton)
Vue.component('b-embed', bEmbed)
Vue.component('b-form', bForm)
Vue.component('b-form-checkbox', bFormCheckbox)
Vue.component('b-form-checkbox-group', bFormCheckboxGroup)
Vue.component('b-form-file', bFormFile)
Vue.component('b-form-group', bFormGroup)
Vue.component('b-form-input', bFormInput)
Vue.component('b-form-invalid-feedback', bFormInvalidFeedback)
Vue.component('b-form-radio', bFormRadio)
Vue.component('b-form-radio-group', bFormRadioGroup)
Vue.component('b-form-row', bFormRow)
Vue.component('b-form-row', bFormRow)
Vue.component('b-form-select', bFormSelect)
Vue.component('b-form-text', bFormText)
Vue.component('b-form-textarea', bFormTextarea)
Vue.component('b-form-valid-feedback', bFormValidFeedback)
Vue.component('b-image', bImage)
Vue.component('b-image-lazy', bImageLazy)
Vue.component('b-input-group', bInputGroup)
Vue.component('b-input-group-addon', bInputGroupAddon)
Vue.component('b-input-group-append', bInputGroupAppend)
Vue.component('b-input-group-prepend', bInputGroupPrepend)
Vue.component('b-input-group-text', bInputGroupText)
Vue.component('b-jumbotron', bJumbotron)
Vue.component('b-link', bLink)
Vue.component('b-list-group', bListGroup)
Vue.component('b-list-group-item', bListGroupItem)
Vue.component('b-media', bMedia)
Vue.component('b-media-aside', bMediaAside)
Vue.component('b-media-body', bMediaBody)
Vue.component('b-modal', bModal)
Vue.component('b-nav', bNav)
Vue.component('b-nav-form', bNavForm)
Vue.component('b-nav-item', bNavItem)
Vue.component('b-nav-item-dropdown', bNavItemDropdown)
Vue.component('b-nav-text', bNavText)
Vue.component('b-navbar', bNavbar)
Vue.component('b-navbar-brand', bNavbarBrand)
Vue.component('b-navbar-nav', bNavbarNav)
Vue.component('b-navbar-toggle', bNavbarToggle)
Vue.component('b-pagination', bPagination)
Vue.component('b-pagination-nav', bPaginationNav)
Vue.component('b-popover', bPopover)
Vue.component('b-progress', bProgress)
Vue.component('b-progress-bar', bProgressBar)
Vue.component('b-row', bRow)
Vue.component('b-tab', bTab)
Vue.component('b-table', bTable)
Vue.component('b-tabs', bTabs)
Vue.component('b-tooltip', bTooltip)

 

 

3. VueJS로 개발하기


[ Vue Router - 화면 전환 ]

일반적으로 View에서 화면인 전한되는 것을 Routing이라고 한다. 일반적인 웹 어플리케이션은 해당 웹 페이지를 서버에 요청하고, 서버가 html을 돌려 주었을 때 그것을 렌더링 엔진을 통해 화면에 보여준다. SPA(Single Page Application)는 해당 화면에 대한 정보를 미리 가지고 있다가, 해당 화면으로 넘어갈 때 서버에 요청하는 것이 아니라 클라이언트 내부에서 돔을 변경하여 화면을 전환한다.

 

URL을 요청하기 위해서는 /router/index.js의 router에 history 모드를 추가해주어야 한다.

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import LoginView from '@/components/login/LoginView'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    }
  // #을 제거하기 위해 history를 모드로 추가한다.
  mode: 'history'
})

 

Vue에서 다른 페이지로 라우팅을 해주기 위해서는 /router/index.js의 routes에 다른 화면을 추가해주어야 한다. 아래의 예시에서는 LoginView를 추가하였다.

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import LoginView from '@/components/login/LoginView'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    {
      path: '/login/loginView',
      name: 'LoginView',
      component: LoginView
    }
  ],
  mode: 'history'
})

 

현재의 화면이 다른 화면으로 전환하기 위해서는 router-link 태그를 사용하거나 router 메소드를 사용하는 방법이 있다. 파라미터나 리퀘스트 정보 등을 함께 전송하기 위해서는 router method를 사용하면 되고, 단순 화면 이동을 위해서는 router-link를 사용하면 된다. 여기서 사용되는 router-link는 a 태그로 변환된다.

이러한 코드를 담고있는 HelloWorld.vue 파일은 아래와 같다.

  <div>
    <!-- Provides extra visual weight and identifies the primary action in a set of buttons -->
    <router-link to="/login/loginView">
      <button color="primary" >router-link</button>
    </router-link>

    <!-- Default button -->
    <button color="default" @click="onBtnClicked()">router.push</button>

  </div>
</template>

<script>
import { mdbBtn } from 'mdbvue'

export default {
  name: 'HelloWorld',
  components: {
    mdbBtn
  },
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  },
  methods: {
    onBtnClicked () {
      this.$router.push('/login/loginView')
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

 

라우팅된 화면은 App.vue의 <router-view/>에 출력된다. 적용된 router-view 태그는 라우팅 정보가 바뀌면 해당하는 View를 그려 다른 화면으로 전환하게 된다.

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <router-view/>
  </div>
</template>

<script>
import { mdbBtn } from 'mdbvue'
export default {
  name: 'App',
  components: {
    mdbBtn
  }
}
</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>

 

라우팅에 따라 아래와 같은 이벤트를 호출하여 함수를 동작할 수 있다.

  • beforeRouteUpdate: 라우터 업데이트 될 때
  • beforeRouteLeave: 현재 라우터를 떠날 때
  • beforeRouteEnter: 현재 라우터로 들어오기 직전

 

이벤트를 적용하기 위해 `/router/index.js`를 아래와 같이 수정할 수 있다.

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import LoginView from '@/components/login/LoginView'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    {
      path: '/login/loginView',
      name: 'LoginView',
      component: LoginView,
      beforeEnter: function (to, from, next) {
        alert('Route will be updated.')
        next()
      }
    }
  ],
  mode: 'history'
})

 

위의 예에서 next는 Parameter에 따라 다른 동작을 하게 된다.

  • next() => 라우트 이동
  • next(false) => 라우트 이동 중지
  • next('routePath') => 해당 라우트 경로로 이동

 

[ Axios - 서버 통신 ]

서버와 통신하기 위한 라이브러리는 axios, fetch, superagent 등이 있다. Vue JS의 창시자인 에반 유는 axios를 사용할 것을 권장하고 있다. Axios를 사용하기 위해서는 해당 프로젝트 폴더로 이동한 후에 아래의 명령어를 통해 Axios를 추가하면 된다.

npm install --save axios

 

위의 과정을 통해 axios가 설치되면, /src/index.js에 해당 모듈을 추가하고 전역적으로 사용하기 위해서 변수를 프로토타입에 추가해준다.

import Vue from 'vue'
import App from './App'
import router from './router'
import axios from 'axios'
import 'bootstrap-css-only/css/bootstrap.min.css'
import 'mdbvue/build/css/mdb.css'

Vue.prototype.$axios = axios
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

 

그리고 개발 서버로 API가 호출되도록 Proxy 설정을 진행해야 한다. Proxy 룰을 설정하기 위해서는 config/index.js에 있는 dev.proxyTable 옵션을 수정해야 한다. 간단한 예제로 설정을 해보면 다음과 같다.

// config/index.js
module.exports = {
  // ...
  dev: {
    proxyTable: {
      // proxy all requests starting with /api to jsonplaceholder
      '/api': {
        target: 'http://localhost:8090',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
}

 

위의 예제에서 /api 접두사를 제거한 후에 proxy 설정을 날린다고 할 때 대상 경로를 다시 작성하기 위해 pathRewrite를 작성한다. 그 결과로 Vue JS 내부에서 /api/user/login에 대한 요청은 http://localhost:8090/user/login로 프록시 처리되게 된다.

 

axios를 사용하는 방법에는 get(데이터 불러오기), post(데이터 추가하기), patch(특정 데이터 수정하기), delete(데이터 삭제하기) 등이 있는데, post를 LoginView에 적용하면 아래와 같다.

<template>
  <!-- Material form login -->
  <form>
    <p class="h4 text-center mb-4">Sign in</p>
    <div class="grey-text">
      <mdb-input v-model="userEmail" label="Your email" icon="envelope" type="email"/>
      <mdb-input v-model="userPw" label="Your password" icon="lock" type="password"/>
    </div>
    <div class="text-center">
      <mdb-btn @click="requestLogin">Login</mdb-btn>
    </div>
  </form>
  <!-- Material form login -->
</template>

<script>
import { mdbInput, mdbBtn } from 'mdbvue'

export default {
  name: 'LoginView',
  components: {
    mdbInput,
    mdbBtn
  },
  data () {
    return {
      userEmail: '',
      userPw: '',
      msg: 'Welcome to Your Vue.js App'
    }
  },
  methods: {
    requestLogin: function () {
      this.$axios.post('/api/user/login',
        {userEmail: this.userEmail, userPw: this.userPw}
      ).then(response => {
        console.log(response)
      }).catch((exception) => {
        console.error('ERRORR!!!! : ', exception)
      })
    }
  }
}
</script>

 

 

4. 기타 VueJS 설명


[ VueJS 디렉토리 구조 ]

build 
→ 배포시 관련 설정들이 들어있는 폴더

config 
→ webpack관련 설정들이 포함되어 있는 폴더

index.html
→ VueJs HTML 시작페이지로, 배포시 index.html도 같이 배포된다.

src
→ VueJs의 소스 코드들이 있는 폴더로 이 디렉토리에서 개발을 진행하게 된다.

static
→ VueJs와 무관하게 공통으로 사용해야 할 정적 파일들을 관리한다.

test 
→ 개발하면서 유닛테스트를 진행할 수 있도록 준비되어 있는 폴더

# 빌드 후 생성되는 폴더 
dist → 빌드를 완료하게 되면 dist폴더에 모든 파일과 index.html까지 포함되어 생성된다. 이 폴더 안에 있는 모든 파일을 배포 공간에 넣어두면 서비스를 운영할 수 있다.

package.json
→ npm 의존성 모듈 목록 및 프로젝트 기본 설정들이 표기되어 있다. 또한  개발모드와 배포모드의 명령어 들이 정의되어 있다.

webpack.config.js
→ 개발을 완료하고 존재하는 여러 파일들을 하나로 묶어주고 관리해주는 `webpack`의 설정파일
(내용이 어려울 수 있으니 여기에서는 추후에 다시 설명할 예정)

 

[ VueJS src 디렉토리 구조 ]

assets
→ Image나 css등 공통으로 `Vuejs`에서 요청하고 관리될 Resource 파일들을 저장하는 곳

App.vue
→ Vuejs의 최상위 컴포넌트로, 여기에서 본격적으로 `Vuejs`로 개발한다.

main.js
→ Vue 인스턴스를 새로 만들고 시작하는 부분으로, 전역으로 처리해야 하는 일을 진행한다.

 

[ 정적 자원의 처리 ]

src/assets와 static/는 웹펙에 의해 처리되느냐 안되느냐의 차이가 있다.

웹팩은 모듈 번들러로, 추가적으로 가져와야하는 것들을 하나의 js파일로 만들어준다.

 

src/assets는 웹팩에 의해 처리되는 정적 자원으로 아래와 같은 과정을 통해 처리된다. 먼저 *.vue 컴포넌트 안에 있는 모든 html 템플릿과 css들은 URL 경로를 찾기 위해 vue-html-loader와 css-loader에 의해 분석된다. 예를 들어 <img src="./logo.png">, backgroud:url(./logo.png)에서 "./logo.png"는 상대 경로를 나타내며, logo.png는 JavaScript가 아니기 때문에 모듈 디펜던시로 취급되어 url-loader와 file-loader로 웹팩에 의해 처리된다. 이 로더들은 기본적으로 탑재되어 있기 때문에 배포를 위해 상대/모듈 경로를 신경쓸 필요가 없다.

static/에 위치하는 파일들은 웹팩에 의해 처리되지 않고, 최종 경로에 같은 이름으로 복사된다. config/injdex.js에 있는 build.assetsPublicPath와 build.assetsSubDirectory에 의해 결정되어지는 절대 경로를 이용하여 이 파일들에 접근할 수 있다. config/index.js에는 기본적으로 아래와 같이 설정되어 있다.

// config/index.js
module.exports = {
  // ...
  build: {
    assetsPublicPath: '/',
    assetsSubDirectory: 'static'
  }
}

 

위의 구성을 따르면 static/에 위치하는 파일들은 절대경로인 /static/{fileName}으로 접근할 수 있다. 만약 assetsSubDirectory를 assets로 바꾼다면 /assets/{fileName}으로 파일에 접근할 수 있다.

 

 

[ 환경 분리 ]

보통 test, dev, prod로 개발 환경을 다르게 구성하는 경우가 많은데 이러한 설정은 config/prod.env.js에서 처리한다. String 변수는 ' "{문자열}" ' 로 사용해야 한다.

// config/prod.env.js
module.exports = {
  NODE_ENV: '"production"',
  DEBUG_MODE: false,
  API_KEY: '"..."' // this is shared between all environments
}

// config/dev.env.js
module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',
  DEBUG_MODE: true // this overrides the DEBUG_MODE value of prod.env
})

// config/test.env.js
module.exports = merge(devEnv, {
  NODE_ENV: '"testing"'
})

 

 

 

 

참고 자료

반응형