Liberarsi dai framework con i Web Component.pptx

MassimoArtizzu1 13 views 66 slides Jun 13, 2024
Slide 1
Slide 1 of 66
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42
Slide 43
43
Slide 44
44
Slide 45
45
Slide 46
46
Slide 47
47
Slide 48
48
Slide 49
49
Slide 50
50
Slide 51
51
Slide 52
52
Slide 53
53
Slide 54
54
Slide 55
55
Slide 56
56
Slide 57
57
Slide 58
58
Slide 59
59
Slide 60
60
Slide 61
61
Slide 62
62
Slide 63
63
Slide 64
64
Slide 65
65
Slide 66
66

About This Presentation

In Italian
Presentazione sulle feature e l'utilizzo dei Web Component nell sviluppo di pagine e applicazioni web. Racconto delle ragioni storiche dell'avvento dei Web Component. Evidenziazione dei vantaggi e delle sfide poste, indicazione delle best practices, con particolare accento sulla p...


Slide Content

LIBERARSI DAI FRAMEWORK ‹#› CON I WEB COMPONENT Imola, 12/6/2024

‹#› Massimo Artizzu Web Architect @ GELLIFY MaxArt2501

DEPENDENCIES, RIGHT? ‹#›

WE LOVE THEM. ‹#›

HOW DID WE GET HERE? ‹#›

‹#›

‹#›

‹#›

SVELTE 4 SVELTE 5 SVELTE 4 ‹#›

‹#›

‹#›

‹#›

‹#›

IT SHOULDN’T BE LIKE THIS… ‹#›

THE WEB May I use <center> ? You may NEVER BREAKS ‹#›

‹#› FAIR WARNING

widget The ’ 00s element directive (?!) applet 😱 component A BIT OF HISTORY ‹#›

2011 AND OVER... ‹#›

BUT, AREN’T WEB COMPONENTS, LIKE, DEAD? 💀 ‹#›

Custom elements Templates Shadow DOM HTML Imports 💀 Concept introduced by Alex Russell by Google Initial support behind flag in Chrome 27, stable in Chrome 33 [email protected] released, usage in YouTube FIRST STEPS VO 2011 2013 2014 ‹#›

Definition of new elements that can be handled by the browser via the usual DOM methods and properties such as createElement , innerHTML and setAttribute . It consists in mapping in a global registry a tag name that must include a dash with a runtime that defines the custom element’s life cycle . Custom Elements registry my-alert { ... } my-button { ... } my-video-player { ... } Created Connected Disconnected Attribute changed CUSTOM ELEMENTS ‹#›

Introduction of the element <template> , which is an inert piece of DOM exposed as a DocumentFragment . Does not load Does not update <body> <template> <img src = "logo.png" alt = "The logo" > <h1> Title goes here </h1> </template> </body> TEMPLATES The problem is: you have to create data binding by yourself via JavaScript. 1 2 3 4 5 6 ‹#›

We don’t talk about HTML Imports But, in short, it was designed as a system to load a chunk of HTML , that could comprise CSS and JS too. 👎 Deprecated in Chrome 70 (10/2018) » 💀 Removed in Chrome 80 (02/2020) HTML IMPORTS <head> <link rel = "import" href = "components.html" > </head> 1 2 3 ‹#›

🦿 💦 v1 VENDORS ROUND TABLE ‹#›

ES6 IN THE MEANWHILE… ES2015 ‹#›

CUSTOM ELEMENTS V1 ADOPTION DATES OCTOBER v.54 v.41 SEPTEMBER v.10 2016 v.63 OCTOBER 2018 😞 JANUARY v.79 2020 😱 ‹#›

BUT ARE THEY USED? ‹#› Source: chromestatus.com

WHAT ABOUT THE OTHERS ? ‹#› Source: w3techs.com

<html lang = "en" > <head> ... </header> <body> </body> </html> ‹#›

OVERALL INTEREST ‹#› Source: github.com/web-platform-tests/interop

UI Kits Leaf components Widgets Wrappers Micro-frontends ‹#› USE CASES AND GOALS

CAN WE DITCH FRONTEND FRAMEWORKS? USE CASES AND GOALS ‹#› No router No state management No view updates

Create a class Register it Use it in the DOM DEFINING A CUSTOM ELEMENT 1 class CoolCard extends HTMLElement { } 1 2 window . customElements . define ( 'cool-card' , CoolCard ); 1 2 3 <cool-card> This is so cool! </cool-card> ‹#›

Global object, i nstance of the class CustomElementRegistry . define ( tagName , constructor ) . get ( tagName ) Defines a Custom Element Returns the class that represents the given tag name, or null . . getName ( constructor ) Returns the tag name that represents the given class, or null . ( It’s new! ) . whenDefined ( tagName ) Returns a promise that resolves when a CE with the given name is defined. . upgrade ( element ) Allows to manually upgrade elements in detached nodes . WHAT IS customElements ? ‹#›

Use it in a HTML document 1 2 3 <cool-card> This is so cool! </cool-card> USING CUSTOM ELEMENTS With . innerHTML and others 1 2 element . insertAdjacentHTML ( 'beforeend' , '<cool-card>Wow!</cool-card>' ); Create it w ith createElement 1 2 3 const card = document . createElement ( 'cool-card' ); card . textContent = 'Aw yeah!' ; …also with new ! 😱 1 2 const card = new CoolCard (); document . body . appendChild ( card ); ‹#›

NOW, FOR THE FUNCTIONALITY… ‹#›

CUSTOM ELEMENT DATA FLOW ‹#› <custom- element> attributes properties methods events (anything that JavaScript can do, really) properties

ATTRIBUTE OR PROPERTY? ‹#› PROPERTIES ATTRIBUTES Basically any data Single-parameter actions Easily serializable With declarative meaning . cardTitle card-title

LIFE CYCLE Created constructor D isconnected disconnectedCallback A ttribute c hanged attributeChangedCallback C onnected connectedCallback ‹#›

C onstructors should be be fast . Value initialization Method bindings Shadow DOM and Internals setup Register event listeners* ‹#› THE CONSTRUCTOR

SHOULD NOT DO Expensive computations Loading data Any other side effect THE CONSTRUCTOR CANNOT DO Set an attribute on the element Change its DOM children ‹#›

C alled when the element is attached to the DOM connectedCallback() ‹#› Define the Shadow DOM Register event listeners Set/remove initial attributes Schedule side effects

Called when the element is detached from the DOM dis connectedCallback() ‹#› Remove event listeners Tear down side effects Reduce its internal state footprint

adoptedCallback() Called when the element is moved from a document to another 👉 Document . adoptNode () ‹#›

B asically never… adoptedCallback() ‹#›

Called when one of the observedAttributes changes value attributeChang edCallback() ‹#› Define an attribute list Observe the new values coming 1 2 static observedAttributes = [ 'card-title' , 'open' ]; 1 2 3 attributeChangedCallback ( attribute , oldValue , newValue ) { if ( attribute === 'open' ) { ... }}

A system to define the internal DOM structure of a component, that replaces the one defined by the subtree of the descendant nodes. SHADOW DOM ‹#›

‹#› SHADOW DOM

constructor () { super (); this . attachShadow ({ mode: 'open' }); 1 2 3 4 5 6 7 this . shadowRoot . innerHTML = ` <link rel="stylesheet" href="card.css"> <header>...</header> ` ; ‹#› SHADOW DOM

. attachShadow () is not exclusive to Custom Elements! The more you know… 💫 <article> <aside> <blockquote> <body> <div> <footer> <h1> <h2> <h3> <h4> <h5> <h6> <header> <main> <nav> <p> <section> <span> ‹#› SHADOW DOM

SLOTS <cool-card> <div slot = "title" > My title! </div> And this is the rest. <b> Also in bold! </b> </cool-card> #shadow-root <header> <slot name = "title" /> </header> <section> <slot></slot> </section> My title ! And this is the rest. Also in bold! ‹#›

IMPERATIVE SLOTS <cool-card> <header> Title! </header> And this is the rest. <b> Also in bold! </b> </cool-card> this . attachShadow ({ mode: 'open' , // Default: 'named' slotAssignment: 'manual' }); T itle! And this is the rest. Also in bold! ‹#› #shadow-root <div> <slot></slot> </div> <section> <slot></slot> </section> slot . assign (... nodes );

<input type = "text" placeholder = "Find" > #shadow-root <div pseudo = "-webkit-input-placeholder" > Find </div> <div> Value </div> </input> SHADOW DOM NOTE: Browsers adapted this concept from/to built-in elements. 1 2 3 4 5 6 7 ‹#›

<style>p { color : blue ; } </style> <p> I'm blue </p> 1 2 3 4 5 6 7 STYLE ENCAPSULATION <cool-card> #shadow-root <p> I'm not... </p> </cool-card> I’m not… I’m blue! ‹#›

<cool-card> #shadow-root <style>p { color : blue } </style> <p> Now I'm blue! </p> </cool-card> 1 2 3 4 5 6 7 <p> Now I'm not... </p> Now I’m blue! Now I’m not… ‹#› STYLE ENCAPSULATION

‹#›

<div class = "max-w-7xl mx-auto px-4 sm:px-6 md:px-8 mt-20 sm:mt-24 lg:mt-32 <div class = "relative row-start-1 col-start-6 xl:col-start-7 col-span-7 x <div class = "-mx-4 sm:mx-0" > <div class = "relative overflow-hidden shadow-xl flex bg-slate-800 h-[ <div class = "relative w-full flex flex-col" > <div class = "flex-none border-b border-slate-500/30" > <div class = "flex items-center h-8 space-x-1.5 px-3" > <div class = "w-2.5 h-2.5 bg-slate-600 rounded-full" > WHAT WE’RE DOING NOW… ‹#› import React from 'react' ; import styles from './Button.module.css' ; export default function Button () { return <button className = { styles . error } > Error Button </button> ; }

ADVANTAGES OF STYLE ENCAPSULATION ‹#› Shorter stylesheets Consistent appearance Manageable cascade Less need for classes More semantic oriented Compact selectors Cleaner markup <header class = "card-header" > ... </header> .card-header { font-weight : bold ; } <header> ... </header> header { font-weight : bold ; } <header class = "is-open" > ... </header> .is-open { background : lightgray ; } <header aria-expanded = "true" > ... </header> [ aria-expanded = " true " ] { background : lightgray ; } <header class = "card-header" > <button class = "close" > ... </header> .card-header > .close { border : none ; } <header> <button> ... </button> </header> button { border : none ; }

BUT I WANT MY SWEET UTILITY CLASSES! ‹#›

BUT I WANT TO STYLE MY COMPONENTS FROM OUTSIDE! ‹#›

STYLING THE HOST ‹#› You can’t style what’s in the Shadow DOM , but you can style the custom element itself 1 2 3 :host { background : white ; } 1 2 3 cool-card { background : orange ; } Orange background?!

INHERITED PROPERTIES ‹#› 1 2 3 cool-card { color : blue ; } 1 2 3 Blue again! header { background : var ( --header-color , #d9d9d9 ); } Some standard properties are inherited : Custom properties are inherited by default: Orange header?! 1 2 3 cool-card { --header-color : orange ; }

--cool-base-unit : 1rem ; --cool-font-bold : 700 ; --cool-font-regular : 400 ; --cool-font-light : 300 ; --cool-font : Roboto; --cool-heading-1 : calc ( var ( --cool-base-unit , 1rem ) * 2 ); --cool-font-size : var ( --cool-base-unit , 1rem ); --cool-primary-color : rebeccapurple ; --cool-accent-color : hotpink ; --cool-warning-color : orange ; --cool-spacing-lg : calc ( var ( --cool-base-unit , 1rem ) * 4 ); --cool-spacing-xs : calc ( var ( --cool-base-unit , 1rem ) * 0.5 ); --cool-fast-animation : 150ms ; --cool-slow-animation : 300ms ; --cool-radius-lg : calc ( var ( --cool-base-unit , 1rem ) * 2 ); --cool-radius-xs : calc ( var ( --cool-base-unit , 1rem ) * 0.25 ); --cool-shadow-color : rgb ( / .35 ); --cool-shadow-lg : calc ( var ( --cool-base-unit , 1rem ) * 1 ) calc ( var ( --cool-base-unit , 1rem ) * 0.5 ) calc ( var ( --cool-base-unit , 1rem ) * 2 ) var ( --cool-shadow-color , rgb ( / .35 )) DESIGN TOKENS ‹#›

::placeholder ::marker ::-webkit-calendar-picker-indicator ::-webkit-resize ::-webkit-progress-value SHADOW PARTS ‹#› Orange header?! <cool-card> #shadow-root <header part = "header" > ... </header> ... </cool-card> cool-card::part( header ) { background : orange ; }

OPEN-STYLABLE COMPONENTS? ‹#›

WHAT ABOUT INTERACTIONS ? ‹#›