Expert Frontend Developer, Sngular
Expert Frontend Developer, Sngular
¿Los Webcomponents son tu camino?
Expert Software Developer en Sngular con más de 10 años de experiencia en el desarrollo de aplicaciones trabajando para empresas como BBVA, ING, Carrefour, Mapfre o el Corte Inglés, entre otras. Amante del desarrollo Front-end y el diseño UX, especialista en JavaScript con experiencia trabajando con las tecnologías más destacadas de su ecosistema, como Angular, React, Vue.js, Node.js y LitElement.
Web Components
PWA
WebRTC
WebXR
WebAssembly
Características que nunca pensamos tener
WebSocket
WebWorkers
ServiceWorkers
WebGL
¡Y mucho más!
¿Qué son Web Components?
¿Cómo funcionan?
¿Cómo podemos crear Web Components?
¿Para qué sirven?
¿Quiénes somos?
¿Por qué existimos?
¿Valen la pena?
¿Los Webcomponents son tu camino?
Funciona en los navegadores e internet a través de hipervinculos y conexión entre servidores
Text
HTML
Javascript
CSS
Son las tres tecnologías top en el mundo web.
Los materiales para construir tu aplicación.
Gracias a ellos y los avances que han tenido estas tecnologías, la web es como la conocemos.
En el inicio de la web solo era una herramienta que permita acceder a diferentes archivos a través de hipervinculos e internet. Javascript ni CSS existían y HTML casí no tenía funcionalidades.
La web se hizo más popular y con más características, css y javascript aparecieron también la web 2.0 interconectada entre ordenadores y servidores.
¿Los Webcomponents son tu camino?
¿Los Webcomponents son tu camino?
¡La web ya NO es como antes!
Los avances en el área hace importante la arquitectura.
Gracias a los avances que han tenido estas tecnologías, la web es como la conocemos!
Crear sitios web se complica
Conectamos la casa para darle vida.
Planificamos qué es lo mejor para el tipo de casa que queremos ;)
Las piezas de la casa son reutilizables.
Construimos la estructura con estas piezas
Nuestros componentes son piezas reutilizables
Estas piezas están encapsuladas y pueden ser
Se encargan de pintar nuestros componentes sin tener que preocuparse de alguna lógica de negocio.
Se encargan de transformar la lógica de negocio, construir cómo mostrar nuestras piezas y manejar el estado.
Visuales
Lógicos
¿Los Webcomponents son tu camino?
Existe una alta oferta de librerías y frameworks en Javascript. Una heladería con muchos sabores.
Al haber tantas ofertas con diversos pros y contras es complicado aprender y especializarse en alguna de ellas.
Los componentes dependen de las librerías y frameworks. Cada vez que cargues un componente de una librería que no tengas agregada, deberás hacerlo, lo que agregará tamaño al proyecto.
Se tiende a elegir un solo framework por proyecto, así los componentes serán creados en una sola tecnología por lo que si deseas hacer otro proyecto con otra tecnología tendrás que rehacer parte del código.
¿Los Webcomponents son tu camino?
Componentes nativos, independientes y reutilizables.
Los Web Componentes son un tipo de componentes que cumplen ciertas espeficaciones y funcionan bajo un entorno nativo.
Puedes diseñar y utilizar nuevos tipos de elementos en el DOM
class MySearch extends HTMLElement {...}
customElements.define("my-search", MySearch);Permite encapsular estilos CSS y HTML de tu componente.
constructor() {
super();
this.attachShadow({ mode: "open" });
}Te permite exportar, importar y reutilizar documentos JS bajo un estándar sencillo y modular.
export class MySearch extends HTMLElement {...}
import { MySearch } from "./src/MySearch.js";Define cómo declarar fragmentos de HTML que no se cargan en la página hasta que son instanciados.
const template = document.createElement("template");
template.innerHTML = `<p>Soy un párrafo</p>`¿Los Webcomponents son tu camino?
En esta ocasión vamos a crear un componente de tipo input con botón.
Soy un botón
Soy un input
Soy un label
Classes
Properties
Attributes
Methods
Events
Template
getTemplate() {
const template = document.createElement("template");
template.innerHTML = `
<style>
${this.getStyles()}
</style>
<label part="label">${this.label}</label>
<input
type="text"
value="${this.value}"
placeholder="${this.placeholder}"
part="input"
/>
<button part="button">
<slot>${this.button}</slot>
</button>
`;
return template;
}
<my-search value="hello world" name="my name"></my-search>
static get observedAttributes() {
return ["button", "label", "placeholder", "value"];
}
attributeChangedCallback(name, oldVal, newVal) {
if (oldVal === newVal) {
return;
}
this[name] = newVal;
}
dispatchCustomEvent(eventName, detail) {
this.dispatchEvent(
new CustomEvent(eventName, {
bubbles: true,
composed: true,
detail,
})
);
}
addEventListeners() {
this.buttonEl.addEventListener("click", () => {
this.dispatchCustomEvent("my-search-button-click", {
button: this.button || this.innerHTML,
value: this.value,
})
});
this.inputEl.addEventListener("input", () => {
this.dispatchCustomEvent("my-search-input-change", {
value: this.inputEl.value,
});
});
}
connectedCallback() {
this.addEventListeners();
}
constructor()
connectedCallback()
attributeChangedCallback()
disconnectedCallback()
adoptedCallback()
Podemos agregar estilos CSS:
getStyles() {
return `
:host {
display: block;
font-family: sans-serif;
font-weight: 300;
font-size: 1rem;
margin: 0.7rem 0;
}
input {
border: none;
border-bottom: 1px solid var(--my-search-input-border-color, #ccc);
padding: 0.5rem;
}
label {
display: block;
padding-left: 0.5rem;
font-size: 0.8rem;
}
button {
border: none;
background-color: #5f3993;
cursor: pointer;
outline: none;
color: white;
padding: 10px;
border-radius: 5px;
min-width: 6rem;
min-height: 2rem;
}
button:hover {
background-color: #9f7fcd;
}
button:active, button:focus {
background-color: #472b6e;
}
`;
}
<style>
${this.getStyles()}
</style>
export class MySearch extends HTMLElement {
static get observedAttributes() {
return ["button", "label", "placeholder", "value"];
}
constructor() {
super();
this.attachShadow({ mode: "open" });
}
connectedCallback() {
this.render();
this.buttonEl = this.shadowRoot.querySelector("button");
this.slotNode = this.buttonEl.querySelector("slot");
this.inputEl = this.shadowRoot.querySelector("input");
this.addEventListeners();
}
disconnectedCallback() {
super.disconnectedCallback();
this.removeEventListeners();
}
get button() {
return this.getAttribute("button") || "";
}
set button(data) {
this.setAttribute("button", data);
}
get value() {
return this.getAttribute("value") || "";
}
set value(data) {
this.setAttribute("value", data);
}
get placeholder() {
return this.getAttribute("placeholder") || "";
}
set placeholder(data) {
this.setAttribute("placeholder", data);
}
get label() {
return this.getAttribute("label") || "";
}
set label(data) {
this.setAttribute("label", data);
}
attributeChangedCallback(name, oldVal, newVal) {
if (oldVal === newVal) {
return;
}
this[name] = newVal;
}
addEventListeners() {
this.buttonEl.addEventListener("click", () => {
this.dispatchCustomEvent("my-search-button-click", {
button: this.button || this.innerHTML,
value: this.value,
})
});
this.inputEl.addEventListener("input", () => {
this.dispatchCustomEvent("my-search-input-change", {
value: this.inputEl.value,
});
});
}
removeEventListeners() {
this.buttonEl.removeEventListener("click", () => {});
this.inputEl.removeEventListener("input", () => {});
}
dispatchCustomEvent(eventName, detail) {
this.dispatchEvent(
new CustomEvent(eventName, {
bubbles: true,
composed: true,
detail,
})
);
}
getTemplate() {
const template = document.createElement("template");
template.innerHTML = `
<style>
${this.getStyles()}
</style>
<label part="label">${this.label}</label>
<input
type="text"
value="${this.value}"
placeholder="${this.placeholder}"
part="input"
/>
<button part="button">
<slot>${this.button}</slot>
</button>
`;
return template;
}
getStyles() {
return `
:host {
display: block;
font-family: sans-serif;
font-weight: 300;
font-size: 1rem;
margin: 0.7rem 0;
}
input {
border: none;
border-bottom: 1px solid var(--my-search-input-border-color, #ccc);
padding: 0.5rem;
}
label {
display: block;
padding-left: 0.5rem;
font-size: 0.8rem;
}
button {
border: none;
background-color: #5f3993;
cursor: pointer;
outline: none;
color: white;
padding: 10px;
border-radius: 5px;
min-width: 6rem;
min-height: 2rem;
}
button:hover {
background-color: #9f7fcd;
}
button:active, button:focus {
background-color: #472b6e;
}
`;
}
render() {
this.shadowRoot.appendChild(this.getTemplate().content.cloneNode(true));
}
}
Para agregar un Web Component debes definirlo en el documento HTML de tu página web.
import { MySearch } from "./src/MySearch.js";
window.customElements.define("my-search", MySearch);
{
"name": "@marsgotta/my-search",
"description": "Webcomponent my-search following open-wc recommendations",
"license": "MIT",
"author": "Mars Gotta",
"version": "0.0.0",
"main": "index.js",
"module": "index.js",
"scripts": {
"analyze": "cem analyze --litelement",
"start": "web-dev-server"
},
"devDependencies": {
"@custom-elements-manifest/analyzer": "^0.4.17",
"@web/dev-server": "^0.1.25"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"rules": {}
},
"customElements": "custom-elements.json"
}
$ npm login
$ npm publish
Sí, siempre que el desarrollador lo permita
Puedes ver el WebComponents y ejemplos de implementación de este en Angular, Vue y React en este repositorio
¿Los Webcomponents son tu camino?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Native Search WebComponent</title>
<script type="module" src="../my-search.js"></script>
</head>
<body>
<my-search
value="Hello World"
label="I'm a label"
button="I'm a button"
>
</my-search>
<style>
<script type="module">
document.querySelectorAll('my-search').forEach(function(element) {
element.addEventListener('my-search-button-click', function(event) {
alert('clicked: ' + event.detail.button + ' - value: ' + event.detail.value);
});
element.addEventListener('my-search-input-change', function(event) {
console.log('inputed: ' + event.detail.value);
});
});
</script>
</body>
</html>import { Component } from '@angular/core';
import "@marsgotta/my-search/my-search.js";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
title = 'angular-app';
}
<my-search
value="Hello World"
label="I'm a label"
button="I'm a button"
></my-search>app.component.ts
app.component.html
<template>
<div class="hello">
<my-search
value="Hello World"
label="I'm a label"
button="I'm a button"
></my-search>
</div>
</template>
<script>
import "@marsgotta/my-search/my-search.js";
export default {
name: 'HelloWorld',
}
</script>import "./App.css";
import "@marsgotta/my-search/my-search.js";
function App() {
return (
<div className="App">
<my-search
value="Hello World"
label="I'm a label"
button="I'm a button"
></my-search>
</div>
);
}
export default App;
¿Los Webcomponents son tu camino?
¿Los Webcomponents son tu camino?
¿Los Webcomponents son tu camino?
¿Los Webcomponents son tu camino?
¡Sigue investigando!
Si te interesan los Web Components, esta charla sólo es la punta del iceberg
¿Los Webcomponents son tu camino?