Study/Frontend

Vue 3 + TS + AntDV 프로젝트 세팅하기

LireEruel 2023. 10. 18. 14:11

Vue 3부터는 vite 기반으로 프로젝트가 생성됩니다.

오늘은 npm과 yarn이 있다고 가정하고 프로젝트를 세팅하도록 하겠습니다.

기본적인 세팅을 함께하고, 제가 하는 프로젝트 초기 세팅도 함께 해보겠습니다.

 

Vue 3 생성하기

npm create vite@latest

위 명령어를 입력하면 여러가지 설정을 할 수 있습니다.


그리고 yarn을 입력해서 패키지를 설치합니다.

yarn

success가 뜨고, yarn lock 파일이 생긴 것을 볼 수 있습니다.


이제 실행해봅시다.

yarn dev

 

http://localhost:5173/ 에 접속해봅시다.

이렇게 간단히, 프로젝트를 생성하였습니다.

화면에 보이는 것처럼 VS CODE에 Volar를 설치하는 것이 더 편합니다.


Ant Design Vue 적용하기

이제 Ant Design Vue를 적용해보겠습니다.

 yarn add ant-design-vue@4.x
yarn add unplugin-vue-components -D

root 폴더의 vite.config.ts를 아래 내용으로 바꿔주세요.

 

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import Components from "unplugin-vue-components/vite";
import { AntDesignVueResolver } from "unplugin-vue-components/resolvers";
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    Components({
      resolvers: [
        AntDesignVueResolver({
          importStyle: false, // css in js
        }),
      ],
    }),
  ],
});

 

이제 Ant Design Vue 설정이 다 되었습니다. 

잘 되었는지 확인해봅시다.

 

App.vue를 아래 처럼 작성해주세요.

<script setup lang="ts">
import { Button } from "ant-design-vue";
</script>

<template>
  <Button>Ant Design Vue의 버튼!</Button>
</template>

그리고 http://localhost:5173/ 이곳에서 확인해주세요.

 

버튼이 보이면 성공입니다!

 


프로젝트 구조 세팅하기

Project structure는 아래 링크를 기반으로 합니다.

https://github.com/hirotaka/bulletproof-vue/blob/main/docs/project-structure.md

src
|
+-- assets            # assets folder can contain all the static files such as images, fonts, etc.
|
+-- components        # shared components used across the entire application
|
+-- config            # all the global configuration, env variables etc. get exported from here and used in the app
|
+-- features          # feature based modules
|
+-- composables       # encapsulate and reuse stateful logic used across the entire application
|
+-- lib               # re-exporting different libraries preconfigured for the application
|
+-- providers         # all of the application providers
|
+-- routes            # routes configuration
|
+-- stores            # global state stores
|
+-- test              # test utilities and mock server
|
+-- types             # base types used across the application
|
+-- utils             # shared utility functions

 

커스텀 Axios 추가하기

yarn add axios

src /lib/commonAxios.ts 를 만들어주세요.

* 앞으로 얘기 안해도 중간의 폴더(여기서는 lib)도 만들어야합니다.

 

commonAxios.ts는 아래에 있습니다.

import { notification } from "ant-design-vue";
import axios from "axios";

const cancelTokenSource = axios.CancelToken.source();

const commonAxios = axios.create({
  cancelToken: cancelTokenSource.token,
});

commonAxios.interceptors.request.use(function (config): any {
  if (typeof window === undefined) {
    return;
  }

  // 이 부분에 cookie 확인해서 유효성 검증하는 코드를 추가할 수 있습니다.

  config.headers = Object.assign({}, config.headers, {
    "Content-Type": "application/json",
    // 'access_token': cookies['access_token'],
  });

  return config;
});

commonAxios.interceptors.response.use(
  function (response) {
    return response;
  },
  function (error) {
    console.log(error);
    console.error("error", error?.response);
    const errorCode = String(error?.response?.status ?? "");

    if (errorCode === "401") {
      notification.error({
        key: "error-notification",
        message: "토큰이 만료되었습니다. 로그인을 다시 해주세요.",
        description: errorCode,
      });
    } else if (errorCode === "403") {
      notification.error({
        key: "error-notification",
        message: "권한이 없습니다.",
        description: errorCode,
      });
    } else {
      notification.error({
        key: "error-notification",
        message: "API 에러 발생",
        description: errorCode,
      });
    }
    return Promise.reject(error);
  }
);

export default commonAxios;
앞으로 api를 만들 때에는 axios 말고 우리가 만든 commonAxios를 사용해야합니다.

 

App.vue 수정하기.

yarn add vue-router
yarn add sass

src/App.vue를 수정해주세요.

 

<script setup lang="ts">
import { RouterView } from "vue-router";
</script>

<template>
  <div class="app">
    <router-view class="header" name="header" />
    <div class="contents">
      <router-view class="body" name="body" />
    </div>
    <router-view class="footer" name="footer" />
  </div>
</template>

<style lang="scss" scoped>
.app {
  color: rgba(0, 0, 0, 0.85);
  display: flex;
  position: fixed;
  width: 100%;
  height: 100%;
  flex-direction: column;
}

.contents {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  min-width: 600px;
  overflow-y: auto;
}
</style>

src 밑에 위 사진을 참고해서 파일들을 만들어주세요.

App.scss

DefaultFooter.cue

DefaultHeader.vue

router/index.ts입니다.

 

각 파일의 내용은 아래에 있으니 차분히 옮겨줍시다.

 

App.scss

scss는 기본적인 스타일을 넣어놨으므로, 필요에 따라 수정해도 됩니다.


:host {
  width: 100%;
  height: 100%;
}

*::-webkit-scrollbar {
  width: 16px;
  height: 16px;
}

*::-webkit-scrollbar-track {
  background: transparent;
}

*::-webkit-scrollbar-thumb {
  border: 6px solid rgba(0, 0, 0, 0);
  background-clip: padding-box;
  border-radius: 8px;
  background-color: rgba(0, 0, 0, 0.45);
}

html,
body {
  padding: 0;
  margin: 0;
  width: 100%;
  height: 100%;
}

#app {
  height: 100%;
}


DefaultFooter

<template>
  <div class="footer">
    <span class="copyright-string footer-text">
      Copyright ⓒ SSAFY Corporation. All Rights Reserved.
    </span>
    <router-link class="terms-of-use-link footer-text" to="/">
      이용약관
    </router-link>
    <router-link class="privacy-link footer-text" to="/">
      개인정보처리방침
    </router-link>
  </div>
</template>

<style lang="scss" scoped>
.footer {
  display: flex;
  justify-content: center;
  text-align: center;
  height: 26px;
  margin: 5px 0;
}
.footer-logo {
  width: 105px;
}
.copyright-string {
  margin-left: 40px;
}
.terms-of-use-link,
.privacy-link {
  margin-left: 12px;
}
.footer-text {
  font-size: 12px;
  color: rgba(0, 0, 0, 0.45);
}
</style>

DefaultHeader

<script setup lang="ts">
import { ref } from "vue";
import { RouterLink } from "vue-router";

const menuKey = ref<string[]>([window.location.pathname]);
</script>

<template>
  <a-layout id="components-layout">
    <a-layout-header
      :style="{ position: 'fixed', width: '100%', overflow: 'hidden' }"
    >
      <div style="float: left">
        <router-link to="/" class="app-logo">Home </router-link>
      </div>

      <div class="nav-right">
        <!-- 로그인 -->
        <a-button class="login-button"> 로그인 </a-button>
        <span class="app-bar-padding" />
      </div>
      <a-menu
        v-model:selectedKeys="menuKey"
        class="menu"
        theme="dark"
        mode="horizontal"
        :style="{ lineHeight: '64px' }"
      >
        <a-menu-item key="/">
          <RouterLink to="/"> MenuItem </RouterLink></a-menu-item
        >
        <a-menu-item key="/#">
          <RouterLink to="/#"> MenuItem2 </RouterLink>
        </a-menu-item>
      </a-menu>
    </a-layout-header>
  </a-layout>
</template>

<style lang="scss" scoped>
#components-layout {
  height: 70px;
  width: 100%;
  margin-bottom: 1px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  z-index: 1;
}

#components-layout .menu {
  float: right;
}

#components-layout .nav-right {
  float: right;
  padding-left: 20px;
}

.login-button {
  font-weight: 900;
}
</style>

router/index.ts

import { createRouter, createWebHistory } from "vue-router";
import HelloWorld from "../components/HelloWorld.vue";
import DefaultHeader from "../components/layouts/DefaultHeader.vue";
import DefaultFooter from "../components/layouts/DefaultFooter.vue";

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: "/",
      name: "hello",
      components: {
        header: DefaultHeader,
        body: HelloWorld,
        footer: DefaultFooter,
      },
    },
  ],
});

export default router;

 

router와 App.scss를 적용하기 위해 src/main.ts를 수정합니다.

import { createApp } from "vue";
import "./assets/App.scss";
import App from "./App.vue";
import router from "./router";

const app = createApp(App);

app.use(router);
app.mount("#app");