SlideShare a Scribd company logo
+
한장현
han41858@gmail.com
han41858.tistory.com
1
• 전 삼성SDS 선임
• TV플랫폼 JavaScript 어플리케이션 구현
• 리테일 솔루션 서버 & 프론트엔드 구현
• 프리랜서 개발자
• han41858.tistory.com 블로그 운영
• Angular 2 번역서 집필중
• GDG Korea Web Tech 운영진
한장현 (Janghyun Han)
2
3
ngular
1.6.0-rc.2 safety-insurance
4
• 마술 같은 2-way binding
• HTML 표준을 기반으로 기능 확장
• 체계적인 컴포넌트, Web Component로 가는 길
• Front-end 전체를 커버하는 프레임워크
• Google 에서 관리, 개선
• 풍부한 사용자 삽질 경험
Angular를 쓰는 이유
5
Class, inheritance
import/export
Arrow function
Promise
ECMAScript 2015
6
• 간단해지는 코드, syntax sugar
• 클래스, 상속, 모듈 구성 ⇒ 아키텍처 진화
• 브라우저들 지원 계속
• 결국엔 표준, transpiler는 거쳐갈 뿐
ES6를 쓰는 이유
7
8
ES6ES5
script src
<script src="bundle.js"></script>
"devDependencies": {
"angular": "^1.5.8",
"babel-cli": "^6.18.0",
"babel-loader": "^6.2.7",
"babel-preset-es2015": "^6.18.0",
"webpack": "^1.13.3"
}
<script src="angular.js"></script>
<script src="index.js"></script>
"devDependencies": {
"angular": "^1.5.8"
}
9
index.js
ES6ES5
(function () {
var ngApp = angular.module('angular1es5', []);
})();
import angular from 'angular';
(() => {
const ngApp = angular.module('angular1es6', []);
})();
10
Webpack
// this is ES5
var webpack = require('webpack');
module.exports = {
entry : [
'./index.js'
],
output : {
filename : 'build/bundle.js',
sourceMapFilename: '[name].map'
},
module : {
loaders : [
{
test : /.js$/,
loader : 'babel?presets[]=es2015
exclude : /node_modules/
},
{
test : /.pug$/,
loader : 'pug-loader',
exclude : /node_modules/
}
]
},
plugins : [
// new webpack.optimize.UglifyJsPlugin({minimize: true})
]
};
webpack.config.js
"devDependencies": {
"angular": "^1.5.8",
"angular-route": "^1.5.8",
"babel-cli": "^6.18.0",
"babel-loader": "^6.2.7",
"babel-preset-es2015": "^6.18.0",
"file-loader": "^0.9.0",
"pug": "^2.0.0-beta6",
"pug-loader": "^2.3.0",
"webpack": "^1.13.3",
"webpack-dev-server": "^1.16.2"
}
package.json
11
export default class HomeCtrl {
constructor () {
console.log('HomeCtrl.constructor()');
}
}
/view/homeCtrl.js
p this is home
/view/home.pug
import angular from 'angular';
import ngRoute from 'angular-route';
import HomeCtrl from './view/homeCtrl';
const main = () => {
console.log('main()');
const ngApp = angular.module('angular1es6', ['ngRoute']);
ngApp.config(($routeProvider, $locationProvider) => {
console.log('this is angular config');
$routeProvider
.when('/', {
template : require('./view/home.pug'),
controller : 'HomeCtrl',
controllerAs : 'Ctrl'
})
.otherwise({
redirectTo : '/'
});
// need to angular.js routing
$locationProvider.html5Mode({
enabled : true,
requireBase : false
});
});
ngApp.controller('HomeCtrl', HomeCtrl);
};
main();
index.js + ngRoute
12
webpack-dev-server
13
ngApp.directive('CustomDirective', () => new CustomDirective);
ngApp.filter('groupBy', GroupBy);
ngApp.service('CustomSvc', CustomSvc);
ngApp.controller('CustomCtrl', CustomCtrl);
Angular Components
ngApp.directive('CustomDirective', CustomDirective);
ngApp.filter('groupBy', GroupBy);
ngApp.service('CustomSvc', CustomSvc);
ngApp.controller('CustomCtrl', CustomCtrl);
function
Class
new Class
14
Filter
ES6ES5
ngApp.filter('uppercase', uppercase);
function uppercase () {
return function (item) {
return item.toUpperCase();
};
}
<script src="uppercase.filter.js"></script>
const uppercase = () => {
return (input) => {
return input.toUpperCase();
};
};
export default uppercase;
import uppercase from './uppercase.filter';
ngApp.filter('uppercase', uppercase);
15
.ctrlRoot
p this is home ctrl
p {{ Ctrl.title }}
button(ng-click="Ctrl.select()") Select
export default class HomeCtrl {
constructor () {
console.log('HomeCtrl.constructor()');
this.title = 'this is title';
}
select () {
console.log('HomeCtrl.select()');
}
}
$routeProvider
.when('/', {
template : require('./view/home.pug'),
controller : 'HomeCtrl',
controllerAs : 'Ctrl'
})
ngApp.controller('HomeCtrl', HomeCtrl);
function HomeCtrl ($scope) {
console.log('home controller');
$scope.title = 'this is title';
$scope.select = function () {
console.log('HomeCtrl.select()');
}
}
Controller
ES6ES5
.ctrlRoot
p this is home ctrl
p {{ title }}
button(ng-click="select()") Select
16
Service
ES6ES5
ngApp.service('myService', myService);
<script src="./view/myService.js"></script>
function myService () {
this.testFnc = function () {
console.log('myService.testFnc()');
};
return this;
}
export default class MyService {
constructor () {
console.log('MyService');
}
testFnc () {
console.log('MyService.testFnc()');
}
}
ngApp.service('MyService', MyService);
export default class HomeCtrl {
constructor (MyService) {
this.MyService = MyService;
}
select () {
this.MyService.testFnc();
}
}
static 있어야 할 것 같지만 없어야 함
17
ngApp.directive('myDirective', () => new MyDirective);
export default class MyDirective {
constructor () {
console.log('MyDirective.constructor()');
this.restrict = 'E';
this.template = '<p>message : {{ this.msg }}</p>';
this.scope = {
msg : '@'
};
}
link (scope) {
console.log(scope.msg);
}
}
ngApp.directive('myDirective', myDirective);
function myDirective () {
return {
restrict : 'E',
template : '<p>message : {{ msg }}</p>',
scope : {
msg : '@'
},
controller : function ($scope) {
console.log('myDirective.controller()');
console.log($scope.msg);
}
}
}
<script src="myDirective.js"></script>
Directive
ES6ES5
directive 등록할 때 () => new18
Directive vs. Component
19
Directive vs. Component
const customInput = {
bindings : {
model : '='
},
template : '<input ng-model="$ctrl.model"></input>',
controller : function () {
this.$onInit = () => {
}
}
};
export default customInput;
ngApp.component('customInput', customInput);ngApp.directive('customInput', () => new customInput);
export default class customInput {
constructor () {
this.restrict = 'E';
this.scope = {
model : '='
};
this.template = '<input ng-model="model"></input>';
}
controller () {
}
}
20
static delete (param) {
const self = this;
return util.objValidate(param, {
userID : Constants.TYPE.EMAIL
}, Constants.ERROR.USER_CTRL.NO_PARAMETER, log, 'delete()')
.then(param => self.isExists(param))
.then(param => {
// delete records
return recordCtrl.deleteAll({
userID : param.userID
})
.then(() => {
log('remove records ok');
// param 자체를 다시 돌려주기 위해 Promise 필요
return Promise.resolve(param);
});
})
.then(param => {
// delete cards
return cardCtrl.deleteAll({
userID : param.userID
})
.then(() => {
log('remove cards ok');
return Promise.resolve(param);
});
})
.then(param => {
// delete assets
return assetCtrl.deleteAll({
userID : param.userID
})
.then(() => {
log('remove assets ok');
return Promise.resolve(param);
});
})
.then(param => {
// delete user
return User.remove({
userID : param.userID
})
.then(() => {
return Promise.resolve(param);
}, error => {
log(error);
return Promise.reject(new ERROR(Constants.ERROR.MONGOOSE.REMOVE_FAILED, log, 'delete()'));
});
})
.then(param => {
log(`delete ok : ${param.userID}`);
return Promise.resolve(true);
});
}
Promise
21
ngApp.config(($routeProvider, $locationProvider) => {
// include styles
require('./view/home.styl');
$routeProvider
.when('/', {
template : require('./view/home.pug'),
controller : 'HomeCtrl',
controllerAs : 'Ctrl'
})
.otherwise({
redirectTo : '/'
});
});
배포 : webpack
import가 아니므로 require 22
Angular 1 + ES6 + BDD
= Hell
23
describe('homeCtrl.test', () => {
it('module import', () => {
expect(true).to.be.true;
});
});
λ karma start
(node:7564) DeprecationWarning: Using Buffer without `new` will soon stop working. Use `new Buffer()`, or preferably `Buffer.from()`,
`Buffer.allocUnsafe()` or `Buffer.alloc()` instead.
18 11 2016 02:53:45.852:INFO [framework.browserify]: bundle built
18 11 2016 02:53:45.941:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
18 11 2016 02:53:45.941:INFO [launcher]: Launching browser Chrome with unlimited concurrency
18 11 2016 02:53:45.952:INFO [launcher]: Starting browser Chrome
18 11 2016 02:53:47.283:INFO [Chrome 54.0.2840 (Windows 10 0.0.0)]: Connected on socket /#AjAqCwTlrwmVmV_sAAAA with id
16857313
Chrome 54.0.2840 (Windows 10 0.0.0): Executed 1 of 1 SUCCESS (0.005 secs / 0.001 secs)
BDD 시작
24
λ karma start
(node:12196) DeprecationWarning: Using Buffer without `new` will soon stop working. Use `new Buffer()`, or preferably `Buffer.from()`, `Buffer.allocUnsafe()` or `Buffer.alloc()` instead.
18 11 2016 02:19:10.237:INFO [framework.browserify]: bundle built
18 11 2016 02:19:10.343:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
18 11 2016 02:19:10.343:INFO [launcher]: Launching browser Chrome with unlimited concurrency
18 11 2016 02:19:10.353:INFO [launcher]: Starting browser Chrome
18 11 2016 02:19:11.676:INFO [Chrome 54.0.2840 (Windows 10 0.0.0)]: Connected on socket /#sBpP4RL0XFZAwPtxAAAA with id 52822107
Chrome 54.0.2840 (Windows 10 0.0.0) ERROR
Uncaught SyntaxError: Unexpected token import
at test/homeCtrl.test.js:1
import HomeCtrl from '../view/homeCtrl';
describe('homeCtrl.test', () => {
it('module import', () => {
console.log(HomeCtrl);
expect(true).to.be.true;
expect(HomeCtrl).to.be.ok;
});
});
λ karma start
(node:11580) DeprecationWarning: Using Buffer without `new` will soon stop working. Use `new Buffer()`, or preferably `Buffer.from()`, `Buffer.allocUnsafe()` or `Buffer.alloc()` instead.
18 11 2016 02:31:24.248:INFO [framework.browserify]: bundle built
18 11 2016 02:31:24.339:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
18 11 2016 02:31:24.339:INFO [launcher]: Launching browser Chrome with unlimited concurrency
18 11 2016 02:31:24.349:INFO [launcher]: Starting browser Chrome
18 11 2016 02:31:25.657:INFO [Chrome 54.0.2840 (Windows 10 0.0.0)]: Connected on socket /#pvpyGrXqq2TZPTgmAAAA with id 30236974
LOG: class HomeCtrl { ... }
Chrome 54.0.2840 (Windows 10 0.0.0): Executed 1 of 1 SUCCESS (0.007 secs / 0.002 secs)
babel : node6
λ karma start
(node:13196) DeprecationWarning: Using Buffer without `new` will soon stop working. Use `new Buffer()`, or preferably `Buffer.from()`, `Buffer.allocUnsafe()` or `Buffer.alloc()` instead.
18 11 2016 02:58:38.638:INFO [framework.browserify]: bundle built
18 11 2016 02:58:38.728:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
18 11 2016 02:58:38.729:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
18 11 2016 02:58:38.738:INFO [launcher]: Starting browser PhantomJS
18 11 2016 02:58:40.301:INFO [PhantomJS 2.1.1 (Windows 8 0.0.0)]: Connected on socket /#JeRwavdozVZCC8HJAAAA with id 75347319
LOG: function HomeCtrl(MyService) { ... }
PhantomJS 2.1.1 (Windows 8 0.0.0): Executed 1 of 1 SUCCESS (0.008 secs / 0.001 secs)
babel : es2015
ES6가 돌지 않는다…
+
25
var $httpBackend;
beforeEach(function () {
module('angular1es5');
inject(function (_$httpBackend_) {
$httpBackend = _$httpBackend_;
});
});
module 선언, injection 불가
ES6ES5
const $injector, $httpBackend;
beforeEach(() => {
$injector = angular.injector(['angular1es6']);
$httpBackend = $injector.get('$httpBackend');
});
Object is not a constructor (evaluating 'module('angular1es6')')
r:/temp/test/homeCtrl.test.js:15:9 <-
R:/temp/3871fde1c6cf6c302eeae7add18a3b02.browserify:22:9
26
ngMock vs. ngMockE2E
The ngMock module provides support to inject
and mock Angular services into unit tests. In
addition, ngMock also extends various core ng
services such that they can be inspected and
controlled in a synchronous manner within test
code.
The ngMockE2E is an angular module which
contains mocks suitable for end-to-end testing.
Currently there is only one mock present in this
module - the e2e $httpBackend mock.
ngMock ngMockE2E
Fake HTTP backend implementation suitable for end-to-
end testing or backend-less development of applications
that use the $http service.
Fake HTTP backend implementation suitable for unit
testing applications that use the $http service.
.when()
.expect()
.flush()
.verifyNoOutstandingExpectation()
.verifyNoOutstandingRequest()
.resetExpectations()
.when()
ngMockE2E에는 $location 없음 27
Promise + http.flush()
Chrome 54.0.2840 (Windows 10 0.0.0) homeCtrl.test http test ok FAILED
Error: No pending request to flush !
at Function.$httpBackend.flush (node_modules/angular-mocks/angular-mocks.js:1799:34)
at r:/temp/test/homeCtrl.test.js:36:17
promise 함수로 부르면 동작 안함
flush() 타이밍 달라짐
flush는 Util에서 수행
const $injector = angular.injector(['angular1es6']);
const $httpBackend = $injector.get('$httpBackend');
const $http = $injector.get('$http');
beforeEach(() => {
$httpBackend.expectGET('/test')
.respond(['this', 'is', 'GET', 'test', 'data']);
});
it('ok', () => {
return new Promise(resolve => {
$http.get('/test').then(result => {
console.log('get().then()');
console.log(result);
console.log(result.data);
resolve(true);
});
$httpBackend.flush();
});
});
동작하는 코드
static post (uri, param, config) {
// use new promise for flush()
return new Promise((resolve, reject) => {
this.http.post(uri, param, config)
.then(result => {
resolve(result);
}, error => {
console.error(error);
reject(false);
});
if (this.httpBackend && this.httpBackend.flush) {
this.httpBackend.flush();
}
});
}
it('ok', () => {
return new Promise(resolve => {
Promise.resolve()
.then(() => {
$http.get('/test').then(result => {
console.log('get().then()');
console.log(result);
console.log(result.data);
resolve(true);
});
});
$httpBackend.flush();
});
});
28
여러 test 파일 동시 실행
const $injector = angular.injector(['angular1es6']);
const $httpBackend = $injector.get('$httpBackend');
const $http = $injector.get('$http');
Chrome 54.0.2840 (Windows 10 0.0.0) SignInCtrl test logic submit() with ajax error response response error test FAILED
AssertionError: expected [Error: Unexpected request: POST /api/user/signIn
No more request expected] to be an instance of ERROR
Chrome 54.0.2840 (Windows 10 0.0.0) SignUpCtrl test logic submit() error response response error test FAILED
AssertionError: expected [Error: [$rootScope:inprog] $digest already in progress
const ngApp = angular.module(appName, ['ngMock']); // working with $location, but not $httpBackend.whenPOST()...
var $injector = angular.injector(['MoneyBook']);
const $httpBackend = $injector.get('$httpBackend');
const $http = $injector.get('$http');
ClientUtil.http = $http;
ClientUtil.httpBackend = $httpBackend;
29
생성자 안에서 Promise
export default class HomeCtrl {
constructor () {
console.log('HomeCtrl.constructor()');
Promise.resolve(() => {
// do something
});
}
}
describe('constructor()', () => {
it('ok', () => {
// expect what...?
});
});
export default class HomeCtrl {
constructor () {
console.log('HomeCtrl.constructor()');
this.somethingPromise();
}
somethingPromise(){
return Promise.resolve()
.then() => {
// do something
});
}
}
30
Promise + $scope.$apply()
export default class HomeCtrl {
constructor () {
console.log('HomeCtrl.constructor()');
this.count = 0;
}
select () {
console.log('HomeCtrl.select()');
return Promise.resolve()
.then(() => {
this.count++;
});
}
}
export default class HomeCtrl {
constructor ($scope) {
console.log('HomeCtrl.constructor()');
this.$scope = $scope;
this.count = 0;
}
select () {
console.log('HomeCtrl.select()');
return Promise.resolve()
.then(() => {
this.count++;
this.$scope.$apply();
});
}
}
31
+ =
32

More Related Content

What's hot

Ansible loves Python, Python Philadelphia meetup
Ansible loves Python, Python Philadelphia meetupAnsible loves Python, Python Philadelphia meetup
Ansible loves Python, Python Philadelphia meetup
Greg DeKoenigsberg
 
Nginx and friends - putting a turbo button on your site
Nginx and friends - putting a turbo button on your siteNginx and friends - putting a turbo button on your site
Nginx and friends - putting a turbo button on your site
Wim Godden
 
Find bottleneck and tuning in Java Application
Find bottleneck and tuning in Java ApplicationFind bottleneck and tuning in Java Application
Find bottleneck and tuning in Java Application
guest1f2740
 
Future Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NETFuture Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NET
Gianluca Carucci
 
Node.js in action
Node.js in actionNode.js in action
Node.js in action
Simon Su
 
Europython 2011 - Playing tasks with Django & Celery
Europython 2011 - Playing tasks with Django & CeleryEuropython 2011 - Playing tasks with Django & Celery
Europython 2011 - Playing tasks with Django & Celery
Mauro Rocco
 
Flexviews materialized views for my sql
Flexviews materialized views for my sqlFlexviews materialized views for my sql
Flexviews materialized views for my sql
Justin Swanhart
 
Taking a Test Drive
Taking a Test DriveTaking a Test Drive
Taking a Test Drive
Graham Lee
 
Rxjs marble-testing
Rxjs marble-testingRxjs marble-testing
Rxjs marble-testing
Christoffer Noring
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
Piotr Pelczar
 
Spring 4 - A&BP CC
Spring 4 - A&BP CCSpring 4 - A&BP CC
Spring 4 - A&BP CC
JWORKS powered by Ordina
 
"Swoole: double troubles in c", Alexandr Vronskiy
"Swoole: double troubles in c", Alexandr Vronskiy"Swoole: double troubles in c", Alexandr Vronskiy
"Swoole: double troubles in c", Alexandr Vronskiy
Fwdays
 
Guide to Node.js: Basic to Advanced
Guide to Node.js: Basic to AdvancedGuide to Node.js: Basic to Advanced
Guide to Node.js: Basic to Advanced
Espeo Software
 
Why Redux-Observable?
Why Redux-Observable?Why Redux-Observable?
Why Redux-Observable?
Anna Su
 
NetApp ontap simulator
NetApp ontap simulatorNetApp ontap simulator
NetApp ontap simulator
Ashwin Pawar
 
Jeroen Vloothuis Bend Kss To Your Will
Jeroen Vloothuis   Bend Kss To Your WillJeroen Vloothuis   Bend Kss To Your Will
Jeroen Vloothuis Bend Kss To Your Will
Vincenzo Barone
 
Performance measurement and tuning
Performance measurement and tuningPerformance measurement and tuning
Performance measurement and tuning
AOE
 
Celery
CeleryCelery
"The little big project. From zero to hero in two weeks with 3 front-end engi...
"The little big project. From zero to hero in two weeks with 3 front-end engi..."The little big project. From zero to hero in two weeks with 3 front-end engi...
"The little big project. From zero to hero in two weeks with 3 front-end engi...
Fwdays
 
BATTLESTAR GALACTICA : Saison 5 - Les Cylons passent dans le cloud avec Vert....
BATTLESTAR GALACTICA : Saison 5 - Les Cylons passent dans le cloud avec Vert....BATTLESTAR GALACTICA : Saison 5 - Les Cylons passent dans le cloud avec Vert....
BATTLESTAR GALACTICA : Saison 5 - Les Cylons passent dans le cloud avec Vert....
La Cuisine du Web
 

What's hot (20)

Ansible loves Python, Python Philadelphia meetup
Ansible loves Python, Python Philadelphia meetupAnsible loves Python, Python Philadelphia meetup
Ansible loves Python, Python Philadelphia meetup
 
Nginx and friends - putting a turbo button on your site
Nginx and friends - putting a turbo button on your siteNginx and friends - putting a turbo button on your site
Nginx and friends - putting a turbo button on your site
 
Find bottleneck and tuning in Java Application
Find bottleneck and tuning in Java ApplicationFind bottleneck and tuning in Java Application
Find bottleneck and tuning in Java Application
 
Future Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NETFuture Decoded - Node.js per sviluppatori .NET
Future Decoded - Node.js per sviluppatori .NET
 
Node.js in action
Node.js in actionNode.js in action
Node.js in action
 
Europython 2011 - Playing tasks with Django & Celery
Europython 2011 - Playing tasks with Django & CeleryEuropython 2011 - Playing tasks with Django & Celery
Europython 2011 - Playing tasks with Django & Celery
 
Flexviews materialized views for my sql
Flexviews materialized views for my sqlFlexviews materialized views for my sql
Flexviews materialized views for my sql
 
Taking a Test Drive
Taking a Test DriveTaking a Test Drive
Taking a Test Drive
 
Rxjs marble-testing
Rxjs marble-testingRxjs marble-testing
Rxjs marble-testing
 
Asynchronous programming done right - Node.js
Asynchronous programming done right - Node.jsAsynchronous programming done right - Node.js
Asynchronous programming done right - Node.js
 
Spring 4 - A&BP CC
Spring 4 - A&BP CCSpring 4 - A&BP CC
Spring 4 - A&BP CC
 
"Swoole: double troubles in c", Alexandr Vronskiy
"Swoole: double troubles in c", Alexandr Vronskiy"Swoole: double troubles in c", Alexandr Vronskiy
"Swoole: double troubles in c", Alexandr Vronskiy
 
Guide to Node.js: Basic to Advanced
Guide to Node.js: Basic to AdvancedGuide to Node.js: Basic to Advanced
Guide to Node.js: Basic to Advanced
 
Why Redux-Observable?
Why Redux-Observable?Why Redux-Observable?
Why Redux-Observable?
 
NetApp ontap simulator
NetApp ontap simulatorNetApp ontap simulator
NetApp ontap simulator
 
Jeroen Vloothuis Bend Kss To Your Will
Jeroen Vloothuis   Bend Kss To Your WillJeroen Vloothuis   Bend Kss To Your Will
Jeroen Vloothuis Bend Kss To Your Will
 
Performance measurement and tuning
Performance measurement and tuningPerformance measurement and tuning
Performance measurement and tuning
 
Celery
CeleryCelery
Celery
 
"The little big project. From zero to hero in two weeks with 3 front-end engi...
"The little big project. From zero to hero in two weeks with 3 front-end engi..."The little big project. From zero to hero in two weeks with 3 front-end engi...
"The little big project. From zero to hero in two weeks with 3 front-end engi...
 
BATTLESTAR GALACTICA : Saison 5 - Les Cylons passent dans le cloud avec Vert....
BATTLESTAR GALACTICA : Saison 5 - Les Cylons passent dans le cloud avec Vert....BATTLESTAR GALACTICA : Saison 5 - Les Cylons passent dans le cloud avec Vert....
BATTLESTAR GALACTICA : Saison 5 - Les Cylons passent dans le cloud avec Vert....
 

Viewers also liked

2016 W3C Conference #1 : 웹 개발의 현재와 미래
2016 W3C Conference #1 : 웹 개발의 현재와 미래2016 W3C Conference #1 : 웹 개발의 현재와 미래
2016 W3C Conference #1 : 웹 개발의 현재와 미래
양재동 코드랩
 
2016 W3C Conference #7 : Electron, 웹 기술로 담아내는 데스크톱 애플리케이션
2016 W3C Conference #7 : Electron, 웹 기술로 담아내는 데스크톱 애플리케이션2016 W3C Conference #7 : Electron, 웹 기술로 담아내는 데스크톱 애플리케이션
2016 W3C Conference #7 : Electron, 웹 기술로 담아내는 데스크톱 애플리케이션
양재동 코드랩
 
2016 W3C Conference #9 : 컨테이너와 웹 어플리케이션
2016 W3C Conference #9 : 컨테이너와 웹 어플리케이션2016 W3C Conference #9 : 컨테이너와 웹 어플리케이션
2016 W3C Conference #9 : 컨테이너와 웹 어플리케이션
양재동 코드랩
 
2016 W3C Conference #2 : VANILA JS로 개발하기
2016 W3C Conference #2 : VANILA JS로 개발하기2016 W3C Conference #2 : VANILA JS로 개발하기
2016 W3C Conference #2 : VANILA JS로 개발하기
양재동 코드랩
 
2016 W3C Conference #5 : UNIVERSAL RENDERING (React.JS 중심)
2016 W3C Conference #5 : UNIVERSAL RENDERING (React.JS 중심)2016 W3C Conference #5 : UNIVERSAL RENDERING (React.JS 중심)
2016 W3C Conference #5 : UNIVERSAL RENDERING (React.JS 중심)
양재동 코드랩
 
2016 W3C Conference #8 : IONIC으로 하이브리드 앱 개발하기, 사례와 시사점
2016 W3C Conference #8 : IONIC으로 하이브리드 앱 개발하기, 사례와 시사점2016 W3C Conference #8 : IONIC으로 하이브리드 앱 개발하기, 사례와 시사점
2016 W3C Conference #8 : IONIC으로 하이브리드 앱 개발하기, 사례와 시사점
양재동 코드랩
 
2016 ABCD 소개
2016 ABCD 소개2016 ABCD 소개
2016 ABCD 소개
성일 한
 
2016 W3C Conference #6 : ReactiveX + Meteor 종단간 암호화 구현 사례
2016 W3C Conference #6 : ReactiveX + Meteor 종단간 암호화 구현 사례2016 W3C Conference #6 : ReactiveX + Meteor 종단간 암호화 구현 사례
2016 W3C Conference #6 : ReactiveX + Meteor 종단간 암호화 구현 사례
양재동 코드랩
 
모바일 디버깅
모바일 디버깅모바일 디버깅
모바일 디버깅yongwoo Jeon
 
Devfest
DevfestDevfest
Devfest
yongwoo Jeon
 
EcmaScript6(2015) Overview
EcmaScript6(2015) OverviewEcmaScript6(2015) Overview
EcmaScript6(2015) Overview
yongwoo Jeon
 
Laravel 로 배우는 서버사이드 #5
Laravel 로 배우는 서버사이드 #5Laravel 로 배우는 서버사이드 #5
Laravel 로 배우는 서버사이드 #5
성일 한
 
Web Components 101 polymer & brick
Web Components 101 polymer & brickWeb Components 101 polymer & brick
Web Components 101 polymer & brickyongwoo Jeon
 
CF Korea Meetup - Spring Cloud Services
CF Korea Meetup - Spring Cloud ServicesCF Korea Meetup - Spring Cloud Services
CF Korea Meetup - Spring Cloud Services
Jay Lee
 
내가 환경을 노래하는 이유 | 정욱재 노리플라이
내가 환경을 노래하는 이유 | 정욱재 노리플라이내가 환경을 노래하는 이유 | 정욱재 노리플라이
내가 환경을 노래하는 이유 | 정욱재 노리플라이
cbs15min
 
Data-binding AngularJS
Data-binding AngularJSData-binding AngularJS
Data-binding AngularJS
EunYoung Kim
 
XECon2015 :: [2-2] 박상현 - React로 개발하는 SPA 실무 이야기
XECon2015 :: [2-2] 박상현 - React로 개발하는 SPA 실무 이야기XECon2015 :: [2-2] 박상현 - React로 개발하는 SPA 실무 이야기
XECon2015 :: [2-2] 박상현 - React로 개발하는 SPA 실무 이야기
XpressEngine
 
안정적인 서비스 운영 2013.08
안정적인 서비스 운영   2013.08안정적인 서비스 운영   2013.08
안정적인 서비스 운영 2013.08
Changyol BAEK
 
FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6
Dmitry Soshnikov
 

Viewers also liked (20)

2016 W3C Conference #1 : 웹 개발의 현재와 미래
2016 W3C Conference #1 : 웹 개발의 현재와 미래2016 W3C Conference #1 : 웹 개발의 현재와 미래
2016 W3C Conference #1 : 웹 개발의 현재와 미래
 
2016 W3C Conference #7 : Electron, 웹 기술로 담아내는 데스크톱 애플리케이션
2016 W3C Conference #7 : Electron, 웹 기술로 담아내는 데스크톱 애플리케이션2016 W3C Conference #7 : Electron, 웹 기술로 담아내는 데스크톱 애플리케이션
2016 W3C Conference #7 : Electron, 웹 기술로 담아내는 데스크톱 애플리케이션
 
2016 W3C Conference #9 : 컨테이너와 웹 어플리케이션
2016 W3C Conference #9 : 컨테이너와 웹 어플리케이션2016 W3C Conference #9 : 컨테이너와 웹 어플리케이션
2016 W3C Conference #9 : 컨테이너와 웹 어플리케이션
 
2016 W3C Conference #2 : VANILA JS로 개발하기
2016 W3C Conference #2 : VANILA JS로 개발하기2016 W3C Conference #2 : VANILA JS로 개발하기
2016 W3C Conference #2 : VANILA JS로 개발하기
 
2016 W3C Conference #5 : UNIVERSAL RENDERING (React.JS 중심)
2016 W3C Conference #5 : UNIVERSAL RENDERING (React.JS 중심)2016 W3C Conference #5 : UNIVERSAL RENDERING (React.JS 중심)
2016 W3C Conference #5 : UNIVERSAL RENDERING (React.JS 중심)
 
2016 W3C Conference #8 : IONIC으로 하이브리드 앱 개발하기, 사례와 시사점
2016 W3C Conference #8 : IONIC으로 하이브리드 앱 개발하기, 사례와 시사점2016 W3C Conference #8 : IONIC으로 하이브리드 앱 개발하기, 사례와 시사점
2016 W3C Conference #8 : IONIC으로 하이브리드 앱 개발하기, 사례와 시사점
 
2016 ABCD 소개
2016 ABCD 소개2016 ABCD 소개
2016 ABCD 소개
 
2016 W3C Conference #6 : ReactiveX + Meteor 종단간 암호화 구현 사례
2016 W3C Conference #6 : ReactiveX + Meteor 종단간 암호화 구현 사례2016 W3C Conference #6 : ReactiveX + Meteor 종단간 암호화 구현 사례
2016 W3C Conference #6 : ReactiveX + Meteor 종단간 암호화 구현 사례
 
모바일 디버깅
모바일 디버깅모바일 디버깅
모바일 디버깅
 
Devfest
DevfestDevfest
Devfest
 
Web component
Web componentWeb component
Web component
 
EcmaScript6(2015) Overview
EcmaScript6(2015) OverviewEcmaScript6(2015) Overview
EcmaScript6(2015) Overview
 
Laravel 로 배우는 서버사이드 #5
Laravel 로 배우는 서버사이드 #5Laravel 로 배우는 서버사이드 #5
Laravel 로 배우는 서버사이드 #5
 
Web Components 101 polymer & brick
Web Components 101 polymer & brickWeb Components 101 polymer & brick
Web Components 101 polymer & brick
 
CF Korea Meetup - Spring Cloud Services
CF Korea Meetup - Spring Cloud ServicesCF Korea Meetup - Spring Cloud Services
CF Korea Meetup - Spring Cloud Services
 
내가 환경을 노래하는 이유 | 정욱재 노리플라이
내가 환경을 노래하는 이유 | 정욱재 노리플라이내가 환경을 노래하는 이유 | 정욱재 노리플라이
내가 환경을 노래하는 이유 | 정욱재 노리플라이
 
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 실무 이야기
 
안정적인 서비스 운영 2013.08
안정적인 서비스 운영   2013.08안정적인 서비스 운영   2013.08
안정적인 서비스 운영 2013.08
 
FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6
 

Similar to 2016 W3C Conference #4 : ANGULAR + ES6

Solving anything in VCL
Solving anything in VCLSolving anything in VCL
Solving anything in VCL
Fastly
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API's
Antônio Roberto Silva
 
Live deployment, ci, drupal
Live deployment, ci, drupalLive deployment, ci, drupal
Live deployment, ci, drupal
Andrii Podanenko
 
Building and deploying React applications
Building and deploying React applicationsBuilding and deploying React applications
Building and deploying React applications
Astrails
 
Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2
markstory
 
Capistrano
CapistranoCapistrano
Capistrano
Jason Noble
 
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
Igor Bronovskyy
 
Introduction to angular js
Introduction to angular jsIntroduction to angular js
Introduction to angular js
Marco Vito Moscaritolo
 
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 202010 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
Matt Raible
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gears
dion
 
(DEV204) Building High-Performance Native Cloud Apps In C++
(DEV204) Building High-Performance Native Cloud Apps In C++(DEV204) Building High-Performance Native Cloud Apps In C++
(DEV204) Building High-Performance Native Cloud Apps In C++
Amazon Web Services
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
Francois Zaninotto
 
Patterns Are Good For Managers
Patterns Are Good For ManagersPatterns Are Good For Managers
Patterns Are Good For Managers
AgileThought
 
Angular JS deep dive
Angular JS deep diveAngular JS deep dive
Angular JS deep dive
Axilis
 
Railsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshareRailsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshare
tomcopeland
 
Real World Lessons on the Pain Points of Node.JS Application
Real World Lessons on the Pain Points of Node.JS ApplicationReal World Lessons on the Pain Points of Node.JS Application
Real World Lessons on the Pain Points of Node.JS Application
Ben Hall
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
Yekmer Simsek
 
Developing web-apps like it's 2013
Developing web-apps like it's 2013Developing web-apps like it's 2013
Developing web-apps like it's 2013
Laurent_VB
 
MinbilDinbil Django Speed Tricks
MinbilDinbil Django Speed TricksMinbilDinbil Django Speed Tricks
MinbilDinbil Django Speed Tricks
Lorenzo Setale
 
Slaven tomac unit testing in angular js
Slaven tomac   unit testing in angular jsSlaven tomac   unit testing in angular js
Slaven tomac unit testing in angular js
Slaven Tomac
 

Similar to 2016 W3C Conference #4 : ANGULAR + ES6 (20)

Solving anything in VCL
Solving anything in VCLSolving anything in VCL
Solving anything in VCL
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API's
 
Live deployment, ci, drupal
Live deployment, ci, drupalLive deployment, ci, drupal
Live deployment, ci, drupal
 
Building and deploying React applications
Building and deploying React applicationsBuilding and deploying React applications
Building and deploying React applications
 
Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2
 
Capistrano
CapistranoCapistrano
Capistrano
 
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
 
Introduction to angular js
Introduction to angular jsIntroduction to angular js
Introduction to angular js
 
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 202010 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gears
 
(DEV204) Building High-Performance Native Cloud Apps In C++
(DEV204) Building High-Performance Native Cloud Apps In C++(DEV204) Building High-Performance Native Cloud Apps In C++
(DEV204) Building High-Performance Native Cloud Apps In C++
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
Patterns Are Good For Managers
Patterns Are Good For ManagersPatterns Are Good For Managers
Patterns Are Good For Managers
 
Angular JS deep dive
Angular JS deep diveAngular JS deep dive
Angular JS deep dive
 
Railsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshareRailsconf2011 deployment tips_for_slideshare
Railsconf2011 deployment tips_for_slideshare
 
Real World Lessons on the Pain Points of Node.JS Application
Real World Lessons on the Pain Points of Node.JS ApplicationReal World Lessons on the Pain Points of Node.JS Application
Real World Lessons on the Pain Points of Node.JS Application
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
 
Developing web-apps like it's 2013
Developing web-apps like it's 2013Developing web-apps like it's 2013
Developing web-apps like it's 2013
 
MinbilDinbil Django Speed Tricks
MinbilDinbil Django Speed TricksMinbilDinbil Django Speed Tricks
MinbilDinbil Django Speed Tricks
 
Slaven tomac unit testing in angular js
Slaven tomac   unit testing in angular jsSlaven tomac   unit testing in angular js
Slaven tomac unit testing in angular js
 

Recently uploaded

A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
sonjaschweigert1
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
DianaGray10
 
How to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For FlutterHow to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For Flutter
Daiki Mogmet Ito
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
Matthew Sinclair
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
Aftab Hussain
 
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AIEnchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Vladimir Iglovikov, Ph.D.
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
DianaGray10
 
Microsoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdfMicrosoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdf
Uni Systems S.M.S.A.
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
Neo4j
 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
Kari Kakkonen
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
KatiaHIMEUR1
 
Data structures and Algorithms in Python.pdf
Data structures and Algorithms in Python.pdfData structures and Algorithms in Python.pdf
Data structures and Algorithms in Python.pdf
TIPNGVN2
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
Neo4j
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Paige Cruz
 
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with SlackLet's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
shyamraj55
 
Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...
Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...
Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...
Zilliz
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
名前 です男
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
Zilliz
 
Large Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial ApplicationsLarge Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial Applications
Rohit Gautam
 

Recently uploaded (20)

A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
 
How to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For FlutterHow to use Firebase Data Connect For Flutter
How to use Firebase Data Connect For Flutter
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
 
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AIEnchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
 
Microsoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdfMicrosoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdf
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
 
Data structures and Algorithms in Python.pdf
Data structures and Algorithms in Python.pdfData structures and Algorithms in Python.pdf
Data structures and Algorithms in Python.pdf
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
GraphSummit Singapore | Neo4j Product Vision & Roadmap - Q2 2024
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
 
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with SlackLet's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
Let's Integrate MuleSoft RPA, COMPOSER, APM with AWS IDP along with Slack
 
Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...
Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...
Introducing Milvus Lite: Easy-to-Install, Easy-to-Use vector database for you...
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
 
Large Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial ApplicationsLarge Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial Applications
 

2016 W3C Conference #4 : ANGULAR + ES6

  • 2. • 전 삼성SDS 선임 • TV플랫폼 JavaScript 어플리케이션 구현 • 리테일 솔루션 서버 & 프론트엔드 구현 • 프리랜서 개발자 • han41858.tistory.com 블로그 운영 • Angular 2 번역서 집필중 • GDG Korea Web Tech 운영진 한장현 (Janghyun Han) 2
  • 3. 3
  • 5. • 마술 같은 2-way binding • HTML 표준을 기반으로 기능 확장 • 체계적인 컴포넌트, Web Component로 가는 길 • Front-end 전체를 커버하는 프레임워크 • Google 에서 관리, 개선 • 풍부한 사용자 삽질 경험 Angular를 쓰는 이유 5
  • 7. • 간단해지는 코드, syntax sugar • 클래스, 상속, 모듈 구성 ⇒ 아키텍처 진화 • 브라우저들 지원 계속 • 결국엔 표준, transpiler는 거쳐갈 뿐 ES6를 쓰는 이유 7
  • 8. 8
  • 9. ES6ES5 script src <script src="bundle.js"></script> "devDependencies": { "angular": "^1.5.8", "babel-cli": "^6.18.0", "babel-loader": "^6.2.7", "babel-preset-es2015": "^6.18.0", "webpack": "^1.13.3" } <script src="angular.js"></script> <script src="index.js"></script> "devDependencies": { "angular": "^1.5.8" } 9
  • 10. index.js ES6ES5 (function () { var ngApp = angular.module('angular1es5', []); })(); import angular from 'angular'; (() => { const ngApp = angular.module('angular1es6', []); })(); 10
  • 11. Webpack // this is ES5 var webpack = require('webpack'); module.exports = { entry : [ './index.js' ], output : { filename : 'build/bundle.js', sourceMapFilename: '[name].map' }, module : { loaders : [ { test : /.js$/, loader : 'babel?presets[]=es2015 exclude : /node_modules/ }, { test : /.pug$/, loader : 'pug-loader', exclude : /node_modules/ } ] }, plugins : [ // new webpack.optimize.UglifyJsPlugin({minimize: true}) ] }; webpack.config.js "devDependencies": { "angular": "^1.5.8", "angular-route": "^1.5.8", "babel-cli": "^6.18.0", "babel-loader": "^6.2.7", "babel-preset-es2015": "^6.18.0", "file-loader": "^0.9.0", "pug": "^2.0.0-beta6", "pug-loader": "^2.3.0", "webpack": "^1.13.3", "webpack-dev-server": "^1.16.2" } package.json 11
  • 12. export default class HomeCtrl { constructor () { console.log('HomeCtrl.constructor()'); } } /view/homeCtrl.js p this is home /view/home.pug import angular from 'angular'; import ngRoute from 'angular-route'; import HomeCtrl from './view/homeCtrl'; const main = () => { console.log('main()'); const ngApp = angular.module('angular1es6', ['ngRoute']); ngApp.config(($routeProvider, $locationProvider) => { console.log('this is angular config'); $routeProvider .when('/', { template : require('./view/home.pug'), controller : 'HomeCtrl', controllerAs : 'Ctrl' }) .otherwise({ redirectTo : '/' }); // need to angular.js routing $locationProvider.html5Mode({ enabled : true, requireBase : false }); }); ngApp.controller('HomeCtrl', HomeCtrl); }; main(); index.js + ngRoute 12
  • 14. ngApp.directive('CustomDirective', () => new CustomDirective); ngApp.filter('groupBy', GroupBy); ngApp.service('CustomSvc', CustomSvc); ngApp.controller('CustomCtrl', CustomCtrl); Angular Components ngApp.directive('CustomDirective', CustomDirective); ngApp.filter('groupBy', GroupBy); ngApp.service('CustomSvc', CustomSvc); ngApp.controller('CustomCtrl', CustomCtrl); function Class new Class 14
  • 15. Filter ES6ES5 ngApp.filter('uppercase', uppercase); function uppercase () { return function (item) { return item.toUpperCase(); }; } <script src="uppercase.filter.js"></script> const uppercase = () => { return (input) => { return input.toUpperCase(); }; }; export default uppercase; import uppercase from './uppercase.filter'; ngApp.filter('uppercase', uppercase); 15
  • 16. .ctrlRoot p this is home ctrl p {{ Ctrl.title }} button(ng-click="Ctrl.select()") Select export default class HomeCtrl { constructor () { console.log('HomeCtrl.constructor()'); this.title = 'this is title'; } select () { console.log('HomeCtrl.select()'); } } $routeProvider .when('/', { template : require('./view/home.pug'), controller : 'HomeCtrl', controllerAs : 'Ctrl' }) ngApp.controller('HomeCtrl', HomeCtrl); function HomeCtrl ($scope) { console.log('home controller'); $scope.title = 'this is title'; $scope.select = function () { console.log('HomeCtrl.select()'); } } Controller ES6ES5 .ctrlRoot p this is home ctrl p {{ title }} button(ng-click="select()") Select 16
  • 17. Service ES6ES5 ngApp.service('myService', myService); <script src="./view/myService.js"></script> function myService () { this.testFnc = function () { console.log('myService.testFnc()'); }; return this; } export default class MyService { constructor () { console.log('MyService'); } testFnc () { console.log('MyService.testFnc()'); } } ngApp.service('MyService', MyService); export default class HomeCtrl { constructor (MyService) { this.MyService = MyService; } select () { this.MyService.testFnc(); } } static 있어야 할 것 같지만 없어야 함 17
  • 18. ngApp.directive('myDirective', () => new MyDirective); export default class MyDirective { constructor () { console.log('MyDirective.constructor()'); this.restrict = 'E'; this.template = '<p>message : {{ this.msg }}</p>'; this.scope = { msg : '@' }; } link (scope) { console.log(scope.msg); } } ngApp.directive('myDirective', myDirective); function myDirective () { return { restrict : 'E', template : '<p>message : {{ msg }}</p>', scope : { msg : '@' }, controller : function ($scope) { console.log('myDirective.controller()'); console.log($scope.msg); } } } <script src="myDirective.js"></script> Directive ES6ES5 directive 등록할 때 () => new18
  • 20. Directive vs. Component const customInput = { bindings : { model : '=' }, template : '<input ng-model="$ctrl.model"></input>', controller : function () { this.$onInit = () => { } } }; export default customInput; ngApp.component('customInput', customInput);ngApp.directive('customInput', () => new customInput); export default class customInput { constructor () { this.restrict = 'E'; this.scope = { model : '=' }; this.template = '<input ng-model="model"></input>'; } controller () { } } 20
  • 21. static delete (param) { const self = this; return util.objValidate(param, { userID : Constants.TYPE.EMAIL }, Constants.ERROR.USER_CTRL.NO_PARAMETER, log, 'delete()') .then(param => self.isExists(param)) .then(param => { // delete records return recordCtrl.deleteAll({ userID : param.userID }) .then(() => { log('remove records ok'); // param 자체를 다시 돌려주기 위해 Promise 필요 return Promise.resolve(param); }); }) .then(param => { // delete cards return cardCtrl.deleteAll({ userID : param.userID }) .then(() => { log('remove cards ok'); return Promise.resolve(param); }); }) .then(param => { // delete assets return assetCtrl.deleteAll({ userID : param.userID }) .then(() => { log('remove assets ok'); return Promise.resolve(param); }); }) .then(param => { // delete user return User.remove({ userID : param.userID }) .then(() => { return Promise.resolve(param); }, error => { log(error); return Promise.reject(new ERROR(Constants.ERROR.MONGOOSE.REMOVE_FAILED, log, 'delete()')); }); }) .then(param => { log(`delete ok : ${param.userID}`); return Promise.resolve(true); }); } Promise 21
  • 22. ngApp.config(($routeProvider, $locationProvider) => { // include styles require('./view/home.styl'); $routeProvider .when('/', { template : require('./view/home.pug'), controller : 'HomeCtrl', controllerAs : 'Ctrl' }) .otherwise({ redirectTo : '/' }); }); 배포 : webpack import가 아니므로 require 22
  • 23. Angular 1 + ES6 + BDD = Hell 23
  • 24. describe('homeCtrl.test', () => { it('module import', () => { expect(true).to.be.true; }); }); λ karma start (node:7564) DeprecationWarning: Using Buffer without `new` will soon stop working. Use `new Buffer()`, or preferably `Buffer.from()`, `Buffer.allocUnsafe()` or `Buffer.alloc()` instead. 18 11 2016 02:53:45.852:INFO [framework.browserify]: bundle built 18 11 2016 02:53:45.941:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/ 18 11 2016 02:53:45.941:INFO [launcher]: Launching browser Chrome with unlimited concurrency 18 11 2016 02:53:45.952:INFO [launcher]: Starting browser Chrome 18 11 2016 02:53:47.283:INFO [Chrome 54.0.2840 (Windows 10 0.0.0)]: Connected on socket /#AjAqCwTlrwmVmV_sAAAA with id 16857313 Chrome 54.0.2840 (Windows 10 0.0.0): Executed 1 of 1 SUCCESS (0.005 secs / 0.001 secs) BDD 시작 24
  • 25. λ karma start (node:12196) DeprecationWarning: Using Buffer without `new` will soon stop working. Use `new Buffer()`, or preferably `Buffer.from()`, `Buffer.allocUnsafe()` or `Buffer.alloc()` instead. 18 11 2016 02:19:10.237:INFO [framework.browserify]: bundle built 18 11 2016 02:19:10.343:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/ 18 11 2016 02:19:10.343:INFO [launcher]: Launching browser Chrome with unlimited concurrency 18 11 2016 02:19:10.353:INFO [launcher]: Starting browser Chrome 18 11 2016 02:19:11.676:INFO [Chrome 54.0.2840 (Windows 10 0.0.0)]: Connected on socket /#sBpP4RL0XFZAwPtxAAAA with id 52822107 Chrome 54.0.2840 (Windows 10 0.0.0) ERROR Uncaught SyntaxError: Unexpected token import at test/homeCtrl.test.js:1 import HomeCtrl from '../view/homeCtrl'; describe('homeCtrl.test', () => { it('module import', () => { console.log(HomeCtrl); expect(true).to.be.true; expect(HomeCtrl).to.be.ok; }); }); λ karma start (node:11580) DeprecationWarning: Using Buffer without `new` will soon stop working. Use `new Buffer()`, or preferably `Buffer.from()`, `Buffer.allocUnsafe()` or `Buffer.alloc()` instead. 18 11 2016 02:31:24.248:INFO [framework.browserify]: bundle built 18 11 2016 02:31:24.339:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/ 18 11 2016 02:31:24.339:INFO [launcher]: Launching browser Chrome with unlimited concurrency 18 11 2016 02:31:24.349:INFO [launcher]: Starting browser Chrome 18 11 2016 02:31:25.657:INFO [Chrome 54.0.2840 (Windows 10 0.0.0)]: Connected on socket /#pvpyGrXqq2TZPTgmAAAA with id 30236974 LOG: class HomeCtrl { ... } Chrome 54.0.2840 (Windows 10 0.0.0): Executed 1 of 1 SUCCESS (0.007 secs / 0.002 secs) babel : node6 λ karma start (node:13196) DeprecationWarning: Using Buffer without `new` will soon stop working. Use `new Buffer()`, or preferably `Buffer.from()`, `Buffer.allocUnsafe()` or `Buffer.alloc()` instead. 18 11 2016 02:58:38.638:INFO [framework.browserify]: bundle built 18 11 2016 02:58:38.728:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/ 18 11 2016 02:58:38.729:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency 18 11 2016 02:58:38.738:INFO [launcher]: Starting browser PhantomJS 18 11 2016 02:58:40.301:INFO [PhantomJS 2.1.1 (Windows 8 0.0.0)]: Connected on socket /#JeRwavdozVZCC8HJAAAA with id 75347319 LOG: function HomeCtrl(MyService) { ... } PhantomJS 2.1.1 (Windows 8 0.0.0): Executed 1 of 1 SUCCESS (0.008 secs / 0.001 secs) babel : es2015 ES6가 돌지 않는다… + 25
  • 26. var $httpBackend; beforeEach(function () { module('angular1es5'); inject(function (_$httpBackend_) { $httpBackend = _$httpBackend_; }); }); module 선언, injection 불가 ES6ES5 const $injector, $httpBackend; beforeEach(() => { $injector = angular.injector(['angular1es6']); $httpBackend = $injector.get('$httpBackend'); }); Object is not a constructor (evaluating 'module('angular1es6')') r:/temp/test/homeCtrl.test.js:15:9 <- R:/temp/3871fde1c6cf6c302eeae7add18a3b02.browserify:22:9 26
  • 27. ngMock vs. ngMockE2E The ngMock module provides support to inject and mock Angular services into unit tests. In addition, ngMock also extends various core ng services such that they can be inspected and controlled in a synchronous manner within test code. The ngMockE2E is an angular module which contains mocks suitable for end-to-end testing. Currently there is only one mock present in this module - the e2e $httpBackend mock. ngMock ngMockE2E Fake HTTP backend implementation suitable for end-to- end testing or backend-less development of applications that use the $http service. Fake HTTP backend implementation suitable for unit testing applications that use the $http service. .when() .expect() .flush() .verifyNoOutstandingExpectation() .verifyNoOutstandingRequest() .resetExpectations() .when() ngMockE2E에는 $location 없음 27
  • 28. Promise + http.flush() Chrome 54.0.2840 (Windows 10 0.0.0) homeCtrl.test http test ok FAILED Error: No pending request to flush ! at Function.$httpBackend.flush (node_modules/angular-mocks/angular-mocks.js:1799:34) at r:/temp/test/homeCtrl.test.js:36:17 promise 함수로 부르면 동작 안함 flush() 타이밍 달라짐 flush는 Util에서 수행 const $injector = angular.injector(['angular1es6']); const $httpBackend = $injector.get('$httpBackend'); const $http = $injector.get('$http'); beforeEach(() => { $httpBackend.expectGET('/test') .respond(['this', 'is', 'GET', 'test', 'data']); }); it('ok', () => { return new Promise(resolve => { $http.get('/test').then(result => { console.log('get().then()'); console.log(result); console.log(result.data); resolve(true); }); $httpBackend.flush(); }); }); 동작하는 코드 static post (uri, param, config) { // use new promise for flush() return new Promise((resolve, reject) => { this.http.post(uri, param, config) .then(result => { resolve(result); }, error => { console.error(error); reject(false); }); if (this.httpBackend && this.httpBackend.flush) { this.httpBackend.flush(); } }); } it('ok', () => { return new Promise(resolve => { Promise.resolve() .then(() => { $http.get('/test').then(result => { console.log('get().then()'); console.log(result); console.log(result.data); resolve(true); }); }); $httpBackend.flush(); }); }); 28
  • 29. 여러 test 파일 동시 실행 const $injector = angular.injector(['angular1es6']); const $httpBackend = $injector.get('$httpBackend'); const $http = $injector.get('$http'); Chrome 54.0.2840 (Windows 10 0.0.0) SignInCtrl test logic submit() with ajax error response response error test FAILED AssertionError: expected [Error: Unexpected request: POST /api/user/signIn No more request expected] to be an instance of ERROR Chrome 54.0.2840 (Windows 10 0.0.0) SignUpCtrl test logic submit() error response response error test FAILED AssertionError: expected [Error: [$rootScope:inprog] $digest already in progress const ngApp = angular.module(appName, ['ngMock']); // working with $location, but not $httpBackend.whenPOST()... var $injector = angular.injector(['MoneyBook']); const $httpBackend = $injector.get('$httpBackend'); const $http = $injector.get('$http'); ClientUtil.http = $http; ClientUtil.httpBackend = $httpBackend; 29
  • 30. 생성자 안에서 Promise export default class HomeCtrl { constructor () { console.log('HomeCtrl.constructor()'); Promise.resolve(() => { // do something }); } } describe('constructor()', () => { it('ok', () => { // expect what...? }); }); export default class HomeCtrl { constructor () { console.log('HomeCtrl.constructor()'); this.somethingPromise(); } somethingPromise(){ return Promise.resolve() .then() => { // do something }); } } 30
  • 31. Promise + $scope.$apply() export default class HomeCtrl { constructor () { console.log('HomeCtrl.constructor()'); this.count = 0; } select () { console.log('HomeCtrl.select()'); return Promise.resolve() .then(() => { this.count++; }); } } export default class HomeCtrl { constructor ($scope) { console.log('HomeCtrl.constructor()'); this.$scope = $scope; this.count = 0; } select () { console.log('HomeCtrl.select()'); return Promise.resolve() .then(() => { this.count++; this.$scope.$apply(); }); } } 31