</> htmx 2.0 & Web Components Un combo pour le développement web Horacio Gonzalez 2024-09-12
A presentation at FinistDevs in September 2024 in Brest, France by Horacio Gonzalez
</> htmx 2.0 & Web Components Un combo pour le développement web Horacio Gonzalez 2024-09-12
Horacio Gonzalez @LostInBrittany Espagnol Perdu en Bretagne
Créez des interfaces utilisateur modernes avec la simplicité et la puissance de l’hypertexte
Les limites arbitraires du HTML ● Pourquoi seules les balises <a> et <form> peuvent-elles effectuer des requêtes HTTP(S) ? ● Pourquoi seuls les événements de clic et d’envoi peuvent-ils les déclencher ? ● Pourquoi seules les méthodes GET et POST sont-elles disponibles ? ● Pourquoi les balises <a> et <form> forcent le remplacement de l’intégralité de l’écran ? ● Pourquoi autant des limites arbitraires à HTML ?
Objectif: de l’interactivité dans l’hypertexte htmx étend les fonctionnalités de HTML ● effectuer des requêtes AJAX ● effectuer des transitions CSS ● gérer des WebSockets ● gérer les événements envoyés par le serveur avec seulement des attributs HTML déclaratifs.
Mais à quoi ça sert tout ça ? Car c’est bien beau et sémantique, mais j’ai du mal à voir l’intérêt…
Et si on faisait un petit saut arrière dans le temps ? À une époque révolue, où les dinosaurs codaient avec struts
Souvenez-vous du modèle MVC Avec la navigation page par page
L’époque dorée d’une génération de frameworks Generant des vues HTML
Vers 2005 on voit arriver AJAX C’est la naissance du Web 2.0
Et les pages webs deviennent des apps dynamiques À coup de JavaScript, avec JQuery
On bascule vers des Single Page Apps
Des apps de plus en plus complexes Avec l’apparition des frameworks JavaScript
Et les backends deviennent des API REST Servant du JSON
On a gagné des fonctionnalités Mais on a perdu de la simplicité et le côté sémantique
Pour beaucoup d’app c’est overkill On ne veut qu’un site web avec un peu de dynamisme !
</> htmx peut être la bonne solution C’est du HTML étendu ● Simplicité ● Sémantique ● Dynamisme
On veut du code ! Des exemples ! Des exemples ! example-01.html <script src=”https://unpkg.com/htmx.org@2.0.2”></script> <!— have a button that POST on a click via AJAX and replace the content of #status div with the response —> <button hx-post=”/clicked” hx-target=”#status”> Click Me </button> <div id=”status”>Not yet clicked</div>
Trop de blabla, on veut un exemple ! example-01.html <script src=”https://unpkg.com/htmx.org@2.0.2”></script> <!— have a button that POST on a click via AJAX and replace the content of #status div with the response —> <button hx-post=”/clicked” hx-target=”#status”> Click Me </button> <div id=”status”>Not yet clicked</div>
GET, POST, PUT, DELETE… example-02.html <script src=”https://unpkg.com/htmx.org@2.0.2”></script> <div> <button hx-get=”/test-methods” hx-target=”#status”>Send GET</button> <button hx-post=”/test-methods” hx-target=”#status”>Send POST</button> <button hx-put=”/test-methods” hx-target=”#status”>Send PUT</button> <button hx-delete=”/test-methods” hx-target=”#status”>Send DELETE</button> </div> <div id=”status”>No request sent</div>
Remplacer l’élément par la réponse example-03.html <script src=”https://unpkg.com/htmx.org@2.0.2”></script> <div id=”test-replace”> <button hx-get=”/test-replace/innerHTML”> If you click, this message will be replaced </button> <button hx-get=”/test-replace/outerHTML” hx-swap=”outerHTML”> If you click, this button will become a div </button> <button hx-get=”/test-replace/delete” hx-swap=”delete”> If you click, this button will dissapear when the response is received </button> <button hx-get=”/test-replace/none” hx-swap=”none”> If you click, nothing changes, the response is ignored </button> </div>
Choisir quand émettre la requête example-04.html <script src=”https://unpkg.com/htmx.org@2.0.2”></script> <!— By default, AJAX requests are triggered by the “natural” event of an element: —> <div id=”test-triggers”> <button hx-get=”/trigger/natural” hx-target=”#status”> In a button the natural event is a click </button> <button hx-trigger=”mouseover” hx-get=”/trigger/mouseover” hx-target=”#status”> This button triggers on mouseover </button> <button hx-trigger=”mouseenter” hx-get=”/trigger/mouseenter” hx-target=”#status”> This button triggers on mouseenter </button> <button hx-trigger=”mouseleave” hx-get=”/trigger/mouseleave” hx-target=”#status”> This button triggers on mouseleave </button> </div> <div id=”status”>No AJAX request sent yet</div>
Choisir quand émettre la requête example-05.html <script src=”https://unpkg.com/htmx.org@2.0.2”></script> <!— By default, AJAX requests are triggered by the “natural” event of an element: —> <div id=”test-triggers”> <button hx-trigger=”every 5s” hx-get=”/trigger/5seconds” hx-target=”#status”> Sends request every 5 seconds, no event needed </button> <button hx-trigger=”click[ctrlKey]” hx-get=”/trigger/ctrlclick” hx-target=”#status”> Sends request on click while pressing Ctrl </button> <button hx-trigger=”click[ctrlKey] once” hx-get=”/trigger/ctrlclickonce” hx-target=”#status”> Sends request on the first click while pressing Ctrl </button> </div> <div id=”status”>No AJAX request sent yet</div>
Un spinner pour faire patienter example-06.html <script src=”https://unpkg.com/htmx.org@2.0.2”></script> <!— By default, AJAX requests are triggered by the “natural” event of an element: —> <div id=”test-triggers”> <button hx-trigger=”every 5s” hx-get=”/trigger/5seconds” hx-target=”#status”> Sends request every 5 seconds, no event needed </button> <button hx-trigger=”click[ctrlKey]” hx-get=”/trigger/ctrlclick” hx-target=”#status”> Sends request on click while pressing Ctrl </button> <button hx-trigger=”click[ctrlKey] once” hx-get=”/trigger/ctrlclickonce” hx-target=”#status”> Sends request on the first click while pressing Ctrl </button> </div> <div id=”status”>No AJAX request sent yet</div>
Des extensions presque à l’infini
On veut du code ! Faisons un exemple
Tout le code est disponible https://github.com/LostInBrittany/introduction-to-htmx
Des démos de htmx Du Hello World à la To-do List
What the heck are web component? The 3 minutes context
Web Components Web standard W3C
Web Components Available in all modern browsers: Firefox, Safari, Chrome
Web Components Create your own HTML tags Encapsulating look and behavior
Web Components Fully interoperable With other web components, with any framework
Web Components CUSTOM ELEMENTS SHADOW DOM TEMPLATES
Custom Element To define your own HTML tag <body> … <script> window.customElements.define(‘my-element’, class extends HTMLElement {…}); </script> <my-element></my-element> </body>
Shadow DOM To encapsulate subtree and style in an element <button>Hello, world!</button> <script> var host = document.querySelector(‘button’); const shadowRoot = host.attachShadow({mode:’open’}); shadowRoot.textContent = ‘こんにちは、影の世界!’; </script>
Template To have clonable document 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);
But in fact, it’s just an element… ● ● ● ● Attributes Properties Methods Events
Simple. Fast. Web Components
Modern lightweight web components For the new web paradigm
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
Based on lit-html An efficient, expressive, extensible HTML templating library for JavaScript
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 = [ ‘Sophia Antipolis’, ‘RivieraDev’, ‘Thank you’]; console.log(uppercaseJe suis à ${expression[0]} pour ${expression[1]. $expression[2]!
Little known functionality of template literals
lit-html Templates
let myTemplate = (data) => html<h1>${data.title}</h1> <p>${data.body}</p>
;
Lazily rendered Generates a TemplateResult
It’s a bit like JSX, isn’t it? The good sides of JSX… but in the standard!
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
Une petit démo de Lit Faisons un compteur : my-lit-counter
Lit & </> htmx Amour au premier <tag>
htmx pour structure, lit pour encapsuler l’intelligence Pour htmx les élément lits sont comme n’importe quel tag
Une petit démo de htmx + Lit Faisons un compteur : my-lit-counter
That’s all, folks! Thank you all!