Github Branch Name : vue-endofvue-1.init
summary
강좌에서 개발할 웹어플리케이션에 대해서 확인하고 일반적인 웹개발 절차와 API 문서에 대해서 알아본다.
1.1 Introduce Application
회원가입, 로그인, CRUD가 발생하는 기본적인 웹어플리케이션
1.2 Procedure of Front-End Development
웹 개발 절차
요구사항 > 서비스 기획 > UI, UX 상세 설계 > GUI 디자인 > 퍼블리싱 > Back-End API 개발 > Front-End 개발 > QA
Front-End 개발자의 역할
Client UI에 대한 코드 작성
기획, 디자인, 퍼블리싱, Back-End 개발자와 소통
2. Configuration of Development Environment
Github Branch Name : vue-endofvue-2.environment
summary
개발환경 구성에 대해서 알아본다(깃허브, 필수 설치 프로그램, )
2.2 개발 환경 (Visual Studio Code Gitbash Terminal)
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으로 사용)
NVM(Node Version Manager)
NVM을 이용하여 nodejs 특정 버전을 설치, 업그레이드 및 다운그레이드 가능
Node js
NVM Github
NVM 설치
$ 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 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 run dev
...중략...
VUE TIL SERVER IS RUNNING ON 3000
// ' 3000' 에 대한 포트를 사용중이면 하기에서 변경 가능
// src > app.js > port 번호 수정
http://localhost:3000/api/docs로 접속하여 API 서버 확인
MongoDB Site
src > app.js의 const db에서 하기의 생성된 DB를 연결
bash command > npm run dev > Server 기동 > http://localhost:3000/api/docs 접속 > /signup API Test
2.5 개발 환경(Swagger UI API)
Node js로 작서된 Back-End API 코드를 Front-End 개발자와 커뮤니케이션하기 위한 API UI
RESTfull API를 직접 테스트 할 수 있는 API UI
2.6 개발 환경(프로젝트 구성 - 프로젝트 생성, ESLint & Prettier)
웹팩 데브 서버 설명 글
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 파일에 하기와 같이 개발자 커스텀 설정 가능
rules : {
"no-console" : "error" , // 정상을 위하여 "off"로 설정 필요
// "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
// "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
} ,
console 명령서 사용시 error 출력으로 설정함으로 하기와 같이 오류 발생
ESLint 구문 오류시 해당 구문에 빨간줄이 생기지 않을 경우
VSCode 설정 > settings.json에 하기 코드 추가
"editor.codeActionsOnSave" : {"source.fixAll.eslint" : true },
"eslint.workingDirectories" : [{"mode" : " auto" }],
Prettier (일관성 있는 코드 포맷을 위한 웹팩)
하기의 이미지처럼 prettier 구문을 적용하면 코드에 붉은색 라인이 생기며 빌드 오류 발생
해결 방법
설정의 eslint: validate > settings.json 파일에서 하기 축
"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 ,
prettier 확장 프로그램에서 사용안함(작업영역) 설정
설정의 Format on Save 체크 해지
파일의 절대 경로를 사용해야 하는 이유
Vue.js 공식팀에서 권고하는 스타일 가이드 준수
3. Router & Design of Component
// vue-til 소스를 최초에 설치할 경우
$ git clone https://github.com/joshua1988/vue-til
$ git checkout 1_setup
$ npm i
LoginPage, SignupPage 생성 및 라우터 설정
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' ) ,
} ,
] ,
} ) ;
4. Development of Member Register
5. Configuration of Project
Github Branch Name : vue-endofvue-5.configure
summary
axios 사용 api 콤포넌트에서 환경 설정 값을 사용
참고 자료
VUE_APP 접두사가 붙으면 코드에서 자동 인식
7. Store & Login State Management
Github Branch Name : vue-endofvue-7.store_state
summary
css/common.css, css/reset.css
App.vue, AppHeader.vue
vue router > router-link를 사용(html 레벨)
vue router > router.push를 사용(javascript 레벨)
7.3 로그인 후 사용자 정보 표시(store를 사용)
개발용 라이브러리와 배포용 라이브러리 구분하기 문서
npm run build는 package.json의 dependencies에 해당하는 라이브러리를 포함하여 빌드
package.json의 devDependencies는 빌드될때 포함되지 않음
Vuex를 활용하여 Store, State, mutations & getters를 활용
8. API Authentication by Token
Github Branch Name : vue-endofvue-8.api_auth_token
summary
API를 통하여 통신할 경우 JWT(Json Web Token)인증을 통하여 통신
Json web 토큰 문서
액시오스 인터셉터 문서
인터셉터를 통하여 axios.create에서의 token값 할당에 대한 초기화 문제를 해결
9. Development of Retrieve Note Data
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 >
< / t e m p l a t e >
< script >
export default {
props : {
postItem : {
type : Object ,
required : true ,
} ,
} ,
} ;
</ script >
10. Management of Authentication Value using Browser Storage
Github Branch Name : vue-endofvue-10.mgmt_auth_browser_storage
summary
쿠키 저장
store > index.js의 state에서 쿠키값 보존을 위한 코드 추가
state : {
username : getUserFromCookie ( ) || '' ,
token : getAuthFromCookie ( ) || '' ,
} ,
async, await를 왜 사용하는지 반드시 인지하고 넘어 가야 함
자바스크립트는 기본이 비동기 처리 방식이나 async, await를 사용하여 동기화 처리 필요
11. Development of Create Note Data
Github Branch Name : vue-endofvue-11.dev_create
summary
참고 싸이트
Github Branch Name : vue-endofvue-12.middle_adj
summary
개발 툴 및 필요 프로그램 설치
API 서버 프로젝트 클론
<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')
12.8. API 인증 처리를 위한 토큰 관리
JSON Web Token
Authorization 토큰 값으로 API 인증을 받는 방법
axios.interceptors
학습 노트 목록 표시 기능 구현
목록 아이템 컴포넌트화
스피너를 이용한 데이터 로딩 상태 표시
12.10. 브라우저 저장소를 이용한 인증 값 관리
쿠키를 이용한 로그인 인증 값 저장
actions를 이용한 컴포넌트 로직 정리
학습 노트 생성 기능 구현
학습 노트 본문 길이 유효성 검사
데이터 성격 별로 API 함수 모듈화
학습 노트 삭제 기능
날짜 형식 포맷팅 filter
라우터 심화
프런트엔트 테스트
13. API Function Modularity
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 } ;
14. & 15. Development of Delete Note Data & Modify Note Data
Github Branch Name : vue-endofvue-14.dev_delete
summary
게시물 삭제
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 함수 사용
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
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
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 ( ) ;
} ) ;
18. Introduce of Front-End Testing
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)' ,
] ,
} ;
// jest 함수들의 eslint 인식 빨간펜 처리
// .eslintrc.js
env: {
node: true,
jest: true,
},
18.2 Jest 일반 사항
제일 먼저 jest.config 파일의 설정을 참고하며, 설정 파일이 없다면 하기의 기본 설정 폴더를 참고
일반적으로 테스트 스크립트 파일은 테스트 대상의 인근에 생성하고 관리
또는 jest.config.js파일에서와 같이 __tests__와 같이 폴더 생성하여 관리
18.3 Jest Test Code 작성
import { shallowMount } from '@vue/test-utils' ;
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 : 'test@abc.com' ,
} ;
} ,
} ) ;
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 : 'a@a.com' ,
password : '1234' ,
} ;
} ,
} ) ;
const button = wrapper . find ( 'button' ) ; // '.btn'
expect ( button . element . disabled ) . toBeTruthy ( ) ;
} ) ;
Github Branch Name : vue-endofvue-19.end
summary
프로젝트 구성 방법
REST API를 이용한 CRUD Application 구현 방법
Back-End API 문서 보는 방법 및 Back-End 개발자와 협업할때의 주의 사항
axios 인터셉터와 모듈화를 이용한 API 함수 설계
Router 페이지 권한 처리
Front-End 테스트 방법