Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

5,671 views

Published on

GDG DevFest 2017 Seoul
프론트엔드 모던 프레임워크 낱낱히 파헤치기 세션의 발표자료입니다.

이 발표자료에서는 여러분이 항상 궁금해 하신
프론트엔드 프레임워크의 삼총사
Angular, React, VueJS를 다차원적으로 깊이있게 비교하고 각각의 이점과 특화된 기능을 소개하고 있습니다.

이러한 프레임워크를 경험해보지 못한 분들을 위해 프레임워크 별로 특징부터 쉽게 접근하여 설명하기 때문에 경험 불문하고 가볍게 읽어 보실 수 있습니다.

Published in: Technology

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

  1. 1. 한성민 IGAWorks SungMin Han 프론트엔드 모던 프레임워크 낱낱히 파헤치기
  2. 2. 오늘날의 프론트엔드 모던 프레임워크 톺아보기 실무자를 위한 Tips 이번 세션에서는
  3. 3. 오늘날의 프론트엔드
  4. 4. 웹 프론트 기술의 흐름 jQuery Vanila Javascript AngularJS React VueJS Angular 2006 2013 2009 2014 2016
  5. 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
  6. 6. 2017 프론트엔드 로드맵
  7. 7. 동적 렌더링 모듈링 / 번들링 타이핑 현재 프론트진형의 중요 키워드 테스트 자동화
  8. 8. 동적 렌더링 모듈링 / 번들링 타이핑 2017년 프론트 진형 중요 키워드 테스트 자동화 Two-way binding, SPA, Virtual DOM, Change Detection … CommonJS, AMD, UMD, Uglify, Grunt, Webpack … Typescript, Proptypes, Flow, Props … UnitTest, e2e Test, HeadLess Browser …
  9. 9. 그리고 그것들을 제공하는 많은 도구들
  10. 10. Angular 완전하고 빠른 프레임워크 React 활발하고 오픈 되어 있으며 합리적인 프레임워크 VueJS 가볍고 친숙하며 장점만을 합쳐놓은 프레임워크 그러던 중 나타난 프레임워크들 그리고 프레임워크는 그 모든 것을 쉽게 만들어주었나니..
  11. 11. Angular 완전하고 빠른 프레임워크 React 활발하고 오픈 되어 있으며 합리적인 프레임워크 VueJS 가볍고 친숙하며 장점만을 합쳐놓은 프레임워크 그러던 중 나타난 프레임워크들 그리고 프레임워크는 그 모든 것을 쉽게 만들어주었나니..
  12. 12. Angular 모든 기능이 빌트인되어 있으며 성능이 훌륭하지만, 진입장벽이 가장 높음 React 에코시스템이 활발하게 움직이고 또 그것을 장려하지만 의존과 버전에 민감하고 라이브러리 자체의 기능만으로는 부족함 VueJS 프레임워크 자체가 가볍고 진입장벽이 낮으며 각 프레임워크의 장점을 흡수 다만 크기가 커질 수록 재활용성은 떨어지며, 테스트하기 어렵고 느림 이를 풀어 설명하자면
  13. 13. 모던 프레임워크 톺아보기
  14. 14. 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
  15. 15. 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
  16. 16. 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
  17. 17. 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
  18. 18. 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>
  19. 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> 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)
  20. 20. 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;
  21. 21. 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
  22. 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; render DOM React code
  23. 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; 1way binding (viewmodel -> view) React code
  24. 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 (view -> viewmodel) React code
  25. 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; state changed React code
  26. 26. 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>
  27. 27. 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)
  28. 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 1way binding (viewmodel -> view)
  29. 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 (view -> viewmodel)
  30. 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 view query (it is not bind)
  31. 31. 트랜드 - Trend Fight 1
  32. 32. Google Trend 2017. 11 29,994 star 81,002 star 73,628 star GitHub Stars
  33. 33. Deview 2016 투표 133 164 Unkown
  34. 34. Stack Overflow tagged questions 81,631 63,721 10,978
  35. 35. React 트랜드 및 에코시스템이 가장 활발 VueJS가 무서운 속도로 트랜드를 따라잡고 있음 Angular가 AngularJS 까지 포함한다면 가장 큼
  36. 36. 진입장벽 – Entry barriers Fight 2
  37. 37. Blogged from Marius Duta 일반적인 케이스에서 Angular의 학습곡선이 압도적으로 높고 Vue의 학습곡선이 가장 낮음 학습곡선
  38. 38. 각 프레임워크를 배우기 위해서 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
  39. 39. 각 프레임워크 컴포넌트 라이프사이클
  40. 40. Angular 진입전에 다른 프레임워크 경험 권장 React의 라이프 사이클과 상태관리는 상대적 어려움 AngularJS를 사용하고 있다면 VueJS 권장
  41. 41. 성능 – Performance Fight 3
  42. 42. Benchmark Vue2 >= Angular > React AOT Compilation 이후 성능 비교에서는 Angular가 더욱 빠를 것으로 예상
  43. 43. TreeShaking TreeShaking (나무털기) 마치 나무에 달린 열매를 털듯이 사용하지 않는 모듈은 빌드 단계에서 제외시키는 최적화 기법 지원 지원 (Webpack2) 지원 (Webpack2)
  44. 44. 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 옵션을 통해 추가적으로 최적화가 가능하니 참고해주세요
  45. 45. 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 "])), …
  46. 46. AOT 성능 변화 크기 (minified) 지연시간 (initial load) 메모리 (snapshot) 442KB 585ms 38.5MB 198KB 305ms 15.3MB -55% -48% -60% JIT AOT JIT AOT
  47. 47. 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
  48. 48. VirtualDOM 기존의 비싼 비용의 Native DOM 처리를 javascript 상의 diff 알고리즘을 통해 저렴한 비용으로 효율적인 처리가 가능해짐 MDN에 공개된 브라우저 Layout 처리
  49. 49. Angular의 최적화가 적용되지 않은 케이스에서는 VueJS가 성능이 빠를 것으로 예상됩니다. (VueJS에서 제공하는 자료와 벤치마크 데이터 참조)
  50. 50. 구성요소 – Component Fight 4
  51. 51. 모듈 구성 @NgModule Main @Component @Injectable @NgModule Vue Vue.component Vue.directive Vue.filter Vue.mixin ReactDOM.render Component or Class Component or Class
  52. 52. 마이크로 프로젝트에는 VueJS 권장 서버사이드 랜더링이 필요한 프로젝트에는 React 대규모의 프로젝트에는 Angular
  53. 53. 템플릿 {{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
  54. 54. 템플릿 표현식은 Angular가 체계적이지만 VueJS가 접근장벽이 낮음 AngularJS (Angular 1)는 VueJS 템플릿과 유사
  55. 55. 변화감지 ChangeDetection NgZone RxJS Props / State Reconciliation React Fiber Redux Redux Saga Redux Thunk Watcher VirtualDOM (based Snabdom) vuex vue-rx
  56. 56. Angular Change Detection & NgZone NgZone의 몽키패칭된 이벤트로부터 변화를 감지하여 Change Detection Strategy에 맞게 변화를 전파 setTimeout, addEventListener, requestAnimationFrame NgZone Monkey Patched Tick
  57. 57. 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 변경
  58. 58. VueJS watcher & VirtualDOM data 프로퍼티에서 Object.defineProperty()를 통해 Watcher가 변화를 감지 변화를 수신 시 render 함수에 의해 VirtualDOM에 따른 DOM 변경
  59. 59. 프로덕션 배포 ng-cli react-scripts build.js
  60. 60. 오픈소스 - Open source Fight 5
  61. 61. Progressive Web App(PWA)
  62. 62. Native Mobile
  63. 63. Native Desktop 모두 Electron 지원
  64. 64. Server Side Rendering Angular Universal ReactDOMServer vue-server-renderer
  65. 65. 각 프레임워크 별 오픈소스는 계속적으로 발전 중 따라서 어느것이 더 안정적인가 더 알려져있는가가 선택사항이 될 수 있음
  66. 66. 실무자를 위한 Tips
  67. 67. 1. MVVM 상태관리에 유념하세요
  68. 68. MVVM 패턴은 Model-View-ViewModel의 약자 MVVM View ViewModel ViewModel Data binding Event receiving Update 데이터 바인딩에 사용되는 채널 (변수)는 유사한 것 끼리 최대한 합치세요 데이터 바인딩에 사용되는 데이터가 정적이라면 이를 함수로 구현하지 마세요
  69. 69. 2. Immutable은 무적이 아닙니다.
  70. 70. Immutable (불변성) Immutable ViewModel의 사이드 이펙트를 줄이기위해 Immutable을 고려하시는 분들이 계실 겁니다. Immutable을 제공하기 위해 우리는 큰 비용이 발생하는 DeepCopy를 사용합니다. 또한 Immutable 객체는 기존 Prop와 전혀 다른 객체이므로 무조건 랜더링이 업데이트 됩니다. Immutable ValueUpdate Dispatch Reducer Notify shouldComponentUpdate
  71. 71. 3. HMR이라고 아시나요?
  72. 72. HMR (Hot Module Replacement) Webpack의 HMR(Hot Module Replacement)는 Angular, React, VueJS에서 코드를 수정하고 저장할 때 새로고침을 할 필요 없이 더군다나 기존 상태를 잃지 않고 코드가 바로 교체되고 새로 저장한 코드를 즉시 사용할 수 있습니다.
  73. 73. 4. ShadowDOM 사용해보셨나요?
  74. 74. Shadow DOM ShadowDOM은 각 컴포넌트에 독립적으로 스타일을 지정하고 싶을 때 사용할 수 있는 논리적으로 구분된 가상의 DOM 범위입니다. React는 ReactShadow, Angular는 encapsulation 속성을 통해 쉽게 사용가능합니다. VueJS는.. 다음장으로!
  75. 75. 5. Webpack의 끔찍한 빌드속도
  76. 76. Webpack build optimization 빌드 과정은 때묻지 않은 초기 스캐폴딩에서는 그렇게 오래 기다리지 않아도 됩니다. 애드혹 빌드 과정일 경우 보통 5초 내외로 완료되곤 합니다. Watch 옵션을 켜서 메모리 캐시를 활용하면 더욱 빠릅니다. (1초 안팎) 문제는 어느정도 규모가 있는 프로젝트에서는 빌드 과정이 10분 이상 넘어갑니다. 다행이도 Webpack 빌드 과정은 다음장의 최적화 방식을 따라 하여 성능을 높일 수 있습니다.
  77. 77. Webpack Dll Plugin Webpack Dll Plugin은 변경이 자주 발생하지 않는 번들 파일을 미리 빌드 해놓고 일반적인 변경사항에 대한 빌드에서 dll로 지정한 빌드된 번들파일을 최종적으로 묶어서 결과적으로 빌드 속도를 상승시켜주는 역할을 합니다. 설정법이 어렵지 않으며 Webpack 공식문서에 공개되어 있으니 참고하여 주세요 new webpack.DllReferencePlugin({ context: root, manifest: manifest });
  78. 78. Question?
  79. 79. Show more in GitHub! https://github.com/KennethanCeyer/gdg-devfest-seoul-frontend-frameworks
  80. 80. 감사합니다. GitHub: https://github.com/KennethanCeyer Email: kennethan@nhpcw.com

×