Modern Web Developement
Transcript of Modern Web Developement
Pros Cons
Cross browser API
Powerful DOM queries
OOTB Ajax
Plugins system
Tight coupling with HTML tags
Tracking DOM events is hard
Misleading API("on" might be on or delegate, it depends)
Slow
Pros Cons
Cross browser API
Powerful DOM queries
OOTB Ajax, PJax, etc.
Plugins system
Traversing DOM was slow
Some of the modules were crappy
Tried to provide everything
Contributing was hardLoading modules
WidgetsApp framework
Designed to serve the old browsers
Pros Cons
Two way data binding
Declarative HTML
Complex conceptsSlow dirty checkingLogic everywhere
Client-side framework(rendering on the server is possible, but tricky)
They invented Karma :)
Pros Cons
True MVC pattern
Templating system based on Handlebars
A lot of black magicContext switchingComplicated two-way data binding
Pros Cons
Minimal (view part only)
One-way data flow
Requires change of mindset
Simple concepts
Fast (60 fps)
Isomorphic applications, client-side applications, native applications
Abolishes the rules made of stone
REACT
ES6 & 7 main features
Classes
Modules importing
Syntactic sugar over functions
Class and properties decorators (annotations)
Variables and constants
Block scoping
Built-in Promises
Template strings
Default function parameter values
Function generators
Symbols
Proxies … more here
ES6 & 7 main features
EcmaScript 6 and 7 in action
1 import screwdriver from '/tools/bag'; 2 import pliers from '/tools/bag'; 3 import Visible from '/state/Visible'; 4 import {Attribute as attr} from '/attributes/Attribute'; 5 6 @Visible 7 class Component extends Base { 8 constructor() { 9 super(); 10 } 11 12 helloWorld() { 13 return { 14 myProp: () => { return 'Hello World!';} 15 }; 16 } 17 18 @attr 19 prop1 = 23; 20 } 21 22 export default Some;
EcmaScript 6 and 7 in action
1 import screwdriver from '/tools/bag'; 2 import pliers from '/tools/bag'; 3 import Visible from '/state/Visible'; 4 import {Attribute as attr} from '/attributes/Attribute'; 5 6 @Visible 7 class Component extends Base { 8 constructor() { 9 super(); 10 } 11 12 helloWorld() { 13 return { 14 myProp: () => { return 'Hello World!';} 15 }; 16 } 17 18 @attr 19 prop1 = 23; 20 } 21 22 export default Some;
Imports
EcmaScript 6 and 7 in action
1 import screwdriver from '/tools/bag'; 2 import pliers from '/tools/bag'; 3 import Visible from '/state/Visible'; 4 import {Attribute as attr} from '/attributes/Attribute'; 5 6 @Visible 7 class Component extends Base { 8 constructor() { 9 super(); 10 } 11 12 helloWorld() { 13 return { 14 myProp: () => { return 'Hello World!';} 15 }; 16 } 17 18 @attr 19 prop1 = 23; 20 } 21 22 export default Some;
Classannotations
EcmaScript 6 and 7 in action
1 import screwdriver from '/tools/bag'; 2 import pliers from '/tools/bag'; 3 import Visible from '/state/Visible'; 4 import {Attribute as attr} from '/attributes/Attribute'; 5 6 @Visible 7 class Component extends Base { 8 constructor() { 9 super(); 10 } 11 12 helloWorld() { 13 return { 14 myProp: () => { return 'Hello World!';} 15 }; 16 } 17 18 @attr 19 prop1 = 23; 20 } 21 22 export default Some;
Classes
EcmaScript 6 and 7 in action
1 import screwdriver from '/tools/bag'; 2 import pliers from '/tools/bag'; 3 import Visible from '/state/Visible'; 4 import {Attribute as attr} from '/attributes/Attribute'; 5 6 @Visible 7 class Component extends Base { 8 constructor() { 9 super(); 10 } 11 12 helloWorld() { 13 return { 14 myProp: () => { return 'Hello World!';} 15 }; 16 } 17 18 @attr 19 prop1 = 23; 20 } 21 22 export default Some;
Inheritance
EcmaScript 6 and 7 in action
1 import screwdriver from '/tools/bag'; 2 import pliers from '/tools/bag'; 3 import Visible from '/state/Visible'; 4 import {Attribute as attr} from '/attributes/Attribute'; 5 6 @Visible 7 class Component extends Base { 8 constructor() { 9 super(); 10 } 11 12 helloWorld() { 13 return { 14 myProp: () => { return 'Hello World!';} 15 }; 16 } 17 18 @attr 19 prop1 = 23; 20 } 21 22 export default Some;
Functions
EcmaScript 6 and 7 in action
1 import screwdriver from '/tools/bag'; 2 import pliers from '/tools/bag'; 3 import Visible from '/state/Visible'; 4 import {Attribute as attr} from '/attributes/Attribute'; 5 6 @Visible 7 class Component extends Base { 8 constructor() { 9 super(); 10 } 11 12 helloWorld() { 13 return { 14 myProp: () => { return 'Hello World!';} 15 }; 16 } 17 18 @attr 19 prop1 = 23; 20 } 21 22 export default Some;
Fat arrows
EcmaScript 6 and 7 in action
1 import screwdriver from '/tools/bag'; 2 import pliers from '/tools/bag'; 3 import Visible from '/state/Visible'; 4 import {Attribute as attr} from '/attributes/Attribute'; 5 6 @Visible 7 class Component extends Base { 8 constructor() { 9 super(); 10 } 11 12 helloWorld() { 13 return { 14 myProp: () => { return 'Hello World!';} 15 }; 16 } 17 18 @attr 19 prop1 = 23; 20 } 21 22 export default Some;
Props annotations
EcmaScript 6 and 7 in action
1 import screwdriver from '/tools/bag'; 2 import pliers from '/tools/bag'; 3 import Visible from '/state/Visible'; 4 import {Attribute as attr} from '/attributes/Attribute'; 5 6 @Visible 7 class Component extends Base { 8 constructor() { 9 super(); 10 } 11 12 helloWorld() { 13 return { 14 myProp: () => { return 'Hello World!';} 15 }; 16 } 17 18 @attr 19 prop1 = 23; 20 } 21 22 export default Some;
Classproperties
EcmaScript 6 and 7 in action
1 import screwdriver from '/tools/bag'; 2 import pliers from '/tools/bag'; 3 import Visible from '/state/Visible'; 4 import {Attribute as attr} from '/attributes/Attribute'; 5 6 @Visible 7 class Component extends Base { 8 constructor() { 9 super(); 10 } 11 12 helloWorld() { 13 return { 14 myProp: () => { return 'Hello World!';} 15 }; 16 } 17 18 @attr 19 prop1 = 23; 20 } 21 22 export default Some;
Module exports
React like libraries/frameworks
Cyclejs
r-js
Copernicium
jFlux
vbridge
Tungsten.js
Cape.js
… more here
Plenty of Virtual DOM implementations
A lot of on GitHub
as part of framework/library or just like a module
Let’s implement Drag&Drop
1 var dragTarget = document.getElementById('dragTarget'); 2 3 var mousedown = Observable.fromEvent(dragTarget, 'mousedown'); 4 var mousemove = Observable.fromEvent(document, 'mousemove'); 5 var mouseup = Observable.fromEvent(dragTarget, 'mouseup'); 6 7 var mousedrag = mousedown.flatMap(function(mousedown) { 8 var startX = mousedown.offsetX, 9 startY = mousedown.offsetY; 10 11 return mousemove.map(function(mousemove) { 12 mousemove.preventDefault(); 13 14 return { 15 left: mousemove.clientX - startX, 16 top: mousemove.clientY - startY 17 }; 18 }).takeUntil(mouseup); 19 }); 20 21 var subscription = mousedrag.subscribe(function(pos) { 22 dragTarget.style.top = pos.top + 'px'; 23 dragTarget.style.left = pos.left + 'px'; 24 });
Let’s implement Drag&Drop
1 var dragTarget = document.getElementById('dragTarget'); 2 3 var mousedown = Observable.fromEvent(dragTarget, 'mousedown'); 4 var mousemove = Observable.fromEvent(document, 'mousemove'); 5 var mouseup = Observable.fromEvent(dragTarget, 'mouseup'); 6 7 var mousedrag = mousedown.flatMap(function(mousedown) { 8 var startX = mousedown.offsetX, 9 startY = mousedown.offsetY; 10 11 return mousemove.map(function(mousemove) { 12 mousemove.preventDefault(); 13 14 return { 15 left: mousemove.clientX - startX, 16 top: mousemove.clientY - startY 17 }; 18 }).takeUntil(mouseup); 19 }); 20 21 var subscription = mousedrag.subscribe(function(pos) { 22 dragTarget.style.top = pos.top + 'px'; 23 dragTarget.style.left = pos.left + 'px'; 24 });
Get the drag target
Let’s implement Drag&Drop
1 var dragTarget = document.getElementById('dragTarget'); 2 3 var mousedown = Observable.fromEvent(dragTarget, 'mousedown'); 4 var mousemove = Observable.fromEvent(document, 'mousemove'); 5 var mouseup = Observable.fromEvent(dragTarget, 'mouseup'); 6 7 var mousedrag = mousedown.flatMap(function(mousedown) { 8 var startX = mousedown.offsetX, 9 startY = mousedown.offsetY; 10 11 return mousemove.map(function(mousemove) { 12 mousemove.preventDefault(); 13 14 return { 15 left: mousemove.clientX - startX, 16 top: mousemove.clientY - startY 17 }; 18 }).takeUntil(mouseup); 19 }); 20 21 var subscription = mousedrag.subscribe(function(pos) { 22 dragTarget.style.top = pos.top + 'px'; 23 dragTarget.style.left = pos.left + 'px'; 24 });
Observables from events
Let’s implement Drag&Drop
1 var dragTarget = document.getElementById('dragTarget'); 2 3 var mousedown = Observable.fromEvent(dragTarget, 'mousedown'); 4 var mousemove = Observable.fromEvent(document, 'mousemove'); 5 var mouseup = Observable.fromEvent(dragTarget, 'mouseup'); 6 7 var mousedrag = mousedown.flatMap(function(mousedown) { 8 var startX = mousedown.offsetX, 9 startY = mousedown.offsetY; 10 11 return mousemove.map(function(mousemove) { 12 mousemove.preventDefault(); 13 14 return { 15 left: mousemove.clientX - startX, 16 top: mousemove.clientY - startY 17 }; 18 }).takeUntil(mouseup); 19 }); 20 21 var subscription = mousedrag.subscribe(function(pos) { 22 dragTarget.style.top = pos.top + 'px'; 23 dragTarget.style.left = pos.left + 'px'; 24 });
Process these as arrays
Let’s implement Drag&Drop
1 var dragTarget = document.getElementById('dragTarget'); 2 3 var mousedown = Observable.fromEvent(dragTarget, 'mousedown'); 4 var mousemove = Observable.fromEvent(document, 'mousemove'); 5 var mouseup = Observable.fromEvent(dragTarget, 'mouseup'); 6 7 var mousedrag = mousedown.flatMap(function(mousedown) { 8 var startX = mousedown.offsetX, 9 startY = mousedown.offsetY; 10 11 return mousemove.map(function(mousemove) { 12 mousemove.preventDefault(); 13 14 return { 15 left: mousemove.clientX - startX, 16 top: mousemove.clientY - startY 17 }; 18 }).takeUntil(mouseup); 19 }); 20 21 var subscription = mousedrag.subscribe(function(pos) { 22 dragTarget.style.top = pos.top + 'px'; 23 dragTarget.style.left = pos.left + 'px'; 24 });
Map mouse move
Let’s implement Drag&Drop
1 var dragTarget = document.getElementById('dragTarget'); 2 3 var mousedown = Observable.fromEvent(dragTarget, 'mousedown'); 4 var mousemove = Observable.fromEvent(document, 'mousemove'); 5 var mouseup = Observable.fromEvent(dragTarget, 'mouseup'); 6 7 var mousedrag = mousedown.flatMap(function(mousedown) { 8 var startX = mousedown.offsetX, 9 startY = mousedown.offsetY; 10 11 return mousemove.map(function(mousemove) { 12 mousemove.preventDefault(); 13 14 return { 15 left: mousemove.clientX - startX, 16 top: mousemove.clientY - startY 17 }; 18 }).takeUntil(mouseup); 19 }); 20 21 var subscription = mousedrag.subscribe(function(pos) { 22 dragTarget.style.top = pos.top + 'px'; 23 dragTarget.style.left = pos.left + 'px'; 24 });
Stop on mouse up
Let’s implement Drag&Drop
1 var dragTarget = document.getElementById('dragTarget'); 2 3 var mousedown = Observable.fromEvent(dragTarget, 'mousedown'); 4 var mousemove = Observable.fromEvent(document, 'mousemove'); 5 var mouseup = Observable.fromEvent(dragTarget, 'mouseup'); 6 7 var mousedrag = mousedown.flatMap(function(mousedown) { 8 var startX = mousedown.offsetX, 9 startY = mousedown.offsetY; 10 11 return mousemove.map(function(mousemove) { 12 mousemove.preventDefault(); 13 14 return { 15 left: mousemove.clientX - startX, 16 top: mousemove.clientY - startY 17 }; 18 }).takeUntil(mouseup); 19 }); 20 21 var subscription = mousedrag.subscribe(function(pos) { 22 dragTarget.style.top = pos.top + 'px'; 23 dragTarget.style.left = pos.left + 'px'; 24 });
Update position on mousedrag
Can be dynamically collapsed or uncollapsed along the main axis while preserving the container’s cross size.
Can be laid out in any flow direction (leftwards, rightwards, downwards, upwards)
Can have display order reversed or rearranged at the style layer (i.e., visual order can be independent of source and speech order)
Can be laid out linearly along a single (main) axis or wrapped into multiple lines along a secondary (cross) axis
Can “flex” element’s sizes to respond to the available space
Can be aligned with respect to their container or each other
Child elements in Flexbox
Webpack’s CSS Modules
MyComponent.css
1 .main { 2 border-width: 2px; 3 border-style: solid; 4 border-color: #777; 5 padding: 0 20px; 6 margin: 0 6px; 7 max-width: 400px; 8 } 9 10 .text { 11 color: #777; 12 font-size: 24px; 13 font-family: helvetica, arial, sans-serif; 14 font-weight: 600; 15 }
Webpack’s CSS Modules
MyComponent.js
1 import styles from './MyComponent.css'; 2 import React, {Component} from 'react'; 3 4 export default class MyComponent extends Component { 5 6 render() { 7 return ( 8 <div className={styles.main}> 9 <p className={styles.text}>Scoped Selectors</p> 10 </div> 11 ); 12 } 13 };
Webpack’s CSS Modules
Webpack will compile the CSS classes
prefix and isolate them so they won’t clash
1 .main { 2 border-width: 2px; 3 border-style: solid; 4 border-color: #777; 5 padding: 0 20px; 6 margin: 0 6px; 7 max-width: 400px; 8 } 9 10 .main :global p { 11 color: #777; 12 font-size: 24px; 13 font-family: helvetica, arial, sans-serif; 14 font-weight: 600; 15 }
Webpack’s CSS Modules
MyComponent.css
This will style al `p` inside the component
Webpack’s CSS Modules
MyComponent.js
1 import styles from './MyComponent.css'; 2 import React, {Component} from 'react'; 3 4 export default class MyComponent extends Component { 5 6 render() { 7 return ( 8 <div className={styles.main}> 9 <p>content</p> 10 </div> 11 ); 12 } 13 }; `p` will be styled b/c of
the global selector
Webpack’s CSS Modules
1 .container { 2 border-width: 2px; 3 border-style: solid; 4 padding: 0 20px; 5 margin: 0 6px; 6 max-width: 400px; 7 }
layout.css
Webpack’s CSS Modules
1 .main { 2 extends: container from "layout.css"; 3 border-color: red; 4 }
MyComponent.css
Pioneer.js
Feature: TODO MVC
Background:
Given I am viewing todomvc
Scenario: Adding and Completing
When I add a new todo
And I finish it
Then I should see no undone todos
Pioneer.js
1 module.exports = function() { 2 this.Given(/^I am viewing todomvc$/, function() { 3 return this.driver.visit('http://todomvc.com/architecture-examples/backbone/'); 4 }); 5 6 this.When(/^I add a new todo$/, function() { 7 return this.Widget.fill({ 8 selector: '#new-todo', 9 value: ['doge', Driver.Key.Enter] 10 }) 11 });
Pioneer.js
1 this.When(/^I finish it$/, function() { 2 return this.Widget.click({ 3 selector: '#todo-list .toggle' 4 }); 5 }); 6 return this.Then(/^I should see no undone todos$/, function() { 7 return this.Widget.read({ 8 selector: '#todo-count' 9 }).should.eventually.eql('0 items left'); 10 }); 11 };