Upload
peychevi
View
2.589
Download
0
Embed Size (px)
Citation preview
Modern Web Development
@ipeychev
Evolution of the Web frameworks and libraries
2006 2015
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
2006 2014
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
2009 2015
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 :)
2010 2015
Pros Cons
Auto-synced models via REST API
Robust event system
Bare-bones featuresjQuery like views
2011 2015
Pros Cons
True MVC pattern
Templating system based on Handlebars
A lot of black magicContext switchingComplicated two-way data binding
2013 2015
REACT
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
React in a nutshell
React in a nutshell
Library, not a framework
Implements one-way reactive data
flow
Blazingly fast
React in a nutshell
Virtual DOM
JSX
JavaScript syntax extension (JSX)
React in a nutshell
Native applications
Isomorphic applications
Client-side applications
Creating UI with React
Main UI
Nested Components
Data flow
Creating a component
Render the component
Change the state
And rendering is fast
Virtual DOM rulez
Performance
EcmaScript 6 and 7
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
What is the situation
now?
One-way directional data flow wins
Plenty of React-wanna-be frameworks and libraries
Plenty of Flux implementations
React like libraries/frameworks
Mithril
Mercury
Vue.js
Ripple.js
Riot Reactive
Cito.js
Hyperd
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
The other frameworks evolve
Ember changes to benefit from React’s ideas
Angular too
Framework evolution in the wrong way
Reactive programming
(warning - changes the mindset)
Changes the way we think about
asynchronous programming
Everything is Observable
Reactive programming
including the 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 });
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
CSSacronym for CSS Seriously Sucks ;)
Flexbox
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
Modular CSS
Every time you add CSS rule,
Global CSS sucks
you risk clashing with something else
Webpack’s CSS modules
CSS as modules,local scope by default
Webpack’s CSS Modules
The CSS for a module is isolated,
despite of class names like ‘.main’
Webpack’s CSS Modules
You can extend
and import classes
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
Webpack’s CSS Modules
Global selectors are available
(but please avoid them)
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
CSS inheritance from shared modules
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
This is CSS finally fixed
Testing
Unit tests
Karma + Mocha + Chai + Sinon
Integration/Functional tests
Pioneer.js
Nightwatch.js
Intern … more here
Pioneer.js
You write the tests in the English-like Gherkin syntax
Cucumber
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 };
Future
?
!
It is yours, work on it
Thank you!
ipeychev