SlideShare ist ein Scribd-Unternehmen logo
1 von 82
한성민
IGAWorks
SungMin Han
프론트엔드 모던 프레임워크
낱낱히 파헤치기
오늘날의 프론트엔드
모던 프레임워크 톺아보기
실무자를 위한 Tips
이번 세션에서는
오늘날의 프론트엔드
웹 프론트 기술의 흐름
jQuery
Vanila
Javascript
AngularJS
React
VueJS
Angular
2006 2013
2009 2014
2016
조금 더 넓게..
jQuery
Vanila
Javascript
AngularJS
React
VueJS
Angular
2006 2013
2009 2014
2016
XMLHTTPRequest(XHR)
2002
ES2015
2015
Node.js
2013
Redux
2015
RxJS
2012
Typescript
2012
Ember.js
2011
CoffeScript
2009
AMD
2010
CommonJS
(CJS)
2009
ES2016
2016
WebAssembly
2015
2017 프론트엔드 로드맵
동적 렌더링
모듈링 / 번들링
타이핑
현재 프론트진형의 중요 키워드
테스트 자동화
동적 렌더링
모듈링 / 번들링
타이핑
2017년 프론트 진형 중요 키워드
테스트 자동화
Two-way binding, SPA, Virtual DOM, Change Detection …
CommonJS, AMD, UMD, Uglify, Grunt, Webpack …
Typescript, Proptypes, Flow, Props …
UnitTest, e2e Test, HeadLess Browser …
그리고 그것들을 제공하는 많은 도구들
Angular
완전하고 빠른 프레임워크
React
활발하고 오픈 되어 있으며 합리적인 프레임워크
VueJS
가볍고 친숙하며 장점만을 합쳐놓은 프레임워크
그러던 중 나타난 프레임워크들
그리고 프레임워크는 그 모든 것을 쉽게 만들어주었나니..
Angular
완전하고 빠른 프레임워크
React
활발하고 오픈 되어 있으며 합리적인 프레임워크
VueJS
가볍고 친숙하며 장점만을 합쳐놓은 프레임워크
그러던 중 나타난 프레임워크들
그리고 프레임워크는 그 모든 것을 쉽게 만들어주었나니..
Angular
모든 기능이 빌트인되어 있으며 성능이 훌륭하지만, 진입장벽이 가장 높음
React
에코시스템이 활발하게 움직이고 또 그것을 장려하지만
의존과 버전에 민감하고 라이브러리 자체의 기능만으로는 부족함
VueJS
프레임워크 자체가 가볍고 진입장벽이 낮으며 각 프레임워크의 장점을 흡수
다만 크기가 커질 수록 재활용성은 떨어지며, 테스트하기 어렵고 느림
이를 풀어 설명하자면
모던 프레임워크 톺아보기
Angular
릴리즈
개발자/개발사
버전
언어
모델
컴파일
2016년 6월 공식출시
Google Inc
2017년 11월 기준 v5.0.1 stable
Typescript, Dart, Javascript
MVVM / Change Detection / NgZone
JIT (built-in core) / AOT (ng, ngc) / TreeShaking with ng cli
React
릴리즈
개발자/개발사
버전
언어
모델
컴파일
2013년 3월 공식출시
Facebook, Instagram
2017년 11월 기준 V16.1.1 stable
Javascript, JSX
View Engine / Virtual DOM / PropTypes
JIT (built-in core) / TreeShaking with Webpack2
VueJS
릴리즈
개발자/개발사
버전
언어
모델
컴파일
2014년 2월 공식출시
Evan you
2017년 11월 기준 V2.5.3 stable
Javascript, JSX(호환)
MVVM / VirtualDOM / core와 companion 분리 / Vuex
JIT (built-in core) / TreeShaking with Webpack2
Angular code
import { Component, ViewChild, ElementRef } from '@angular/core';
const DEFAULT_INITIALIZE_FOOD_LIST: string[] = [ '치킨', '탕수육',
'닭도리탕' ];
@Component({
selector: 'mukkit-list',
templateUrl: './mukkit_list.html',
styleUrls: [ './mukkit_list.css' ]
})
export class MukkitListComponent {
public foodList: string[] = [...DEFAULT_INITIALIZE_FOOD_LIST];
public newFood: string;
@ViewChild('input') inputEl: ElementRef;
ngAfterViewInit() {
this.focusFood();
}
focusFood(): void {
this.inputEl.nativeElement.focus();
}
enterFood($event: KeyboardEvent): void {
if ($event.keyCode === 13) {
this.addFood();
}
}
addFood(): void {
if (this.foodList.indexOf(this.newFood) === -1) {
this.foodList.push(this.newFood);
this.newFood = '';
} else {
alert('해당 음식은 이미 있습니다.');
}
}
}
mukkit_list.component.ts
Angular code
mukkit_list.html
<div class="mukkit-list-container">
<img width="180" src="data:image…">
<h2>먹킷리스트</h2>
</div>
<ul class="mukkit-list">
<li *ngFor="let food of foodList">
<span>{{food}}</span>
</li>
<li>
<input type="text"
#input
[(ngModel)]="newFood"
(keypress)="enterFood($event);">
<button (click)="addFood();">먹킷리스트 추가</button>
</li>
</ul>
Angular code
mukkit_list.html
<div class="mukkit-list-container">
<img width="180" src="data:image…">
<h2>먹킷리스트</h2>
</div>
<ul class="mukkit-list">
<li *ngFor="let food of foodList">
<span>{{food}}</span>
</li>
<li>
<input type="text"
#input
[(ngModel)]="newFood"
(keypress)="enterFood($event);">
<button (click)="addFood();">먹킷리스트 추가</button>
</li>
</ul>
export class MukkitListComponent {
public foodList: string[] = [...DEFAULT_INITIALIZE_FOOD_LIST];
public newFood: string;
@ViewChild('input') inputEl: ElementRef;
…
enterFood($event: KeyboardEvent): void {
…
}
addFood(): void {
…
}
}
mukkit_list.component.ts
1way binding (viewmodel -> view)
2way binding (videmodel <-> view)
view query (it is not bind)
1way binding (view <- viewmodel)
MukkitList.js
React code
import React, { Component } from 'react';
import logo from './logo.svg';
import './MukkitList.css';
const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ];
class MukkitList extends Component {
constructor(props) {
super(props);
this.state = {
foodList: [...DEFAULT_INITIALIZE_FOOD_LIST],
newFood: ''
};
}
changeFood(event) {
this.setState({'newFood': event.target.value});
}
enterFood(event) {
if (event.key === 'Enter') this.addFood();
}
addFood(event) {
if (this.state.foodList.indexOf(this.state.newFood) === -1) {
this.setState({
foodList: [...this.state.foodList, this.state.newFood],
newFood: ''
});
} else {
alert('해당 음식은 이미 있습니다.');
}
}
render() {
return (
<div className="container">
<header className="mukkit-list-header">
<img src={logo} className="mukkit-list-logo" alt="logo" />
<h2 className="mukkit-list-title">먹킷리스트</h2>
</header>
<ul className="mukkit-list">
{this.state.foodList.map((food, index) => <li key={index}><span>{food}</span></li>)}
<li>
<input type="text“ value={this.state.newFood}
onChange={this.changeFood.bind(this)}
onKeyPress={this.enterFood.bind(this)} />
<button onClick={this.addFood.bind(this)}>먹킷리스트 추가</button>
</li>
</ul >
</div >
);
}
}
export default MukkitList;
MukkitList.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './MukkitList.css';
const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ];
class MukkitList extends Component {
constructor(props) {
super(props);
this.state = {
foodList: [...DEFAULT_INITIALIZE_FOOD_LIST],
newFood: ''
};
}
changeFood(event) {
this.setState({'newFood': event.target.value});
}
enterFood(event) {
if (event.key === 'Enter') this.addFood();
}
addFood(event) {
if (this.state.foodList.indexOf(this.state.newFood) === -1) {
this.setState({
foodList: [...this.state.foodList, this.state.newFood],
newFood: ''
});
} else {
alert('해당 음식은 이미 있습니다.');
}
}
render() {
return (
<div className="container">
<header className="mukkit-list-header">
<img src={logo} className="mukkit-list-logo" alt="logo" />
<h2 className="mukkit-list-title">먹킷리스트</h2>
</header>
<ul className="mukkit-list">
{this.state.foodList.map((food, index) => <li key={index}><span>{food}</span></li>)}
<li>
<input type="text“ value={this.state.newFood}
onChange={this.changeFood.bind(this)}
onKeyPress={this.enterFood.bind(this)} />
<button onClick={this.addFood.bind(this)}>먹킷리스트 추가</button>
</li>
</ul >
</div >
);
}
}
export default MukkitList;
1way binding (videmodel -> view)
React code
MukkitList.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './MukkitList.css';
const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ];
class MukkitList extends Component {
constructor(props) {
super(props);
this.state = {
foodList: [...DEFAULT_INITIALIZE_FOOD_LIST],
newFood: ''
};
}
changeFood(event) {
this.setState({'newFood': event.target.value});
}
enterFood(event) {
if (event.key === 'Enter') this.addFood();
}
addFood(event) {
if (this.state.foodList.indexOf(this.state.newFood) === -1) {
this.setState({
foodList: [...this.state.foodList, this.state.newFood],
newFood: ''
});
} else {
alert('해당 음식은 이미 있습니다.');
}
}
render() {
return (
<div className="container">
<header className="mukkit-list-header">
<img src={logo} className="mukkit-list-logo" alt="logo" />
<h2 className="mukkit-list-title">먹킷리스트</h2>
</header>
<ul className="mukkit-list">
{this.state.foodList.map((food, index) => <li key={index}><span>{food}</span></li>)}
<li>
<input type="text“ value={this.state.newFood}
onChange={this.changeFood.bind(this)}
onKeyPress={this.enterFood.bind(this)} />
<button onClick={this.addFood.bind(this)}>먹킷리스트 추가</button>
</li>
</ul >
</div >
);
}
}
export default MukkitList;
render DOM
React code
MukkitList.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './MukkitList.css';
const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ];
class MukkitList extends Component {
constructor(props) {
super(props);
this.state = {
foodList: [...DEFAULT_INITIALIZE_FOOD_LIST],
newFood: ''
};
}
changeFood(event) {
this.setState({'newFood': event.target.value});
}
enterFood(event) {
if (event.key === 'Enter') this.addFood();
}
addFood(event) {
if (this.state.foodList.indexOf(this.state.newFood) === -1) {
this.setState({
foodList: [...this.state.foodList, this.state.newFood],
newFood: ''
});
} else {
alert('해당 음식은 이미 있습니다.');
}
}
render() {
return (
<div className="container">
<header className="mukkit-list-header">
<img src={logo} className="mukkit-list-logo" alt="logo" />
<h2 className="mukkit-list-title">먹킷리스트</h2>
</header>
<ul className="mukkit-list">
{this.state.foodList.map((food, index) => <li key={index}><span>{food}</span></li>)}
<li>
<input type="text“ value={this.state.newFood}
onChange={this.changeFood.bind(this)}
onKeyPress={this.enterFood.bind(this)} />
<button onClick={this.addFood.bind(this)}>먹킷리스트 추가</button>
</li>
</ul >
</div >
);
}
}
export default MukkitList;
1way binding (viewmodel -> view)
React code
MukkitList.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './MukkitList.css';
const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ];
class MukkitList extends Component {
constructor(props) {
super(props);
this.state = {
foodList: [...DEFAULT_INITIALIZE_FOOD_LIST],
newFood: ''
};
}
changeFood(event) {
this.setState({'newFood': event.target.value});
}
enterFood(event) {
if (event.key === 'Enter') this.addFood();
}
addFood(event) {
if (this.state.foodList.indexOf(this.state.newFood) === -1) {
this.setState({
foodList: [...this.state.foodList, this.state.newFood],
newFood: ''
});
} else {
alert('해당 음식은 이미 있습니다.');
}
}
render() {
return (
<div className="container">
<header className="mukkit-list-header">
<img src={logo} className="mukkit-list-logo" alt="logo" />
<h2 className="mukkit-list-title">먹킷리스트</h2>
</header>
<ul className="mukkit-list">
{this.state.foodList.map((food, index) => <li key={index}><span>{food}</span></li>)}
<li>
<input type="text“ value={this.state.newFood}
onChange={this.changeFood.bind(this)}
onKeyPress={this.enterFood.bind(this)} />
<button onClick={this.addFood.bind(this)}>먹킷리스트 추가</button>
</li>
</ul >
</div >
);
}
}
export default MukkitList;
1way binding (view -> viewmodel)
React code
MukkitList.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './MukkitList.css';
const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ];
class MukkitList extends Component {
constructor(props) {
super(props);
this.state = {
foodList: [...DEFAULT_INITIALIZE_FOOD_LIST],
newFood: ''
};
}
changeFood(event) {
this.setState({'newFood': event.target.value});
}
enterFood(event) {
if (event.key === 'Enter') this.addFood();
}
addFood(event) {
if (this.state.foodList.indexOf(this.state.newFood) === -1) {
this.setState({
foodList: [...this.state.foodList, this.state.newFood],
newFood: ''
});
} else {
alert('해당 음식은 이미 있습니다.');
}
}
render() {
return (
<div className="container">
<header className="mukkit-list-header">
<img src={logo} className="mukkit-list-logo" alt="logo" />
<h2 className="mukkit-list-title">먹킷리스트</h2>
</header>
<ul className="mukkit-list">
{this.state.foodList.map((food, index) => <li key={index}><span>{food}</span></li>)}
<li>
<input type="text“ value={this.state.newFood}
onChange={this.changeFood.bind(this)}
onKeyPress={this.enterFood.bind(this)} />
<button onClick={this.addFood.bind(this)}>먹킷리스트 추가</button>
</li>
</ul >
</div >
);
}
}
export default MukkitList;
state changed
React code
MukkitList.vue
VueJS code
<template>
<ul class="mukkit-list">
<li v-for="food in foodList">
<span>{{food}}</span>
</li>
<li>
<input type="text"
ref="input"
v-model="newFood"
v-on:keypress.enter="addFood">
<button v-on:click="addFood">먹킷리스트 추가</button>
</li>
</ul>
</template>
<script>
const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ]
export default {
name: 'MukkitList',
data () {
return {
foodList: [...DEFAULT_INITIALIZE_FOOD_LIST],
newFood: ''
}
},
mounted () {
this.focusFood()
},
methods: {
focusFood () {
this.$refs.input.focus()
},
addFood () {
if (this.foodList.indexOf(this.newFood) === -1) {
this.foodList.push(this.newFood)
this.newFood = ''
this.focusFood()
} else {
alert('해당 음식은 이미 있습니다.')
}
}
}
}
</script>
MukkitList.vue
<template>
<ul class="mukkit-list">
<li v-for="food in foodList">
<span>{{food}}</span>
</li>
<li>
<input type="text"
ref="input"
v-model="newFood"
v-on:keypress.enter="addFood">
<button v-on:click="addFood">먹킷리스트 추가</button>
</li>
</ul>
</template>
<script>
const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ]
export default {
name: 'MukkitList',
data () {
return {
foodList: [...DEFAULT_INITIALIZE_FOOD_LIST],
newFood: ''
}
},
mounted () {
this.focusFood()
},
methods: {
focusFood () {
this.$refs.input.focus()
},
addFood () {
if (this.foodList.indexOf(this.newFood) === -1) {
this.foodList.push(this.newFood)
this.newFood = ''
this.focusFood()
} else {
alert('해당 음식은 이미 있습니다.')
}
}
}
}
</script>
VueJS code
2way binding (videmodel <-> view)
MukkitList.vue
<template>
<ul class="mukkit-list">
<li v-for="food in foodList">
<span>{{food}}</span>
</li>
<li>
<input type="text"
ref="input"
v-model="newFood"
v-on:keypress.enter="addFood">
<button v-on:click="addFood">먹킷리스트 추가</button>
</li>
</ul>
</template>
<script>
const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ]
export default {
name: 'MukkitList',
data () {
return {
foodList: [...DEFAULT_INITIALIZE_FOOD_LIST],
newFood: ''
}
},
mounted () {
this.focusFood()
},
methods: {
focusFood () {
this.$refs.input.focus()
},
addFood () {
if (this.foodList.indexOf(this.newFood) === -1) {
this.foodList.push(this.newFood)
this.newFood = ''
this.focusFood()
} else {
alert('해당 음식은 이미 있습니다.')
}
}
}
}
</script>
VueJS code
1way binding (viewmodel -> view)
MukkitList.vue
<template>
<ul class="mukkit-list">
<li v-for="food in foodList">
<span>{{food}}</span>
</li>
<li>
<input type="text"
ref="input"
v-model="newFood"
v-on:keypress.enter="addFood">
<button v-on:click="addFood">먹킷리스트 추가</button>
</li>
</ul>
</template>
<script>
const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ]
export default {
name: 'MukkitList',
data () {
return {
foodList: [...DEFAULT_INITIALIZE_FOOD_LIST],
newFood: ''
}
},
mounted () {
this.focusFood()
},
methods: {
focusFood () {
this.$refs.input.focus()
},
addFood () {
if (this.foodList.indexOf(this.newFood) === -1) {
this.foodList.push(this.newFood)
this.newFood = ''
this.focusFood()
} else {
alert('해당 음식은 이미 있습니다.')
}
}
}
}
</script>
VueJS code
1way binding (view -> viewmodel)
MukkitList.vue
<template>
<ul class="mukkit-list">
<li v-for="food in foodList">
<span>{{food}}</span>
</li>
<li>
<input type="text"
ref="input"
v-model="newFood"
v-on:keypress.enter="addFood">
<button v-on:click="addFood">먹킷리스트 추가</button>
</li>
</ul>
</template>
<script>
const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ]
export default {
name: 'MukkitList',
data () {
return {
foodList: [...DEFAULT_INITIALIZE_FOOD_LIST],
newFood: ''
}
},
mounted () {
this.focusFood()
},
methods: {
focusFood () {
this.$refs.input.focus()
},
addFood () {
if (this.foodList.indexOf(this.newFood) === -1) {
this.foodList.push(this.newFood)
this.newFood = ''
this.focusFood()
} else {
alert('해당 음식은 이미 있습니다.')
}
}
}
}
</script>
VueJS code
view query (it is not bind)
트랜드 - Trend
Fight 1
Google Trend 2017. 11
29,994 star
81,002 star
73,628 star
GitHub Stars
Deview 2016 투표
133
164
Unkown
Stack Overflow tagged questions
81,631
63,721
10,978
React 트랜드 및 에코시스템이 가장 활발
VueJS가 무서운 속도로 트랜드를 따라잡고 있음
Angular가 AngularJS 까지 포함한다면 가장 큼
진입장벽 – Entry barriers
Fight 2
Blogged from Marius Duta
일반적인 케이스에서
Angular의 학습곡선이 압도적으로 높고 Vue의 학습곡선이 가장 낮음
학습곡선
각 프레임워크를 배우기 위해서
Language Module / Components DeploymentData Flow
Others/
Advanced
일반적으로
Typescript
일반적으로
Javascript (ES6)
일반적으로
Javascript (ES6)
Controller / Directive
Pipe / Service
ContentChild / ViewChild
QueryList
Smart Component
Dumb Component
Global Component
Local Component
Directive / Filter / Plugin
RxJS / ng-redux
Redux / MobX
vuex / vue-rx
Bundling
Compilation (ngc)
Bundling
Bundling
DI pattern
ngZone
CD Strategy
Immutable
Link State Optimization
Server-side Rendering
Flow
Computed Property
Observed Property
flow-typed
각 프레임워크 컴포넌트 라이프사이클
Angular 진입전에 다른 프레임워크 경험 권장
React의 라이프 사이클과 상태관리는 상대적 어려움
AngularJS를 사용하고 있다면 VueJS 권장
성능 – Performance
Fight 3
Benchmark
Vue2 >= Angular > React
AOT Compilation 이후 성능 비교에서는 Angular가 더욱 빠를 것으로 예상
TreeShaking
TreeShaking (나무털기)
마치 나무에 달린 열매를 털듯이 사용하지 않는 모듈은
빌드 단계에서 제외시키는 최적화 기법
지원
지원 (Webpack2)
지원 (Webpack2)
AOT(Ahead Of Time)
Ahead Of Time (조기 컴파일)
JIT (Just In Time) 컴파일 방식과는 다르게
사전에 컴파일러가 중간코드로 컴파일하여 사용자 브라우저에서 컴파일 시간을 최소화 하는 최적화 기법
지원
미지원
미지원
JIT
@NgModule
Bootstraping
Javascript
CSS
HTML
@angular/platform-browser-dynamic
Parse
AST
memory
load
CD
host
viewDef
Renderer
pipeDef
ngContentDef
nodeValue
compilation-side
browser-side
AOT
@NgModuleFactory
Bootstraping
Javascript
CSS
HTML
host
viewDef
Renderer
pipeDef
ngContentDef
nodeValue
…
compilation-side
@angular/platform-browser
Parse
AST
load
CD
browser-side
Angular5 부터는 build-optimizer 옵션을 통해 추가적으로 최적화가 가능하니 참고해주세요
AOT Compiled code
function View_MukkitListComponent_0(_l) {
return __WEBPACK_IMPORTED_MODULE_1__angular_core__["_25" /* ɵvid */]
(0, [__WEBPACK_IMPORTED_MODULE_1__angular_core__["_22" /* ɵqud */]
(402653184, 1, { inputEl: 0 }),
(_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_8" /* ɵeld */](1, 0, null, null, 6, "div", [["class", "mukkit-list-
container"]], null, null, null, null, null)),
(_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_24" /* ɵted */](-1, null, ["n "])),
(_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_8" /* ɵeld */](3, 0, null, null, 0, "img", [["src",
"data:image/svg+xml;base64,…"], ["width", "180"]], null, null, null, null, null)),
(_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_24" /* ɵted */](-1, null, ["n "])),
(_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_8" /* ɵeld */](5, 0, null, null, 1, "h2", [], null, null, null, null,
null)),
(_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_24" /* ɵted */](-1, null, ["uBA39uD0B7uB9ACuC2A4uD2B8"])),
(_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_24" /* ɵted */](-1, null, ["n"])),
(_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_24" /* ɵted */](-1, null, ["nn"])),
(_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_8" /* ɵeld */](9, 0, null, null, 17, "ul", [["class", "mukkit-list"]],
null, null, null, null, null)),
(_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_24" /* ɵted */](-1, null, ["n "])),
(_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_3" /* ɵand */](16777216, null, null, 1, null, View_MukkitListComponent_1)),
__WEBPACK_IMPORTED_MODULE_1__angular_core__["_7" /* ɵdid */](
12, 802816, null, 0, __WEBPACK_IMPORTED_MODULE_2__angular_common__["c" /* NgForOf */],
[__WEBPACK_IMPORTED_MODULE_1__angular_core__["R" /* ViewContainerRef */],
__WEBPACK_IMPORTED_MODULE_1__angular_core__["N" /* TemplateRef */],
__WEBPACK_IMPORTED_MODULE_1__angular_core__["u" /* IterableDiffers */]],
{ ngForOf: [0, "ngForOf"] }, null),
(_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_24" /* ɵted */](-1, null, ["n "])),
…
AOT 성능 변화
크기 (minified)
지연시간 (initial load)
메모리 (snapshot)
442KB
585ms
38.5MB
198KB
305ms
15.3MB
-55%
-48%
-60%
JIT AOT
JIT AOT
VirtualDOM
VirtualDOM (가상 DOM)
뷰 모델에서 발생하는 변경사항을 메모리에서 관리하는 논리적 DOM에서 먼저 감지 한 후
실제 DOM의 업데이트를 최소화하여 성능을 향상시키고 UX 측면에서 발생하는 문제를 줄임
미지원
지원
지원
VirtualDOMViewModel
Element A
Element B1
Element B2
Element B
Element A
Element B1
Element B2
Element B
header
.list-item
.list-item
.container
NativeDOM
(Real DOM)
diff patch
VirtualDOM
기존의 비싼 비용의 Native DOM 처리를 javascript 상의 diff 알고리즘을 통해
저렴한 비용으로 효율적인 처리가 가능해짐
MDN에 공개된 브라우저 Layout 처리
Angular의 최적화가 적용되지 않은 케이스에서는
VueJS가 성능이 빠를 것으로 예상됩니다.
(VueJS에서 제공하는 자료와 벤치마크 데이터 참조)
구성요소 – Component
Fight 4
모듈 구성
@NgModule Main
@Component
@Injectable
@NgModule
Vue
Vue.component
Vue.directive
Vue.filter
Vue.mixin
ReactDOM.render
Component or Class
Component or Class
마이크로 프로젝트에는 VueJS 권장
서버사이드 랜더링이 필요한 프로젝트에는 React
대규모의 프로젝트에는 Angular
템플릿
{{interpolation}}
[1way data binding]
[(2way data binding)]
(1way data binding (event))
{{interpolation with pipe | pipeName}}
*ngFor *ngIf
[ngSwitch] [hidden] [innerHTML] [ngClass]
(click) (keypress) (blur) (input) (change)
…
React에서 공식적으로
제공하는 템플릿은 없습니다.
모든 것을
JSX 혹은 Javascript를 이용하여
표현합니다.
react-templates
라이브러리를 이용하면
다른 프레임워크와 유사하게
템플릿을 사용하실 수 있습니다.
v-directive-name:parameter
{{interpolation | filter}}
v-bind:id v-if v-html
v-for v-else v-else-if
v-show v-bind:class v-bind:style
v-on:event-name
v-bind:bind-target-name
{{interpolation}}
:store-name
v-model
템플릿 표현식은 Angular가 체계적이지만
VueJS가 접근장벽이 낮음
AngularJS (Angular 1)는 VueJS 템플릿과 유사
변화감지
ChangeDetection
NgZone
RxJS
Props / State
Reconciliation
React Fiber
Redux
Redux Saga
Redux Thunk
Watcher
VirtualDOM (based Snabdom)
vuex
vue-rx
Angular Change Detection & NgZone
NgZone의 몽키패칭된 이벤트로부터 변화를 감지하여 Change Detection Strategy에 맞게 변화를 전파
setTimeout, addEventListener,
requestAnimationFrame
NgZone
Monkey Patched
Tick
1
React Reconciliation & React Fiber
React Reconciliation
React FibershouldComponentUpdate()
Dealing control by element types
(aka. Pair-wise diff)
2 3
Dealing control by key
(aka. List-wise diff)
Update DOM
render() 호출 시 VirtualDOM 생성 및 Dirty model을 감지하여 React Reconciliation 과정을 진행 후 React Fiber 혹은 DOM 변경
VueJS watcher & VirtualDOM
data 프로퍼티에서 Object.defineProperty()를 통해 Watcher가 변화를 감지 변화를 수신 시
render 함수에 의해 VirtualDOM에 따른 DOM 변경
프로덕션 배포
ng-cli react-scripts build.js
오픈소스 - Open source
Fight 5
Progressive Web App(PWA)
Native Mobile
Native Desktop
모두 Electron 지원
Server Side Rendering
Angular Universal ReactDOMServer vue-server-renderer
각 프레임워크 별 오픈소스는 계속적으로 발전 중
따라서 어느것이 더 안정적인가 더 알려져있는가가
선택사항이 될 수 있음
실무자를 위한 Tips
1. MVVM 상태관리에 유념하세요
MVVM 패턴은 Model-View-ViewModel의 약자
MVVM
View
ViewModel ViewModel
Data binding
Event receiving
Update
데이터 바인딩에 사용되는 채널 (변수)는 유사한 것 끼리 최대한 합치세요
데이터 바인딩에 사용되는 데이터가 정적이라면 이를 함수로 구현하지 마세요
2. Immutable은 무적이 아닙니다.
Immutable (불변성)
Immutable
ViewModel의 사이드 이펙트를 줄이기위해 Immutable을 고려하시는 분들이 계실 겁니다.
Immutable을 제공하기 위해 우리는 큰 비용이 발생하는 DeepCopy를 사용합니다.
또한 Immutable 객체는 기존 Prop와 전혀 다른 객체이므로 무조건 랜더링이 업데이트 됩니다.
Immutable ValueUpdate
Dispatch
Reducer
Notify
shouldComponentUpdate
3. HMR이라고 아시나요?
HMR (Hot Module Replacement)
Webpack의 HMR(Hot Module Replacement)는
Angular, React, VueJS에서 코드를 수정하고 저장할 때 새로고침을 할 필요 없이
더군다나 기존 상태를 잃지 않고 코드가 바로 교체되고 새로 저장한 코드를 즉시 사용할 수 있습니다.
4. ShadowDOM 사용해보셨나요?
Shadow DOM
ShadowDOM은 각 컴포넌트에 독립적으로 스타일을 지정하고 싶을 때 사용할 수 있는
논리적으로 구분된 가상의 DOM 범위입니다.
React는 ReactShadow, Angular는 encapsulation 속성을 통해 쉽게 사용가능합니다.
VueJS는.. 다음장으로!
5. Webpack의 끔찍한 빌드속도
Webpack build optimization
빌드 과정은 때묻지 않은 초기 스캐폴딩에서는 그렇게 오래 기다리지 않아도 됩니다.
애드혹 빌드 과정일 경우 보통 5초 내외로 완료되곤 합니다.
Watch 옵션을 켜서 메모리 캐시를 활용하면 더욱 빠릅니다. (1초 안팎)
문제는 어느정도 규모가 있는 프로젝트에서는 빌드 과정이 10분 이상 넘어갑니다.
다행이도 Webpack 빌드 과정은 다음장의 최적화 방식을 따라 하여 성능을 높일 수 있습니다.
Webpack Dll Plugin
Webpack Dll Plugin은 변경이 자주 발생하지 않는 번들 파일을 미리 빌드 해놓고
일반적인 변경사항에 대한 빌드에서 dll로 지정한 빌드된 번들파일을 최종적으로 묶어서
결과적으로 빌드 속도를 상승시켜주는 역할을 합니다.
설정법이 어렵지 않으며 Webpack 공식문서에 공개되어 있으니 참고하여 주세요
new webpack.DllReferencePlugin({
context: root,
manifest: manifest
});
Question?
Show more in GitHub!
https://github.com/KennethanCeyer/gdg-devfest-seoul-frontend-frameworks
감사합니다.
GitHub: https://github.com/KennethanCeyer
Email: kennethan@nhpcw.com

Weitere ähnliche Inhalte

Was ist angesagt?

다시보는 Angular js
다시보는 Angular js다시보는 Angular js
다시보는 Angular jsJeado Ko
 
Angular2 톺아보기
Angular2 톺아보기 Angular2 톺아보기
Angular2 톺아보기 철민 배
 
React Native를 사용한
 초간단 커뮤니티 앱 제작
React Native를 사용한
 초간단 커뮤니티 앱 제작React Native를 사용한
 초간단 커뮤니티 앱 제작
React Native를 사용한
 초간단 커뮤니티 앱 제작Taegon Kim
 
ReactJS | 서버와 클라이어트에서 동시에 사용하는
ReactJS | 서버와 클라이어트에서 동시에 사용하는ReactJS | 서버와 클라이어트에서 동시에 사용하는
ReactJS | 서버와 클라이어트에서 동시에 사용하는Taegon Kim
 
[XECon+PHPFest 2014] jQuery 개발자에서 AngularJS 개발자 되기
[XECon+PHPFest 2014] jQuery 개발자에서 AngularJS 개발자 되기[XECon+PHPFest 2014] jQuery 개발자에서 AngularJS 개발자 되기
[XECon+PHPFest 2014] jQuery 개발자에서 AngularJS 개발자 되기Jeado Ko
 
Angularjs 도입 선택 가이드
Angularjs 도입 선택 가이드Angularjs 도입 선택 가이드
Angularjs 도입 선택 가이드NAVER D2
 
Angular 기본 개념 잡기
Angular 기본 개념 잡기Angular 기본 개념 잡기
Angular 기본 개념 잡기장현 한
 
Angular2를 위한 컴포넌트 분석과 개발
Angular2를 위한 컴포넌트 분석과 개발Angular2를 위한 컴포넌트 분석과 개발
Angular2를 위한 컴포넌트 분석과 개발Jin wook
 
[NEXT] Andorid에 MVC 패턴 적용하기
[NEXT] Andorid에 MVC 패턴 적용하기[NEXT] Andorid에 MVC 패턴 적용하기
[NEXT] Andorid에 MVC 패턴 적용하기YoungSu Son
 
Angular Seminar [한빛미디어 리얼타임 세미나]
Angular Seminar [한빛미디어 리얼타임 세미나]Angular Seminar [한빛미디어 리얼타임 세미나]
Angular Seminar [한빛미디어 리얼타임 세미나]Woojin Joe
 
Facebook은 React를 왜 만들었을까?
Facebook은 React를 왜 만들었을까? Facebook은 React를 왜 만들었을까?
Facebook은 React를 왜 만들었을까? Kim Hunmin
 
반복적인 작업이 싫은 안드로이드 개발자에게
반복적인 작업이 싫은 안드로이드 개발자에게반복적인 작업이 싫은 안드로이드 개발자에게
반복적인 작업이 싫은 안드로이드 개발자에게Sungju Jin
 
가볍게 살펴보는 AngularJS
가볍게 살펴보는 AngularJS가볍게 살펴보는 AngularJS
가볍게 살펴보는 AngularJSJae Sung Park
 
Data-binding AngularJS
Data-binding AngularJSData-binding AngularJS
Data-binding AngularJSEunYoung Kim
 
XECon2015 :: [2-2] 박상현 - React로 개발하는 SPA 실무 이야기
XECon2015 :: [2-2] 박상현 - React로 개발하는 SPA 실무 이야기XECon2015 :: [2-2] 박상현 - React로 개발하는 SPA 실무 이야기
XECon2015 :: [2-2] 박상현 - React로 개발하는 SPA 실무 이야기XpressEngine
 
Jurano강의 lec1. AndroidAnnotations 시작하기
Jurano강의 lec1. AndroidAnnotations 시작하기Jurano강의 lec1. AndroidAnnotations 시작하기
Jurano강의 lec1. AndroidAnnotations 시작하기Ju-ri Seo
 
[112] 실전 스위프트 프로그래밍
[112] 실전 스위프트 프로그래밍[112] 실전 스위프트 프로그래밍
[112] 실전 스위프트 프로그래밍NAVER D2
 

Was ist angesagt? (18)

다시보는 Angular js
다시보는 Angular js다시보는 Angular js
다시보는 Angular js
 
Angular2 톺아보기
Angular2 톺아보기 Angular2 톺아보기
Angular2 톺아보기
 
React Native를 사용한
 초간단 커뮤니티 앱 제작
React Native를 사용한
 초간단 커뮤니티 앱 제작React Native를 사용한
 초간단 커뮤니티 앱 제작
React Native를 사용한
 초간단 커뮤니티 앱 제작
 
ReactJS | 서버와 클라이어트에서 동시에 사용하는
ReactJS | 서버와 클라이어트에서 동시에 사용하는ReactJS | 서버와 클라이어트에서 동시에 사용하는
ReactJS | 서버와 클라이어트에서 동시에 사용하는
 
[XECon+PHPFest 2014] jQuery 개발자에서 AngularJS 개발자 되기
[XECon+PHPFest 2014] jQuery 개발자에서 AngularJS 개발자 되기[XECon+PHPFest 2014] jQuery 개발자에서 AngularJS 개발자 되기
[XECon+PHPFest 2014] jQuery 개발자에서 AngularJS 개발자 되기
 
Angularjs 도입 선택 가이드
Angularjs 도입 선택 가이드Angularjs 도입 선택 가이드
Angularjs 도입 선택 가이드
 
Angular 기본 개념 잡기
Angular 기본 개념 잡기Angular 기본 개념 잡기
Angular 기본 개념 잡기
 
Angular2를 위한 컴포넌트 분석과 개발
Angular2를 위한 컴포넌트 분석과 개발Angular2를 위한 컴포넌트 분석과 개발
Angular2를 위한 컴포넌트 분석과 개발
 
[NEXT] Andorid에 MVC 패턴 적용하기
[NEXT] Andorid에 MVC 패턴 적용하기[NEXT] Andorid에 MVC 패턴 적용하기
[NEXT] Andorid에 MVC 패턴 적용하기
 
Angular Seminar [한빛미디어 리얼타임 세미나]
Angular Seminar [한빛미디어 리얼타임 세미나]Angular Seminar [한빛미디어 리얼타임 세미나]
Angular Seminar [한빛미디어 리얼타임 세미나]
 
Facebook은 React를 왜 만들었을까?
Facebook은 React를 왜 만들었을까? Facebook은 React를 왜 만들었을까?
Facebook은 React를 왜 만들었을까?
 
Angular2 NgModule
Angular2   NgModuleAngular2   NgModule
Angular2 NgModule
 
반복적인 작업이 싫은 안드로이드 개발자에게
반복적인 작업이 싫은 안드로이드 개발자에게반복적인 작업이 싫은 안드로이드 개발자에게
반복적인 작업이 싫은 안드로이드 개발자에게
 
가볍게 살펴보는 AngularJS
가볍게 살펴보는 AngularJS가볍게 살펴보는 AngularJS
가볍게 살펴보는 AngularJS
 
Data-binding AngularJS
Data-binding AngularJSData-binding AngularJS
Data-binding AngularJS
 
XECon2015 :: [2-2] 박상현 - React로 개발하는 SPA 실무 이야기
XECon2015 :: [2-2] 박상현 - React로 개발하는 SPA 실무 이야기XECon2015 :: [2-2] 박상현 - React로 개발하는 SPA 실무 이야기
XECon2015 :: [2-2] 박상현 - React로 개발하는 SPA 실무 이야기
 
Jurano강의 lec1. AndroidAnnotations 시작하기
Jurano강의 lec1. AndroidAnnotations 시작하기Jurano강의 lec1. AndroidAnnotations 시작하기
Jurano강의 lec1. AndroidAnnotations 시작하기
 
[112] 실전 스위프트 프로그래밍
[112] 실전 스위프트 프로그래밍[112] 실전 스위프트 프로그래밍
[112] 실전 스위프트 프로그래밍
 

Andere mochten auch

엔지니어 관점에서 바라본 데이터시각화
엔지니어 관점에서 바라본 데이터시각화엔지니어 관점에서 바라본 데이터시각화
엔지니어 관점에서 바라본 데이터시각화Kenneth Ceyer
 
Dealing with Python Reactively - PyCon Korea 2017
Dealing with Python Reactively - PyCon Korea 2017Dealing with Python Reactively - PyCon Korea 2017
Dealing with Python Reactively - PyCon Korea 2017Kenneth Ceyer
 
파이썬 리액티브하게 짜기 - PyCon Korea 2017
파이썬 리액티브하게 짜기 - PyCon Korea 2017파이썬 리액티브하게 짜기 - PyCon Korea 2017
파이썬 리액티브하게 짜기 - PyCon Korea 2017Kenneth Ceyer
 
Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요Chang W. Doh
 
1711 azure-live
1711 azure-live1711 azure-live
1711 azure-live세준 김
 
개발자를 위한 웹표준 & 웹접근성이야기
개발자를 위한 웹표준 & 웹접근성이야기개발자를 위한 웹표준 & 웹접근성이야기
개발자를 위한 웹표준 & 웹접근성이야기NAVER D2
 
GDG DevFest 2017 Seoul 블록과 함께하는 파이썬 딥러닝 케라스
GDG DevFest 2017 Seoul 블록과 함께하는 파이썬 딥러닝 케라스GDG DevFest 2017 Seoul 블록과 함께하는 파이썬 딥러닝 케라스
GDG DevFest 2017 Seoul 블록과 함께하는 파이썬 딥러닝 케라스Taeyoung Kim
 
introduction to Web Assembly
introduction to Web Assembly introduction to Web Assembly
introduction to Web Assembly Chang W. Doh
 
[2014널리세미나] 시맨틱한 HTML5 마크업 구조 설계, 어떻게 할까?
[2014널리세미나] 시맨틱한 HTML5 마크업 구조 설계, 어떻게 할까?[2014널리세미나] 시맨틱한 HTML5 마크업 구조 설계, 어떻게 할까?
[2014널리세미나] 시맨틱한 HTML5 마크업 구조 설계, 어떻게 할까?Nts Nuli
 
순환신경망(Recurrent neural networks) 개요
순환신경망(Recurrent neural networks) 개요순환신경망(Recurrent neural networks) 개요
순환신경망(Recurrent neural networks) 개요Byoung-Hee Kim
 
안드로이드 개발에 유용한 도구들
안드로이드 개발에 유용한 도구들안드로이드 개발에 유용한 도구들
안드로이드 개발에 유용한 도구들Sewon Ann
 
인공지능 방법론 - 딥러닝 이해하기
인공지능 방법론 - 딥러닝 이해하기인공지능 방법론 - 딥러닝 이해하기
인공지능 방법론 - 딥러닝 이해하기Byoung-Hee Kim
 
프로그레시브 웹앱이란? - Progressive Web Apps
프로그레시브 웹앱이란? - Progressive Web Apps프로그레시브 웹앱이란? - Progressive Web Apps
프로그레시브 웹앱이란? - Progressive Web AppsGihyo Joshua Jang
 
4. 대용량 아키텍쳐 설계 패턴
4. 대용량 아키텍쳐 설계 패턴4. 대용량 아키텍쳐 설계 패턴
4. 대용량 아키텍쳐 설계 패턴Terry Cho
 
Robot Framework Introduction
Robot Framework IntroductionRobot Framework Introduction
Robot Framework IntroductionPekka Klärck
 
초보 개발자를 위한 웹 프론트엔드 개발 101
초보 개발자를 위한 웹 프론트엔드 개발 101초보 개발자를 위한 웹 프론트엔드 개발 101
초보 개발자를 위한 웹 프론트엔드 개발 101Chang W. Doh
 
Tensorflow for Deep Learning(SK Planet)
Tensorflow for Deep Learning(SK Planet)Tensorflow for Deep Learning(SK Planet)
Tensorflow for Deep Learning(SK Planet)Tae Young Lee
 
나의 이직 이야기
나의 이직 이야기나의 이직 이야기
나의 이직 이야기종립 이
 
20141223 머하웃(mahout) 협업필터링_추천시스템구현
20141223 머하웃(mahout) 협업필터링_추천시스템구현20141223 머하웃(mahout) 협업필터링_추천시스템구현
20141223 머하웃(mahout) 협업필터링_추천시스템구현Tae Young Lee
 
[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...
[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...
[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...탑크리에듀(구로디지털단지역3번출구 2분거리)
 

Andere mochten auch (20)

엔지니어 관점에서 바라본 데이터시각화
엔지니어 관점에서 바라본 데이터시각화엔지니어 관점에서 바라본 데이터시각화
엔지니어 관점에서 바라본 데이터시각화
 
Dealing with Python Reactively - PyCon Korea 2017
Dealing with Python Reactively - PyCon Korea 2017Dealing with Python Reactively - PyCon Korea 2017
Dealing with Python Reactively - PyCon Korea 2017
 
파이썬 리액티브하게 짜기 - PyCon Korea 2017
파이썬 리액티브하게 짜기 - PyCon Korea 2017파이썬 리액티브하게 짜기 - PyCon Korea 2017
파이썬 리액티브하게 짜기 - PyCon Korea 2017
 
Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요Kotlin, 어떻게 동작하나요
Kotlin, 어떻게 동작하나요
 
1711 azure-live
1711 azure-live1711 azure-live
1711 azure-live
 
개발자를 위한 웹표준 & 웹접근성이야기
개발자를 위한 웹표준 & 웹접근성이야기개발자를 위한 웹표준 & 웹접근성이야기
개발자를 위한 웹표준 & 웹접근성이야기
 
GDG DevFest 2017 Seoul 블록과 함께하는 파이썬 딥러닝 케라스
GDG DevFest 2017 Seoul 블록과 함께하는 파이썬 딥러닝 케라스GDG DevFest 2017 Seoul 블록과 함께하는 파이썬 딥러닝 케라스
GDG DevFest 2017 Seoul 블록과 함께하는 파이썬 딥러닝 케라스
 
introduction to Web Assembly
introduction to Web Assembly introduction to Web Assembly
introduction to Web Assembly
 
[2014널리세미나] 시맨틱한 HTML5 마크업 구조 설계, 어떻게 할까?
[2014널리세미나] 시맨틱한 HTML5 마크업 구조 설계, 어떻게 할까?[2014널리세미나] 시맨틱한 HTML5 마크업 구조 설계, 어떻게 할까?
[2014널리세미나] 시맨틱한 HTML5 마크업 구조 설계, 어떻게 할까?
 
순환신경망(Recurrent neural networks) 개요
순환신경망(Recurrent neural networks) 개요순환신경망(Recurrent neural networks) 개요
순환신경망(Recurrent neural networks) 개요
 
안드로이드 개발에 유용한 도구들
안드로이드 개발에 유용한 도구들안드로이드 개발에 유용한 도구들
안드로이드 개발에 유용한 도구들
 
인공지능 방법론 - 딥러닝 이해하기
인공지능 방법론 - 딥러닝 이해하기인공지능 방법론 - 딥러닝 이해하기
인공지능 방법론 - 딥러닝 이해하기
 
프로그레시브 웹앱이란? - Progressive Web Apps
프로그레시브 웹앱이란? - Progressive Web Apps프로그레시브 웹앱이란? - Progressive Web Apps
프로그레시브 웹앱이란? - Progressive Web Apps
 
4. 대용량 아키텍쳐 설계 패턴
4. 대용량 아키텍쳐 설계 패턴4. 대용량 아키텍쳐 설계 패턴
4. 대용량 아키텍쳐 설계 패턴
 
Robot Framework Introduction
Robot Framework IntroductionRobot Framework Introduction
Robot Framework Introduction
 
초보 개발자를 위한 웹 프론트엔드 개발 101
초보 개발자를 위한 웹 프론트엔드 개발 101초보 개발자를 위한 웹 프론트엔드 개발 101
초보 개발자를 위한 웹 프론트엔드 개발 101
 
Tensorflow for Deep Learning(SK Planet)
Tensorflow for Deep Learning(SK Planet)Tensorflow for Deep Learning(SK Planet)
Tensorflow for Deep Learning(SK Planet)
 
나의 이직 이야기
나의 이직 이야기나의 이직 이야기
나의 이직 이야기
 
20141223 머하웃(mahout) 협업필터링_추천시스템구현
20141223 머하웃(mahout) 협업필터링_추천시스템구현20141223 머하웃(mahout) 협업필터링_추천시스템구현
20141223 머하웃(mahout) 협업필터링_추천시스템구현
 
[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...
[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...
[자마린교육/자마린실습]자바,스프링프레임워크(스프링부트) RESTful 웹서비스 구현 실습,자마린에서 스프링 웹서비스를 호출하고 응답 JS...
 

Ähnlich wie GDG DevFest 2017 Seoul 프론트엔드 모던 프레임워크 낱낱히 파헤치기

Deep dive into Modern frameworks - HTML5 Forum 2018
Deep dive into Modern frameworks - HTML5 Forum 2018Deep dive into Modern frameworks - HTML5 Forum 2018
Deep dive into Modern frameworks - HTML5 Forum 2018Kenneth Ceyer
 
[115] clean fe development_윤지수
[115] clean fe development_윤지수[115] clean fe development_윤지수
[115] clean fe development_윤지수NAVER D2
 
Clean Front-End Development
Clean Front-End DevelopmentClean Front-End Development
Clean Front-End Development지수 윤
 
컴포넌트 관점에서 개발하기
컴포넌트 관점에서 개발하기컴포넌트 관점에서 개발하기
컴포넌트 관점에서 개발하기우영 주
 
04.실행환경 실습교재(화면처리)
04.실행환경 실습교재(화면처리)04.실행환경 실습교재(화면처리)
04.실행환경 실습교재(화면처리)Hankyo
 
React Hooks 마법. 그리고 깔끔한 사용기
React Hooks 마법. 그리고 깔끔한 사용기React Hooks 마법. 그리고 깔끔한 사용기
React Hooks 마법. 그리고 깔끔한 사용기NAVER SHOPPING
 
[D2 오픈세미나]5.robolectric 안드로이드 테스팅
[D2 오픈세미나]5.robolectric 안드로이드 테스팅[D2 오픈세미나]5.robolectric 안드로이드 테스팅
[D2 오픈세미나]5.robolectric 안드로이드 테스팅NAVER D2
 
React 실무활용 이야기
React 실무활용 이야기React 실무활용 이야기
React 실무활용 이야기철민 배
 
[114]angularvs react 김훈민손찬욱
[114]angularvs react 김훈민손찬욱[114]angularvs react 김훈민손찬욱
[114]angularvs react 김훈민손찬욱NAVER D2
 
Meteor React Tutorial 따라하기
Meteor React Tutorial 따라하기Meteor React Tutorial 따라하기
Meteor React Tutorial 따라하기Jiam Seo
 
Android 기초강좌 애플리캐이션 구조
Android 기초강좌 애플리캐이션 구조Android 기초강좌 애플리캐이션 구조
Android 기초강좌 애플리캐이션 구조Sangon Lee
 
Naver api for android
Naver api for androidNaver api for android
Naver api for androidSangon Lee
 
Webframeworks angular js 세미나
Webframeworks angular js 세미나Webframeworks angular js 세미나
Webframeworks angular js 세미나WebFrameworks
 
Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018KyungHo Jung
 

Ähnlich wie GDG DevFest 2017 Seoul 프론트엔드 모던 프레임워크 낱낱히 파헤치기 (20)

Deep dive into Modern frameworks - HTML5 Forum 2018
Deep dive into Modern frameworks - HTML5 Forum 2018Deep dive into Modern frameworks - HTML5 Forum 2018
Deep dive into Modern frameworks - HTML5 Forum 2018
 
[115] clean fe development_윤지수
[115] clean fe development_윤지수[115] clean fe development_윤지수
[115] clean fe development_윤지수
 
Clean Front-End Development
Clean Front-End DevelopmentClean Front-End Development
Clean Front-End Development
 
컴포넌트 관점에서 개발하기
컴포넌트 관점에서 개발하기컴포넌트 관점에서 개발하기
컴포넌트 관점에서 개발하기
 
04.실행환경 실습교재(화면처리)
04.실행환경 실습교재(화면처리)04.실행환경 실습교재(화면처리)
04.실행환경 실습교재(화면처리)
 
Redux
ReduxRedux
Redux
 
React Hooks 마법. 그리고 깔끔한 사용기
React Hooks 마법. 그리고 깔끔한 사용기React Hooks 마법. 그리고 깔끔한 사용기
React Hooks 마법. 그리고 깔끔한 사용기
 
[D2 오픈세미나]5.robolectric 안드로이드 테스팅
[D2 오픈세미나]5.robolectric 안드로이드 테스팅[D2 오픈세미나]5.robolectric 안드로이드 테스팅
[D2 오픈세미나]5.robolectric 안드로이드 테스팅
 
[Codelab 2017] ReactJS 기초
[Codelab 2017] ReactJS 기초[Codelab 2017] ReactJS 기초
[Codelab 2017] ReactJS 기초
 
React 실무활용 이야기
React 실무활용 이야기React 실무활용 이야기
React 실무활용 이야기
 
Meteor2015 codelab
Meteor2015 codelab Meteor2015 codelab
Meteor2015 codelab
 
[114]angularvs react 김훈민손찬욱
[114]angularvs react 김훈민손찬욱[114]angularvs react 김훈민손찬욱
[114]angularvs react 김훈민손찬욱
 
Coded ui가이드
Coded ui가이드Coded ui가이드
Coded ui가이드
 
Meteor React Tutorial 따라하기
Meteor React Tutorial 따라하기Meteor React Tutorial 따라하기
Meteor React Tutorial 따라하기
 
Android 기초강좌 애플리캐이션 구조
Android 기초강좌 애플리캐이션 구조Android 기초강좌 애플리캐이션 구조
Android 기초강좌 애플리캐이션 구조
 
Naver api for android
Naver api for androidNaver api for android
Naver api for android
 
MVP 패턴 소개
MVP 패턴 소개MVP 패턴 소개
MVP 패턴 소개
 
react-ko.pdf
react-ko.pdfreact-ko.pdf
react-ko.pdf
 
Webframeworks angular js 세미나
Webframeworks angular js 세미나Webframeworks angular js 세미나
Webframeworks angular js 세미나
 
Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018Droid knights android test @Droid Knights 2018
Droid knights android test @Droid Knights 2018
 

Mehr von Kenneth Ceyer

이미지 프로세싱 in Python Open Source - PYCON KOREA 2020
이미지 프로세싱 in Python Open Source - PYCON KOREA 2020이미지 프로세싱 in Python Open Source - PYCON KOREA 2020
이미지 프로세싱 in Python Open Source - PYCON KOREA 2020Kenneth Ceyer
 
정적 컨텐츠 제너레이터 GatsbyJS에 대해서 알아봅시다.
정적 컨텐츠 제너레이터 GatsbyJS에 대해서 알아봅시다.정적 컨텐츠 제너레이터 GatsbyJS에 대해서 알아봅시다.
정적 컨텐츠 제너레이터 GatsbyJS에 대해서 알아봅시다.Kenneth Ceyer
 
LP(linear programming) Algorithm
LP(linear programming) AlgorithmLP(linear programming) Algorithm
LP(linear programming) AlgorithmKenneth Ceyer
 
AI 연구자를 위한 클린코드 - GDG DevFest Seoul 2019
AI 연구자를 위한 클린코드 - GDG DevFest Seoul 2019AI 연구자를 위한 클린코드 - GDG DevFest Seoul 2019
AI 연구자를 위한 클린코드 - GDG DevFest Seoul 2019Kenneth Ceyer
 
하둡 에코시스템 위에서 환상적인 테이크오프 - DSTS 2019
하둡 에코시스템 위에서 환상적인 테이크오프 - DSTS 2019 하둡 에코시스템 위에서 환상적인 테이크오프 - DSTS 2019
하둡 에코시스템 위에서 환상적인 테이크오프 - DSTS 2019 Kenneth Ceyer
 
AllReduce for distributed learning I/O Extended Seoul
AllReduce for distributed learning I/O Extended SeoulAllReduce for distributed learning I/O Extended Seoul
AllReduce for distributed learning I/O Extended SeoulKenneth Ceyer
 
gRPC와 goroutine 톺아보기 - GDG Golang Korea 2019
gRPC와 goroutine 톺아보기 - GDG Golang Korea 2019gRPC와 goroutine 톺아보기 - GDG Golang Korea 2019
gRPC와 goroutine 톺아보기 - GDG Golang Korea 2019Kenneth Ceyer
 
Test and refactoring
Test and refactoringTest and refactoring
Test and refactoringKenneth Ceyer
 
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018Kenneth Ceyer
 

Mehr von Kenneth Ceyer (10)

이미지 프로세싱 in Python Open Source - PYCON KOREA 2020
이미지 프로세싱 in Python Open Source - PYCON KOREA 2020이미지 프로세싱 in Python Open Source - PYCON KOREA 2020
이미지 프로세싱 in Python Open Source - PYCON KOREA 2020
 
정적 컨텐츠 제너레이터 GatsbyJS에 대해서 알아봅시다.
정적 컨텐츠 제너레이터 GatsbyJS에 대해서 알아봅시다.정적 컨텐츠 제너레이터 GatsbyJS에 대해서 알아봅시다.
정적 컨텐츠 제너레이터 GatsbyJS에 대해서 알아봅시다.
 
LP(linear programming) Algorithm
LP(linear programming) AlgorithmLP(linear programming) Algorithm
LP(linear programming) Algorithm
 
AI 연구자를 위한 클린코드 - GDG DevFest Seoul 2019
AI 연구자를 위한 클린코드 - GDG DevFest Seoul 2019AI 연구자를 위한 클린코드 - GDG DevFest Seoul 2019
AI 연구자를 위한 클린코드 - GDG DevFest Seoul 2019
 
하둡 에코시스템 위에서 환상적인 테이크오프 - DSTS 2019
하둡 에코시스템 위에서 환상적인 테이크오프 - DSTS 2019 하둡 에코시스템 위에서 환상적인 테이크오프 - DSTS 2019
하둡 에코시스템 위에서 환상적인 테이크오프 - DSTS 2019
 
AllReduce for distributed learning I/O Extended Seoul
AllReduce for distributed learning I/O Extended SeoulAllReduce for distributed learning I/O Extended Seoul
AllReduce for distributed learning I/O Extended Seoul
 
gRPC와 goroutine 톺아보기 - GDG Golang Korea 2019
gRPC와 goroutine 톺아보기 - GDG Golang Korea 2019gRPC와 goroutine 톺아보기 - GDG Golang Korea 2019
gRPC와 goroutine 톺아보기 - GDG Golang Korea 2019
 
How to use vim
How to use vimHow to use vim
How to use vim
 
Test and refactoring
Test and refactoringTest and refactoring
Test and refactoring
 
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
 

GDG DevFest 2017 Seoul 프론트엔드 모던 프레임워크 낱낱히 파헤치기

  • 1. 한성민 IGAWorks SungMin Han 프론트엔드 모던 프레임워크 낱낱히 파헤치기
  • 2. 오늘날의 프론트엔드 모던 프레임워크 톺아보기 실무자를 위한 Tips 이번 세션에서는
  • 4. 웹 프론트 기술의 흐름 jQuery Vanila Javascript AngularJS React VueJS Angular 2006 2013 2009 2014 2016
  • 5. 조금 더 넓게.. jQuery Vanila Javascript AngularJS React VueJS Angular 2006 2013 2009 2014 2016 XMLHTTPRequest(XHR) 2002 ES2015 2015 Node.js 2013 Redux 2015 RxJS 2012 Typescript 2012 Ember.js 2011 CoffeScript 2009 AMD 2010 CommonJS (CJS) 2009 ES2016 2016 WebAssembly 2015
  • 7.
  • 8. 동적 렌더링 모듈링 / 번들링 타이핑 현재 프론트진형의 중요 키워드 테스트 자동화
  • 9. 동적 렌더링 모듈링 / 번들링 타이핑 2017년 프론트 진형 중요 키워드 테스트 자동화 Two-way binding, SPA, Virtual DOM, Change Detection … CommonJS, AMD, UMD, Uglify, Grunt, Webpack … Typescript, Proptypes, Flow, Props … UnitTest, e2e Test, HeadLess Browser …
  • 11. Angular 완전하고 빠른 프레임워크 React 활발하고 오픈 되어 있으며 합리적인 프레임워크 VueJS 가볍고 친숙하며 장점만을 합쳐놓은 프레임워크 그러던 중 나타난 프레임워크들 그리고 프레임워크는 그 모든 것을 쉽게 만들어주었나니..
  • 12. Angular 완전하고 빠른 프레임워크 React 활발하고 오픈 되어 있으며 합리적인 프레임워크 VueJS 가볍고 친숙하며 장점만을 합쳐놓은 프레임워크 그러던 중 나타난 프레임워크들 그리고 프레임워크는 그 모든 것을 쉽게 만들어주었나니..
  • 13. Angular 모든 기능이 빌트인되어 있으며 성능이 훌륭하지만, 진입장벽이 가장 높음 React 에코시스템이 활발하게 움직이고 또 그것을 장려하지만 의존과 버전에 민감하고 라이브러리 자체의 기능만으로는 부족함 VueJS 프레임워크 자체가 가볍고 진입장벽이 낮으며 각 프레임워크의 장점을 흡수 다만 크기가 커질 수록 재활용성은 떨어지며, 테스트하기 어렵고 느림 이를 풀어 설명하자면
  • 15. Angular 릴리즈 개발자/개발사 버전 언어 모델 컴파일 2016년 6월 공식출시 Google Inc 2017년 11월 기준 v5.0.1 stable Typescript, Dart, Javascript MVVM / Change Detection / NgZone JIT (built-in core) / AOT (ng, ngc) / TreeShaking with ng cli
  • 16. React 릴리즈 개발자/개발사 버전 언어 모델 컴파일 2013년 3월 공식출시 Facebook, Instagram 2017년 11월 기준 V16.1.1 stable Javascript, JSX View Engine / Virtual DOM / PropTypes JIT (built-in core) / TreeShaking with Webpack2
  • 17. VueJS 릴리즈 개발자/개발사 버전 언어 모델 컴파일 2014년 2월 공식출시 Evan you 2017년 11월 기준 V2.5.3 stable Javascript, JSX(호환) MVVM / VirtualDOM / core와 companion 분리 / Vuex JIT (built-in core) / TreeShaking with Webpack2
  • 18. Angular code import { Component, ViewChild, ElementRef } from '@angular/core'; const DEFAULT_INITIALIZE_FOOD_LIST: string[] = [ '치킨', '탕수육', '닭도리탕' ]; @Component({ selector: 'mukkit-list', templateUrl: './mukkit_list.html', styleUrls: [ './mukkit_list.css' ] }) export class MukkitListComponent { public foodList: string[] = [...DEFAULT_INITIALIZE_FOOD_LIST]; public newFood: string; @ViewChild('input') inputEl: ElementRef; ngAfterViewInit() { this.focusFood(); } focusFood(): void { this.inputEl.nativeElement.focus(); } enterFood($event: KeyboardEvent): void { if ($event.keyCode === 13) { this.addFood(); } } addFood(): void { if (this.foodList.indexOf(this.newFood) === -1) { this.foodList.push(this.newFood); this.newFood = ''; } else { alert('해당 음식은 이미 있습니다.'); } } } mukkit_list.component.ts
  • 19. Angular code mukkit_list.html <div class="mukkit-list-container"> <img width="180" src="data:image…"> <h2>먹킷리스트</h2> </div> <ul class="mukkit-list"> <li *ngFor="let food of foodList"> <span>{{food}}</span> </li> <li> <input type="text" #input [(ngModel)]="newFood" (keypress)="enterFood($event);"> <button (click)="addFood();">먹킷리스트 추가</button> </li> </ul>
  • 20. Angular code mukkit_list.html <div class="mukkit-list-container"> <img width="180" src="data:image…"> <h2>먹킷리스트</h2> </div> <ul class="mukkit-list"> <li *ngFor="let food of foodList"> <span>{{food}}</span> </li> <li> <input type="text" #input [(ngModel)]="newFood" (keypress)="enterFood($event);"> <button (click)="addFood();">먹킷리스트 추가</button> </li> </ul> export class MukkitListComponent { public foodList: string[] = [...DEFAULT_INITIALIZE_FOOD_LIST]; public newFood: string; @ViewChild('input') inputEl: ElementRef; … enterFood($event: KeyboardEvent): void { … } addFood(): void { … } } mukkit_list.component.ts 1way binding (viewmodel -> view) 2way binding (videmodel <-> view) view query (it is not bind) 1way binding (view <- viewmodel)
  • 21. MukkitList.js React code import React, { Component } from 'react'; import logo from './logo.svg'; import './MukkitList.css'; const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ]; class MukkitList extends Component { constructor(props) { super(props); this.state = { foodList: [...DEFAULT_INITIALIZE_FOOD_LIST], newFood: '' }; } changeFood(event) { this.setState({'newFood': event.target.value}); } enterFood(event) { if (event.key === 'Enter') this.addFood(); } addFood(event) { if (this.state.foodList.indexOf(this.state.newFood) === -1) { this.setState({ foodList: [...this.state.foodList, this.state.newFood], newFood: '' }); } else { alert('해당 음식은 이미 있습니다.'); } } render() { return ( <div className="container"> <header className="mukkit-list-header"> <img src={logo} className="mukkit-list-logo" alt="logo" /> <h2 className="mukkit-list-title">먹킷리스트</h2> </header> <ul className="mukkit-list"> {this.state.foodList.map((food, index) => <li key={index}><span>{food}</span></li>)} <li> <input type="text“ value={this.state.newFood} onChange={this.changeFood.bind(this)} onKeyPress={this.enterFood.bind(this)} /> <button onClick={this.addFood.bind(this)}>먹킷리스트 추가</button> </li> </ul > </div > ); } } export default MukkitList;
  • 22. MukkitList.js import React, { Component } from 'react'; import logo from './logo.svg'; import './MukkitList.css'; const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ]; class MukkitList extends Component { constructor(props) { super(props); this.state = { foodList: [...DEFAULT_INITIALIZE_FOOD_LIST], newFood: '' }; } changeFood(event) { this.setState({'newFood': event.target.value}); } enterFood(event) { if (event.key === 'Enter') this.addFood(); } addFood(event) { if (this.state.foodList.indexOf(this.state.newFood) === -1) { this.setState({ foodList: [...this.state.foodList, this.state.newFood], newFood: '' }); } else { alert('해당 음식은 이미 있습니다.'); } } render() { return ( <div className="container"> <header className="mukkit-list-header"> <img src={logo} className="mukkit-list-logo" alt="logo" /> <h2 className="mukkit-list-title">먹킷리스트</h2> </header> <ul className="mukkit-list"> {this.state.foodList.map((food, index) => <li key={index}><span>{food}</span></li>)} <li> <input type="text“ value={this.state.newFood} onChange={this.changeFood.bind(this)} onKeyPress={this.enterFood.bind(this)} /> <button onClick={this.addFood.bind(this)}>먹킷리스트 추가</button> </li> </ul > </div > ); } } export default MukkitList; 1way binding (videmodel -> view) React code
  • 23. MukkitList.js import React, { Component } from 'react'; import logo from './logo.svg'; import './MukkitList.css'; const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ]; class MukkitList extends Component { constructor(props) { super(props); this.state = { foodList: [...DEFAULT_INITIALIZE_FOOD_LIST], newFood: '' }; } changeFood(event) { this.setState({'newFood': event.target.value}); } enterFood(event) { if (event.key === 'Enter') this.addFood(); } addFood(event) { if (this.state.foodList.indexOf(this.state.newFood) === -1) { this.setState({ foodList: [...this.state.foodList, this.state.newFood], newFood: '' }); } else { alert('해당 음식은 이미 있습니다.'); } } render() { return ( <div className="container"> <header className="mukkit-list-header"> <img src={logo} className="mukkit-list-logo" alt="logo" /> <h2 className="mukkit-list-title">먹킷리스트</h2> </header> <ul className="mukkit-list"> {this.state.foodList.map((food, index) => <li key={index}><span>{food}</span></li>)} <li> <input type="text“ value={this.state.newFood} onChange={this.changeFood.bind(this)} onKeyPress={this.enterFood.bind(this)} /> <button onClick={this.addFood.bind(this)}>먹킷리스트 추가</button> </li> </ul > </div > ); } } export default MukkitList; render DOM React code
  • 24. MukkitList.js import React, { Component } from 'react'; import logo from './logo.svg'; import './MukkitList.css'; const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ]; class MukkitList extends Component { constructor(props) { super(props); this.state = { foodList: [...DEFAULT_INITIALIZE_FOOD_LIST], newFood: '' }; } changeFood(event) { this.setState({'newFood': event.target.value}); } enterFood(event) { if (event.key === 'Enter') this.addFood(); } addFood(event) { if (this.state.foodList.indexOf(this.state.newFood) === -1) { this.setState({ foodList: [...this.state.foodList, this.state.newFood], newFood: '' }); } else { alert('해당 음식은 이미 있습니다.'); } } render() { return ( <div className="container"> <header className="mukkit-list-header"> <img src={logo} className="mukkit-list-logo" alt="logo" /> <h2 className="mukkit-list-title">먹킷리스트</h2> </header> <ul className="mukkit-list"> {this.state.foodList.map((food, index) => <li key={index}><span>{food}</span></li>)} <li> <input type="text“ value={this.state.newFood} onChange={this.changeFood.bind(this)} onKeyPress={this.enterFood.bind(this)} /> <button onClick={this.addFood.bind(this)}>먹킷리스트 추가</button> </li> </ul > </div > ); } } export default MukkitList; 1way binding (viewmodel -> view) React code
  • 25. MukkitList.js import React, { Component } from 'react'; import logo from './logo.svg'; import './MukkitList.css'; const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ]; class MukkitList extends Component { constructor(props) { super(props); this.state = { foodList: [...DEFAULT_INITIALIZE_FOOD_LIST], newFood: '' }; } changeFood(event) { this.setState({'newFood': event.target.value}); } enterFood(event) { if (event.key === 'Enter') this.addFood(); } addFood(event) { if (this.state.foodList.indexOf(this.state.newFood) === -1) { this.setState({ foodList: [...this.state.foodList, this.state.newFood], newFood: '' }); } else { alert('해당 음식은 이미 있습니다.'); } } render() { return ( <div className="container"> <header className="mukkit-list-header"> <img src={logo} className="mukkit-list-logo" alt="logo" /> <h2 className="mukkit-list-title">먹킷리스트</h2> </header> <ul className="mukkit-list"> {this.state.foodList.map((food, index) => <li key={index}><span>{food}</span></li>)} <li> <input type="text“ value={this.state.newFood} onChange={this.changeFood.bind(this)} onKeyPress={this.enterFood.bind(this)} /> <button onClick={this.addFood.bind(this)}>먹킷리스트 추가</button> </li> </ul > </div > ); } } export default MukkitList; 1way binding (view -> viewmodel) React code
  • 26. MukkitList.js import React, { Component } from 'react'; import logo from './logo.svg'; import './MukkitList.css'; const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ]; class MukkitList extends Component { constructor(props) { super(props); this.state = { foodList: [...DEFAULT_INITIALIZE_FOOD_LIST], newFood: '' }; } changeFood(event) { this.setState({'newFood': event.target.value}); } enterFood(event) { if (event.key === 'Enter') this.addFood(); } addFood(event) { if (this.state.foodList.indexOf(this.state.newFood) === -1) { this.setState({ foodList: [...this.state.foodList, this.state.newFood], newFood: '' }); } else { alert('해당 음식은 이미 있습니다.'); } } render() { return ( <div className="container"> <header className="mukkit-list-header"> <img src={logo} className="mukkit-list-logo" alt="logo" /> <h2 className="mukkit-list-title">먹킷리스트</h2> </header> <ul className="mukkit-list"> {this.state.foodList.map((food, index) => <li key={index}><span>{food}</span></li>)} <li> <input type="text“ value={this.state.newFood} onChange={this.changeFood.bind(this)} onKeyPress={this.enterFood.bind(this)} /> <button onClick={this.addFood.bind(this)}>먹킷리스트 추가</button> </li> </ul > </div > ); } } export default MukkitList; state changed React code
  • 27. MukkitList.vue VueJS code <template> <ul class="mukkit-list"> <li v-for="food in foodList"> <span>{{food}}</span> </li> <li> <input type="text" ref="input" v-model="newFood" v-on:keypress.enter="addFood"> <button v-on:click="addFood">먹킷리스트 추가</button> </li> </ul> </template> <script> const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ] export default { name: 'MukkitList', data () { return { foodList: [...DEFAULT_INITIALIZE_FOOD_LIST], newFood: '' } }, mounted () { this.focusFood() }, methods: { focusFood () { this.$refs.input.focus() }, addFood () { if (this.foodList.indexOf(this.newFood) === -1) { this.foodList.push(this.newFood) this.newFood = '' this.focusFood() } else { alert('해당 음식은 이미 있습니다.') } } } } </script>
  • 28. MukkitList.vue <template> <ul class="mukkit-list"> <li v-for="food in foodList"> <span>{{food}}</span> </li> <li> <input type="text" ref="input" v-model="newFood" v-on:keypress.enter="addFood"> <button v-on:click="addFood">먹킷리스트 추가</button> </li> </ul> </template> <script> const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ] export default { name: 'MukkitList', data () { return { foodList: [...DEFAULT_INITIALIZE_FOOD_LIST], newFood: '' } }, mounted () { this.focusFood() }, methods: { focusFood () { this.$refs.input.focus() }, addFood () { if (this.foodList.indexOf(this.newFood) === -1) { this.foodList.push(this.newFood) this.newFood = '' this.focusFood() } else { alert('해당 음식은 이미 있습니다.') } } } } </script> VueJS code 2way binding (videmodel <-> view)
  • 29. MukkitList.vue <template> <ul class="mukkit-list"> <li v-for="food in foodList"> <span>{{food}}</span> </li> <li> <input type="text" ref="input" v-model="newFood" v-on:keypress.enter="addFood"> <button v-on:click="addFood">먹킷리스트 추가</button> </li> </ul> </template> <script> const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ] export default { name: 'MukkitList', data () { return { foodList: [...DEFAULT_INITIALIZE_FOOD_LIST], newFood: '' } }, mounted () { this.focusFood() }, methods: { focusFood () { this.$refs.input.focus() }, addFood () { if (this.foodList.indexOf(this.newFood) === -1) { this.foodList.push(this.newFood) this.newFood = '' this.focusFood() } else { alert('해당 음식은 이미 있습니다.') } } } } </script> VueJS code 1way binding (viewmodel -> view)
  • 30. MukkitList.vue <template> <ul class="mukkit-list"> <li v-for="food in foodList"> <span>{{food}}</span> </li> <li> <input type="text" ref="input" v-model="newFood" v-on:keypress.enter="addFood"> <button v-on:click="addFood">먹킷리스트 추가</button> </li> </ul> </template> <script> const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ] export default { name: 'MukkitList', data () { return { foodList: [...DEFAULT_INITIALIZE_FOOD_LIST], newFood: '' } }, mounted () { this.focusFood() }, methods: { focusFood () { this.$refs.input.focus() }, addFood () { if (this.foodList.indexOf(this.newFood) === -1) { this.foodList.push(this.newFood) this.newFood = '' this.focusFood() } else { alert('해당 음식은 이미 있습니다.') } } } } </script> VueJS code 1way binding (view -> viewmodel)
  • 31. MukkitList.vue <template> <ul class="mukkit-list"> <li v-for="food in foodList"> <span>{{food}}</span> </li> <li> <input type="text" ref="input" v-model="newFood" v-on:keypress.enter="addFood"> <button v-on:click="addFood">먹킷리스트 추가</button> </li> </ul> </template> <script> const DEFAULT_INITIALIZE_FOOD_LIST = [ '치킨', '탕수육', '닭도리탕' ] export default { name: 'MukkitList', data () { return { foodList: [...DEFAULT_INITIALIZE_FOOD_LIST], newFood: '' } }, mounted () { this.focusFood() }, methods: { focusFood () { this.$refs.input.focus() }, addFood () { if (this.foodList.indexOf(this.newFood) === -1) { this.foodList.push(this.newFood) this.newFood = '' this.focusFood() } else { alert('해당 음식은 이미 있습니다.') } } } } </script> VueJS code view query (it is not bind)
  • 33. Google Trend 2017. 11 29,994 star 81,002 star 73,628 star GitHub Stars
  • 35. Stack Overflow tagged questions 81,631 63,721 10,978
  • 36.
  • 37. React 트랜드 및 에코시스템이 가장 활발 VueJS가 무서운 속도로 트랜드를 따라잡고 있음 Angular가 AngularJS 까지 포함한다면 가장 큼
  • 38. 진입장벽 – Entry barriers Fight 2
  • 39. Blogged from Marius Duta 일반적인 케이스에서 Angular의 학습곡선이 압도적으로 높고 Vue의 학습곡선이 가장 낮음 학습곡선
  • 40. 각 프레임워크를 배우기 위해서 Language Module / Components DeploymentData Flow Others/ Advanced 일반적으로 Typescript 일반적으로 Javascript (ES6) 일반적으로 Javascript (ES6) Controller / Directive Pipe / Service ContentChild / ViewChild QueryList Smart Component Dumb Component Global Component Local Component Directive / Filter / Plugin RxJS / ng-redux Redux / MobX vuex / vue-rx Bundling Compilation (ngc) Bundling Bundling DI pattern ngZone CD Strategy Immutable Link State Optimization Server-side Rendering Flow Computed Property Observed Property flow-typed
  • 41. 각 프레임워크 컴포넌트 라이프사이클
  • 42. Angular 진입전에 다른 프레임워크 경험 권장 React의 라이프 사이클과 상태관리는 상대적 어려움 AngularJS를 사용하고 있다면 VueJS 권장
  • 44. Benchmark Vue2 >= Angular > React AOT Compilation 이후 성능 비교에서는 Angular가 더욱 빠를 것으로 예상
  • 45. TreeShaking TreeShaking (나무털기) 마치 나무에 달린 열매를 털듯이 사용하지 않는 모듈은 빌드 단계에서 제외시키는 최적화 기법 지원 지원 (Webpack2) 지원 (Webpack2)
  • 46. AOT(Ahead Of Time) Ahead Of Time (조기 컴파일) JIT (Just In Time) 컴파일 방식과는 다르게 사전에 컴파일러가 중간코드로 컴파일하여 사용자 브라우저에서 컴파일 시간을 최소화 하는 최적화 기법 지원 미지원 미지원 JIT @NgModule Bootstraping Javascript CSS HTML @angular/platform-browser-dynamic Parse AST memory load CD host viewDef Renderer pipeDef ngContentDef nodeValue compilation-side browser-side AOT @NgModuleFactory Bootstraping Javascript CSS HTML host viewDef Renderer pipeDef ngContentDef nodeValue … compilation-side @angular/platform-browser Parse AST load CD browser-side Angular5 부터는 build-optimizer 옵션을 통해 추가적으로 최적화가 가능하니 참고해주세요
  • 47. AOT Compiled code function View_MukkitListComponent_0(_l) { return __WEBPACK_IMPORTED_MODULE_1__angular_core__["_25" /* ɵvid */] (0, [__WEBPACK_IMPORTED_MODULE_1__angular_core__["_22" /* ɵqud */] (402653184, 1, { inputEl: 0 }), (_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_8" /* ɵeld */](1, 0, null, null, 6, "div", [["class", "mukkit-list- container"]], null, null, null, null, null)), (_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_24" /* ɵted */](-1, null, ["n "])), (_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_8" /* ɵeld */](3, 0, null, null, 0, "img", [["src", "data:image/svg+xml;base64,…"], ["width", "180"]], null, null, null, null, null)), (_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_24" /* ɵted */](-1, null, ["n "])), (_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_8" /* ɵeld */](5, 0, null, null, 1, "h2", [], null, null, null, null, null)), (_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_24" /* ɵted */](-1, null, ["uBA39uD0B7uB9ACuC2A4uD2B8"])), (_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_24" /* ɵted */](-1, null, ["n"])), (_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_24" /* ɵted */](-1, null, ["nn"])), (_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_8" /* ɵeld */](9, 0, null, null, 17, "ul", [["class", "mukkit-list"]], null, null, null, null, null)), (_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_24" /* ɵted */](-1, null, ["n "])), (_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_3" /* ɵand */](16777216, null, null, 1, null, View_MukkitListComponent_1)), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_7" /* ɵdid */]( 12, 802816, null, 0, __WEBPACK_IMPORTED_MODULE_2__angular_common__["c" /* NgForOf */], [__WEBPACK_IMPORTED_MODULE_1__angular_core__["R" /* ViewContainerRef */], __WEBPACK_IMPORTED_MODULE_1__angular_core__["N" /* TemplateRef */], __WEBPACK_IMPORTED_MODULE_1__angular_core__["u" /* IterableDiffers */]], { ngForOf: [0, "ngForOf"] }, null), (_l()(), __WEBPACK_IMPORTED_MODULE_1__angular_core__["_24" /* ɵted */](-1, null, ["n "])), …
  • 48. AOT 성능 변화 크기 (minified) 지연시간 (initial load) 메모리 (snapshot) 442KB 585ms 38.5MB 198KB 305ms 15.3MB -55% -48% -60% JIT AOT JIT AOT
  • 49. VirtualDOM VirtualDOM (가상 DOM) 뷰 모델에서 발생하는 변경사항을 메모리에서 관리하는 논리적 DOM에서 먼저 감지 한 후 실제 DOM의 업데이트를 최소화하여 성능을 향상시키고 UX 측면에서 발생하는 문제를 줄임 미지원 지원 지원 VirtualDOMViewModel Element A Element B1 Element B2 Element B Element A Element B1 Element B2 Element B header .list-item .list-item .container NativeDOM (Real DOM) diff patch
  • 50. VirtualDOM 기존의 비싼 비용의 Native DOM 처리를 javascript 상의 diff 알고리즘을 통해 저렴한 비용으로 효율적인 처리가 가능해짐 MDN에 공개된 브라우저 Layout 처리
  • 51. Angular의 최적화가 적용되지 않은 케이스에서는 VueJS가 성능이 빠를 것으로 예상됩니다. (VueJS에서 제공하는 자료와 벤치마크 데이터 참조)
  • 54. 마이크로 프로젝트에는 VueJS 권장 서버사이드 랜더링이 필요한 프로젝트에는 React 대규모의 프로젝트에는 Angular
  • 55. 템플릿 {{interpolation}} [1way data binding] [(2way data binding)] (1way data binding (event)) {{interpolation with pipe | pipeName}} *ngFor *ngIf [ngSwitch] [hidden] [innerHTML] [ngClass] (click) (keypress) (blur) (input) (change) … React에서 공식적으로 제공하는 템플릿은 없습니다. 모든 것을 JSX 혹은 Javascript를 이용하여 표현합니다. react-templates 라이브러리를 이용하면 다른 프레임워크와 유사하게 템플릿을 사용하실 수 있습니다. v-directive-name:parameter {{interpolation | filter}} v-bind:id v-if v-html v-for v-else v-else-if v-show v-bind:class v-bind:style v-on:event-name v-bind:bind-target-name {{interpolation}} :store-name v-model
  • 56. 템플릿 표현식은 Angular가 체계적이지만 VueJS가 접근장벽이 낮음 AngularJS (Angular 1)는 VueJS 템플릿과 유사
  • 57. 변화감지 ChangeDetection NgZone RxJS Props / State Reconciliation React Fiber Redux Redux Saga Redux Thunk Watcher VirtualDOM (based Snabdom) vuex vue-rx
  • 58. Angular Change Detection & NgZone NgZone의 몽키패칭된 이벤트로부터 변화를 감지하여 Change Detection Strategy에 맞게 변화를 전파 setTimeout, addEventListener, requestAnimationFrame NgZone Monkey Patched Tick
  • 59. 1 React Reconciliation & React Fiber React Reconciliation React FibershouldComponentUpdate() Dealing control by element types (aka. Pair-wise diff) 2 3 Dealing control by key (aka. List-wise diff) Update DOM render() 호출 시 VirtualDOM 생성 및 Dirty model을 감지하여 React Reconciliation 과정을 진행 후 React Fiber 혹은 DOM 변경
  • 60. VueJS watcher & VirtualDOM data 프로퍼티에서 Object.defineProperty()를 통해 Watcher가 변화를 감지 변화를 수신 시 render 함수에 의해 VirtualDOM에 따른 DOM 변경
  • 62. 오픈소스 - Open source Fight 5
  • 66. Server Side Rendering Angular Universal ReactDOMServer vue-server-renderer
  • 67. 각 프레임워크 별 오픈소스는 계속적으로 발전 중 따라서 어느것이 더 안정적인가 더 알려져있는가가 선택사항이 될 수 있음
  • 69. 1. MVVM 상태관리에 유념하세요
  • 70. MVVM 패턴은 Model-View-ViewModel의 약자 MVVM View ViewModel ViewModel Data binding Event receiving Update 데이터 바인딩에 사용되는 채널 (변수)는 유사한 것 끼리 최대한 합치세요 데이터 바인딩에 사용되는 데이터가 정적이라면 이를 함수로 구현하지 마세요
  • 71. 2. Immutable은 무적이 아닙니다.
  • 72. Immutable (불변성) Immutable ViewModel의 사이드 이펙트를 줄이기위해 Immutable을 고려하시는 분들이 계실 겁니다. Immutable을 제공하기 위해 우리는 큰 비용이 발생하는 DeepCopy를 사용합니다. 또한 Immutable 객체는 기존 Prop와 전혀 다른 객체이므로 무조건 랜더링이 업데이트 됩니다. Immutable ValueUpdate Dispatch Reducer Notify shouldComponentUpdate
  • 74. HMR (Hot Module Replacement) Webpack의 HMR(Hot Module Replacement)는 Angular, React, VueJS에서 코드를 수정하고 저장할 때 새로고침을 할 필요 없이 더군다나 기존 상태를 잃지 않고 코드가 바로 교체되고 새로 저장한 코드를 즉시 사용할 수 있습니다.
  • 76. Shadow DOM ShadowDOM은 각 컴포넌트에 독립적으로 스타일을 지정하고 싶을 때 사용할 수 있는 논리적으로 구분된 가상의 DOM 범위입니다. React는 ReactShadow, Angular는 encapsulation 속성을 통해 쉽게 사용가능합니다. VueJS는.. 다음장으로!
  • 77. 5. Webpack의 끔찍한 빌드속도
  • 78. Webpack build optimization 빌드 과정은 때묻지 않은 초기 스캐폴딩에서는 그렇게 오래 기다리지 않아도 됩니다. 애드혹 빌드 과정일 경우 보통 5초 내외로 완료되곤 합니다. Watch 옵션을 켜서 메모리 캐시를 활용하면 더욱 빠릅니다. (1초 안팎) 문제는 어느정도 규모가 있는 프로젝트에서는 빌드 과정이 10분 이상 넘어갑니다. 다행이도 Webpack 빌드 과정은 다음장의 최적화 방식을 따라 하여 성능을 높일 수 있습니다.
  • 79. Webpack Dll Plugin Webpack Dll Plugin은 변경이 자주 발생하지 않는 번들 파일을 미리 빌드 해놓고 일반적인 변경사항에 대한 빌드에서 dll로 지정한 빌드된 번들파일을 최종적으로 묶어서 결과적으로 빌드 속도를 상승시켜주는 역할을 합니다. 설정법이 어렵지 않으며 Webpack 공식문서에 공개되어 있으니 참고하여 주세요 new webpack.DllReferencePlugin({ context: root, manifest: manifest });
  • 81. Show more in GitHub! https://github.com/KennethanCeyer/gdg-devfest-seoul-frontend-frameworks