Vue 3.0/03.SFC와 Vite

[Vue 3] 03.Vite 기반의 Vue 개발 2

  • -
반응형

이번 포스트에서는 Vite 기반 프로젝트에서 간단한 코딩을 해보자.

소스 코드 작성

 

src의 구조

먼저 src의 구조에 대해 살펴보자. Vue 애플리케이션은 index.html에서 main.js를 로딩하고 main.js에서 App.vue를 이용해서 Vue 애플리케이션을 구성하는 형태로 작성된다. 

애플리케이션을 구성하는 컴포넌트들은 각각 .vue로 작성되며 javascript에서 다른 리소스들을 참조하기 위해서 import 를 이용한다.

기본 프로젝트의 구조

 

.vue 파일의 구조

각각의 .vue 파일은 SFC(Single File Component) 형태로 작성되며 <template>, <script>, <style> 3가지로 구성된다.

  • <template/>
    • html 태그를 작성하는 부분으로 하나의 vue 파일은 최대 1개의 template을 가짐
  • <script/>
    • 하나의 vue 파일은 최대 하나의 <script>를 가짐(<script setup>은 제외)
    • script는 javascript의 module로 실행됨
    • default export 내용은 vue component의 options 객체이거나 기본 객체
    • composition api 방식에서는 <script setup> 형태로  작성해서 component의 setup()에 작성하던 코드를 작성
  • <style/>
    • 컴포넌트에서 사용할 스타일로 하나의 vue에 여러개의 <style> 존재 가능
    • 기본은 전역이며 현재 component에만 적용할 경우는 scoped 속성 사용 (<style scoped></style>)

 

 

.html to .vue

 

.html 기반의 vue application

그럼 앞서 .html 기반으로 작성했던 Todo app을 .vue 기반으로 변경해보자.

https://goodteacher.tistory.com/658

 

[vue 3] 14.Try Yourself!!

이제까지 배운 내용을 바탕으로 아래 요구사항을 만족시키는 앱을 구성해보자. Todo App 요구사항

goodteacher.tistory.com

 

기본적인 코드는 아래를 참조한다.

더보기
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>모두의 코딩</title>
    <style>
      @import "./assets/base.css";
      img {
        width: 50px;
      }
      .title {
        font-size: 3em;
      }

      .header {
        display: flex;
        align-items: center;
      }
      .dash {
        margin: 20px 0px;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <div class="header">
        <img :src="logo" title="logo" />
        <span class="title">{{ title }}</span>
      </div>
      <div class="dash">
        <span>미완성 할일 목록: {{ remains }}</span> &nbsp;
        <label>새로운 할일: <input v-model="newTodo" /></label>
        <button @click="addTodo">추가</button>
      </div>
      <h2>할일목록</h2>
      <ul>
        <li v-for="(item, index) in todos" :key="index">
          <label><input type="checkbox" v-model="item.done" />{{ item.todo }}</label>
        </li>
      </ul>
    </div>
  </body>
</html>
<script src="https://unpkg.com/vue@3"></script>
<script>
  const { createApp, ref,reactive,  computed } = Vue;
  createApp({
    setup() {
      const logo = "./assets/logo.svg";
      const title = "todo app";
      const newTodo = ref("");
      const todos = reactive([{ todo: "study", done: true }]);
      const remains = computed(() => {
        return todos.filter((item) => !item.done).length;
      });
      const addTodo = () => {
        todos.push({ todo: newTodo.value, done: false });
        newTodo.value=""
      };
      return { logo, title, newTodo, todos, remains, addTodo };
    },
  }).mount("#app");
</script>

 

이 내용을 .vue 파일로 작성해보자. App.vue 파일을 아래와 같이 대체해보자.

 

<template>

<template>
  <div class="header">
    <img :src="logo" title="logo" />
    <span class="title">{{ title }}</span>
  </div>
  <div class="dash">
    <span>미완성 할일 목록: {{ remains }}</span> &nbsp;

    <label>새로운 할일: <input v-model="newTodo" /></label>
    <button @click="addTodo">추가</button>
  </div>

  <h2>할일목록</h2>
  <ul>
    <li v-for="(item, index) in todos" :key="index">
      <label><input type="checkbox" v-model="item.done" />{{ item.todo }}</label>
    </li>
  </ul>
</template>

.html 버전에서는 id=app인 영역에 template을 만들고 vue 애플리케이션을 mount 했지만 .vue 기반에서는 <template>에 직접 작성한다. 내용은 동일하다.

 

<style>

style 부분에는 기존의 <style>에 있던 내용을 그대로 옮겨 놓으면 된다.

<style scoped>
@import '@/assets/base.css';
img {
  width: 50px;
}
.title {
  font-size: 3em;
}

.header {
  display: flex;
  align-items: center;
}
.dash {
  margin: 20px 0px;
}
</style>

css와 관련된 내용은 <style> 태그에 작성하는데 scoped 옵션을 이용하면 현재의 component에만 적용된다. assets에 작성된 css를 사용하기 위해서는 @import를 이용한다.

scoped가 적용되면 html로 변환될 때 각 요소에 data-v-xxx 형태의 특별한 attribute를 추가해서 관리해준다.

https://goodteacher.tistory.com/668

 

[vue] <style scoped>의 비밀

이번 포스트에서는 vue component의 의 동작에 대해서 살펴보자. vs SFC와 style SFC는 하나의 파일에 , , 가 들어간다. 문제는 최종적인 application은 SFC로 동작하지 않고 하나의 html 형태로 동작한다는 점

goodteacher.tistory.com

스타일 가이드에 따르면 scoped에는 element 선택자를 사용하지 않기를 권장한다. 속도 때문인데 간단한 예제에서는 상관 없지만 실무에서는 class 선택자를 사용하기를 권장한다.

 

 

https://ko.vuejs.org/style-guide/rules-use-with-caution.html#element-selectors-with-scoped

 

우선순위 D 규칙: 주의해서 사용 | Vue.js

VueConf Toronto - Join the premier Vue.js conference | 9-10 Nov 2023 - Toronto, CanadaView Schedule Use code VUEJS to get 15% off

ko.vuejs.org

 

<script setup>

마지막으로 그래도 손이 좀 가는 script 영역을 작성해보자.

<script setup>
import { ref, reactive, computed } from 'vue'

import logo from '@/assets/logo.svg'
const title = 'todo app'

const newTodo = ref('')

const todos = reactive([{ todo: 'study', done: true }])

const remains = computed(() => {
  return todos.filter((item) => !item.done).length
})

const addTodo = () => {
  todos.push({ todo: newTodo.value, done: false })
  newTodo.value = ''
}
</script>

거의 copy ~ paste 형태로 작성되었다. 큰 차이점을 살펴보면 다음과 같다.

  • <script src="https://unpkg.com/vue@3"></script>로 로딩하지 않는다. 왜냐하면 npm 기반으로 설치되었기 때문이다.
  • Vue에서 {createApp, ref, computed}를 가져왔으나 "vue"에서 ref와 computed 등을 import 해온다.
  • assets의 자원인 logo를 가져올 때 import를 사용한다. 여기서 @는 vite.config.js에 설정된 alias로 .src를 의미한다.
  • 필요한 변수들 (logo, title 등)을 선언 후 return 할 필요가 없다.
  • #app에 mount 할 필요는 없다.

나머지 로직은 전혀 변경될 필요가 없다.

 

실행하기

 

다음으로 package.json에 작성된 script들을 실행하는 방법에 대해 알아보자.

npm run dev

작성된 애플리케이션을 실행하기 위해서는 package.json에 설정된 스크립트를 실행하면 된다. project 위치에서 prompt를 연 후 npm run dev를 입력하면 된다.

C:\Users\itsme\git\vue_basic_v3\03_component\hello_vue>npm run dev  

> hello_vue@0.0.0 dev
> vite


  VITE v4.4.9  ready in 1156 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h to show help

오류가 없다면 Local에 출력된 주소를 브라우저에 입력하면 된다.

npx vite dev --help를 이용하면 유용한 옵션에 대한 도움말을 볼 수 있는데 --open을 입력하면 자동으로 브라우저까지 실행해준다.

C:\Users\itsme\git\vue_basic_v3\03_component\hello_vue>npx vite dev --help
vite/4.4.9

Usage:
  $ vite [root]
- - -
Options:
  --host [host]           [string] specify hostname
  --port <port>           [number] specify port
  --https                 [boolean] use TLS + HTTP/2
  --open [path]           [boolean | string] open browser on startup

이제 package.json의 scripts에서 "dev": "vite" 부분을 아래처럼 수정해보자.

"dev": "vite --open",

이제 npm run dev 실행 시 바로 브라우저가 실행됨을 확인할 수 있다.

 

npm run build

작성된 애플리케이션을 배포하기 위해서는 npm run build 명령을 사용한다.  배포라는 것은 .vue나 assets들을 브라우저가 알아먹을 수 있는 .html 등으로 변경해서 특정 경로에 만들어준다. 기본 배포 폴더는 애플리케이션에 dist를 만들고 거기에 배포하면 된다.

C:\Users\itsme\git\vue_basic_v3\03_component\hello_vue>npm run build

> hello_vue@0.0.0 build
> vite build

vite v4.4.9 building for production...
✓ 13 modules transformed.
dist/assets/logo-277e0e97.svg    0.28 kB │ gzip:  0.20 kB
dist/index.html                  0.42 kB │ gzip:  0.28 kB
dist/assets/index-dca93e77.css   3.94 kB │ gzip:  0.88 kB
dist/assets/index-c72ef113.js   54.04 kB │ gzip: 21.91 kB
✓ built in 790ms

배포된 dist의 index.html 이 애플리케이션의 시작 파일이 된다.

npx vite build --help로 도움말을 보면 outDir을 통해 경로를 지정할 수 있음을 알 수 있다. 특정 위치의 서버에 배포할 때 유용한 설정이다.

 

npm run preview

npm run preview는 배포된 프로젝트를 이용해서 로컬에서 preview server를 실행한다. npm run dev가 개발중인 .vue등을 이용하는 반면 npm run preview는 배포된 결과물을 이용하는 점이 다르다.

 

npm run lint

프로젝트 생성 시 eslint를 선택했을 때 생성되는 스크립트인 npm run lint는 eslint를 이용해서 소스코드를 분석하고 프로그램의 오류, 버그, 스타일 오류 등을 처리해준다. 그런데 개발 과정에 자동으로 lint가 표시되는데 따로 할 필요가 있을까? 궁금하다.

평상시 eslint 옵션을 꺼 놓고 한방에 처리 할 때 정도?

"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore",

 

npm run format

프로젝트 생성 시 prettier를 선택했을 때 생성되는 스크립트인 npm run format는 prettier를 이용한 소스 코드의 포멧 작업을 처리하기 위해서 사용한다. 

"format": "prettier --write src/"

개발시에는 개발자가 원하는 스타일로 개발하다가 팀의 표준 스타일로 일괄적으로 포멧을 잡아야 한다면 유용하게 사용할 수 있겠다. --config 옵션을 이용해서 Prettier의 설정 파일을 지정할 수 있다.

--config <path>          Path to a Prettier configuration file 
                         (.prettierrc, package.json, prettier.config.js).

 

반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.