Web components en 2019, on en est où ? Horacio Gonzalez @LostInBrittany @LostInBrittany
A presentation at RivieraDev in May 2019 in Sophia Antipolis, France by Horacio Gonzalez
 
                Web components en 2019, on en est où ? Horacio Gonzalez @LostInBrittany @LostInBrittany
 
                Who are we? Introducing myself and introducing OVH @LostInBrittany
 
                Horacio Gonzalez @LostInBrittany Spaniard lost in Brittany, developer, dreamer and all-around geek Flutter @LostInBrittany
 
                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
 
                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
 
                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
 
                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
 
                We want the code! https://github.com/LostInBrittany/web-components-interop @LostInBrittany
 
                Some thoughts on tooling Because complexity matters @LostInBrittany
 
                Web dev has become complex It seems you need lots of complex tools @LostInBrittany
 
                But modern JavaScript makes it easy ● ● ● ● Supported almost everywhere Classes More expressive syntax Native module system @LostInBrittany
 
                Why use tools in dev? @pika/web No bundling or transpiling needed https://www.pikapkg.com/blog/pika-web-a-future-without-webpack/ @LostInBrittany
 
                The 3 minutes context What the heck are web component? @LostInBrittany
 
                Web Components Web standard W3C @LostInBrittany
 
                Web Components Available in all modern browsers: Firefox, Safari, Chrome @LostInBrittany
 
                Web Components Create your own HTML tags Encapsulating look and behavior @LostInBrittany
 
                Web Components Fully interoperable With other web components, with any framework @LostInBrittany
 
                Web Components @LostInBrittany
 
                Custom Element
<body> … <script> window.customElements.define(‘my-element’, class extends HTMLElement {…}); </script> <my-element></my-element> </body> @LostInBrittany 
                Shadow DOM <button>Hello, world!</button> <script> var host = document.querySelector(‘button’); const shadowRoot = host.attachShadow({mode:’open’}); shadowRoot.textContent = ‘こんにちは、影の世界!’; </script> @LostInBrittany
 
                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
 
                But in fact, it’s just an element… ● ● ● ● @LostInBrittany
 
                Sometimes I feel a bit grumpy The stories of the grumpy old speaker… @LostInBrittany
 
                On Polymer tour since 2014 @LostInBrittany
 
                Image: bu.edu Web components == Revolution @LostInBrittany
 
                Images: BitRebels & Brickset Building a world brick by brick @LostInBrittany
 
                Is the promise unfulfilled? It’s 2019 now, where is your revolution, dude? @LostInBrittany
 
                Is it a conspiracy? @LostInBrittany
 
                Am I only a dreamer? @LostInBrittany
 
                Well, revolution IS there But it’s a silent one… @LostInBrittany
 
                They are there, in everyday sites More than you can imagine @LostInBrittany
 
                The components architecture won Components, components everywhere @LostInBrittany
 
                Web components ARE platform Truly part of the platform… @LostInBrittany
 
                Why those libs? Why people don’t use vanilla? @LostInBrittany
 
                Web component standard is low level At it should be! @LostInBrittany
 
                Standard == basic bricks Standard exposes an API to: ○ Define elements ○ Encapsulate DOM @LostInBrittany
 
                Libraries are helpers They give you higher-level primitives @LostInBrittany
 
                Different high-level primitives Each one tailored to a use @LostInBrittany
 
                Sharing the same base High-performant, low-level, in-the-platform web components standard @LostInBrittany
 
                Libraries aren’t a failure of standard They happen by design @LostInBrittany
 
                Vanilla Web Components @LostInBrittany
 
                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
 
                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
 
                Custom Elements don’t: ● Scope CSS styles ○ Shadow DOM ● Scope JavaScript ○ ES2015 ● “Reproject” children into <slot> elements ○ Shadow DOM @LostInBrittany
 
                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
 
                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
 
                Using web components @LostInBrittany
 
                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
 
                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
 
                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
 
                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
 
                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
 
                my-counter custom element @LostInBrittany
 
                Let’s talk libraries What’s new? @LostInBrittany
 
                Lot’s of players, lot of evolutions LitElement SkateJS It’s JavaScript after all… @LostInBrittany
 
                Stencil Powering the new Ionic 4! @LostInBrittany
 
                Not another library A Web Component compiler @LostInBrittany
 
                Not a beta anymore Ionic 4 released, powered by Stencil! @LostInBrittany
 
                A build time tool To generate standard web components @LostInBrittany
 
                Fully featured ● Virtual DOM ● Async rendering ● Reactive data-binding ● TypeScript ● JSX @LostInBrittany
 
                And the cherry on the cake Server-Side Rendering @LostInBrittany
 
                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
 
                Hands on Stencil @LostInBrittany
 
                Hands on Stencil @LostInBrittany
 
                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
 
                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
 
                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
 
                Some concepts @Component({ tag: ‘shadow-component’, styleUrl: ‘shadow-component.scss’, shadow: true }) export class ShadowComponent { } Optional Shadow DOM @LostInBrittany
 
                Some concepts stencil.config.js exports.config = { namespace: ‘myname’, generateDistribution: true, generateWWW: false, … }; Generate distribution @LostInBrittany
 
                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
 
                Polymer Is the old player still alive? @LostInBrittany
 
                Polymer has evolved in 2018 Image: © Nintendo Polymer 3 is here! @LostInBrittany
 
                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
 
                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
 
                And they are still custom elements 100% interoperable @LostInBrittany
 
                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
 
                What’s Polymer status today? Well, how could I say… it’s complicated @LostInBrittany
 
                It seems it’s going to be deprecated… Technically yes… and that means good @LostInBrittany news!
 
                Let’s try to see clearer Let’s dive into Polymer history… @LostInBrittany
 
                A tool built for another paradigm No web component support on browsers No React, Angular or Vue innovations @LostInBrittany
 
                No so well suited for the current one The current platform is way more powerful The state of art has evolved @LostInBrittany
 
                Let’s learn from its lessons The current platform is way more powerful The state of art has evolved @LostInBrittany
 
                And let it rest… There will have no Polymer 4… @LostInBrittany
 
                So Polymer as we know it is dead… But the Polymer Project is indeed alive! @LostInBrittany
 
                But I have invested so much on it! What to do? @LostInBrittany
 
                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
 
                And without metaphors? Polymer Project != Polymer library Polymer Project well alive Polymer library was only one library @LostInBrittany
 
                Polymer Is the old player still alive? @LostInBrittany
 
                LitElement New kid on the block @LostInBrittany
 
                Born from the Polymer team For the new web paradigm @LostInBrittany
 
                Modern lightweight web components For the new web paradigm @LostInBrittany
 
                Based on lit-html An efficient, expressive, extensible HTML templating library for JavaScript @LostInBrittany
 
                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
 
                lit-html Templates
let myTemplate = (data) => html<h1>${data.title}</h1> <p>${data.body}</p>;
Lazily rendered Generates a TemplateResult @LostInBrittany
 
                It’s a bit like JSX, isn’t it? The good sides of JSX… but in the standard! @LostInBrittany
 
                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
 
                One more thing…* *Let’s copy from the master @LostInBrittany
 
                Polymer is not important WebComponents ARE @LostInBrittany
 
                Use the Platform, Luke… WebComponents ARE native @LostInBrittany
 
                Do you love your framework? Oh yeah, we all do @LostInBrittany
 
                Would you marry your framework? Like until death… @LostInBrittany
 
                How much does cost the divorce? Do you remember when you dropped AngularJS for Angular? @LostInBrittany
 
                Why recode everything again? Reuse the bricks in your new framework @LostInBrittany
 
                Lots of web components libraries LitElement SkateJS For different need and sensibilities @LostInBrittany
 
                And some good news Angular Elements Vue Web Component Wrapper Frameworks begin to understand it @LostInBrittany
 
                So for your next app Choose a framework, no problem… But please, help your future self Use Web Components! @LostInBrittany
 
                Conclusion That’s all folks! @LostInBrittany
