Vue.js 3 정리하기 (Vue-CLI 4, Vue 3, Composition API, TypeScript, Vuex 4)
Vue.js 3 버전에 대한 글입니다. 이런 방식도 있다는 참고하는 글이며, 무조건 이 글의 내용이 정답은 아닙니다. 이상하거나 틀린 부분에 대해 피드백해주시면 감사하겠습니다. 저의 경험과 구글링을 통해 작성된 글입니다. 내용이 길기 때문에 목차를 참고하시면서 원하시는 부분을 참고하시면 될 것 같습니다. 어느 한 부분을 깊게 적는다기보다 얇고 넓은 메뉴얼같은 정리글입니다.
목차
- Vue-CLI 설치하기
- 프로젝트 생성하기
- 프로젝트 구조 살펴보기
- Vue 3 알아보기
- Composition API 사용하기
- TypeScript 도입하기
- Vuex 도입하기
- Vue 3 컨퍼런스(Vueconf.US) 키노트 내용 요약
- 기타
- 후기
1. Vue-CLI 설치하기
Vue-CLI 최신 버전 글로벌로 설치하기
- CLI는 Command Line Interface의 약자로 명령어를 이용하여 프로젝트를 구성하는 역할을 한다.
- 먼저 node.js가 설치되어야 하고, 전역적으로 Vue-CLI를 설치해야한다.
- 21.04.11 기준으로 v4.5.12가 Latest
npm install -g @vue/cli
- 버전에 대한 자세한 사항은 Vue-CLI GitHub(https://github.com/vuejs/vue-cli/releases)를 참고한다. 현재 v5-alpha 버전도 pre-release하고 있다.
- Vue-CLI 5 계획은 다음과 같다. 현재까지 v5.0.0-alpha.8 버전까지 pre-release 되어있다.
Vue-CLI 5의 계획
- 기본적으로 Webpack 5를 사용하므로서 캐시에 대한 더 나은 성능을 얻을 수 있음
- Cypress 6, Jest 26, Mocha 8, ESLint 7 등 지원
- 비동기 컨피그 로딩 지원
- Node.js 8, 11, 13 지원 중단
- TSLint 지원 중단
- node-sass 지원 중단
- extension-less Vue SFC Imports 지원 중단 (
import A from './A.vue';
은 가능, import A from './A';
불가능)
- 그 외 기타
참고
2. 프로젝트 생성하기
npm install -g @vue/cli
import A from './A.vue';
은 가능, import A from './A';
불가능)1) vue 프로젝트를 만들기 위해 다음과 같은 명령어를 실행한다.
vue create hello-world
2) Please pick a preset:
[ ] Default ([Vue 2] babel, eslint)
[ ] Default (Vue 3 Preview) ([Vue 3] babel, eslint)
[x] Manually select features
3) Check the features needed for your project:
(*) Choose Vue version
(*) Babel
(*) TypeScript
( ) Progressive Web App (PWA) Support
(*) Router
(*) Vuex
(*) CSS Pre-processors
(*) Linter / Formatter
( ) Unit Testing
( ) E2E Testing
- Unit Testing을 선택하면
Mocha + Chai
와Jest
중에서 선택할 수 있다. - jest를 사용하는 Vue Test Utils 2은 현재 rc.4 버전이며, 공식문서는 다음과 같다. (참고 : https://next.vue-test-utils.vuejs.org/)
- E2E Testing을 선택하면
Cypress (Chrome only)
와Nightwatch (WebDriver-based)
와WebdriverIO (WebDriver/DevTools based)
중에서 선택할 수 있다.
4) Choose a version of Vue.js that you want to start the project with
[ ] 2.x
[x] 3.x (Preview)
- Vue 3 + Composition API 방식을 사용하기 위해서 Vue 3.x 버전을 선택한다.
- 현재 Vue 3에서 IE11 지원 중단에 대해 논의를 하고 있다. (https://github.com/vuejs/rfcs/discussions/296)
5) Use class-style component syntax? (y/N)
N
- 컴포넌트 선언 시 클래스 기반 API를 선호하는 경우 vue-class-component 데코레이터 사용 여부 (참고 : https://class-component.vuejs.org/)
6) Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? (Y/n)
Y
- TypeScript에 Babel을 같이 사용 여부
7) Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n)
Y
- 프로젝트의 성향에 맞도록 선택한다.
- History Mode 설정설정에 대한 공식문서 (참고 : https://next.router.vuejs.org/guide/essentials/history-mode.html#different-history-modes)
8) Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default):
[x] Sass/SCSS (with dart-sass)
[ ] Sass/SCSS (with node-sass)
[ ] Less
[ ] Stylus
- Libsass, node-sass는 deprecated 상태이므로 dart-sass를 선택하였음. (참고 : https://sass-lang.com/blog/libsass-is-deprecated)
- Vue-CLI v5에서 지원 안함.
9) Pick a linter / formatter config: (Use arrow keys)
[ ] ESLint with error prevention only
[ ] ESLint + Airbnb config
[ ] ESLint + Standard config
[ ] ESLint + Prettier
[ ] TSLint (deprecated)
- 프로젝트 팀원과의 규칙과 취향대로 선택한다.
- TSLint는 deprecated이므로 선택하지 않는다. (참고 : https://www.npmjs.com/package/tslint). Vue-CLI v5에서 지원 안함.
- 만일
Airbnb
를 규칙을 사용하고 싶고peerDependencies
를 줄이려면ESLint with error prevention only
를 선택 후에 추후npx install-peerdeps --dev eslint-config-airbnb-base
로 설치해준다. - npm info eslint-config-airbnb@latest peerDependencies
{ eslint: '^5.16.0 || ^6.8.0 || ^7.2.0', 'eslint-plugin-import': '^2.21.2', 'eslint-plugin-jsx-a11y': '^6.3.0', 'eslint-plugin-react': '^7.20.0', 'eslint-plugin-react-hooks': '^4 || ^3 || ^2.3.0 || ^1.7.0' }
- npm info eslint-config-airbnb-base@latest peerDependencies
{ eslint: '^5.16.0 || ^6.8.0 || ^7.2.0', 'eslint-plugin-import': '^2.21.2' }
10) Pick additional lint features:
(*) Lint on save
(*) Lint and fix on commit
- 저장 시 lint 검사, commit 시 lint와 fix 선택
11) Where do you prefer placing config for Babel, ESLint, etc.?
[x] In dedicated config files
[ ] In package.json
- Babel, ESLint 같은 설정을 따로 관리할 것인지 package.json에 같이 관리할 것인지 선택하는데, dedicated config files가 관리성 측면에서 좋아보인다.
12) Save this as a preset for future projects? (y/N)
N
3. 프로젝트 구조 살펴보기
폴더 구조 (with. Webstorm)
- node_modules : package.json에 종속되어있는 라이브러리들
- public : webpack의 처리를 받지않고 퍼블리싱되는 정적 자산을 포함하는 폴더 (static assets)
- src : 애플리케이션 디렉토리
- src\assets : css나 img 등의 정적 자산을 저장하는 폴더, webpack의 처리를 받을 수 있어 css-pre processor 사용 가능
- src\components : 컴포넌트를 담는 폴더
- src\router : Vue Router 관련 폴더
- src\store : Vuex 관련 폴더
- src\views : 라우터 페이지가 관련 폴더
- src\App.vue : 프로젝트 최상위 컴포넌트 파일
- src\main.ts : 프로젝트의 entry ts 파일
- src\shims-vue.d.ts : TypeScript가 vue파일의 component가 어떠한 인터페이스인지를 정의하여 import할 수 있게 한다.
- .eslintrc.js : ESLint 설정 파일
- .gitignore : git 규칙 설정 파일
- babel.config.js
- package.json
- package-lock.json
- tsconfig.json
Vue 3 Project Style Guide
- Vue 3 공식 스타일 가이드를 참고하여 프로젝트 규칙을 정한다.
- 우선 순위를 레벨화 : A(필수), B(적극 권장), C(권장), D(주의해서 사용)
- 스타일 가이드 공식문서 : https://v3.vuejs.org/style-guide/
기타 설정
- 필요에 따라 라이브러리를 추가 설치한다. (axios, lodash-es, eslint-config-airbnb-base, stylelint, stylelint-order, stylelint-webpack-plugin, day.js, vue-i18n 등)
- 필요에 따라 .env 파일 추가, eslint 옵션(룰) 수정, .gitignore 옵션 수정, vue.config.js 파일 추가 등
프로젝트 구조에 대한 생각
- router의 페이지는 views 폴더에 넣어서 관리하는 것이 기본적이라고 생각한다. 페이지 내부에 있는 컴포넌트들은 하나의 컴포넌트일 수도 있지만, 복합적으로 합쳐진 컴포넌트가 될 수도 있다.
- 프로젝트의 UI 설계를 기준으로 공통적으로 사용할 컴포넌트와 컴포넌트 모듈화에 대한 규칙을 정해야한다. 어느 부분까지 공통적으로 관리할지 또는 어느 단위까지 쪼개면 효율적이 될 것인지에 대한 개발 팀 내의 규칙을 정해놓고 시작하면 좋을 것 같다.
- 어느정도 덩치가 있는 프로젝트의 폴더 구조는 비즈니스적 단위로 나누는 것보다 지역성의 원칙을 고려하여 기능 단위로 나누는 것이 재사용률이 높고 유지보수성이 높다고 생각한다.
- Vue 프로젝트는 주로 SFC를 사용하여 컴포넌트 단위로 개발한다. 컴포넌트가 많아지기 때문에 아토믹 디자인(atomic design)을 적용한다면 컴포넌트 기반으로 개발할 때 components 폴더 내부를 깔끔하게 정의할 수 있다.
- 아토믹 디자인을 적용하는데 단점은 있다. 우선 UI 설계가 확실하여야 하며, 복합 컴포넌트로 복합 컴포넌트를 만드는 경우에 이를 정확히 나누는 기준이 애매하다.
- 아토믹 디자인에 대한 좋은 글 : https://ui.toast.com/weekly-pick/ko_20200213
- 아토믹 디자인에 대한 좋은 글2 : https://kciter.so/posts/effective-atomic-design?fbclid=IwAR0sRLe7L9QlfjbKR_UjCs4N7dnc5RDvdsGRFwZ6-ii09Fi1vdYRQt1GBYw
4. Vue 3 알아보기
Vue 3이 되면서 변경된 사항
- Vue 3은 2020년 9월 19일에 정식 릴리즈되었다. (https://github.com/vuejs/vue-next/releases/tag/v3.0.0)
- Vue 3의 GitHub는 다음과 같다. (https://github.com/vuejs/vue-next)
- Vue 2에서 Vue 3으로 마이그레이션 하는 공식 문서가 존재한다. (https://v3.vuejs.org/guide/migration/introduction.html#overview)
-
Vue 3의 간략한 특징 (참고 : https://increment.com/frontend/making-vue-3/)
- 코드베이스를 TypeScript로 전환 및 재개발
- 새로운 렌더링 전략 (가상 DOM 로직 변경)
- 더 나은 mount, update, memory 성능
- Vue 전역과 API 내부를 재구성하여 실제 개발자가 사용한 부분만 코스트를 지불하는 일명, 트리쉐이킹 기법으로 사용하지 않는 코드를 제거함으로서 최종 번들 용량을 줄임
- 컴포넌트의 로직을 유연하게 구성할 수 있도록 하는 함수 기반의 Composition API 지원
- 그 외 기타
-
v-model 로직 변경
- Vue2와 비교하여 Vue3의 v-model의 컴파일 코드량이 간결해짐
- v-model의 prop, event명칭이 변경 (prop: value -> modelValue, event: input -> update:modelValue)
- 양방향 바인딩에 필요한 .sync 수식어(modifier)가 필요없어지게 되었고, 여러 개의 v-model을 사용할 수 있다.
- 커스텀 수식어(modifier) 기능이 추가
-
Reactivity 동작 로직 변경
- Vue2의 반응형은 Object.defineProperty로 구현되어있음. Vue3의 반응형은 Proxy와 Reflect로 구현되어있음.
- Vue 3 공식문서 반응형 관련 설명 : https://v3.vuejs.org/guide/reactivity.html#reactivity-in-depth
- Vue 3 반응형 동작 원리 글 : https://ui.toast.com/weekly-pick/ko_20210112
-
Vue 인스턴스 생성 방법 변경
- Vue 2 : new 생성자 사용
- Vue 3 : createApp() 함수 사용
- Vue 인스턴스의 설정을 글로벌 범위 일괄 적용이 아닌 애플리케이션의 컨텍스트를 특정 인스턴스 각각에 구성할 수 있도록 변경되었다.
-
Fragment, Teleport, Suspense 지원
- Fragment : SFC 환경의 컴포넌트 내 template 내부에서 다중 루트 노드를 허용한다. Vue 2에서는 단일 루트 노드라 불필요한 div로 wrapping을 해야하는 번거로움이 있었다.
- Teleport : React의 Portal 개념을 차용해서 만들어진 기능이다. 특정 돔에 컴포넌트를 렌더링할 수 있는 기능이다. 보통 modal, notification, popup과 같은 팝업 형태에서 사용한다. 코드 관리 측면에서 관련 UI를 동일한 위치에서 유지시키기 좋은 기능이다.
- Suspense : 조건이 충족될 때까지 컴포넌트 대신 대체 컨텐츠를 렌더링하는 특수 컴포넌트이다. 네트워크 스피드를 보완하기 위한 개념으로 네트워크 환경이 안좋은 경우에도 사용자의 만족도를 보존하기 위한 방식이다. 보통 비동기 API 데이터를 로드하는 동안 스켈레톤 로딩 스크린을 구현하는데 사용한다.
-
Composition API 지원
- 컴포넌트의 로직을 유연하게 구성할 수 있도록 하는 함수 기반의 API 방식을 지원한다.
- Vue 2에서도 Plugin을 설치하여 Composition API을 사용할 수 있다. 21.04.12일 기준으로 v1.0.0-rc.6버전이 pre-release되어있다. (https://github.com/vuejs/composition-api)
-
그 외
- 라이프사이클 훅 이름 변경 (onXXX로 변경)
- Event Bus 제거
- Filter 속성 제거
- Inline-template 제거
- emits 속성 추가
- 기타 등등
- 이 밖에 설명하지 못한 부분이 많이 남아있다. 자세한 사항에 대해서는 Vue 2 -> 3 마이그레이션 공식문서 한글번역을 참고하면 된다. (https://v3.ko.vuejs.org/guide/migration/introduction.html)
Vue 3에 대한 개인적인 생각
- Vue 2보다 새로운 개념들이 더 추가되어 러닝커브는 약간 증가하였으나 개발자의 편의성이 증가되었다. RFC를 통해 개발자들의 의견을 수렴하여 더 나은 방향으로 가려는 모습들이 많이 보였다.
- Vue.js RFC Github : https://github.com/vuejs/rfcs
- React 16의 장점을 가져와 Vue 3에 합치려는 모습이 보인다. React를 사용한 사람들도 개념과 사용법이 익숙하게 느낄 수 있다.
- Vue 3 프로젝트를 여러 번 진행하다보니 Vue 2보다 명시적으로 코딩하게 되었고, 불편한 API에 대해 삭제되거나 개선된 기능들이 많이 보였다.
- 특히, Vue 3의 Composition API 방식을 사용하여 Vue의 라이프사이클 훅을 좀더 스마트 사용할 수 있게 되었다. 또한, 기능 단위로 파일을 모듈화하여 코드의 재사용성을 높이는 부분은 매력적으로 느껴졌다.
5. Composition API 사용하기
Vue 2에서 발생하는 문제점 : 가독성, 유지보수성
- Vue 2에서는 템플릿, 로직, 스타일의 영역으로 관심사를 분리한 SFC(Single File Component) 형태로 주로 개발한다.
<script>
태그 내 옵션을 나열하여 로직을 만드는 방식을 Option-based API 형태이다.
- 복잡하거나 긴 로직이 있는 경우 코드량이 많아지고, data의 변수가 computed, watch, Vue 특유의 라이프사이클 훅에서 사용되었는지 확인하기 어려운 상황인 코드 가독성이 낮은 단점이 존재한다.
Vue의 재사용 방식
- Vue 2의 재사용 방식은 크게 mixins와 slot이 존재한다.
- Composition API 방식을 사용하면 논리를 함수 단위로 추출하여 적은 코드로도 컴포넌트의 기능을 쉽게 가져올 수 있고 높은 유연성을 가짐. 또한 추출된 논리 로직을 파일단위로 관리하여 쉽게 재사용할 수 있음.
Composition API 도입 후
- Composition API 적용 후에는 가독성이 좋아지고 코드 유지보수성이 용이해져 프로젝트 참여의 러닝 커브, 오버헤드가 줄어들었다.
- 팀원들과의 협업 시 코드 재사용률이 늘고 불필요한 코드가 줄었다.
- Composition API 환경에서 선택적, 점진적으로 타입 스크립트를 적용하는 경우에 좋은 환경이다.
- Vue 3 환경에서는 Composition API가 기본으로 빌트인되어 따로 설치없이 사용할 수 있다. Vue 2에서 Composition API를 사용하기 위해서는 @vue/composition plugin을 설치해야한다.
- Composition API 소개 링크 (https://v3.vuejs.org/guide/composition-api-introduction.html)
Composition API 문법
-
setup()
setup(props, context) { ... }
의 형태로 사용할 수 있다. 이는 선택사항이며, 컴포넌트가 생성되기 전에 필요한 것들을 세팅하는 함수이다.
- setup()은 Vue 2의 라이프사이클 훅과 비교하면 beforeCreate와 created 훅 사이에 불려진다.
- 다른 컴포넌트와 달리 this에 접근이 불가하다. 그로인해
this.[??]
코드가 data 옵션의 변수인지 computed인지 코드만 보고 헷갈리는 현상이 없어졌다.
- 첫번째 전달인자로 props가 두번째 전달인자로는 context가 존재한다. 필요에 따라 context를 destructring하여 attr, slots, parent, root, emit 등을 사용할 수 있다.
- data, methods 옵션과 더불어 라이프사이클 훅도 setup() 내부에서 사용 가능하다.
- setup() 내부에서 정의한 객체들을 반환하면 속성들은 템플릿영역의 렌더 컨텍스트에 병합되어 렌더링에 영향을 미치게 된다.
- Vue 2의 option들이 1depth-hierarchy 구조와 달리 Vue 3에서 setup()로 인해 hierarchy 구조가 달라졌다.
-
reactive() vs. ref()
- 대표적인 반응성 방식 2가지는 reactive, ref이다.
- reactive()의 파라미터는 오직 객체만 받으며, 반환 결과로는 인자로 받은 객체와 동일한 반응형 객체로서 원본 객체 내부에 Vue 옵저버만 추가하여 그대로 반환한다. Proxy로 반응형이 구현되어있어 새로운 속성을 추가, 삭제하더라도 감지가 가능하며, 중첩된 객체라도 깊은 감지가 가능하여 반응성이 유지된다. Vue 2의 Vue.Observable API와 동일하다.
- ref()는 객체를 포함한 primitive 타입을 받을 수 있으며, 반응성을 유지하기 위해서 파라미터를 감싼 .value 속성을 가진 가변참조객체를 만들고 그 안에 값을 캡슐화한 결과로 나온다. template 상의 ref와 ref()가 통합되어 주로 onMounted 훅에서 엘리먼트를 가져올 때 사용할 수 있다.
-
method, computed, watch
- method : setup() 내부에서 함수를 정의하고 리턴하여 컴포넌트에 대한 접근 권한을 부여한 다음 템플릿 상에서 사용한다.
- computed : setup() 내부에서 옵션 방식이 아닌 computed() 내 익명함수로 작성하고 리턴하여 사용. computed 내부는 ref로 이루어져있어 .value를 통해 값을 접근한다.
- watch : 첫번째 인자로는 감시할 대상, 두번째는 현재값, 이전값을 알 수 있는 콜백, 세번째는 감시옵션을 넣어 사용한다.
-
그 외 기타 반응형 유틸리티
- toRefs, Unref, toRef, isRef 등
- 참고 : https://v3.vuejs.org/api/basic-reactivity.html
문제점
-
ref() 도입의 어려움
- 반응형이 필요한 변수에 ref()를, 반응형이 필요없는 변수에는 사용하지 않는 것을 구분하는데 처음에 이해하기가 힘들 수 있고, 코딩 시 헷갈릴 수 있는 부분이다.
- 반응형 여부에 따라 변수명을 다르게 짓거나 선언부 부분을 다르게 두는 식으로 완화할 수는 있다.
.value
라는 속성을 계속 붙여줘야하는 스트레스는 Vue 2의 this.
를 남발하는 스트레스와 비견된다.
-
setup() 내 return문이 길어짐
- return { ... } 내 코드량이 길어지는 경우가 있다. Vue 3에서는 명시적인 return문은 템플릿에 노출되는 대상을 명시적으로 제어할 수 있고, 템플릿 내 ref를 찾을 때 도움을 줄 수 있다. 이로인해 유지보수성에 도움이 된다고 생각하여 장황하게 작성하는 방식으로 개발해야한다.
-
Composition API 방식의 적응
- 코드, 파일 모듈화 및 재사용성을 높이기 위해 더 많은 연습과 노력이 필요하다.
6. TypeScript 도입하기
도입 이유
- Vue 3은 TypeScript로 개발되었으며, 앞으로 더 나은 지원을 기대해볼 수 있다.
- 점진적으로 TypeScript화 할 수 있으며, 도입 시 에러를 사전에 방지하고 IDE의 도움으로 개발 생산성을 증대시킬 수 있다.
SFC에서 간단하게 TypeScript 적용하기
<script>
import { reactive, onMounted } from 'vue';
import A from './A.vue';
export default {
name: 'B',
components: {
A,
},
setup() {
const state = reactive({
obj: {},
arr: [],
});
const onClick = () => { ... };
onMounted(() => {
state.arr.filter((i) => i.flag === false);
});
return {
...toRefs(state),
onClick,
};
},
};
</script>
- 다음과 같이 Vue 3 컴포넌트 예제가 있다.
<script lang="ts">
import { defineComponent, reactive, onMounted } from 'vue';
import { Type1, Type2 } from '../types';
import A from './A.vue';
export default defineComponent({
name: 'B',
components: {
A,
},
setup() {
const state = reactive({
obj: { ... } as Type1,
arr: [] as Type2[],
});
const onClick = () => { ... };
onMounted(() => {
state.arr.filter((i: Type2) => i.flag === false);
});
return {
...toRefs(state),
onClick,
};
},
});
</script>
lang="ts"
를 붙여줌으로서 언어 속성을 변경
defineComponent
라는 vue 헬퍼 메소드를 사용하여 컴포넌트 형태를 TypeScript로 명시
info
내 Type1, Type2 타입 적용
filter()
파라미터 내 Type2 타입 적용
7. Vuex 도입하기
Vuex 4
- Vuex 4 공식 문서 : https://next.vuex.vuejs.org/
- Vue 3에서는 Vuex 4를, Vue 2에서는 Vuex 3이 적용된다.
- Vuex는 Vue의 공식적인 에코시스템이며, 애플리케이션의 상태관리 패턴 + 라이브러리이다.
- SPA에서 Vue 컴포넌트 외부에서 상태를 잘 다루기 위해 사용한다.
Vuex 3 -> Vuex 4로 변경점
- Vue 3 초기화 프로세스에 맞추기 위해서 Vuex 4에서는 새로운 store를 만들기 위해
createStore()
함수를 사용한다.
- Vue 애플리케이션에 추가하는 방법도 변경되었다.
Vue 3의 간략한 특징 (참고 : https://increment.com/frontend/making-vue-3/)
- 코드베이스를 TypeScript로 전환 및 재개발
- 새로운 렌더링 전략 (가상 DOM 로직 변경)
- 더 나은 mount, update, memory 성능
- Vue 전역과 API 내부를 재구성하여 실제 개발자가 사용한 부분만 코스트를 지불하는 일명, 트리쉐이킹 기법으로 사용하지 않는 코드를 제거함으로서 최종 번들 용량을 줄임
- 컴포넌트의 로직을 유연하게 구성할 수 있도록 하는 함수 기반의 Composition API 지원
- 그 외 기타
v-model 로직 변경
- Vue2와 비교하여 Vue3의 v-model의 컴파일 코드량이 간결해짐
- v-model의 prop, event명칭이 변경 (prop: value -> modelValue, event: input -> update:modelValue)
- 양방향 바인딩에 필요한 .sync 수식어(modifier)가 필요없어지게 되었고, 여러 개의 v-model을 사용할 수 있다.
- 커스텀 수식어(modifier) 기능이 추가
Reactivity 동작 로직 변경
- Vue2의 반응형은 Object.defineProperty로 구현되어있음. Vue3의 반응형은 Proxy와 Reflect로 구현되어있음.
- Vue 3 공식문서 반응형 관련 설명 : https://v3.vuejs.org/guide/reactivity.html#reactivity-in-depth
- Vue 3 반응형 동작 원리 글 : https://ui.toast.com/weekly-pick/ko_20210112
Vue 인스턴스 생성 방법 변경
- Vue 2 : new 생성자 사용
- Vue 3 : createApp() 함수 사용
- Vue 인스턴스의 설정을 글로벌 범위 일괄 적용이 아닌 애플리케이션의 컨텍스트를 특정 인스턴스 각각에 구성할 수 있도록 변경되었다.
Fragment, Teleport, Suspense 지원
- Fragment : SFC 환경의 컴포넌트 내 template 내부에서 다중 루트 노드를 허용한다. Vue 2에서는 단일 루트 노드라 불필요한 div로 wrapping을 해야하는 번거로움이 있었다.
- Teleport : React의 Portal 개념을 차용해서 만들어진 기능이다. 특정 돔에 컴포넌트를 렌더링할 수 있는 기능이다. 보통 modal, notification, popup과 같은 팝업 형태에서 사용한다. 코드 관리 측면에서 관련 UI를 동일한 위치에서 유지시키기 좋은 기능이다.
- Suspense : 조건이 충족될 때까지 컴포넌트 대신 대체 컨텐츠를 렌더링하는 특수 컴포넌트이다. 네트워크 스피드를 보완하기 위한 개념으로 네트워크 환경이 안좋은 경우에도 사용자의 만족도를 보존하기 위한 방식이다. 보통 비동기 API 데이터를 로드하는 동안 스켈레톤 로딩 스크린을 구현하는데 사용한다.
Composition API 지원
- 컴포넌트의 로직을 유연하게 구성할 수 있도록 하는 함수 기반의 API 방식을 지원한다.
- Vue 2에서도 Plugin을 설치하여 Composition API을 사용할 수 있다. 21.04.12일 기준으로 v1.0.0-rc.6버전이 pre-release되어있다. (https://github.com/vuejs/composition-api)
그 외
- 라이프사이클 훅 이름 변경 (onXXX로 변경)
- Event Bus 제거
- Filter 속성 제거
- Inline-template 제거
- emits 속성 추가
- 기타 등등
Vue 2에서 발생하는 문제점 : 가독성, 유지보수성
- Vue 2에서는 템플릿, 로직, 스타일의 영역으로 관심사를 분리한 SFC(Single File Component) 형태로 주로 개발한다.
<script>
태그 내 옵션을 나열하여 로직을 만드는 방식을 Option-based API 형태이다. - 복잡하거나 긴 로직이 있는 경우 코드량이 많아지고, data의 변수가 computed, watch, Vue 특유의 라이프사이클 훅에서 사용되었는지 확인하기 어려운 상황인 코드 가독성이 낮은 단점이 존재한다.
Vue의 재사용 방식
- Vue 2의 재사용 방식은 크게 mixins와 slot이 존재한다.
- Composition API 방식을 사용하면 논리를 함수 단위로 추출하여 적은 코드로도 컴포넌트의 기능을 쉽게 가져올 수 있고 높은 유연성을 가짐. 또한 추출된 논리 로직을 파일단위로 관리하여 쉽게 재사용할 수 있음.
Composition API 도입 후
- Composition API 적용 후에는 가독성이 좋아지고 코드 유지보수성이 용이해져 프로젝트 참여의 러닝 커브, 오버헤드가 줄어들었다.
- 팀원들과의 협업 시 코드 재사용률이 늘고 불필요한 코드가 줄었다.
- Composition API 환경에서 선택적, 점진적으로 타입 스크립트를 적용하는 경우에 좋은 환경이다.
- Vue 3 환경에서는 Composition API가 기본으로 빌트인되어 따로 설치없이 사용할 수 있다. Vue 2에서 Composition API를 사용하기 위해서는 @vue/composition plugin을 설치해야한다.
- Composition API 소개 링크 (https://v3.vuejs.org/guide/composition-api-introduction.html)
Composition API 문법
-
setup()
setup(props, context) { ... }
의 형태로 사용할 수 있다. 이는 선택사항이며, 컴포넌트가 생성되기 전에 필요한 것들을 세팅하는 함수이다.- setup()은 Vue 2의 라이프사이클 훅과 비교하면 beforeCreate와 created 훅 사이에 불려진다.
- 다른 컴포넌트와 달리 this에 접근이 불가하다. 그로인해
this.[??]
코드가 data 옵션의 변수인지 computed인지 코드만 보고 헷갈리는 현상이 없어졌다. - 첫번째 전달인자로 props가 두번째 전달인자로는 context가 존재한다. 필요에 따라 context를 destructring하여 attr, slots, parent, root, emit 등을 사용할 수 있다.
- data, methods 옵션과 더불어 라이프사이클 훅도 setup() 내부에서 사용 가능하다.
- setup() 내부에서 정의한 객체들을 반환하면 속성들은 템플릿영역의 렌더 컨텍스트에 병합되어 렌더링에 영향을 미치게 된다.
- Vue 2의 option들이 1depth-hierarchy 구조와 달리 Vue 3에서 setup()로 인해 hierarchy 구조가 달라졌다.
-
reactive() vs. ref()
- 대표적인 반응성 방식 2가지는 reactive, ref이다.
- reactive()의 파라미터는 오직 객체만 받으며, 반환 결과로는 인자로 받은 객체와 동일한 반응형 객체로서 원본 객체 내부에 Vue 옵저버만 추가하여 그대로 반환한다. Proxy로 반응형이 구현되어있어 새로운 속성을 추가, 삭제하더라도 감지가 가능하며, 중첩된 객체라도 깊은 감지가 가능하여 반응성이 유지된다. Vue 2의 Vue.Observable API와 동일하다.
- ref()는 객체를 포함한 primitive 타입을 받을 수 있으며, 반응성을 유지하기 위해서 파라미터를 감싼 .value 속성을 가진 가변참조객체를 만들고 그 안에 값을 캡슐화한 결과로 나온다. template 상의 ref와 ref()가 통합되어 주로 onMounted 훅에서 엘리먼트를 가져올 때 사용할 수 있다.
-
method, computed, watch
- method : setup() 내부에서 함수를 정의하고 리턴하여 컴포넌트에 대한 접근 권한을 부여한 다음 템플릿 상에서 사용한다.
- computed : setup() 내부에서 옵션 방식이 아닌 computed() 내 익명함수로 작성하고 리턴하여 사용. computed 내부는 ref로 이루어져있어 .value를 통해 값을 접근한다.
- watch : 첫번째 인자로는 감시할 대상, 두번째는 현재값, 이전값을 알 수 있는 콜백, 세번째는 감시옵션을 넣어 사용한다.
-
그 외 기타 반응형 유틸리티
- toRefs, Unref, toRef, isRef 등
- 참고 : https://v3.vuejs.org/api/basic-reactivity.html
문제점
-
ref() 도입의 어려움
- 반응형이 필요한 변수에 ref()를, 반응형이 필요없는 변수에는 사용하지 않는 것을 구분하는데 처음에 이해하기가 힘들 수 있고, 코딩 시 헷갈릴 수 있는 부분이다.
- 반응형 여부에 따라 변수명을 다르게 짓거나 선언부 부분을 다르게 두는 식으로 완화할 수는 있다.
.value
라는 속성을 계속 붙여줘야하는 스트레스는 Vue 2의this.
를 남발하는 스트레스와 비견된다.
-
setup() 내 return문이 길어짐
- return { ... } 내 코드량이 길어지는 경우가 있다. Vue 3에서는 명시적인 return문은 템플릿에 노출되는 대상을 명시적으로 제어할 수 있고, 템플릿 내 ref를 찾을 때 도움을 줄 수 있다. 이로인해 유지보수성에 도움이 된다고 생각하여 장황하게 작성하는 방식으로 개발해야한다.
-
Composition API 방식의 적응
- 코드, 파일 모듈화 및 재사용성을 높이기 위해 더 많은 연습과 노력이 필요하다.
6. TypeScript 도입하기
도입 이유
- Vue 3은 TypeScript로 개발되었으며, 앞으로 더 나은 지원을 기대해볼 수 있다.
- 점진적으로 TypeScript화 할 수 있으며, 도입 시 에러를 사전에 방지하고 IDE의 도움으로 개발 생산성을 증대시킬 수 있다.
SFC에서 간단하게 TypeScript 적용하기
<script>
import { reactive, onMounted } from 'vue';
import A from './A.vue';
export default {
name: 'B',
components: {
A,
},
setup() {
const state = reactive({
obj: {},
arr: [],
});
const onClick = () => { ... };
onMounted(() => {
state.arr.filter((i) => i.flag === false);
});
return {
...toRefs(state),
onClick,
};
},
};
</script>
- 다음과 같이 Vue 3 컴포넌트 예제가 있다.
<script lang="ts">
import { defineComponent, reactive, onMounted } from 'vue';
import { Type1, Type2 } from '../types';
import A from './A.vue';
export default defineComponent({
name: 'B',
components: {
A,
},
setup() {
const state = reactive({
obj: { ... } as Type1,
arr: [] as Type2[],
});
const onClick = () => { ... };
onMounted(() => {
state.arr.filter((i: Type2) => i.flag === false);
});
return {
...toRefs(state),
onClick,
};
},
});
</script>
lang="ts"
를 붙여줌으로서 언어 속성을 변경
defineComponent
라는 vue 헬퍼 메소드를 사용하여 컴포넌트 형태를 TypeScript로 명시
info
내 Type1, Type2 타입 적용
filter()
파라미터 내 Type2 타입 적용
7. Vuex 도입하기
Vuex 4
- Vuex 4 공식 문서 : https://next.vuex.vuejs.org/
- Vue 3에서는 Vuex 4를, Vue 2에서는 Vuex 3이 적용된다.
- Vuex는 Vue의 공식적인 에코시스템이며, 애플리케이션의 상태관리 패턴 + 라이브러리이다.
- SPA에서 Vue 컴포넌트 외부에서 상태를 잘 다루기 위해 사용한다.
Vuex 3 -> Vuex 4로 변경점
- Vue 3 초기화 프로세스에 맞추기 위해서 Vuex 4에서는 새로운 store를 만들기 위해
createStore()
함수를 사용한다.
- Vue 애플리케이션에 추가하는 방법도 변경되었다.
<script>
import { reactive, onMounted } from 'vue';
import A from './A.vue';
export default {
name: 'B',
components: {
A,
},
setup() {
const state = reactive({
obj: {},
arr: [],
});
const onClick = () => { ... };
onMounted(() => {
state.arr.filter((i) => i.flag === false);
});
return {
...toRefs(state),
onClick,
};
},
};
</script>
<script lang="ts">
import { defineComponent, reactive, onMounted } from 'vue';
import { Type1, Type2 } from '../types';
import A from './A.vue';
export default defineComponent({
name: 'B',
components: {
A,
},
setup() {
const state = reactive({
obj: { ... } as Type1,
arr: [] as Type2[],
});
const onClick = () => { ... };
onMounted(() => {
state.arr.filter((i: Type2) => i.flag === false);
});
return {
...toRefs(state),
onClick,
};
},
});
</script>
lang="ts"
를 붙여줌으로서 언어 속성을 변경defineComponent
라는 vue 헬퍼 메소드를 사용하여 컴포넌트 형태를 TypeScript로 명시info
내 Type1, Type2 타입 적용filter()
파라미터 내 Type2 타입 적용Vuex 4
- Vuex 4 공식 문서 : https://next.vuex.vuejs.org/
- Vue 3에서는 Vuex 4를, Vue 2에서는 Vuex 3이 적용된다.
- Vuex는 Vue의 공식적인 에코시스템이며, 애플리케이션의 상태관리 패턴 + 라이브러리이다.
- SPA에서 Vue 컴포넌트 외부에서 상태를 잘 다루기 위해 사용한다.
Vuex 3 -> Vuex 4로 변경점
- Vue 3 초기화 프로세스에 맞추기 위해서 Vuex 4에서는 새로운 store를 만들기 위해
createStore()
함수를 사용한다. - Vue 애플리케이션에 추가하는 방법도 변경되었다.
Vuex 3에서 추가
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)
Vuex 4에서 추가
import { createApp } from 'vue';
import { store } from './store';
import App from './App.vue';
const app = createApp(App);
app.use(store);
app.mount('#app');
Vuex 4 store 내부 코드를 TypeScript화 하기
export interface RootState { ... }
export interface State { ... }
export const store = createStore<RootState>({
state: {
a: 0,
},
mutations: {
setA: (state: State, payload: number) => {
state.a = payload;
},
increaseA: (state: State) => {
state.a++;
},
},
actions: {
setA: ({ commit }: ActionContext<State, RootState>, payload: number) => {
commit('setA', payload);
}
},
modules: {
moduleA,
moduleB,
},
getters: {
getA: (state: State) => state.a,
},
});
node_modules\vuex\types\index.d.ts
파일을 보면 타입 체킹에 대해 많은 도움을 받을 수 있다.
8. Vue 3 컨퍼런스 키노트 내용요약 (Vueconf.US)
KEYNOTE: Vue 3.0 Update (Evan You)
- 한국 시간 2021년 4월 16일 22시에 온라인 컨퍼런스에서 발표한 내용 간단 요약
- Vueconf.US 사이트 : https://us.vuejs.org/
Vue 최근 동향
- 매주 1.58M devtools extension 사용자
- 매달 9.4M npm 다운로드
- 작년에 비해서 Devtools는 1.1M에서 1.58M으로 43.6% 증가, npm은 6.2M에서 9.4M로 51.6% 증가
Vue 3이 정식 릴리즈 된 후로 어떤 일들이 있었는가?
- 2020년 9월 18일 Vue 3.0 One Piece 정식 릴리즈
Vue 3 안정화
- Vue Router 4 버전이 이제 안정적이다. stable 버전 릴리즈
- 2021년 4월 15일 기준으로 v4.0.6버전이 최신 릴리즈되었음.
- Vue Router 4 Github : https://github.com/vuejs/vue-router-next
- Vue Router 4 공식문서 : https://next.router.vuejs.org/introduction.html
- Vuex 4 버전도 이제 안정적이다.
- 2021년 4월 15일 기준으로 v4.0.0버전이 최신 릴리즈되었음.
- Vuex 4 Github : https://github.com/vuejs/vuex
- Vuex 4 공식문서 : https://vuex.vuejs.org/
- Vue 3버전의 Ecosystem이 하나둘씩 나오고 있음.
- Nuxt 3
- Vuetify
- Quasar
- Element Plus
- Ant Design Vue
DX(Developer eXperience) 탐구
- 향후 개발은 빌드 도구, 코드 작성 경험(authoring experience), IDE 지원으로 이렇게 3가지 방향으로 나아갈 것이다.
New Build Tools (새로운 빌드 도구들)
-
Vite
- Vite라는 새로운 빌드 도구는 Vue 개발자들에게 프레임워크에 구애받지 않고 빠른 빌드 도구를 제공해준다. (비:트 라고 읽음)
- Vite 공식 문서 : https://vitejs.dev/
- SPA 구축을 위한 독립 실행형 Vue-CLI로 사용할 수 있다.
- 네이티브 ESM을 통한 HMR(Hot Module Replacement) 지원한다.
- esbuild 기반의 dependency pre-bundling 지원
- rollup-compatible 플러그인 인터페이스
- 내장 SSR 지원
- 단기적으로 Vite와 vue-cli는 따로 공존하지만, 장기적으로는 빠른 속도의 Vite와 포괄적인 지원을 하는 vue-cli를 합치는 방향으로 갈 것이다.
-
VitePress
- Vue3 + Vite를 이용한 정적 사이트 생성기
- 마크다운의 동적 컴포넌트의 자유로운 혼합
- 정적 컨텐츠에 대한 자동적인 double-payload 제거
- VitePress에 대한 Evan You의 의견 : https://github.com/vitejs/vite/issues/248#issuecomment-633627213
More Ergonomic Syntax (더 인체공학적인 구문)
- Vue 코드를 작성하는 환경을 개선하기 위해 인체공학적인 구문에 대한 실험을 하고 있다.
<script setup>
- RFC : https://github.com/vuejs/rfcs/blob/script-setup-2/active-rfcs/0000-script-setup.md
- SFC에서 더 인체공학적인 Composition API 사용법이다.
- 런타임 성능 향상
- Vue SFC Playground 링크 : https://sfc.vuejs.org/
<template>
<h1>{{ msg }}</h1>
</template>
<script setup>
const msg = 'Hello World!'
</script>
<style> var injections
- RFC : https://github.com/vuejs/rfcs/blob/style-vars-2/active-rfcs/0000-sfc-style-variables.md
v-bind()
를 사용하여 SFC의 <style>
내부에 JS-state-driven 변수를 삽입하는 방식이다.
- 오버헤드 없이
CSS-in-JS
효과를 가져온다.
<template>
<div class="text">hello</div>
</template>
<script>
export default {
data() {
return {
color: 'red',
font: {
size: '2em',
},
}
},
}
</script>
<style>
.text {
color: v-bind(color);
/* expressions (wrap in quotes) */
font-size: v-bind('font.size');
}
</style>
IDE / TS suppert (IDE / 타입스크립트 지원)
- IDE/TS에 대한 많은 프로젝트를 진행 중이다.
- Vetur, VueDX, Volar
- TypeScript와 함께 SFC 템플릿에 대한 타입 체킹, 리펙토링같은 검증하기 위한 도구 제공
향후 계획
- Vue 3에서는 IE11을 지원하지 않는다.
- IE11 지원이 절대적으로 필요한 사용자들을 위해 Vue 2.7버전은 중요한 Vue 3 기능을 backport 하고, TS 지원을 개선한다. (2021년 3분기 추정)
- 아직까지 Vue 3이 정식 릴리즈하고 난 후 Vue 개발자 중에서 약 8%만 Vue 3을 사용한다고 한다. Vue 2과 호환이 되는 Vue 3 전용 마이그레이션 빌드 출시할 예정 (2021년 4월 말 예상)
기타
Vue.js Korea 한국어 사용자 모임
- Vue.js 소식이나 이야기, 질문, 번역 등 활동을 하고 있는 모임
- Slack 초대 주소 : https://bit.ly/2YVqgBt
Vue 3 공식문서 한글 번역
- 깃허브 : https://github.com/vuejs-kr/docs-next
- Vue 3 공식문서 한글 번역 : https://v3.ko.vuejs.org/
후기
- 2021년 4월 15일 기준으로 v4.0.6버전이 최신 릴리즈되었음.
- Vue Router 4 Github : https://github.com/vuejs/vue-router-next
- Vue Router 4 공식문서 : https://next.router.vuejs.org/introduction.html
- 2021년 4월 15일 기준으로 v4.0.0버전이 최신 릴리즈되었음.
- Vuex 4 Github : https://github.com/vuejs/vuex
- Vuex 4 공식문서 : https://vuex.vuejs.org/
- Nuxt 3
- Vuetify
- Quasar
- Element Plus
- Ant Design Vue
Vite
- Vite라는 새로운 빌드 도구는 Vue 개발자들에게 프레임워크에 구애받지 않고 빠른 빌드 도구를 제공해준다. (비:트 라고 읽음)
- Vite 공식 문서 : https://vitejs.dev/
- SPA 구축을 위한 독립 실행형 Vue-CLI로 사용할 수 있다.
- 네이티브 ESM을 통한 HMR(Hot Module Replacement) 지원한다.
- esbuild 기반의 dependency pre-bundling 지원
- rollup-compatible 플러그인 인터페이스
- 내장 SSR 지원
- 단기적으로 Vite와 vue-cli는 따로 공존하지만, 장기적으로는 빠른 속도의 Vite와 포괄적인 지원을 하는 vue-cli를 합치는 방향으로 갈 것이다.
VitePress
- Vue3 + Vite를 이용한 정적 사이트 생성기
- 마크다운의 동적 컴포넌트의 자유로운 혼합
- 정적 컨텐츠에 대한 자동적인 double-payload 제거
- VitePress에 대한 Evan You의 의견 : https://github.com/vitejs/vite/issues/248#issuecomment-633627213
<script setup>
- RFC : https://github.com/vuejs/rfcs/blob/script-setup-2/active-rfcs/0000-script-setup.md
- SFC에서 더 인체공학적인 Composition API 사용법이다.
- 런타임 성능 향상
- Vue SFC Playground 링크 : https://sfc.vuejs.org/
<template>
<h1>{{ msg }}</h1>
</template>
<script setup>
const msg = 'Hello World!'
</script>
<style> var injections
- RFC : https://github.com/vuejs/rfcs/blob/style-vars-2/active-rfcs/0000-sfc-style-variables.md
v-bind()
를 사용하여 SFC의<style>
내부에 JS-state-driven 변수를 삽입하는 방식이다.- 오버헤드 없이
CSS-in-JS
효과를 가져온다.
<template>
<div class="text">hello</div>
</template>
<script>
export default {
data() {
return {
color: 'red',
font: {
size: '2em',
},
}
},
}
</script>
<style>
.text {
color: v-bind(color);
/* expressions (wrap in quotes) */
font-size: v-bind('font.size');
}
</style>
Vue.js Korea 한국어 사용자 모임
- Vue.js 소식이나 이야기, 질문, 번역 등 활동을 하고 있는 모임
- Slack 초대 주소 : https://bit.ly/2YVqgBt
Vue 3 공식문서 한글 번역
- 깃허브 : https://github.com/vuejs-kr/docs-next
- Vue 3 공식문서 한글 번역 : https://v3.ko.vuejs.org/
후기
Vue.js로 개발하면서 Vue.js Korea 한국어 사용자 모임 슬랙이나 구글, 인프런, VueMastery 같은 곳에서 많은 정보를 항상 받기만 했습니다. 지금까지 내가 받았던 정보와 생각들을 모아서 글을 써보자! 라는 생각으로 시작하게되었고 이렇게까지 글이 길어지리라 생각도 못했습니다. 자료를 계속 찾다보니 욕심이 생겼고, 부족한 내용을 보완하다보니 지금의 글이 되었습니다. 뭔가 최대한 많이 써보려고 노력했으나 더 많은 내용을 더 담지 못하는게 아쉬웠고, 글 솜씨가 그리 좋지않아 내용을 정리한다는 것이 어렵다는 사실도 깨달았습니다.
그나마 velog가 마크다운 형태라 노션과 비슷해 적응하는데 쉬웠습니다. 하지만 다른 디바이스에서 작업을 하다보니 임시저장때문에 몇 번 내용도 날린 경험도 생기고, 글쓰는 시간이 오래 걸리다보니 점차 흥미를 잃어가는 나의 모습을 보고 영영 출간이 안될 것 같다는 생각이 들었습니다. 어쩔수없이 억지로나마 내용을 완성시키기 위해 중간중간 날림 부분이 있지만, 부족하게나마 이 글이 다른 개발자분들에게 조금이라도 도움이 되고 성장할 수 있는 계기가 되었으면 좋겠습니다.
마침 블로그 글을 쓰는 도중에 Vueconf.US 컨퍼런스에 참석하는 기회가 생겼고, 온라인으로 들은 키노트 세션 내용도 추가하였습니다.
여담으로 작년 말에는 Vue 3 공식문서 한글 번역(https://v3.ko.vuejs.org/)에 기여해주신 분들 모두 감사합니다. 1차 번역은 완료되었지만 계속 문서가 수정되어 번역은 항상 진행되고 있습니다(https://github.com/vuejs-kr/docs-next).
Author And Source
이 문제에 관하여(Vue.js 3 정리하기 (Vue-CLI 4, Vue 3, Composition API, TypeScript, Vuex 4)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@kdeun1/Vue-3-Composition-API-TypeScript-Vuex-4로-프로젝트-구성하기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)