- Github Branch Name :
vue-endofvue-1.init
- summary
- 강좌에서 개발할 웹어플리케이션에 대해서 확인하고 일반적인 웹개발 절차와 API 문서에 대해서 알아본다.
회원가입
,로그인
,CRUD
가 발생하는 기본적인 웹어플리케이션
- 웹 개발 절차
- 요구사항 > 서비스 기획 > UI, UX 상세 설계 > GUI 디자인 > 퍼블리싱 > Back-End API 개발 > Front-End 개발 > QA
- Front-End 개발자의 역할
- Client UI에 대한 코드 작성
- 기획, 디자인, 퍼블리싱, Back-End 개발자와 소통
- Swagger UI
- Swagger는 개발자가 RESTfull API를 설계, 빌드, 문서화, 소비하는 일을 도와주는 오픈소스 소프트웨어 프레임워크
- Github Branch Name :
vue-endofvue-2.environment
- summary
- 개발환경 구성에 대해서 알아본다(깃허브, 필수 설치 프로그램, )
- Chrome, Git, Visual Studio Code, Node.js LTS 버전(v10.x 이상), Vue.js Dev Tools
- Github
- 개발 소스(Front-End) - Source, API(Back-End) - Source
vue-til-server
의 경우github
의root
에 존재하는vue-til-server-master.zip
다운받아 사용
- VS Code Plugin
- 색 테마 : Night Owl
- 파일 아이콘 테마 : Material Icon Theme
- 뷰 확장 플러그인 : Vetur
- 뷰 코드 스니펫 : Vue VSCode Snippets
- 문법 검사 : ESLint, TSLint
- 실습 환경 보조 : Live Server
- 기타
- git bash는 Windows에서도 Linux 명령어를 사용할 수 있는 환경
- Visual Studio Code에서도
gitbash
터미널을 사용할 수 있다.(본 강좌에서는 사용해야 함) - 기존의
terminal.integrated.shell.windows
에 대해서 VSCode 업데이트 됨에 사용할 수 없음(참고) Visual Studio Code
>ctrl + ,
>terminal.integrated.shell.windows
>setting.json
open > 하기의 코드 추가
"terminal.integrated.profiles.windows": {
"GitBash": {
// 일반적으로 : "C:\\Git\\bin\\bash.exe"
"path":["사용자별 git 설치 경로\\bash.exe"],
"icon":"terminal-bash"
},
"PowerShell": {
"source": "PowerShell",
"icon": "terminal-powershell"
},
"Command Prompt": {
"path": [
"${env:windir}\\Sysnative\\cmd.exe",
"${env:windir}\\System32\\cmd.exe"
],
"args": [],
"icon": "terminal-cmd"
},
},
// "GitBash"로 설정하면 "Bash"가 기본으로 설정 됨
"terminal.integrated.defaultProfile.windows": "Command Prompt",
- Node 버전 확인 및 업그레이드 & 다운그레이드
- 본 강좌의 소스는
node
버전이v10.16.3
으로 진행해야 함 - 특정 버전의 Node를 설치하는 방법은 2가지
- 원하는 LTS 버전을 찾아 해당 OS의 실행 파일로 설치 (GUI로 사용)
- NVM을 사용하여 특정 버전 설치 사용등 (Command Line으로 사용)
$ node -v v14.8.1
- Node js - v10.16.3에서 OS 버전에 맞는 파일을 다운로드 받아 설치 가능
- 본 강좌의 소스는
- NVM(Node Version Manager)
- NVM을 이용하여
nodejs
특정 버전을 설치, 업그레이드 및 다운그레이드 가능 - Node js
- NVM Github
NVM
설치- NVM 설치 및 버전 변경 절차 문서
VSCode
> 터미널을Bash
로 열고 하기 명령어 입력
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
- NVM 명령어 등록
VSCode
> 터미널을Bash
로 열고 하기 명령어 입력
$ vi ~/.bashrc // i : 쓰기모드 진입 export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm // esc : 쓰기모드 해지 // :wq : 저장하고 종료 (:q : 저장하지 않고 종료)
bash
터미널에서 하기 명령어를 입력하여 정상적으로NVM
이 설치 및 명령어가 적용되었는지 확인
$ nvm --version 0.39.0
- 노드 버전을 그냥 전환하고 싶다면
nvm use 버전 이름
사용 - nvm 노드 버전 설치 가이드
node
버전10.16.3
설치
$ nvm install 10.16.3 Downloading and installing node v10.16.3... Downloading https://nodejs.org/dist/v10.16.3/node-v10.16.3-win-x64.zip... ################################# 100.0% Computing checksum with sha256sum Checksums matched! Now using node v10.16.3 (npm v6.9.0) Creating default alias: default -> 10.16.3 (-> v10.16.3) $ node -v v10.16.3
vue-til-server > package.json
파일내 패키지 설치를 위한 명령어 실행
$ npm i
npm run dev
로 서버 실행
$ npm run dev ...중략... VUE TIL SERVER IS RUNNING ON 3000 // '3000'에 대한 포트를 사용중이면 하기에서 변경 가능 // src > app.js > port 번호 수정
http://localhost:3000/api/docs
로 접속하여 API 서버 확인
- NVM을 이용하여
- MongoDB Site
src > app.js
의const db
에서 하기의 생성된 DB를 연결bash
command >npm run dev
> Server 기동 >http://localhost:3000/api/docs
접속 > /signup API Test
Node js
로 작서된Back-End API
코드를Front-End
개발자와커뮤니케이션
하기 위한 API UIRESTfull API
를 직접 테스트 할 수 있는 API UI
- 웹팩 데브 서버 설명 글
- Vue.js 개발 생산성을 높여주는 도구 3가지
vue --version
으로 vue/cli 버전 확인vue create vue-til
으로 프로젝트 생성 (Manual로 선택하며, 하기의 이미지 참고)ESLint
구문 오류(ESLint 란?)- 해결 방법
vue.config.js
파일 생성하고 하기와 같은 코드 삽입빌드 오류
는 발생하나오버레이
안됨
module.exports = { devServer: { overlay: false, }, };
- ESLint 설정 파일 설정 방법
- root >
.eslintrc.js
파일에 하기와 같이 개발자 커스텀 설정 가능
- root >
rules: { "no-console": "error", // 정상을 위하여 "off"로 설정 필요 // "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", // "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", },
- Prettier (일관성 있는 코드 포맷을 위한 웹팩)
- 하기의 이미지처럼
prettier
구문을 적용하면 코드에 붉은색 라인이 생기며 빌드 오류 발생 - 해결 방법
"editor.codeActionsOnSave": { "source.fixAll.eslint": true }, "eslint.workingDirectories": [ { "mode": "auto" } ], // ESLint "eslint.validate":[ "vue", "javascript", "javascriptreact", "typescript", "typescriptreact" ], // don't format on save "editor.formatOnSave": false,
- 하기의 이미지처럼
- 파일의 절대 경로를 사용해야 하는 이유
- 상대 경로를 이용한 컴포넌트
import
는 depth가 많아 질수록 folder가 많아 질수록 복잡해 짐 - 이러한 상대 경로에서의 복잡함을 없애기 위해서 VSCode 설정을 활용한 절대 경로 사용
- jsconfig.json 파일 링크(Vue TIL 리포지토리)
- VSCode의 jsconfig.json 파일 설명 글
- 상대 경로를 이용한 컴포넌트
- Vue.js 공식팀에서 권고하는 스타일 가이드 준수
- Priotiry A : Essential, Priority B : Strongly Recommened
- Vue.js 스타일 가이드 문서
- Github Branch Name :
vue-endofvue-3.router_component
- summary
- 로그인, 회원가입 UI 개발
- 수업 깃헙 리포지토리 안내
// vue-til 소스를 최초에 설치할 경우
$ git clone https://github.com/joshua1988/vue-til
$ git checkout 1_setup
$ npm i
- LoginPage, SignupPage 생성 및 라우터 설정
- router 설치
$ npm i vue-router
- Code Splitting(코드 스플리팅)
export default new VueRouter({ routes: [ { path: '/login', component: () => import('@/views/LoginPage.vue'), }, { path: '/signup', component: () => import('@/views/SignupPage.vue'), }, ], });
- 뷰 라우터 오픈 소스
- 뷰 라우터 History Mode 주의 사항 문서
history
모드의 경우 URL에#
이 없이 나타난다.(서버가 새로운 페이지로 인식하지 못 함)- 서버가 새로운 페이지로 인식을 못 함으로 서버에 설정이 필요함.
- fallback router
- 지정된 경로가 아닌 경우를 대비
export default new VueRouter({
mode: 'history',
routes: [
{
path: '/login',
component: () => import('@/views/LoginPage.vue'),
},
{
path: '/signup',
component: () => import('@/views/SignupPage.vue'),
},
{
path: '*',
component: () => import('@/views/NotFoundPage.vue'),
},
],
});
- Github Branch Name :
vue-endofvue-4.dev_member
- summary
- 회원 가입을 위한
가입 폼 양식
,데이터 바인딩
,이벤트 연결
,API
에 대해서 개발
- 회원 가입을 위한
- 타입스크립트 핸드북
- async await 정리글
- ES6 템플릿 리터럴(백틱) 정리글
- ES6 Destructuring 정리글
SignupPage
에서SignupForm
콤포넌트사용하며,SignupPage
에서Axios
사용
- Github Branch Name :
vue-endofvue-5.configure
- summary
axios
사용api
콤포넌트에서 환경 설정 값을 사용
- 참고 자료
VUE_APP
접두사가 붙으면 코드에서 자동 인식
- Github Branch Name :
vue-endofvue-6.dev_login
- summary
로그인 양식
,API
,Validation
&Exception
기능 구현
- Email Validation 정규 표현식 코드
- 로그인 계정
- ID : [email protected]
- PWD : 1234
- Github Branch Name :
vue-endofvue-7.store_state
- summary
Style
,Main Page
- css/common.css, css/reset.css
- App.vue, AppHeader.vue
vue router > router-link
를 사용(html 레벨)vue router > router.push
를 사용(javascript 레벨)
- 개발용 라이브러리와 배포용 라이브러리 구분하기 문서
npm run build
는package.json
의dependencies
에 해당하는 라이브러리를 포함하여 빌드package.json
의devDependencies
는 빌드될때 포함되지 않음
Vuex
를 활용하여Store
,State
,mutations
&getters
를 활용
- Github Branch Name :
vue-endofvue-8.api_auth_token
- summary
API
를 통하여 통신할 경우JWT(Json Web Token)
인증을 통하여 통신
- Json web 토큰 문서
- 액시오스 인터셉터 문서
- 인터셉터를 통하여
axios.create
에서의token
값 할당에 대한 초기화 문제를 해결
- 인터셉터를 통하여
- Github Branch Name :
vue-endofvue-9.dev_retrieve
- summary
목록 조회
개발,style
적용,컴포넌트화
,로딩 상태
&로딩 스피너
개발
PostItem
에 대하여 컴포넌트화 (MainPage에서props
로 컴포넌트로 값 전달)
// MainPage.vue
<template>
<div>
<div class="main list-container contents">
<h1 class="page-header">Today I Learned</h1>
<ul>
<PostListItem
v-for="postItem in postItems"
v-bind:key="postItem._id"
v-bind:postItem="postItem"
></PostListItem>
</ul>
</div>
</div>
</template>
export default {
components: {
PostListItem,
},
}
// PostListItem.vue
<template>
<li>
<div class="post-title">
{{ postItem.title }}
</div>
<div class="post-contents">
{{ postItem.contents }}
</div>
<div class="post-time">
{{ postItem.createdAt }}
</div>
</li>
</template>
<script>
export default {
props: {
postItem: {
type: Object,
required: true,
},
},
};
</script>
- Github Branch Name :
vue-endofvue-10.mgmt_auth_browser_storage
- summary
- 로그인한 세션 정보를 위하여 쿠키 사용
state: {
username: getUserFromCookie() || '',
token: getAuthFromCookie() || '',
},
- async, await를 왜 사용하는지 반드시 인지하고 넘어 가야 함
- 자바스크립트는 기본이 비동기 처리 방식이나 async, await를 사용하여 동기화 처리 필요
- Github Branch Name :
vue-endofvue-11.dev_create
- summary
- 게시물을 신규 생성하는 UI 개발
- 참고 싸이트
- Github Branch Name :
vue-endofvue-12.middle_adj
- summary
- 개발 툴 및 필요 프로그램 설치
- API 서버 프로젝트 클론
- Prettier
- ESLint
- jsconfig
<router-link>
<router-view>
mode: history
와 서버 배포시 주의 사항- 코드 스플리팅
component: () => import('경로')
- 사용자 폼 처리
- async & await
- axios
- swagger API 문서 보는 방법
axios.create()
- env 파일 설정 방법
- Vue CLI 버전 3 이상에서의 env 파일 규칙
- 사용자 폼 처리 기능 구현
- async & await 에러 처리 방법
- 사용자 폼 유효성 검사
- 뷰엑스를 이용한 사용자 아이디 관리
this.$router.push('/main')
- JSON Web Token
Authorization
토큰 값으로 API 인증을 받는 방법axios.interceptors
- 학습 노트 목록 표시 기능 구현
- 목록 아이템 컴포넌트화
- 스피너를 이용한 데이터 로딩 상태 표시
- 쿠키를 이용한 로그인 인증 값 저장
- actions를 이용한 컴포넌트 로직 정리
- 학습 노트 생성 기능 구현
- 학습 노트 본문 길이 유효성 검사
- 데이터 성격 별로 API 함수 모듈화
- 학습 노트 삭제 기능
- 날짜 형식 포맷팅 filter
- 라우터 심화
- 프런트엔트 테스트
- Github Branch Name :
vue-endofvue-13.api_modularity
- summary
API
function의 모듈화로 기능의 성격별로 또는 서브-도메인의 성격별로 분리(모듈화) 진행- 추후 시스템이 확장될 경우를 대비하여 처음부터
확장성
을 고려하여API 호출 함수
모듈화 필요
- Key Sample Code
api > index.js
파일에서 기능적으로 유사한 함수끼리 모아 분리 모듈화- 인스터스를 2개로 구분하는데
인증전(로그인전)
과인증후(로그인후)
import axios from 'axios'; import { setInterceptors } from './common/interceptors'; // 엑시오스 초기화 함수 (인증전 즉, 로그인 전) function createInstance() { return axios.create({ baseURL: process.env.VUE_APP_API_URL, }); } // 액시오스 초기화 함수 (인증후 즉, 로그인 후) function createInstanceWithAuth(url) { const instance = axios.create({ baseURL: `${process.env.VUE_APP_API_URL}${url}`, }); return setInterceptors(instance); } export const instance = createInstance(); export const posts = createInstanceWithAuth('posts');
api > auth.js
로그인 관련API function 모듈
// 로그인, 회원 가입, 회원 탈퇴 등을 위한 API import { instance } from './index'; // 회원가입 API function registerUser(userData) { return instance.post('signup', userData); } // 로그인 API function loginUser(userData) { return instance.post('login', userData); } export { registerUser, loginUser };
api > posts.js
게시물 관련API function 모듈
// 학습 노트 조작과 관련된 CRUD API 함수 import { posts } from './index'; // 학습 노트 데이터를 조회하는 API function fetchPosts() { return posts.get('/'); } // 학습 노트 데이터를 생성하는 API function createPost(postData) { return posts.post('/', postData); } export { fetchPosts, createPost };
- Github Branch Name :
vue-endofvue-14.dev_delete
- summary
- 게시물 삭제 및 수정
- Toast Popup
- 게시물 삭제
API
에 삭제 함수 생성PostListItem
에서deleteItem
이벤트 처리
async deleteItem() { if (confirm('You want to delete it?')) { await deletePost(this.postItem._id); this.$emit('refresh'); } },
- 게시물 수정
API
에서id
를 인자로 게시물을 조회하는 함수 추가PostEditPage.vue
와PostEditForm.vue
를 생성하여 데이터 변경
삭제
와수정
후push
를 사용하여main
으로 이동
this.$router.push('/main');
- Github Branch Name :
vue-endofvue-16.data_format
- summary
- 특정 데이터의
포맷팅
처리 - 뷰 필터 안내 문서
- 특정 데이터의
- 16.1
Filter
함수 사용- utils > filters.js 정의
export function formatDate(value) { const date = new Date(value); const year = date.getFullYear(); let month = date.getMonth() + 1; month = month > 9 ? month : `0${month}`; const day = date.getDate(); let hours = date.getHours(); hours = hours > 9 ? hours : `0${hours}`; const minutes = date.getMinutes(); return `${year}-${month}-${day} ${hours}:${minutes}`; }
- main.js에 전역으로 사용할 필터 정의
//main.js import { formatDate } from '@/utils/filters'; Vue.filter('formatDate', formatDate);
- 전역으로 정의한 필터 사용
<div class="post-time"> {{ postItem.createdAt | formatDate }} <i class="icon ion-md-create" @click="routeEditPage"></i> <i class="icon ion-md-trash" @click="deleteItem"></i> </div>
- Github Branch Name :
vue-endofvue-17.router_adv
- summary
- 라우터에서 권한 설정
- Logo 클릭시
v-bind:on="computed"
를 사용하여 'main' 또는 'login' 분기 - Logout 클릭시
cookie(til_auth, til_user)
와state의 token
제거 - 라우터 네비게이션 가드 문서
- 라우터 네비게이션 가드 관련 영상(완벽 가이드 수강 권한 필요)
- Sample Code
//routes > index.js
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/post/:id',
component: () => import('@/views/PostEditPage.vue'),
meta: { needAuth: true },
},
]
});
router.beforeEach((to, from, next) => {
if (to.meta.needAuth && !store.getters.isLogin) {
console.log('인증이 필요합니다.');
next('/login');
return;
}
next();
});
- Github Branch Name :
vue-endofvue-18.front_end_test
- summary
- 18.1
Jest
테스트를 위한 환경 설정//`package.json` 설정 "scripts": { "test": "vue-cli-service test:unit --watchAll", }, //--watchAll : 변경즉시 반영 됨
//jest.config.js 설정 module.exports = { preset: '@vue/cli-plugin-unit-jest', testMatch: [ '<rootDir>/src/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)', ], };
// 테스트 실행 명령어 $npm t
// jest 함수들의 eslint 인식 빨간펜 처리 // .eslintrc.js env: { node: true, jest: true, },
- 18.2
Jest
일반 사항- 제일 먼저
jest.config
파일의 설정을 참고하며, 설정 파일이 없다면 하기의 기본 설정 폴더를 참고test > unit > *.spec.js
- 일반적으로
테스트 스크립트
파일은 테스트대상의 인근
에 생성하고 관리 - 또는
jest.config.js
파일에서와 같이__tests__
와 같이 폴더 생성하여 관리
- 제일 먼저
- 18.3
Jest Test Code
작성- vuejs test library
import { shallowMount } from '@vue/test-utils';
- find() function sample
import LoginForm from './LoginForm.vue'; import { shallowMount } from '@vue/test-utils'; describe('LoginForm.vue', () => { test('ID는 이메일 형식이여야 한다.', () => { const wrapper = shallowMount(LoginForm); const idInput = wrapper.find('#username'); console.log(idInput.html()); }); });
- 인스턴스를 생성한
vue
페이지의computed
에도 접근 가능
describe('LoginForm.vue', () => { test('ID는 이메일 형식이여야 한다.', () => { const wrapper = shallowMount(LoginForm, { data() { return { username: '[email protected]', }; }, }); const idInput = wrapper.find('#username'); console.log('InputBox Value ', idInput.element.value); console.log(wrapper.vm.isUsernameValid); }); });
LoginForm.vue
에서로그인
버튼의 활성/비활성화 코드 추가후 테스트 코드 작성
// LoginForm.vue <button :disabled="!isUsernameValid || !password" type="submit" class="btn" v-bind:class="!isUsernameValid || !password ? 'disabled' : null" > // LoginForm.spec.js test('#3. ID와 PWD가 입력되지 않으면 로그인 버튼이 비활성화 된다.', () => { const wrapper = shallowMount(LoginForm, { data() { return { // 값이 없으면 통과, 값이 있으면 실패 username: '[email protected]', password: '1234', }; }, }); const button = wrapper.find('button'); // '.btn' expect(button.element.disabled).toBeTruthy(); });
- Github Branch Name :
vue-endofvue-19.end
- summary
- 프로젝트 구성 방법
- ESLint, Prettier
- env
- REST API를 이용한 CRUD Application 구현 방법
- Back-End API 문서 보는 방법 및 Back-End 개발자와 협업할때의 주의 사항
- axios 인터셉터와 모듈화를 이용한 API 함수 설계
- Router 페이지 권한 처리
- Front-End 테스트 방법
- 프로젝트 구성 방법