Web components en 2019, on en est où?

A presentation at RivieraDev in May 2019 in Sophia Antipolis, France by Horacio Gonzalez

Slide 1

Slide 1

Web components en 2019, on en est où ? Horacio Gonzalez @LostInBrittany @LostInBrittany

Slide 2

Slide 2

Who are we? Introducing myself and introducing OVH @LostInBrittany

Slide 3

Slide 3

Horacio Gonzalez @LostInBrittany Spaniard lost in Brittany, developer, dreamer and all-around geek Flutter @LostInBrittany

Slide 4

Slide 4

OVH: A Global Leader on Cloud 200k Private cloud VMs running 1 Dedicated IaaS Europe 2018 27 Datacenters Own 15 Tbps Hosting capacity : 1.3M Physical Servers 360k Servers already deployed 2020 50 Datacenters Netwok with 35 PoPs

1.3M Customers in 138 Countries @LostInBrittany

Slide 5

Slide 5

OVH : Key Figures 1.3M Customers worldwide in 138 Countries 1.5 Billions euros investment over five years 28 Datacenters (growing) 350k Dedicated Servers 200k Private cloud VMs running 650k Public cloud Instances created in a month 20TB bandwidth capacity 35 Points of presence 4TB Anti DDoS capacity Hosting capacity : 1.3M Physical Servers @LostInBrittany

  • 2 500 Employees in 19 countries 18 Years of Innovation

Slide 6

Slide 6

Ranking & Recognition 1st European Cloud Provider* 1st Hosting provider in Europe 1st Provider Microsoft Exchange Certified vCloud Datacenter Certified Kubernetes platform (CNCF) Vmware Global Service Provider 2013-2016 Veeam Best Cloud Partner of the year (2018) @LostInBrittany

  • Netcraft 2017 -

Slide 7

Slide 7

OVH: Our solutions Cloud Web Hosting Mobile Hosting Telecom VPS Containers ▪ Dedicated Server Domain names VoIP Public Cloud Compute ▪ Data Storage Email SMS/Fax Private Cloud ▪ Network and Database CDN Virtual desktop Serveur dédié Security Object Storage Web hosting Cloud HubiC Over theBox ▪ Licences Cloud Desktop Securities MS Office Hybrid Cloud Messaging MS solutions @LostInBrittany

Slide 8

Slide 8

We want the code! https://github.com/LostInBrittany/web-components-interop @LostInBrittany

Slide 9

Slide 9

Some thoughts on tooling Because complexity matters @LostInBrittany

Slide 10

Slide 10

Web dev has become complex It seems you need lots of complex tools @LostInBrittany

Slide 11

Slide 11

But modern JavaScript makes it easy ● ● ● ● Supported almost everywhere Classes More expressive syntax Native module system @LostInBrittany

Slide 12

Slide 12

Why use tools in dev? @pika/web No bundling or transpiling needed https://www.pikapkg.com/blog/pika-web-a-future-without-webpack/ @LostInBrittany

Slide 13

Slide 13

The 3 minutes context What the heck are web component? @LostInBrittany

Slide 14

Slide 14

Web Components Web standard W3C @LostInBrittany

Slide 15

Slide 15

Web Components Available in all modern browsers: Firefox, Safari, Chrome @LostInBrittany

Slide 16

Slide 16

Web Components Create your own HTML tags Encapsulating look and behavior @LostInBrittany

Slide 17

Slide 17

Web Components Fully interoperable With other web components, with any framework @LostInBrittany

Slide 18

Slide 18

Web Components @LostInBrittany

Slide 19

Slide 19

Custom Element

<body> … <script> window.customElements.define(‘my-element’, class extends HTMLElement {…}); </script> <my-element></my-element> </body> @LostInBrittany

Slide 20

Slide 20

Shadow DOM <button>Hello, world!</button> <script> var host = document.querySelector(‘button’); const shadowRoot = host.attachShadow({mode:’open’}); shadowRoot.textContent = ‘こんにちは、影の世界!’; </script> @LostInBrittany

Slide 21

Slide 21

Template <template id=”mytemplate”> <img src=”” alt=”great image”> <div class=”comment”></div> </template> var t = document.querySelector(‘#mytemplate’); // Populate the src at runtime. t.content.querySelector(‘img’).src = ‘logo.png’; var clone = document.importNode(t.content, true); document.body.appendChild(clone); @LostInBrittany

Slide 22

Slide 22

But in fact, it’s just an element… ● ● ● ● @LostInBrittany

Slide 23

Slide 23

Sometimes I feel a bit grumpy The stories of the grumpy old speaker… @LostInBrittany

Slide 24

Slide 24

On Polymer tour since 2014 @LostInBrittany

Slide 25

Slide 25

Image: bu.edu Web components == Revolution @LostInBrittany

Slide 26

Slide 26

Images: BitRebels & Brickset Building a world brick by brick @LostInBrittany

Slide 27

Slide 27

Is the promise unfulfilled? It’s 2019 now, where is your revolution, dude? @LostInBrittany

Slide 28

Slide 28

Is it a conspiracy? @LostInBrittany

Slide 29

Slide 29

Am I only a dreamer? @LostInBrittany

Slide 30

Slide 30

Well, revolution IS there But it’s a silent one… @LostInBrittany

Slide 31

Slide 31

They are there, in everyday sites More than you can imagine @LostInBrittany

Slide 32

Slide 32

The components architecture won Components, components everywhere @LostInBrittany

Slide 33

Slide 33

Web components ARE platform Truly part of the platform… @LostInBrittany

Slide 34

Slide 34

Why those libs? Why people don’t use vanilla? @LostInBrittany

Slide 35

Slide 35

Web component standard is low level At it should be! @LostInBrittany

Slide 36

Slide 36

Standard == basic bricks Standard exposes an API to: ○ Define elements ○ Encapsulate DOM @LostInBrittany

Slide 37

Slide 37

Libraries are helpers They give you higher-level primitives @LostInBrittany

Slide 38

Slide 38

Different high-level primitives Each one tailored to a use @LostInBrittany

Slide 39

Slide 39

Sharing the same base High-performant, low-level, in-the-platform web components standard @LostInBrittany

Slide 40

Slide 40

Libraries aren’t a failure of standard They happen by design @LostInBrittany

Slide 41

Slide 41

Vanilla Web Components @LostInBrittany

Slide 42

Slide 42

A very basic web component class MyElement extends HTMLElement { // This gets called when the HTML parser sees your tag constructor() { super(); // always call super() first in the ctor. this.msg = ‘Hello, RivieraDev!’; } // Called when your element is inserted in the DOM or // immediately after the constructor if it’s already in the DOM connectedCallback() { this.innerHTML = <p>${this.msg}</p>; } } customElements.define(‘my-element’, MyElement); @LostInBrittany

Slide 43

Slide 43

Custom Elements: ● Let you define your own HTML tag with bundled JS behavior ● Trigger lifecycle callbacks ● Automatically “upgrade” your tag when inserted in the document @LostInBrittany

Slide 44

Slide 44

Custom Elements don’t: ● Scope CSS styles ○ Shadow DOM ● Scope JavaScript ○ ES2015 ● “Reproject” children into <slot> elements ○ Shadow DOM @LostInBrittany

Slide 45

Slide 45

Adding ShadowDOM class MyElementWithShadowDom extends HTMLElement { // This gets called when the HTML parser sees your tag constructor() { super(); // always call super() first in the ctor. this.msg = ‘Hello from inside the ShadowDOM, RivieraDev!’; this.attachShadow({ mode: ‘open’ }); } // Called when your element is inserted in the DOM or // immediately after the constructor if it’s already in the DOM connectedCallback() { this.shadowRoot.innerHTML = <p>${this.msg}</p>; } } customElements.define(‘my-element-with-shadowdom’, MyElementWithShadowDom); @LostInBrittany

Slide 46

Slide 46

Using web components <!doctype html> <html lang=”en”> <head> <meta charset=”utf-8”> <title>Testing basic web component</title> <style> p { color: brown; } </style> </head> <body> <my-element></my-element> <my-element-with-shadowdom></my-element-with-shadowdom> <script src=”my-element.js”></script> <script src=”my-element-with-shadowdom.js”></script> </body> </html> @LostInBrittany

Slide 47

Slide 47

Using web components @LostInBrittany

Slide 48

Slide 48

Lifecycle callbacks class MyElementLifecycle extends HTMLElement { constructor() { // Called when an instance of the element is created or upgraded super(); // always call super() first in the ctor. } static get observedAttributes() { // Tells the element which attributes to observer for changes return []; } connectedCallback() { // Called every time the element is inserted into the DOM } disconnectedCallback() { // Called every time the element is removed from the DOM. } attributeChangedCallback(attrName, oldVal, newVal) { // Called when an attribute was added, removed, or updated } adoptedCallback() { // Called if the element has been moved into a new document } } @LostInBrittany

Slide 49

Slide 49

my-counter custom element class MyCounter extends HTMLElement { constructor() { super(); this._counter = 0; this.attachShadow({ mode: ‘open’ }); } connectedCallback() { this.render(); this.display(); } static get observedAttributes() { return [‘counter’] } attributeChangedCallback(attr, oldVal, newVal) { if (oldVal !== newVal) { this[attr] = newVal; } } @LostInBrittany

Slide 50

Slide 50

my-counter custom element get counter() { return this._counter; } set counter(value) { if (value != this._counter) { this._counter = Number.parseInt(value); this.setAttribute(‘counter’, value); this.display(); } } increment() { this.counter = this.counter + 1; this.dispatchEvent(new CustomEvent( ‘increased’, { detail: { counter: this.counter } })); } @LostInBrittany

Slide 51

Slide 51

my-counter-with-templates let template = <style> ... </style> <div class="container"> <div id="icon"> <img src="../step-05/img/web-components.png"> </div> <div id="value"> 0 </div> </div>; @LostInBrittany

Slide 52

Slide 52

my-counter-with-templates render() { let templ = document.createElement(‘template’); templ.innerHTML = template; this.shadowRoot.appendChild(templ.content.cloneNode(true)); let button = this.shadowRoot.getElementById(‘icon’); button.addEventListener(‘click’, this.increment.bind(this)); } display() { console.log(this.shadowRoot.getElementById(‘value’)) this.shadowRoot.getElementById(‘value’).innerHTML = ${this.counter}; } @LostInBrittany

Slide 53

Slide 53

my-counter custom element @LostInBrittany

Slide 54

Slide 54

Let’s talk libraries What’s new? @LostInBrittany

Slide 55

Slide 55

Lot’s of players, lot of evolutions LitElement SkateJS It’s JavaScript after all… @LostInBrittany

Slide 56

Slide 56

Stencil Powering the new Ionic 4! @LostInBrittany

Slide 57

Slide 57

Not another library A Web Component compiler @LostInBrittany

Slide 58

Slide 58

Not a beta anymore Ionic 4 released, powered by Stencil! @LostInBrittany

Slide 59

Slide 59

A build time tool To generate standard web components @LostInBrittany

Slide 60

Slide 60

Fully featured ● Virtual DOM ● Async rendering ● Reactive data-binding ● TypeScript ● JSX @LostInBrittany

Slide 61

Slide 61

And the cherry on the cake Server-Side Rendering @LostInBrittany

Slide 62

Slide 62

Hands on Stencil Clone the starter project git clone https://github.com/ionic-team/stencil-app-starter my-app cd my-app git remote rm origin npm install Start a live-reload server npm start @LostInBrittany

Slide 63

Slide 63

Hands on Stencil @LostInBrittany

Slide 64

Slide 64

Hands on Stencil @LostInBrittany

Slide 65

Slide 65

Some concepts render() { return ( <div>Hello {this.name}</div> ) } render() { return ( <div>{this.name ? <p>Hello {this.name}</p> : <p>Hello World</p>}</div> ); } JSX declarative template syntax @LostInBrittany

Slide 66

Slide 66

Some concepts import { Component } from ‘@stencil/core’; @Component({ tag: ‘todo-list’, styleUrl: ‘todo-list.scss’ }) export class TodoList { @Prop() color: string; @Prop() favoriteNumber: number; @Prop() isSelected: boolean; @Prop() myHttpService: MyHttpService; } Decorators @LostInBrittany

Slide 67

Slide 67

Some concepts import { Event, EventEmitter } from ‘@stencil/core’; … export class TodoList { @Event() todoCompleted: EventEmitter; someAction(todo: Todo) { this.todoCompleted.emit(todo); } @Listen(‘todoCompleted’) todoCompletedHandler(event: CustomEvent) { console.log(‘Received the custom todoCompleted event: ‘, event.detail); } } Events @LostInBrittany

Slide 68

Slide 68

Some concepts @Component({ tag: ‘shadow-component’, styleUrl: ‘shadow-component.scss’, shadow: true }) export class ShadowComponent { } Optional Shadow DOM @LostInBrittany

Slide 69

Slide 69

Some concepts stencil.config.js exports.config = { namespace: ‘myname’, generateDistribution: true, generateWWW: false, … }; Generate distribution @LostInBrittany

Slide 70

Slide 70

Stencil import { Component, Prop, PropWillChange, State, Event, EventEmitter } from ‘@stencil/core’; @Component({ tag: ‘stencil-counter’, styleUrl: ‘stencil-counter.scss’, shadow: true }) export class StencilCounter { @Prop() counter: number; @State() currentCount: number; @Event() currentCountChanged: EventEmitter; @Watch(‘counter’) counterChanged(newValue: number) { this.currentCount = newValue; } componentWillLoad() { this.currentCount = this.counter; } increase() { this.currentCount++; this.currentCountChanged.emit({ counter: this.currentCount }); } render() { return ( <div class=”container”> <div class=”button” onClick={() => this.increase()}> <img src=”./img/stencil.png” /> </div> <div class=”value” > {this.currentCount} </div> </div> ); } } @LostInBrittany

Slide 71

Slide 71

Polymer Is the old player still alive? @LostInBrittany

Slide 72

Slide 72

Polymer has evolved in 2018 Image: © Nintendo Polymer 3 is here! @LostInBrittany

Slide 73

Slide 73

Classes, JavaScript modules… import {html, PolymerElement} from ‘/node_modules/@polymer/polymer/polymer-element.js’; class MyPolymerCounter extends PolymerElement { static get template() { <style> :host { font-size: 5rem; } button { font-size: 5rem; border-radius: 1rem; padding: 0.5rem 2rem; } </style> <button on-click=”increment”>+</button> <span>[[counter]]</span> `; } @LostInBrittany

Slide 74

Slide 74

But it’s still mostly syntactic sugar static get properties() { return { counter: { type: Number, reflectToAttribute:true, value: 0 } }; } increment() { this.counter = Number.parseInt(this.counter) + 1; this.dispatchEvent(new CustomEvent(‘increased’, {detail: {counter: this.counter}})); } } window.customElements.define(‘my-polymer-counter’, MyPolymerCounter); @LostInBrittany

Slide 75

Slide 75

And they are still custom elements 100% interoperable @LostInBrittany

Slide 76

Slide 76

Interoperation pattern <div class=”container”> <my-polymer-counter counter=”[[value]]” on-increased=”_onCounterChanged”></my-polymer-counter> <my-counter counter=”[[value]]” on-increased=”_onCounterChanged”></my-counter> </div> <div class=”container”> <div class=”value”>Shared value: [[value]]</div> </div> Attributes for data in Events for data out @LostInBrittany

Slide 77

Slide 77

What’s Polymer status today? Well, how could I say… it’s complicated @LostInBrittany

Slide 78

Slide 78

It seems it’s going to be deprecated… Technically yes… and that means good @LostInBrittany news!

Slide 79

Slide 79

Let’s try to see clearer Let’s dive into Polymer history… @LostInBrittany

Slide 80

Slide 80

A tool built for another paradigm No web component support on browsers No React, Angular or Vue innovations @LostInBrittany

Slide 81

Slide 81

No so well suited for the current one The current platform is way more powerful The state of art has evolved @LostInBrittany

Slide 82

Slide 82

Let’s learn from its lessons The current platform is way more powerful The state of art has evolved @LostInBrittany

Slide 83

Slide 83

And let it rest… There will have no Polymer 4… @LostInBrittany

Slide 84

Slide 84

So Polymer as we know it is dead… But the Polymer Project is indeed alive! @LostInBrittany

Slide 85

Slide 85

But I have invested so much on it! What to do? @LostInBrittany

Slide 86

Slide 86

That’s why web components are top You can keep using all your Polymer components and create the new ones with a new library… And it simply works! @LostInBrittany

Slide 87

Slide 87

And without metaphors? Polymer Project != Polymer library Polymer Project well alive Polymer library was only one library @LostInBrittany

Slide 88

Slide 88

Polymer Is the old player still alive? @LostInBrittany

Slide 89

Slide 89

LitElement New kid on the block @LostInBrittany

Slide 90

Slide 90

Born from the Polymer team For the new web paradigm @LostInBrittany

Slide 91

Slide 91

Modern lightweight web components For the new web paradigm @LostInBrittany

Slide 92

Slide 92

Based on lit-html An efficient, expressive, extensible HTML templating library for JavaScript @LostInBrittany

Slide 93

Slide 93

Do you know tagged templates? function uppercaseExpression(strings, …expressionValues) { var finalString = ” for ( let i = 0; i < strings.length; i++ ) { if (i > 0) { finalString += expressionValues[i - 1].toUpperCase() } finalString += strings[i] } return finalString } const expressions = [ ‘Tours’, ‘Touraine Tech’, ‘Thank you’]; console.log( uppercaseExpressionI am so happy to be in ${expressions[0]} for ${expressions[1]} again! ${expressions[2]}, ${expressions[1]}! ) Little known functionality of template literals @LostInBrittany

Slide 94

Slide 94

lit-html Templates let myTemplate = (data) => html<h1>${data.title}</h1> <p>${data.body}</p>; Lazily rendered Generates a TemplateResult @LostInBrittany

Slide 95

Slide 95

It’s a bit like JSX, isn’t it? The good sides of JSX… but in the standard! @LostInBrittany

Slide 96

Slide 96

LitElement import { LitElement, html } from ‘lit-element’; // Create your custom component class CustomGreeting extends LitElement { // Declare properties static get properties() { return { name: { type: String } }; } // Initialize properties constructor() { super(); this.name = ‘World’; } // Define a template render() { return html<p>Hello, ${this.name}!</p>; } } // Register the element with the browser customElements.define(‘custom-greeting’, CustomGreeting); Lightweight web-components using lit-html @LostInBrittany

Slide 97

Slide 97

One more thing…* *Let’s copy from the master @LostInBrittany

Slide 98

Slide 98

Polymer is not important WebComponents ARE @LostInBrittany

Slide 99

Slide 99

Use the Platform, Luke… WebComponents ARE native @LostInBrittany

Slide 100

Slide 100

Do you love your framework? Oh yeah, we all do @LostInBrittany

Slide 101

Slide 101

Would you marry your framework? Like until death… @LostInBrittany

Slide 102

Slide 102

How much does cost the divorce? Do you remember when you dropped AngularJS for Angular? @LostInBrittany

Slide 103

Slide 103

Why recode everything again? Reuse the bricks in your new framework @LostInBrittany

Slide 104

Slide 104

Lots of web components libraries LitElement SkateJS For different need and sensibilities @LostInBrittany

Slide 105

Slide 105

And some good news Angular Elements Vue Web Component Wrapper Frameworks begin to understand it @LostInBrittany

Slide 106

Slide 106

So for your next app Choose a framework, no problem… But please, help your future self Use Web Components! @LostInBrittany

Slide 107

Slide 107

Conclusion That’s all folks! @LostInBrittany