1 첫 번째 프로젝트 시작하기
source: categories/study/vue-beginner-lv5/vue-beginner-lv5_1.md
1.1 Vue.js 타입스크립트 프로젝트 생성
vue create vue-todo
Vue CLI v4.5.15
? Please pick a preset: (Use arrow keys)
❯ Default ([Vue 2] babel, eslint)
Default (Vue 3) ([Vue 3] babel, eslint)
Manually select features
# preset: 뷰 플러그인의 집합
# Manually select features 선택
Vue CLI v4.5.15
? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert s
election)
◉ Choose Vue version
◉ Babel
❯◉ TypeScript
◯ Progressive Web App (PWA) Support
◯ Router
◯ Vuex
◯ CSS Pre-processors
◉ Linter / Formatter
◯ Unit Testing
◯ E2E Testing
# vue에서 TypeScript를 구성하실 때 직접 구성하시지 마시고,
# Vue CLI에서 제공하고있는 TypeScript를 선택해서 구성하시는 것을 추천드립니다.
# space bar를 눌러서 TypeScript를 선택합니다.
Vue CLI v4.5.15
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS, Linter
? Choose a version of Vue.js that you want to start the project with (Use arrow keys)
❯ 2.x
3.x
# vue 버전은 2.x를 선택해줍니다.
Vue CLI v4.5.15
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use class-style component syntax? (Y/n)
# 이 구간이 제가 가장 많이 말씀드리고 싶은 구간인데,
# 이미 vue에서 TypeScript를 사용하시는 분들은 class component로 작성하셨을 확률이 굉장히 높습니다.
# 그런데 저는 개인적으로 class component를 추천하지 않습니다.
# 그 이유에 대해서는 이 다음 시간에 간단히 말씀드리겠습니다.
# 일단 class component 형태가 아닌 extend 형태로 작성하는 것을 추천드리기 때문에 n을 입력해줍니다.
Vue CLI v4.5.15
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use class-style component syntax? No
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? (Y/n)
# 바벨과 타입스크립트를 같이 사용할건지를 묻고있습니다. y를 입력해 같이 구성하겠다고 선택해주시면됩니다.
Vue CLI v4.5.15
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use class-style component syntax? No
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Pick a linter / formatter config: (Use arrow keys)
❯ ESLint with error prevention only
ESLint + Airbnb config
ESLint + Standard config
ESLint + Prettier
TSLint (deprecated)
# ESLint + Prettier 로 사용하시는 것을 추천드립니다.
# 마이크로소프트에서 타입스크립트를 ESLint로 개발하는 것으로 결정이 낫기 때문에 TSLint는 사용하지 않는 것을 추천드립니다.
Vue CLI v4.5.15
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use class-style component syntax? No
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Pick a linter / formatter config: Prettier
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◉ Lint on save
◯ Lint and fix on commit
# Lint on save 엔터
Vue CLI v4.5.15
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use class-style component syntax? No
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Pick a linter / formatter config: Prettier
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
❯ In dedicated config files
In package.json
# 마지막으로 주의하셔야하는게 많은 분들이 dedicated config files에 대해 간과하시는 것 같습니다.
# 설정 파일은 별도의 설정 파일로 분리하시는 것이 확장성있게 프로젝트를 관리하실 수 있습니다.
# In dedicated config files 선택
Vue CLI v4.5.15
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use class-style component syntax? No
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Pick a linter / formatter config: Prettier
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N)
# 전체적인 프로젝트 구성이 끝났습니다.
# 현재 프리셋을 미래 프로젝트를 위해 저장할 것이냐에 대해선 n을 입력하시면 됩니다.
git diff
- 다음시간
- 왜 클래스 컴포넌트를 권장하지 않는지 그 이유에 대해..
1.2 클래스 문법을 권장하지 않는 이유
- https://github.com/vuejs/rfcs/pull/17
- https://github.com/vuejs/rfcs/pull/42
- https://github.com/vuejs/rfcs/issues/63
vue에서 TypeScript를 사용할 때 왜 클래스 문법을 권장하지 않는지에 대해 이야기해보도록 하겠습니다.
2019 5월 21일 vue 창시자 에반유 글
Update: the Class API proposal is being dropped.
- composition API : Vue 3의 가장 핵심적인 API
- 인스턴스 옵션 속성이 하나 추가된 것이라고 보면됨
- 그런 논의가 2019년 5월부터 있었다고 보시면됨
- vue 같은 경우는 다른 프레임워크와 다르게 커뮤니티와 많은 대화를 나누고 그리고 우리가 이런 방향으로 갈테니까 너네가 한번 봐줄래? 어때? 이런 문화가 활발함
- RFC(Request For Comment)
- 여튼 RFC라고해서 우리가 신규 기능을 이렇게 개발해나갈건데, 너네가 이거를 어떻게 받아들이는지 의견을 줘. 이런거임.
- 여튼 2019년 5월 에반유가 우리가 제안했던 Class API를 떨구겠다 라고 발표함
- 앵귤러 같은 느낌인 Class 문법으로 Vue 3로 가야겠다 라고 생각하다가 결국엔 Class API를 버림
- 최종적으로 나온 형태
- vue3에 setup 이라는 옵션이 생김
- 그리고 setup 옵션 안에 여러가지 API들이 제공됨
- 이 setup이라는 옵션이라는 것은 vue component를 작성할 때 Single File Component 내에서.. vue 2에선
data
,methods
,computed
.. 를 썼잖아요? - 그거와 마찬가지로 그 옆에
setup
이라는 옵션이 추가된 것임 (setup은 vue 3에서 추가된 인스턴스 속성) - 이
setup
이라는 속성은 쓰셔도돼고 안쓰셔도됨 - 이러한 내용들을 2번째 프로젝트할 때 얘기를 할거고,
setup
이라는 것은 알면 좋은거지 필수는 아니다 라고 이해하시면됨
-
여튼 Class API 에 대한 문법들을 버렸다기보다는 이제는 vue 3가 나아가는 방향 속에 Class API는 없다라는 것임
- Class API를 권장하지 않는 이유 중에 하나는..
- 맛보기 코드
- 위 맛보기 코드를 보시면 앵귤러로 가는 느낌이 들고, (탐탁치 않음)
- 이거는 vue의 정체성을 많이 훼손시키는 문법이라고 생각이듦
- 그래서 위 문법들을 vue 3에서 사용하지 못하게하느냐. 그게 아니라 앞으로 저런 방향으로 진화되진 않는다는 것임.
- 호환까진 되지만 저 Class 문법이라는 것을 추가적으로 개선하여 반영하진 않는다는 것
- 지금 뷰 프로젝트에 타입스크립트를 시작하시는 분들이라고하면
- 기존 프로젝트에선 위와 같이 Class 문법으로해서 프로퍼티 데코레이터로 추가적인 문법들을 배우지 마시고,
- 이번 강의에서 다루는 문법을 가지고 한번 해보시면 (vue extend 문법을 사용할겁니다) 원래 하던대로하면서 타입스크립트의 이점을 가져가실 수 있을거임
정리
- 이미 많은 실무 프로젝트들이 Class 문법으로 뷰에서 타입스크립트를 적용했을 확률이 큼
- 그랬을 때 그걸 당장 버리고 바꿔야된다 가 아니라
- 추후에 뭔가 개선하시게되면 Vue 3를 가지고 개선하시게될 확률이 클텐데
- 그때 저희가 좋아하는 vue 스타일.. 옵션 속성들을 가지고 (
new Vue
안에key: value
형태로 설정했었죠?) 기존 형태대로 가시면 될거같음
왜 Class 스타일이 안좋은지 이유가 명확하진 않지만.. 이건 내가 더 찾아봐야되고..
여기선 그냥 앵귤러스러워서..?
여튼 그리고 뷰 컴포지션 API란 정확히 뭐지?
이런 설명들이 좀 부족한듯
더 찾아봐야됨
클래스 API 제안이 삭제된 이유 (2019년 5월 21일 에반유)
왜?
두가지 주요 이유
- 현재 클래스 API 제안에는 여전히 다양한 엣지 케이스/사양 의존도/해결되지 않은 질문이 있음
-
고급 반응성 API(Advanced Reactivity API) 및 동적 라이프 사이클 주입(Dynamic Lifecycle Injection)에서 제안된 새로운 API는 Class 보다 더 나은 구성(Composition) 요소 API 역할을 할 수 있는 "Composition Function"라는 새로운 패턴을 가능하게 합니다.(일시적으로)
Composition Function과 Class API를 모두 제공하면 기본적으로 동일한 작업을 수행하는 3가지 방법이 발생합니다.
이것은 우리가 어떤 희생을 치르더라도 피하고 싶은 것입니다.
Class에 비해 Composition Function의 장점은 아래에서 더 자세히 설명합니다.
현재 Class 제안의 문제점
타이핑(유형, type) 복잡성
RFC(Request For Comment)에 명시된 대로 Class API를 도입하는 주요 목표는 더 나은 TypeScript 추론 지원과, 그와 함께 제공되는 대체 API를 제공하는 것입니다.
그러나 Vue component가 여러 소스에서 선언된 속성을 단일 this 컨텍스트로 병합해야 한다는 사실은 Class 기반 API에서도 약간의 문제를 만듭니다.
한 가지 예는 props
의 타이핑(유형, type)입니다.
this
에 props
를 병합하려면 component class
에 대한 일반 인수를 사용하거나 decorator
를 사용해야합니다.
하지만 둘 다 문제가 있습니다.
- 일반 argument 에는 여전히 런타임
props
옵션 선언이 필요합니다.- 이로인해 어색하고 중복되는 이중 선언이 발생합니다.
decorators
를 사용하면 특히TypeScript
의 현재 구현이TC39
제안과 완전히 동기화되지 않은 경우 많은 불확실성이 있는 2단계 사양에 의존하게됩니다.- 또한
this.$props
에decorators
로 선언된props
유형을 노출할 방법이 없습니다.- 이는
TSX
지원을 중단합니다.
- 이는
또한 현재 Class Methods의 arguments에 대한 컨텍스트 Type(유형) 지정을 활용할 수 있는 방법이 없습니다.
즉, Class의 렌더링 함수에 전달된 arguments는 Class의 다른 properties를 기반으로 유추된 형식(Type)을 가질 수 없습니다.
예약된 메서드의 네임스페이스
우리는 Class 선언에서 "예약된" 메서드를 처리하는 방법에 대해 논의했습니다.
이 설명은 @glen-84
에 의해 매우 잘 요약되어 있습니다.
제안된 솔루션 중 어느 것도 완벽해 보이지 않습니다.
구현 복잡성
Class를 지원하는 것은 실제로 추가적인 내부 코드로 다루어야하는 수많은 엣지 케이스를 포함합니다.
이것은 반응성(Reactivity) 추적을 위해 this
로 Proxy를 사용해야 하는 우리의 필요성과 생성자의 this
(따라서 모든 클래스 필드 이니셜라이저)가 다른 모든 위치의 this
와 다를 것이라는 사실과 주로 관련이 있습니다.
또한 Class와 Object Composition Component 선언(트리쉐이킹 할 수 없는) 간에 앞뒤로 변환하는 코드를 포함해야합니다.
의심스러운 이득
위의 모든 문제로 인해 Class API를 도입함으로써 얻을 수 있는 이점은 의심스럽습니다.
- 주요 목적을 잘 달성하지 못합니다.(더 나은 TypeScript 지원이라는 목적)
- 내부 구현을 복잡하게 만듭니다.
- 논리 구성을 개선하지 않습니다.
대체: Composition Functions
Class API 이후에 Advanced Reactivity API와 Dynamic Lifecycle Injection이라는 두 가지 새로운 API 세트도 제안했습니다.
이것들을 결합하여 우리는 컴포넌트 로직을 선언하는 새로운 방법인 함수 호출을 사용하는 것을 발견하게 되었습니다.
이것은 React Hooks에서 영감을 받았지만 Vue의 자체 반응성(reactivity) 시스템에 뿌리를 두고 있습니다.
Feature Parity (동등한 기능)
composition functions
를 사용하면 component
의 논리가 주로 새 setup()
함수 내에서 함수 호출을 사용하여 선언됩니다. (이것은 본질적으로 data()
이지만 목적에 더 잘 맞도록 이름이 지정됨)
이러한 함수 호출은 거의 모든 기존 component options
과 기능이 동일합니다.
// everything tree-shakable
import {
value,
computed,
watch,
onMounted,
inject
} from 'vue'
const App = {
// same as before
props: {
a: String,
b: Number
},
// same as before
components: {
// ...
},
setup(props) {
// data
const count = value(1)
// computed
const plusOne = computed(() => count.value + 1)
// methods
function inc() {
count.value++
}
// watch
watch(() => props.b + count.value, val => {
console.log('changed: ', val)
})
// lifecycle
onMounted(() => {
console.log('mounted!')
})
// dependency injection
const injected = inject(SomeSymbol)
// other options like el, extends and mixins are no longer necessary
// expose bindings on render context
// any value containers will be unwrapped when exposed
// any non-containers will be exposed as-is, including functions
return {
count,
plusOne,
inc,
injected
}
},
// template: `same as before`,
render({ state, props, slots }) {
// `this` points to the render context and works same as before (exposes everything)
// `state` exposes bindings returned from `setup()` (with value wrappers unwrapped)
}
}
더 나은 TypeScript 지원
위의 예는 argument 위치에 있는 한 예외 케이스 없이 완벽하게 입력할 수 있습니다.
import { createComponent } from 'vue'
const App = createComponent({
props: {
// ...
},
setup(props) {
// infer : 유추하다.
// props type inferred from `props` option
// composition functions are all easily typed since they
// don't rely on `this`
return {
// ...
}
},
render({ state, props }) {
// `state` type inferred from return value of setup()
// `this` type inferred from a merge of state and props
}
})
// The resulting type of `App` also supports TSX props inference
내부 Typing도 훨씬 덜 복잡합니다.
더 나은 Composition(구성) 기능
여기에 설명된 것처럼 Composition Function을 사용하면 옵션이 아닌 주제별로 논리를 그룹화하기가 매우 쉽습니다.
또한 mixins
의 단점(네임스페이스 충돌 및 불분명한 속성 소스) 없이 다양한 Composition(구성) 요소에서 쉽게 추출 및 재사요할 수 있습니다.
더 나은 Compatibility (호환성)
Composition Functions은 2.x 개체 구문 위에 완전히 호환되는 확장(extension)으로 볼 수 있습니다.
이는 마이그레이션이 점진적으로 수행될 수 있음을 의미합니다.
이것이 Class API를 삭제해야하는 설득력 있는 이유를 제공하기를 바랍니다.
Composition Functions을 공식적으로 도입하기 위해 별도의 RFC를 마련할 것입니다.
1.3 강의 진행 방식 및 첫 번째 프로젝트 소개
1.3.1 Vue.js에서 타입스크립트를 적용하는 방법
- 서비스를 처음 구축할 때부터 타입스크립트를 사용한다.
- 이 경우는 거의 없다. vue.js 2014년도에 나온 프레임워크
- 2018년 부터 여러 기업에서 vue.js로 정말 많은 서비스를 만들면서 이미 구축되어있는 서비스들이 많다.
- 이런 서비스에 타입스크립트를 점진적으로 입혀나가는 경우가 많지 애초에 처음부터 타입스크립트를 설정해서 작업해나가는 경우는 거의 없다.
- 기존에 이미 구현된 서비스에 타입스크립트를 점진적으로 적용한다.
타입스크립트는 자바스크립트와 별개의 언어이다.
따라서 타입스크립트를 점진적으로 적용할 수 있기 때문에 무조건 처음부터 적용해야된다 라는 생각은 안해도된다.
두번째 프로젝트에서 이미 만들어진 앱에 타입스크립트를 점진적으로 적용해보도록 하겠다.
첫번째 프로젝트 vue-todo
는 처음부터 타입스크립트를 적용해 진행하도록 하겠다.
1.4 프로젝트 설명
-
tsconfig.json
- 타입스크립트가 현재 프로젝트 폴더에 대해 어떻게 해석해 나갈 것인지를 정해주는 옵션들
- 그것이 바로
compilerOptions
compilerOptions
의target
,module
,strict
"target"
:"esnext"
- target: string (웹스톰 마우스커서 오버시 뜨는 설명)
Set the JavaScript language version for emitted JavaScript and include compatible library declarations. - 내보내는 JavaScript 버전(몇 버전으로 내보낼지)을 설정하고 호환되는 라이브러리 선언을 포함합니다.
- target: string (웹스톰 마우스커서 오버시 뜨는 설명)
"module"
:"esnext"
- module: string (웹스톰 마우스커서 오버시 뜨는 설명)
Specify what module code is generated. - 생성되는 모듈 코드를 지정합니다.
- module: string (웹스톰 마우스커서 오버시 뜨는 설명)
"strict"
:true
- strict: boolean (웹스톰 마우스커서 오버시 뜨는 설명)
Enable all strict type checking options. - 모든 엄격한 유형 검사 옵션을 활성화합니다.
- strict: boolean (웹스톰 마우스커서 오버시 뜨는 설명)
- 각 옵션에 마우스 커서를 오버하면 설명이 뜹니다.
프로젝트 시작시 타입스크립트를 자동 세팅되게 설정하면 이렇게 vue 코어팀에서 만들어놓은 설정을 그대로 가져다 쓸 수 있다.
1.4.1 tsconfig.json의 paths 속성 관련해서..
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env"
],
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
예전 vue 버전에선 jsconfig.json(VS CODE 내부적으로 사용하는 설정 파일)
같은 설정 파일로 component 내에서 @/
했을 때, src/
경로를 바라보게끔 하는, 그런 기능들을 봤을겁니다.
지금 vue 버전은 @
, ~
이런 것들이 자동으로 설정되어있습니다.
(내가 알기론 이렇다고 알고 있음)
여튼 강의내용은
- 이전엔
jsconfig.json(VS CODE 내부적으로 사용하는 설정 파일)
파일에서 위tsconfig.json
과 동일하게compilerOptions
의paths
에서@/
를 설정했었다. tsconfig.json
는 타입스크립트 설정 파일이지만 에디터에서 이를 인식해.. 즉, VS CODE에서 이tsconfig.json
을 인식해 똑같이@/
를 인식한다.- 즉,
jsconfig.json
을 따로 설정 안해도 된다 라는 취지인듯?
1.4.2 babel.config.js
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"],
};
뷰 내부적으로 이미 babel preset
설정해놓은걸 그대로 설정
1.4.3 .eslintrc.js
module.exports = {
root: true,
env: {
node: true,
},
extends: [
"plugin:vue/essential",
"eslint:recommended",
"@vue/typescript/recommended",
"@vue/prettier",
"@vue/prettier/@typescript-eslint",
],
parserOptions: {
ecmaVersion: 2020,
},
rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
},
};
.eslint.js
도 이미 prettier
까지 설정 되어있다.
rules
안에 원하는 prettier
옵션 값을 지정하면 된다.
main.ts
: 기존main.js
에서main.ts
로 바뀐 것뿐-
shims-vue.d.ts
: 타입스크립트가 해당 프로젝트를 보고 해석을 한다고 말씀을 드렸었죠?
타입스크립트 내부적으로TS Language Server
가 작동하고 있고..
이를 흔히 타입스크립트 컴파일 이라고 얘기하는데
어쨌든 프로젝트 폴더 내부적으로 파일들의 관계를 해석하거나 타입스크립트의 타입 추론 기능을 제공하기 위해TS Language Server
가 작동하고 있다 라고 보시면 됩니다.그런데 타입스크립트는
*.vue
파일을 제대로 인식 못할거임.
왜?
모르는 확장자이기 때문.
이를shims-vue.d.ts
파일에 명시함. 그래서 타입스크립트에게 알려줌.
*.vue
파일을 모두Vue
타입으로 인식해줘!
declare module "*.vue" {
// *.vue 파일을 만나면 아래 코드로 인식해줘!
import Vue from "vue";
export default Vue;
}
이렇게 모든 *.vue
파일을 타입스크립트가 제대로 인식하게 해주면된다.