Software">
Introducción a Web Components en JavaScript
Introducción a Web Components en JavaScript
Web Components incluye cuatro especificaciones que nos van a servir para cambiar
radicalmente el modo en el que construimos las páginas web, aportando nuevas herramientas
capaces de extender el lenguaje HTML. Las veremos por separado y luego las utilizaremos en
conjunto.
Los componentes, también llamados Custom Elements, son el corazón y objetivo final de este
estándar y tienen como objetivo construir nuevos elementos para el lenguaje HTML. Éstos son
como etiquetas HTML nuevas que puedes desarrollar tú mismo con muy poco esfuerzo, de modo
que puedas realizar componentes para implementar cualquier tipo de tarea en el ámbito de una
web, interfaz de usuario, etc.
Por todo ello es una tecnología que ya podemos usar y beneficiarnos de extraordinarias
posibilidades. En este manual vamos a recorrer diversos puntos del estándar para explicarlo, de
modo que los desarrolladores puedan aprender y comenzar a usar Web Components.
Web Components es un estándar de la W3C que está siendo definido en el momento de escribir
este manual. Explicaremos con detalle en qué consiste el estándar y su filosofía. Las
especificaciones están a distintos niveles de finalización pero, como ya se encuentran publicados
sus borradores, varios navegadores las vienen implementando. Todos los navegadores en algún
momento se adaptarán para soportar Web Components, pero para los navegadores antiguos
explicaremos cómo usar el Polyfill, que nos aporta compatibilidad entre los clientes web que no
lo implementan todavía.
Web Components es un estándar Javascript, por lo que no es necesario el uso de librerías para
crear nuestros propios componentes. Aún así existen ibrerías como Lit que todavía permiten
agregar funcionalidad encima del estándar, con pesos cercanos a los 5KB de código. Son una
excelente opción para desarrollar componentes reutilizables y están dando mucho de que
hablar últimamente.
Otras librerías como Angular o React también permiten desarrollar componentes pero no están
basados en el estándar Web Components.
Si las conoces te puedes hacer una idea de qué son componentes y cómo permiten organizar y
reutilizar tu código. Aunque para ser exactos el estándar es bastante más importante que una
tecnología en particular, cuya vida depende del equipo de desarrollo y el tiempo que consiga
permanecer "de moda".
Vamos a comenzar explicando el objetivo que vienen a cubrir los Web Components y luego
trataremos acerca de las 4 especificaciones que podemos encontrar en esta tecnología. Además
en este artículo vamos a aclarar algunos puntos interesantes sobre la tecnología y su evolución,
a lo largo de sus diversas versiones y el soporte de los navegadores.
Los Web Components nos ofrecen un estándar que va enfocado a la creación de todo tipo de
componentes utilizables en una página web, para realizar interfaces de usuario y elementos que
nos permitan presentar información (o sea, son tecnologías que se desarrollan en el lado del
cliente). Los propios desarrolladores serán los que puedan, en base a las herramientas que
incluye Web Components crear esos nuevos elementos y publicarlos para que otras personas
también los puedan usar.
En resumen, este nuevo estándar viene a facilitar la creación de nuevos elementos que
enriquezcan la web. Pero además, está pensado para que se puedan reutilizar de una manera
sencilla y también extender, de modo que seamos capaces de crear unos componentes en base
a otros.
Como veremos, al diseñarse los estándares para los Web Components también se ha procurado
que se pueda trabajar con los componentes de manera aislada, permitiendo que las nuevas
piezas puedan usarse en el contexto de una web sin que afecten a otras ya existentes.
Paralelamente se ha tratado de que el proceso de cargar un nuevo componente en una página
se pueda realizar de manera atómica (un solo bloque) en lugar de como se suele hacer con
muchas librerías y plugins actuales que requieren de escribir los estilos por una parte y el
javascript por otra.
Nota: El W3C está encargado de mantener los estándares, pero lo cierto es que sus
procedimientos para permitir la evolución de la web son un poco pesados. Nos referimos a que
los desarrolladores habitualmente detectamos necesidades mucho antes que la W3C realice un
estándar para poder cubrirlas. De hecho, pueden pasar años desde que algo comienza a ser
usado en el mundo de la web hasta que se presenta el estándar. En resumen, el mundo de la
web va mucho más rápido que la definición de los estándares.
EJEMPLO 1: El ejemplo más típico que veremos por ahí es un mapa de Google. Hoy, si no usamos
web components, cuando queremos mostrar un mapa en una página web, tenemos que crear
código en tres bloques.
Un CSS para definir algún estilo sobre el mapa, por ejemplo sus dimensiones
Lo más importante, un Javascript para que puedas generar el mapa, indicando las coordenadas
que deseas visualizar (para centrar la vista inicial) y muchos otros detalles de configuración que
tu mapa necesite.
EJEMPLO 2: Otro ejemplo sería un calendario, que necesitas de nuevo básicamente tres partes:
Son tres lenguajes diferentes, que se especifican en bloques de código separados y usualmente
en archivos separados. Sin Web Components, para tener todos los bloques agrupados y tener
un código único para embeber un elemento se usaba generalmente la etiqueta IFRAME, que
permite cargar un HTML, CSS y Javascript y reducir su ámbito a un pequeño espacio de la página.
Esta técnica se sigue utilizando, pero en el futuro se va a sustituir gracias a las bondades de los
Web Components.
Se puede expresar un mapa de Google con una etiqueta propietaria, que no pertenece al
estándar del HTML, que simplifica la tarea y la acota a un pequeño bloque independiente.
Para incluir un calendario que indique los días que estamos libres u ocupados podremos usar
una etiqueta propietaria en la que indicamos las características de ese calendario.
<google-calendar-busy-now
calendarId="TU_ID_CAL"
apiKey="TU_LLAVE_API"
busyLabel="Ocupado"
freeLabel="Estoy libre">
</google-calendar-busy-now>
Son dos ejemplos tomados directamente de Web Components reales, creados por el equipo de
Google. Tienen como intención reflejar:
Es como si estuviéramos inventando etiquetas nuevas. Esa es una de las capacidades de los Web
Components, pero no la única.
Las etiquetas propietarias que nos estamos inventando son "google-map" y "google-calendar-
busy-now"
No tenemos el HTML por un lado, el CSS y el Javascript por otro. Es simplemente la etiqueta
nueva y ésta ya es capaz de lanzar el comportamiento.
Obviamente, en algún lugar habrá un Javascript que se encargará de procesar esa etiqueta, pero
será genérico para cualquier tipo de mapa y reutilizable. Lo que además debe verse es que en el
HTML estás colocando información que antes estaría en el Javascript. Por ejemplo en el caso del
mapa de google los atributos latitude="12.678" longitude="-67.211" antes eran datos que se
escribían en el Javascript. Ahora se declaran en el HTML. El Javascript por tanto es genérico y no
tendremos que programarlo nosotros, sino que nos vendrá dado por Google o por el creador
del web component de turno.
Actualizado en septiembre de 2018: Aunque estemos ante una tecnología relativamente nueva,
ya han surgido diversos cambios en el estándar que es importante explicar. Se trata de las
versiones de Web Components V0 y V1 y sus implicaciones.
Este estándar ha sido impulsado principalmente por Google, empresa donde comenzaron el
diseño de Web Components, según como ellos mismos consideraban que debería ser. Sin
embargo, para la creación de estándares abiertos, como el HTML, CSS, etc. no solamente opina
una empresa, sino un conjunto de empresas y profesionales bien posicionados en el sector. Es
por ello que, al tiempo que Web Components pasaba de ser un proyecto particular a un estándar
abierto, se fueron introduciendo modificaciones.
La versión del estándar que conocemos hoy se llama ", cuando Google "Web Components V1".
Esta versión ya podemos considerarla definitivamente un estándar abierto, dado que en el
proceso de su creación han participado todo un bloque de empresas y profesionales de diversas
áreas de la informática.
Web Components V1 trajo con si una novedad principal con respecto la versión V0, la sustitución
de los HTML Imports por los ES6 Module Imports. Enseguida hablaremos de ello con más detalle.
Custom Elements:
Esta especificación describe el método que nos permitirá crear nuevas etiquetas personalizadas,
propietarias. Estas etiquetas las podremos ingeniar para dar respuesta a cualquier necesidad
que podamos tener. Son los casos básicos que hemos visto en los puntos anteriores de este
artículo.
HTML Templates:
Permite importar un pedazo de código que podrás usar en un lugar de tu página. Ese código
podrá tener HTML, CSS y Javascript. El HTML no se visualizará directamente en la página, pero
lo podrías acceder con Javascript e inyectar en algún lugar. Pero aunque se llame
específicamente "HTML Imports", realmente sirve para cargar de una manera única tanto HTML
como CSS como Javascript. Además podrás tener dentro un "HTML Template", con las ventajas
que ellos aportan. Mendiante código Javascript seremos capaces también de registrar
componentes personalizados "Custom Elements" o realizar otro tipo de acciones sobre el
contenido de la página que sean necesarias.
Shadow DOM:
Este sistema permite tener una parte del DOM oculta a otros bloques de la página. Se dice
comúnmente que estamos encapsulando parte del DOM para que no interfiera con otros
elementos de la página.
Básicamente te sirve para solucionar un caso común que ocurre al incluir un plugin de terceros.
A veces usan clases o identificadores para aplicar estilos que afectan a otros elementos de la
página, descolocando cosas que no debería o alterando su aspecto. Pues con el Shadow DOM
podemos hacer que los componentes tengan partes que no estarían visibles desde fuera,
pudiendo colocar estilos que solo afectan al Shadow DOM de un web component y evitando que
estilos de la página sean capaces de afectar al Shadow DOM.
Nota: Estas 4 especificaciones, aunque las tengamos por separado, están encaminadas a trabajar
en conjunto para un mismo fin: poder realizar tus propios componentes para la web. Las
veremos más adelante con detalle.
ES MODULES - Coyuntura de los HTML Imports y su evolución a los Imports de ES6 definitiva
Los HTML Imports fue la parte de Web Components que menos apoyos obtuvo por parte de la
comunidad durante el proceso de estandarización. Tanto es así que muchos navegadores nunca
los han llegado a soportar.
El problema de los HTML Imports era que cubria un mismo objetivo de otra herramienta usada
para requerir código, los ES6 Modules. Mientras que los HTML Imports estaban preparados para
requerir archivos HTML, con los Module imports de ES6 estaban preparados para traerse código
Javascript, pero esta diferencia no fue suficiente para convencer a la comunidad de la necesidad
de un estándar para importar código en la web.
Así que finalmente se decidió usar los ES6 Modules, que actualmente ya están disponibles en
los navegadores, en detrimento de los HTML Imports. Esto tuvo una implicación importante en
los Web Components, porque antes se programaban dentro de archivos HTML y se comenzó a
programar dentro de archivos Javascript. Hoy queda casi como una anécdota, pero el
desarrollador que ha seguido de cerca la evolución de este estándar seguro que tiene una
opinión sobre si era más conveniente o menos el escribir componentes en el contexto de
ficheros HTML o en ficheros Javascript.
Ventajas de ES6 Modules respecto a HTML Imports: Se adapta mejor a las costumbres de la
comunidad en cuanto al desarrollo frontend, ya que los desarrolladores están acostumbrados a
escribir componentes en frameworks Javascript, dentro de archivos Javascript. Pero sobre todo,
gracias a escribir en archivos Javascript es más fácil hacer convivir Web Components en el marco
de cualquier proyecto web, ya que las mismas herramientas que se usan para llevar a producción
código frontend son las que se usan para llevar a producción elementos personalizados del
estándar Web Components.
Ventajas de HTML Imports respecto a ES6 Modules: La curva de aprendizaje para personas que
no tengan muchos conocimientos de programación era mucho más sencilla. Al escribirse todo
en el contexto de un archivo HTML el procedimiento era mucho más similar a cómo se desarrolla
una web tradicional. Al escribir los templates en archivos HTML, el editor ayuda mejor al
desarrollador, con completado de código, resaltado de sintaxis, etc. En resumen, la experiencia
de desarrollo es más sencilla y ayuda a que cualquier persona pueda crear sus propios
componentes con bastantes menos conocimientos de Javascript.
Sea como sea, lo cierto es que Web Components con ES6 Modules crea muchas menos fricciones
con el proceso de desarrollo de aplicaciones modernas y resulta mucho más sencillo integrar las
ventajas de este estándar en el estado del desarrollo actual. Sin embargo, no se ha descartado
definitivamente la incorporación de alguna herramienta o especificación que permita escribir
los templates en archivos HTML, para poder definitivamente aunar las ventajas de HTML imports
y ES6 Imports.
Actualmente Web Components es un estándar Javascript soportado por todos los navegadores
del mercado. Es decir, que los puedes usar tal cual, sin preocuparte de si tal navegador o tal otro
los muestre bien o mal.
No obstante, hay navegadores como Internet Explorer que no reciben actualizaciones, dado que
su propio fabricante ha retirado completamente el soporte a ese software. Esos navegadores no
son compatibles con el estándar Web Components, ni lo serán nunca. Aún así, para los
navegadores desactualizados es posible usar lo que llamamos un Polyfill.
Custom Elements
Soporte total en Chrome, Opera y Android Browser > 4.4.4 y Chrome para Android 46
HTML Templates
Estado de la especificación: LS (Living Standard, por la Whatwg)
Soporte total para todos los navegadores menos IE y Opera mini (Edge lo aplicará de manera
inminente)
HTML Imports
Soporte total en Chrome, Opera y Android Browser > 44 y Chrome para Android 46
Shadow DOM
Soporte total en Chrome, Opera y Android Browser > 4.4 y Chrome para Android 46
Hoy todos los navegadores soportan o están desarrollando el soporte a todas las
especificaciones del estándar, menos los HTML Imports, que están en estado de discusión.
Además el soporte de los imports con Javascript es prácticamente total:
Soporte total en todos los navegadores modernos (Inclusive Edge pero excluido Internet
Explorer)
Como has podido ver, el que más soporte le da es Chrome. Otros navegadores como Firefox o
Edge apenas están empezando, por lo que tendríamos que usar algún tipo de Polyfill. De todos
modos, para saber el soporte en el momento actual una rápida consulta a [Link] te
ofrecerá la información actualizada.
No obstante, lo cierto es que diversos actores se han apresurado a presentar algunas librerías
que nos permiten desarrollar hoy mismo con la tecnología de los Web Components. Te las
resumimos a continuación:
Lit:
Lit, antes conocido con el nombre de LitElement, es una micro-librería para el desarrollo de
custom elements (pesa más o menos 5KB, por lo que su huella es mínima y sus ventajas muy
elevadas). Lit está creada por un equipo de desarrollo dependiente de Google que trata de cubrir
las necesidades que el estándar no llega a resolver, para conseguir una experienca de desarrollo
de alto nivel. A nuestro modo de ver, Lit es la mejor alternativa para desarrollar componentes.
Polymer:
Es una librería impulsada por Google que actualmente se encuentra solo en fase de
mantenimiento. Fue la mejor alternativa para desarrollar Web Components, aunque el propio
equipo de desarrollo de Polymer publicó más adelante LitElement / Lit, que mejora todavía las
prestaciones de Polymer, el rendimiento y reduce el peso.
Stencil
Es la librería desarrollada por el equipo de Ionic, que pretende ser lo más abierta posible, para
que se pueda usar junto con cualquier stack de tecnologías moderno. Se integra muy bien con
el novedoso Ionic 4, aunque lo podemos usar donde queramos.
X-Tag:
Si te interesa este tema, te recomendamos un artículo completo dedicado a analizar las librerías
basadas en el estándar de Web Components.
Conclusión
Hemos conocido únicamente la punta del iceberg en lo que respecta a web components, pero
en breve analizaremos cada una de las partes de este estándar que va a revolucionar el
desarrollo front end.
Muchos sitios están ya usando partes de las especificaciones de Web Components para producir
sus interfaces e implementar funcionalidad del lado del cliente, como por ejemplo Youtube o
Github. No dejes de usarlo porque no estén totalmente disponibles en los navegadores, puesto
que puedes usar los mencionados polyfills para obtener esa compatibilidad. Te estarás
preparando para el futuro.
En los próximos artículos vamos a recorrer cada una de las partes de Web Components para ver
ejemplos sobre cómo se implementan, ya en la práctica. Comenzaremos viendo cómo se hace
un Custom Element con Javascript nativo.
En el Manual de Web Components usamos generalmente código de Web Components V0, por
lo que algunas cosas pueden hacerse de manera distinta, sobre todo en lo que se refiere a los
HTML Imports. Sin embargo, la filosofía sigue siendo la misma, por lo que sigue siendo una buena
lectura, aunque los ejemplos puedan no funcionar en navegadores actuales. De todos modos, si
lo que quieres es desarrollar con Web Components lo ideal sería usar además alguna librería
como Polymer o Stencil, ya que ye simplifican bastante el proceso de trabajo y te llevan mucho
más lejos con menos esfuerzo.
Enlace: [Link]
Cómo realizar Custom Elements con Javascript básico, basando los estándares de los Web
Components y sin usar ninguna librería.
En el anterior artículo conocimos qué son los Web Components y por qué estas especificaciones
representan una novedad muy significativa en el mundo del desarrollo de interfaces de usuario
y aplicaciones web con Javascript del lado del cliente en general.
Conocimos que una de las especificaciones es la de "Custom Elements", que quizás sea la más
representativa porque es la que nos permite hacer nuevos elementos del HTML, que realizan
funcionalidades personalizadas o presentan información de una nueva manera. Además, estos
Custom Elements los puedes usar directamente en tu página, sin necesidad de programación.
Para ser correctos el desarrollador que crea el custom element generalmente sí necesitará
realizar tareas de programación, aunque todos aquellos que lo usen, lo harán mediante la
expresión de una etiqueta, de manera declarativa.
Actualización: Hemos actualizado el código de este artículo para mostrar los ejemplos usando el
estándar definitivo de Web Components V1, que es el que finalmente se ha instaurado, así que
el texto está al día. El vídeo final no obstante pertenece a una versión antigua de Web
Components.
Los Custom Elements no son algo totalmente ajeno al HTML tradicional. Si lo ves bien, un
ejemplo de Custom Element que conocemos de toda la vida es una etiqueta SELECT, que permite
definir por medio de un código HTML sencillo un componente que tiene un comportamiento
propio: lo pulsamos y nos permite ver varias opciones sobre las que podemos escoger una o
varias. Esos SELECT los podemos agrupar con otros campos para hacer componentes mayores,
como serían formularios. Obviamente, esos elementos existen desde toda la vida y no los
habíamos entendido desde la perspectiva de los web components, pero nos hacen entender
bien en qué se basa esta novedad de los custom elements.
En este y en los próximos artículos del manual de Web Components vamos a aprender a usar las
diferentes especificaciones de web componets usando Javascript estándar, o sea, lo que se
conoce en el argot de los desarrolladores como VanillaJS. Es importante porque veremos que
para crear nuevos custom elements no necesito ninguna librería externa al Javascript que ya te
soportan de manera nativa los navegadores.
No obstante, debemos insistir en que el desarrollo de web components será mucho más rápido
si nos basamos en alguna librería que nos facilite ciertos procesos habituales, principalmente
por hacer nuestras horas de desarrollo más productivas.
Las librerías como Polymer, LitElement o Stencil también nos aportan una capa adicional en
relación a la compatibilidad, además de optimizar algunos procesos interesantes de cara a crear
aplicaciones web más rápidas. Es por ello que los ejemplos de este manual tienen un valor más
didáctico que otra cosa, ya que conocer los procesos de Javascript para la creación de Web
Components ayudará mucho a la hora de entender cómo se realizan usando una librería por
encima.
Nota: Si te interesa saber más sobre estas bibliotecas de utilidad para desarrollo encima del
estándar, te recomendamos la lectura del artículo Librerías Javascript basadas en el estándar
Web Components.
Iremos poco a poco introduciéndonos en el mundo de los Custom Elements, creando elementos
sencillos que no nos compliquen demasiado la vida inicialmente. Obviamente, de momento no
serán los más atractivos funcional o estéticamente, pero facilitará el aprendizaje.
Nota: Aunque en este artículo usaremos solamente la especificación de los Custom Elements, lo
habitual es que se usen en conjunto varias, o todas, las especificaciones de Web Components.
Verás que sencillo es esto. Vamos a crear un componente llamado "dw-holamundo". Una vez
definido lo usaremos de esta manera:
<dw-holamundo></dw-holamundo>
<script>
[Link]('dw-holamundo', DwHolamundo);
</script>
Ya está! tenemos registrado nuestro primer custom element y sabemos usarlo. Si estabas
esperando alguna complejidad adicional, sentimos decepcionarte.
Nuestro problema es que, tal cual hemos hecho nuestro elemento personalizado, no hace
absolutamente nada. Tendremos que asignarle algún comportamiento, alguna forma, lo que
sea, para que realmente tenga sentido nuestro primer ejemplo. Ahora veremos cómo mejorarlo
pero antes quiero que veas el código fuente de este ejercicio:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
</head>
<body>
<dw-holamundo></dw-holamundo>
<script>
[Link]('dw-holamundo', DwHolamundo);
</script>
</body>
</html>
¿No te está faltando algo? ¿Dónde está el script de la librería que da soporte a los web
components? (es una pregunta con trampa)
La respuesta ya la debes saber, porque lo hemos comentado. Web Components es algo que
funciona tal cual en los navegadores, Javascript puro y estándar. No obstante, quizás hayas
pensado en la necesidad de usar un Polyfill, para que los navegadores antiguos puedan entender
estas sentencias nuevas de Javascript.
Nota: El tema de los Polyfill lo veremos con detalle más adelante, pero de momento tenemos
que comentar que este código lo vas a poder ejecutar sin problemas en cualquier navegador
excepto Internet Explorer (Chrome, Firefox, Safari, Opera y Edge, que esta migrando a
Chromium también posiblemente ya puedas en el momento de leer este texto). Dado que es un
estándar del W3C los navegadores ya lo han implementado en bloque. Insistimos, es Javascript
nativo. Sin embargo, si quieres extender soporte a todos los demás navegadores, aunque sean
viejos, necesitas implementar un polyfill. Tienes más información sobre esto en el artículo qué
son los Web Components.
Para aplicar algún comportamiento específico a nuestro primer web component se nos complica
un poco el código, porque requerimos de varios pasos. Realmente son pocas sentencias con las
que esperamos te familiarizarás rápidamente.
Decidir la clase molde que vamos a usar para partir como base para la especialización de nuestro
componente. El la clase es algo propio de Javascript y es algo así como el molde con el que se va
a crear el elemento personalizado. Podemos usar como molde otros elementos de HTML, o
simplemente el prototipo de un elemento HTML genérico, que nos lo ofrece la clase que hemos
usado para extender "HTMLElement"
Por medio del constructor de la clase, aplicar cualquier código Javascript que permita construir
el componente con sus particularidades. Existen diversos eventos propios del estándar de los
Custom Elements donde también puedo asignar comportamientos cuando se están creando los
elementos, además del constructor. Por ejemplo el "connectedCallback", que se ejecuta cada
vez que el custom element inserta en la página. Existen en el estándar varios eventos de estos
para realizar acciones en distintos momentos del ciclo de vida de los web components. Los
veremos más adelante con detalle
Ahora te muestro el código completo, solo la parte de Javascript que es la que ha cambiado, con
estas tres acciones que acabamos de comentar.
constructor() {
super();
[Link]('dw-holamundo', DwHolamundo);
Tómate un tiempo para revisar el código y identifica estos tres bloques necesarios para poder
definir nuestro elemento personalizado.
Verás que se define la clase del componente, que hemos llamado "DwHolamundo". Esta clase
es la que implementará este custom element.
La clase se crea en base a otra clase, y por medio de la herencia (extends) conseguimos que
nuestro componente especialice a otra etiqueta HTML existente. Ese prototipo en este caso,
sobre el que partimos para definir nuestro custom element se llama "HTMLElement".
La única cosa propia de este componente que estamos agregando encima del elemento HTML
genérico está en la línea [Link] = "Hola Mundo!";. Por medio de este código solamente
se está accediendo al elemento concreto que se está creando y asignando un texto a su
propiedad "textContent", con lo que conseguiremos escribir algo dentro del contenido del
Custom Element que se está definiendo.
El código que estoy usando lo tienes en GitHub en esta dirección: Código hola-mundo-web-
[Link] del repositorio de ejemplos de web components.
Ten en cuenta que este primer custom element lo hemos hecho muy sencillo, evitando tocar
algunos temas importantes, que reservamos para próximos artículos del Manual de Web
Components. Más que nada por dejar las cosas fáciles al principio y evitar más complejidades
de las estrictamente necesarias para este "hola mundo".
Para completar y ampliar estas explicaciones te recomendamos ver el siguiente vídeo en el que
mostramos cómo se crean Web Components con Javascript nativo, es decir, sin usar ninguna
librería más allá de las que nos ofrece el estándar de Javascript.
Por favor, ten en cuenta que este vídeo fue grabado con un código ligéramente diferente, ya
que utilizaba la versión anterior de Web components que finalmente no vió la luz como un
estándar definitivo. Por tanto, sigue las indicaciones en el texto del artículo que acabas de leer.
[Link]
En este artículo vamos a ver un sencillo ejemplo que nos permita explorar otra de las
prestaciones de los Web Components. Se basa simplemente en la posibilidad de crear unos
componentes en base a otros. Para ello usaremos las técnicas de creación de Custom Elements
ya relatadas en el artículo anterior, agregando nuevo conocimiento práctico.
Por tanto, te recomendamos saltar este artículo y aprender a realizar los llamados "Autonomous
Custom Element" (los basados en clases, usando etiquetas nuevas con nombres inventados por
ti mismo), que son los componentes que se pueden usar de manera autónoma, sin extender una
etiqueta nativa como un botón. Quizás más adelante retomen esta propuesta y permitan
exender etiquetas nativas, pero va a depender de si finalmente se apoya o no esta modalidad
de creación de componentes.
Creemos que el concepto de extensión se debe entender, pero queremos insistir en ello porque
es una de las principales filosofías de trabajo que nos traen los Web Components. Básicamente,
este estándar se ha creado de manera que permita que los desarrolladores extiendan el HTML,
creando aquellos nuevos elementos esenciales para realizar su tarea.
Esa capacidad de extensión no solo se da con elementos que existan actualmente en el HTML,
sino también con otros custom elements. Es algo que vemos continuamente en todos los
ámbitos.
En un coche tenemos varios elementos, ruedas, motor, suspensión y éstos a su vez están
formados de otros elementos: por ejemplo el motor a base de un cilindros, pistones, bielas,
cigueñal, etc. En el mundo del lenguaje de las personas tenemos las letras y éstas forman
palabras y las palabras forman frases, etc.
En el mundo de la web podemos tener sistemas compuestos de varios elementos, como un
cuadro de búsqueda, que está hecho de un botón y un campo de texto. Para construir una web
podré usar botones y campos de texto, pero si lo que quiero hacer es un campo de búsqueda,
usaré directamente el componente de búsqueda. Este componente funciona exactamente igual
que si fuera un elemento suelto, es decir, tiene un nuevo tag (etiqueta) que usaré para insertarlo
en una página. Por tanto, su complejidad y los componentes internos que necesite para
representarse, quedarán encapsulados y protegidos del exterior.
Ten en cuenta que el siguiente código está desactualizado por no haberse concretado
finalmente en el estándar esta modalidad de desarrollo de componentes. como se explicó ya.
En el momento en el que nos encontramos todavía es un poco pronto para hacer un ejemplo
complejo, con el que podamos representar la capacidad de los Web Components, de asociarse
unos con otros para crear elementos sofisticados. Para hacer todo esto necesitamos hablar
antes de otras especificaciones de las 4 disponibles en este estándar. Así que nos vamos a
conformar por ahora de hacer un elemento que extienda a otro.
Crearemos un tipo de botón nuevo, que especializa los botones que existen en el lenguaje HTML
común. Nuestro botón se llama "botonholamundo". No hemos sido demasiado originales. Su
comportamiento es tan básico como representarse con un texto ya definido (escrito dentro del
botón) "Hola Mundo!".
Usando el botón:
Para empezar vamos a ver cómo usaríamos este custom element, porque difiere un poco del
ejemplo del artículo anterior.
<button is="dw-botonholamundo"></button>
Como puedes ver, ahora no estoy creando una nueva etiqueta personalizada, sino una
especialización de una etiqueta ya existente.
La etiqueta sobre la que he partido como base es BUTTON y le hemos colocado el atributo
is="dw-botonholamundo" para indicar que no es un botón normal, sino uno que lo extiende y
especializa.
Para comenzar, al crear el prototipo no vamos a partir del prototipo genérico de elemento
HTML, sino del prototipo de un elemento HTML botón: [Link].
Ahora asignamos un pequeño comportamiento a este botón, que especializa el botón genérico
del HTML. Realmente solo le estamos cambiando el texto.
[Link] = function() {
};
A la hora de registrar el componente hay otro detalle fundamental para crear estos elementos
que extienden otros y es el uso del atributo "extends" al que le hemos colocado el valor del
elemento que está extendiendo: "button".
[Link]('dw-botonholamundo', {
prototype: prototipo,
extends: 'button'
});
Con eso es todo! Ya tenemos nuestro "dw-botonholamundo" listo, un botón que especializa y
extiende los botones básicos que existen en el HTML tradicional.
Esperamos que te haya gustado, prueba a extender otros elementos y hacer tus propios
experimentos. Nosotros para seguir avanzando vamos a aprender en el siguiente artículo otra
de las especificaciones de los Web Components como es el sistema de templates.
Estamos revisando poco a poco los distintos elementos de los Web Components en Javascript,
el estándar de la W3C para el desarrollo del lado del cliente. En pasados artículos ya
presentamos los Web Components y además vimos cómo se desarrollan Custom Elements.
Ahora le toca el turno al estándar Template, que nos permite crear plantillas que podemos
completar con datos y presentar luego en el contenido de la página mediante Javascript. Es una
novedad muy importante, ya disponible en casi todos los navegadores, por lo que deberíamos
tenerlo presente para desarrollar con Javascript. En este artículo explicaremos en qué consiste
y veremos ejemplos para entender su funcionamiento, siempre con Vanilla JS (Javascript nativo).
Los sistemas de templates son uno de los componentes de aplicaciones web que nos facilitan el
mantenimiento del código. Es una herramienta general que encontramos en diferentes
lenguajes y es básica para separar la capa de presentación de la programación de procesos o la
obtención de datos.
En Javascript hasta el momento no contábamos con ningún sistema para hacer templating, por
lo que teníamos que usar alguna librería de terceros, como podría ser Handlebars JS.
Afortunadamente para los desarrolladores la W3C ha sido consciente de esta necesidad en los
estándares abiertos y ha creado un sistema de templates que los navegadores son capaces de
interpretar de manera nativa.
Como veremos a continuación, para utilizar sistema de templates requerimos usar dos
componentes principales. Por un lado tendremos un HTML con el conjunto de elementos que
contiene nuestra plantilla y por otro lado necesitaremos de un poco de Javascript para volcar
datos dentro y presentarlos junto con el contenido de la página.
Etiqueta template
La parte de HTML para implementar el sistema de plantillas de los Web Components se escribe
mediante la etiqueta TEMPLATE.
La etiqueta TEMPLATE es bastante especial, puesto que es la única etiqueta de contenido que
no tiene una representación directa en el renderizado de la página. Dicho de otra manera, el
navegador al leer una etiqueta TEMPLATE no la inserta en el contenido visible de la página, sino
que la interpreta y la deja simplemente en memoria para que luego mediante Javascript se
pueda utilizar. Por tanto, cuando en navegador encuentra un template no hace nada con él,
aparte de leerlo, esperando que se use más adelante de alguna manera.
La forma de un template en HTML es como cualquier otro código HTML, sin nada en particular,
aparte de estar englobada entre las etiquetas de apertura y cierre de la plantilla.
<template>
<p>Esto es un template!!</p>
</template>
Como hemos mencionado, para usar un template aparecido entre el HTML de la página,
necesitamos un poco de Javascript.
Esos tres pasos los vamos a ver representados a continuación en el siguiente código.
[Link](clone);
Como verás también, los templates tienen un atributo "content" que contiene el HTML de
dentro de la etiqueta TEMPLATE.
Ahora podemos ver cómo sería una página elemental que está usando el template system nativo
de Javascript.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Template simple</title>
</head>
<body>
<h1>Template simple</h1>
<template id="mitemplate">
<p>Esto es un template!!</p>
</template>
<script>
[Link](clone);
</script>
</body>
</html>
Este código es realmente poco útil por dos motivos. Primero porque generalmente vas a usar el
sistema de templating junto con otros estándares de los Web Components. Pero segundo
porque si querías presentar un texto directamente en la página podrías haberlo colocado tal cual
en el cuerpo, en vez de accionar el sistema de plantillas y volcar ese contenido con Javascript.
Paralelamente, como hemos dicho, es muy habitual contar con algún tipo de repetición que nos
permita iterar y repetir varias veces el template en el cuerpo de la página.
Otra cosa que veremos en el ejemplo a continuación es que habitualmente dentro de un
template podrás encontrar no solo código HTML, sino también código CSS que afectará a los
elementos de este template.
Ahora veremos un ejemplo más completo de uso de templates, en el que ya tenemos un bucle
que recorre un array para repetir un template determinadas veces
En nuestro ejemplo vamos a hacer un listado de ciudades del mundo, con un encabezamiento
que rotule el título de este template. Antes de comenzar este código vamos a aclarar dos puntos.
Estilos CSS son válidos en un template: Aparte de código HTML podrás incluir también código
CSS en un template. Este código lo colocas como siempre, con la etiqueta STYLE. La novedad es
que estos estilos solo afectan al HTML del template, es decir, no salen para afuera y por tanto
no afectan a otros elementos del cuerpo de la página. Este punto es muy interesante y a la vez
muy útil porque permite que coloquemos estilos a etiquetas sin preocuparnos que éstos puedan
trastocar el aspecto del resto de la página.
Unos templates contienen a otros: Cuando tienes un template más elaborado, puede que te
encuentres en la necesidad de anidar templates. Por ejemplo en nuestro caso, identificamos dos
bloques fundamentales:
Titular del template, el encabezado, que aparece una única vez. Cada una de las ciudades, que
estará en un template que se repetirá una serie de veces, una vez por cada ciudad. Entendidos
los puntos anteriores, serás capaz de interpretar bien este código.
<template id="templatesimple">
<style>
h1{
color: red;
}
p{
background-color: #ddd;
}
</style>
<h1>Ciudades del mundo</h1>
<template id="templateciudades">
<p></p>
</template>
</template>
var p = [Link]("#templateciudades").[Link]("p");
[Link](function(ciudad){
[Link] = ciudad;
[Link](newP);
});
[Link](clone);
Nota: Casi sin lugar a dudas te parecerá algo complejo para la relativamente sencilla tarea que
se está realizando. Sin embargo, librerías como Polymer te ayudan a simplificar bastante este
código.
Conclusión
Hemos conocido el sistema de templates nativo de Javascript y hemos hecho un par de ejemplos
para aclarar cómo se usa, en un template básico y en otro que incluye una repetición.
Ya hemos advertido que el verdadero uso de los templates se da cuando los usas en conjunto
con otras herramientas del estándar de los web components, por ejemplo cuando el template
forma parte de un Custom Element.
Aunque te pueda haber parecido complejo el código Javascript para usar un template tenemos
que insistir en dos puntos:
El template que usas dentro de un Custom Element queda encapsulado en el custom element,
por lo que lo puedes programar una vez y usar infinitas veces en uno o varios proyectos. O sea,
al final toda la complejidad se queda en el código que vas a reutilizar sin preocuparte de nada
Existen librerías que nos permiten volcar de una manera más sencilla datos en los templates,
que facilitarán crear templates con variables que se rellenan con propiedades de un objeto. Esa
parte no la incluye el estándar de Javascript así que para hacer un código verdaderamente fácil
de mantener se recomendaría usar alguna librería adicional como LitElement. LitElement es la
evolución de la librería Polymer, creada por el mismo equipo pero mucho más ligera y rápida.
LitElement permite sacarle partido a los template string literals de Javascript, creando un
sistema de templating de mucho más alto nivel, que mejorará mucho la experiencia de
desarrollo y la mantenibilidad de los proyectos.
En futuros artículos seguiremos usando el sistema de template de Web Components, por lo que
podrás ver nuevos ejemplos en breve.
Explicaciones y ejemplos de uso de Shadow DOM el estándar de Web Componentes que nos
sirve para crear elementos del DOM encapsulados en otros elementos de la página.
De todas las especificaciones de los Web Components, el estándar de la W3C para el desarrollo
de componentes modulares y completamente reutilizables, Shadow DOM nos ofrece los
mecanismos más importantes para que los módulos sean realmente autónomos e
independientes de otros elementos de la página. En síntesis, Shadow DOM permite insertar
elementos dentro del DOM de la página, pero sin exponerlos hacia afuera, de modo que no se
puedan tocar accidentalmente.
Cuando creamos un custom element a menudo éste necesita generar nuevos elementos, como
botones, campos de texto, iconos, párrafos, que colocará debajo de su jerarquía. Todos esos
elementos que cree el custom element podremos decir que le pertenecen directamente. El
custom element dueño de sus elementos podrá, o no, ocultarlos de modo que no se puedan
acceder desde fuera. Si se decide ocultar o encapsular esos elementos se usará el Shadow DOM.
En ese caso, los elementos estarán físicamente en el DOM de la página, dependiendo
únicamente del custom element que los ha generado y solo se podrán manipular por su dueño.
Básicamente, este DOM oculto a otros elementos de la página es el que nos permite aislar los
componentes, produciendo la deseada encapsulación. El beneficio básico es que, al usar un
custom element en la página, su contenido encapsulado no podrá interaccionar con otros
elementos de fuera, evitando daños colaterales: Sobre todo, otros elementos de la página no
podrán romper el estilo o comportamiento del custom element que usó el Shadow DOM.
Nota: Quizás hayas experimentado alguna vez la desagradable situación que al insertar un plugin
jQuery éste rompe estilos en tu página. O el componente no funciona porque otras partes de tu
código interaccionan con él, u otros estilos CSS que tenías declarados de manera global. Todo
esto está solucionado en los Web Components y mucho depende directamente de la
especificación de Shadow DOM.
Ahora vamos a crear unos ejemplos básicos en los que usaremos la especificación de Shadow
DOM para que, mediante Javascript, podamos crear e inyectar nuevos elementos en el DOM de
la página, pero posibilitando que estén ocultos.
Nota: Como otras especificaciones de los Web Components, podemos usar Shadow DOM sin
necesidad de utilizarlo en conjunto con otras especificaciones como la de Custom Elements. Sin
embargo, lo cierto es que cobra especial sentido y utilidad cuando usamos varias de las
especificaciones en conjunto. Por ello, el siguiente ejemplo tiene sobre todo valor didáctico,
pero no ilustra del todo su uso más habitual. Veremos ejemplos que usen el Shadow DOM junto
con otras especificaciones más adelante, siendo que en este artículo en el último ejemplo
mezclaremos la especificación de Template y la de Shadow DOM.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Shadow DOM</title>
<style>
p{
color: red;
}
</style>
</head>
<body>
<div id="elem"></div>
<script>
//un elemento de la página
var elem = [Link]("#elem");
//cambiamos el contenido de ese elemento, esto será creado como "shadow DOM"
[Link] = "<p>Esto va al shadow DOM</p>";
</script>
</body>
</html>
Más tarde, cuando ya hemos decidido que queremos usar Shadow DOM, tenemos que producir
una raíz donde se va a insertar todo elemento que vaya a estar encapsulado. A esa raíz se la
conoce como "Shadow Root" y se genera con la siguiente instrucción:
Por último tenemos que añadir nuevos elementos dentro del Shadow Root y eso lo podemos
hacer mediante varios mecanismos. Un ejemplo sería editar su propiedad innerHTML.
Ese párrafo no se podrá tocar desde fuera. Por eso, si te fijas, en la cabecera teníamos un estilo
que aplicaría a todos los párrafos de la página y, sin embargo, a la hora de la verdad, no está
afectando al párrafo que hemos colocado dentro del Shadow Root.
Nota: Como ves en este ejemplo, insistimos nuevamente, no es necesario incluir ningún tipo de
librería adicional para que el navegador entienda el Shadow DOM. Sin embargo, de momento
esto solo funcionará en Chrome y Opera que son los que más se han apresurado a cumplir el
estándar. Por supuesto, si usas el correspondiente polyfill podrás ver el ejemplo funcionando
también en otros navegadores. Sobre el Polyfill hablaremos también en detalle en artículos
futuros, aunque también tenemos unas notas interesantes que aportar más tarde.
Obviamente, en ocasiones conviene poder saltarse la regla y aplicar estilos a elementos que
están dentro de shadow DOM. Para ello tenemos un selector llamado ::shadow. En realidad es
un pseudo elemento que se usa anteponiendo al selector que queramos aplicar dentro de un
nodo Shadow Root.
Para que el párrafo anterior estuviera afectado por el CSS tendríamos que usar ::shadow de la
siguiente manera.
<style>
::shadow p{
color: red;
}
</style>
Es una funcionalidad útil, aunque debes tener en cuenta que el pseudo elemento ::shadow se
ha marcado como "depretated" (va a estar obsoleto y por tanto no se aplicará soporte en
navegadores en adelante). No obstante, aunque este pseudoelemento sirva para saltarse el
encapsulamiento entendemos que resulta bastante interesante, por lo que esperaríamos que
se permita el uso de alguna alternativa similar para poder cubrir esta previsible necesidad.
Quizás la parte que resulta más complicado de simular meditante un polyfill, dentro de lo que
respecta a los web components, es la de Shadow DOM. Por ello, el soporte a esta especificación
de la W3C en los "polyfilled browsers" no es completo.
Por tanto, aunque el navegador muestre en la página aquellos elementos que se hayan colocado
dentro de un Shadow Root, realmente no existirá esa mencionada encapsulación y se podrán
tocar desde fuera, o alterar su aspecto con CSS definidos de manera global.
Ese motivo también hace que librerías como Polymer toquen el Shadow DOM, al menos por
ahora, de una manera especial, no aportando todas las ventajas que tendría a priori en los
navegadores que no lo soportan de manera nativa. Esto se hace para evitar afectar muy
negativamente al rendimiento de las aplicaciones con Web Components y para que el
comportamiento sea diferente en navegadores que lo implementan de manera nativa y los que
no.
Antes de acabar, vamos a ver cómo alterar un poco nuestro ejemplo para que podamos usar un
template, cuyo contenido se va a insertar como Shadow DOM. Recuerda que vimos templates
de Web Components en un artículo anterior.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Shadow DOM</title>
</head>
<body>
<div id="elem"></div>
<template>
<p>Esto es un template!!</p>
</template>
<script>
//accedo al template
var template = [Link]('template').content;
//clono el contenido del template
var clone = [Link](true);
//accedo a un elemento
var elem = [Link]("#elem");
//creo el shadow root
var shadow = [Link]();
//le añado el clon del template
[Link](clone);
</script>
</body>
</html>
La diferencia es bien poca, simplemente tengo que acceder al template y clonar aquella parte
que quiero usar dentro del Sadow DOM de otro elemento.
Luego ese clon del template es el que añado al Shadow Root con el método appendChild().
[Link](clone);
FUENTE: [Link]
En este artículo crearemos un completo elemento personalizado (custom element), que incluye
trabajo con Shadow DOM y uso de slots, usando el estándar Javascript Web Components
Estamos actualizando el Manual de Web Components a la versión más reciente y definitiva del
estándar de Javascript, Web Components V1, ya que inicialmente se escribió para la versión
previa (V0) que actualmente ya no está soportada. Además lo estamos ampliando para agregar
nuevos ejemplos como el que nos ocupa en este artículo.
En este ejercicio vamos a realizar un componente nativo de un botón con animación, que
además es capaz de atender a diversos estados. Básicamente es un botón que, cuando se pulsa,
crea una pequeña animación y que además tiene un atributo llamado "status" que permite
actualizar el aspecto del botón, de modo que de un poco de feedback visual al usuario.
Una de las novedades del estándar Web Components V1 es que usa clases (de programación
orientada a objetos) para implementar los componentes. La clase puede extender cualquier
elemento nativo del HTML, pero lo común será extender HTMLElement.
// implementar el componente
Luego registramos el componente con el nombre de la etiqueta, que tiene que contener un
guión, y el nombre de la clase usada para implementarlo.
[Link]('boton-status', BotonStatus);
Podemos aprovechar una de las herramientas más útiles de ES6 como son los template strings
para la creación del template del componente. Esto nos permite interpolar variables o
propiedades del componente de una manera muy sencilla, que además produce un código muy
legible.
Para facilitar la utilización del template dentro del componente me voy a apoyar en un método
getter de Javascript, lo que me permitirá usar este template dentro de la clase del componente,
tal como se usaría una propiedad común.
get template() {
return `
<style>
div {
display: inline-block;
color: #fff;
border-radius: 3px;
padding: 10px;
cursor:pointer;
outline:none;
animation-duration: 0.3s;
animation-timing-function: ease-in;
background-color: #000;
}
div:active{
animation-name: anim;
}
@keyframes anim {
0% {transform: scale(1);}
10%, 40% {transform: scale(0.7) rotate(-1.5deg);}
100% {transform: scale(1) rotate(0);}
}
.neutral {
background-color: #888;
}
.danger {
background-color: #d66;
}
.success {
background-color: #3a6;
}
</style>
<div class="${[Link]}"><slot></slot></div>
`;
}
La parte más interesante del template lo tenemos en la línea siguiente:
<div class="${[Link]}"><slot></slot></div>
Aquí está interesante apreciar como se ha embutido el valor de la propiedad status del
componente. Esta propiedad pertenece al objeto botón, una vez instanciado. Además en breve
veremos cómo poblar esa propiedad con el valor introducido en el atributo "status", indicado al
usar el componente.
Además, muy interesante tambén es la etiqueta SLOT, que sirve para colocar en este punto el
contenido que tenga la etiqueta del componente.
El constructor de la clase es el lugar más apropiado para construir el Shadow DOM del
componente. Además es el lugar donde se deben inicializar las propiedades y donde podemos
hacer otras cosas, como el acceso a los atributos seteados en la etiqueta del componente, para
inicializar las propiedades con ellos.
constructor() {
super();
Inicializamos la propiedad "[Link]" con el valor del atributo status, que hemos obtenido con
[Link]('status'). Sin embargo, si el atributo no estaba definido en la etiqueta,
simplemente lo inicializamos con un valor adecuado, en nuestro caso la cadena "neutral".
Ahora nos queda hacer que nuestro componente sea reactivo y que pueda actualizar su estado
cada vez que el atributo "status" de la etiqueta del componente cambie.
Esto lo tenemos que hacer con el método del ciclo de vida "attributeChangedCallback", que
recibe el nombre del método, con sus valores anterior y nuevo.
[Link]('attributeChangedCallback');
[Link] = newVal;
[Link]([Link]);
[Link] = [Link];
En este ejemplo estamos reaccionando cuando el atributo actualizado sea "status" y cuando el
contenido antiguo sea distinto que el nuevo seteado (aunque esta comprobación quizás sea un
poco innecesaria, porque el método del ciclo de vida sólo debería invocarse cuando realmente
haya cambios).
En caso que se detecten cambios lo que hacemos es actualizar el valor de la propiedad [Link]
y a continuación hacer que se renderice de nuevo el template, asignando la propiedad
[Link] a el innerHTML del shadowRoot. Esto provocará que se procese de nuevo el
contenido de todo el template y se asigne como Shadow DOM.
Solo que nos falta un detalle muy importante, por motivos de optimización, el estándar de Web
Components V1 nos obliga a crear un método getter llamado "observedAttributes", en el que
tenemos que devolver un array de los atributos que en verdad se desean observar.
return ['status'];
De este modo, nuestro Javascript solamente estará pendiente del atributo "status", para invocar
al attributeChangedCallback() solamente cuando éste cambie. De este modo conseguiremos
que attributeChangedCallback() se ejecute solamente cuando es estrictamente necesario.
Con esto hemos terminado nuestro web component, que será capaz de mostrarse con un estilo
determinado, dependiendo de su atributo status (estilos válidos serán "neutral" en color gris,
"success" en color verde y "danger" en color rojo, aparte de que se usará el color negro para
cualquier status desconocido).
El componente lo ideal es que lo guardemos en un archivo con extensión .js, con el mismo
nombre que el nombre del componente. En este caso sería "[Link]". El código completo
sería el siguiente:
constructor() {
super();
get template() {
return `
<style>
div {
display: inline-block;
color: #fff;
border-radius: 3px;
padding: 10px;
cursor:pointer;
outline:none;
animation-duration: 0.3s;
animation-timing-function: ease-in;
background-color: #000;
}
div:active{
animation-name: anim;
}
@keyframes anim {
0% {transform: scale(1);}
10%, 40% {transform: scale(0.7) rotate(-1.5deg);}
100% {transform: scale(1) rotate(0);}
}
.neutral {
background-color: #888;
}
.danger {
background-color: #d66;
}
.success {
background-color: #3a6;
}
</style>
<div class="${[Link]}"><slot></slot></div>
`;
}
[Link]('boton-status', BotonStatus);
Ahora, en cualquier página donde se pretenda usar lo tenemos que incluir como script:
<script src="[Link]"></script>
Y luego utilizar la etiqueta del componente, con los status que deseemos:
Eso es todo, hemos podido crear un componente nativo, completamente basado en las
características de Web Components V1 y sin necesidad de usar ninguna librería Javascript.
FUENTE : [Link]
Explicamos en qué consiste la especificación de Import en los Web Components, junto con
algunos ejemplos de uso.
De entre todas las especificaciones ahora vamos a explicar la relacionada con los import, que es
la última que nos quedaba por ver en el manual de los Web Components. Se trata de una
especificación bastante sencilla que realmente usaremos poco a nivel de Javascript y más a nivel
de HTML. Pero mejor vamos directamente con las explicaciones.
Cuando desarrollamos tradicionalmente del lado del cliente nos valemos del lenguaje HTML
para definir el contenido, del CSS para definir el aspecto y del Javascript para la funcionalidad o
programación en general. Estos tres lenguajes se pueden escribir en el mismo documento HTML,
pero generalmente su código se coloca en archivos independientes por diversos motivos.
Cuando quieres extender el HTML, por medio de lo que tradicionalmente se conoce como
plugins (recuerda los plugin de jQuery), generalmente tienes que incluir diversos códigos por
separado. Por una parte necesitaremos colocar un poco de HTML que es donde se va a embutir
la funcionalidad del plugin, tendrás un script Javascript que colocarás en tu archivo .js del sitio o
en el archivo [Link] junto con otros plugins que quieras usar y por último un poco de CSS que
generalmente colocarás en el archivo de estilos globales de tu sitio.
No existe una regla que sea totalmente obligatoria sobre cómo situar esos pedazos de código
en tu página y a veces genera un poco de confusión, pero sobre todo dificulta la distribución de
plugins y su mantenimiento. Los creadores de los plugins seguramente les gustaría poder decirte
"mira, coloca este archivo aquí y no te preocupes por nada más". Pero no pueden porque esas
tres porciones de código (HTML + CSS + JS) que tendrás que situar en tu proyecto en lugares
diferentes dependiendo de la arquitectura de tu página.
Para ese caso concreto es el que se crea la nueva especificación de los "import". Se trata
básicamente de incluir todo lo necesario para distribuir un componente en un único archivo
.html. Aunque, a pesar de la extensión no tendrá solo el código HTML para funcionar, sino
también sus estilos y su Javascript para darle vida.
En resumen, cuando quieras usar un Web Component en una página web no vas a tener que
estar incluyendo los distintos códigos de los distintos lenguajes por separado, simplemente
colocarás un único import a tu componente y ya lo tendrás listo para usar. ¿interesante, no?
Nota: Hasta el momento no existen en HTML ninguna etiqueta que nos permita traer un código
HTML que tengamos en otro documento. Esta tarea es algo normal en el día a día del desarrollo
y seguro que la has realizado en alguna ocasión si programas en lenguajes como PHP por medio
de las sentencias include o require. Todos los lenguajes tienen herramientas para traerse y usar
código que hay en otros ficheros, la pregunta mejor sería ¿Cómo es que HTML no la tenía?
En el pasado se trató de hacer uso de algún tipo de técnica que nos permitiera acceso a pedazos
de HTML para mantener en un único lugar partes de la página que se repetían innúmeras veces
a lo largo de todo un sitio web, como por ejemplo la cabecera o el pie. Ninguna de las alternativas
se llegó a establecer por diversos motivos y nos veíamos obligados a implementar esa
funcionalidad del lado del servidor.
Los import de Web Components podrían suplir esta necesidad, pero la verdad es que no están
pensados solo para ello. Realmente, como hemos dicho, están pensados para distribuir
componentes en un único archivo que contiene todo el código necesario para que funcionen.
Como ya sabes lo que es un Custom Element, te aclarará saber que con un Import incluyes todo
el código fuente necesario para que el navegador conozca uno de estos elementos
personalizados. El import lo haces en la cabecera de la página y luego a lo largo de todo el cuerpo
podrás usar la etiqueta que implementa el Custom Element todas las veces que necesites.
Para realizar un import en un documento HTML se usa la etiqueta LINK que ya existe desde hace
tiempo en el lenguaje. Anteriormente LINK te servía únicamente para acceder a una hoja de
estilos externa, en un archivo CSS que generalmente enlazas con todas las páginas de tu sitio.
Ahora los LINK tendrán la posibilidad de definir su atributo rel="import" y con ello indicas que
estás usando esta especificación de Web Components.
Esta etiqueta ahora permite enlazar con un archivo HTML que, como decimos, puede tener
código no solo HTML, sino también CSS o incluso Javascript.
Ahora bien, hacer el import no implica que vayas a mostrar un HTML en un lugar concreto de la
página!! No veas el import como si fuera un "include" de un HTML, sino como un enlace a un
código que realmente no se va a mostrar donde está situado tu import, sino donde tú lo
necesites. Como consecuencia, los import se suelen situar en el HEAD de la página. Allí podremos
colocar todos los import que necesitemos en nuestro documento. Luego usaremos los import
donde se necesiten, atendiendo a estas reglas fundamentales:
El HTML de un import no se va a volcar en el sitio donde has definido tu etiqueta LINK. Osea, si
colocas un import a un archivo que solo contiene código HTML será como si no colocases nada,
ese HTML no aparecerá por ningún sitio, tendrás que volcarlo más tarde con Javascript para que
aparezca donde quieras.
El CSS que haya en un archivo que importes se incluirá como CSS de la página, sumándose al CSS
global con la regla de la cascada. Ahora bien, si colocas CSS lo tendrás que incluir con las
correspondientes etiquetas STYLE y barra STYLE.
El Javascript que haya en un import se ejecutará directamente. Pero para colocar un script lo
tendrás que hacer dentro de las etiquetas SCRIPT.
Los import que te traes con la etiqueta LINK rel="import" se acceden mediante HTTP, que es el
protocolo de transferencia de las páginas web. Esto es importante porque un import solo
funcionará si tu página se accede a través de [Link] En definitiva, para que funcionen tendrás
que acceder al documento que realiza el import a través de un servidor web.
Para los que ya conocen Javascript de antes, es algo parecido a lo que pasa con las solicitudes
Ajax. Realmente es que un import es como si fuera una solicitud Ajax para acceder a otro
documento, que el navegador solicita a un servidor web a través del protocolo HTTP.
Contar con un servidor es sencillo y te vale cualquier servidor que puedas conseguir. En último
término, si no sabes cómo proveerte de un servidor web, te vale subir los archivos a un espacio
de hosting web. Pero si trabajas desde hace tiempo en el mundo web sabrás cómo conseguir un
servidor en local, que es lo más adecuado para la etapa de desarrollo. En [Link]
tienes mucha información para conseguir esto.
Terminaremos este artículo con una pequeña práctica sobre Javascript para acceder a un import.
El objetivo es no quedarnos solo en el conocimiento teórico, pero hay que remarcar que esta
práctica no es realmente habitual en el día a día del desarrollo Web Components. Lo que vamos
a hacer es acceder a un código HTML que está dentro de un import para presentarlo en un lugar
de la página, pero recuerda que lo normal es que el import te sirva para incluir código en
diferentes lenguajes que implementa un Custom Element.
Tenemos primero el archivo que vamos a importar, que contiene código HTML simplemente
(insistimos que ésto no es lo más normal).
Ahora, desde cualquier archivo donde vayamos a importar un elemento, usamos en el HEAD la
etiqueta LINK con rel="import" y luego en el href la ruta del archivo a importar.
Recuerda que por hacer el import, ese contenido HTML a importar no se mostrará dentro de la
página. Luego en el código veremos el script que nos permitiría acceder al contenido del import
para presentarlo en un lugar de la página.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HTML Imports</title>
<link rel="import" href="[Link]" id="miimport">
</head>
<body>
<script>
//accedo al elemento import con id=miimport
var importado = [Link]("#miimport");
Explicamos qué es el ciclo de vida en los componentes basados en el estándar Web Components.
Cómo podemos definir callbacks para ejecutar código en los distintos momentos del ciclo de
vida
Los Web Components son una tecnología que ha cambiado el modo con el que se desarrollan
las aplicaciones para navegadores. Ya hemos empezado a hablar sobre ellos en otras ocasiones
en el Manual de Web Components, así que nos centraremos ahora en un tema específico y clave
para los desarrolladores, como es su ciclo de vida.
Básicamente el ciclo de vida está ahí para servir de utilidad a los desarrolladores de
componentes, ya que permiten escribir código Javascript que será ejecutado cuando el
componente va pasando por sus diferentes estados. Esta operación se realiza por medio de lo
que se conoce como funciones "callback": funciones que son declaradas pero que no se ejecutan
hasta que pasan ciertas cosas.
Para comenzar, vamos a describir los estados de un componente que definen su ciclo de vida:
Created: Ocurre cuando el elemento se crea, pero ojo, no tiene que ver con que el elemento se
muestre. Es como su instanciación en memoria de Javascript. Cada elemento de un tipo de
custom element generado, lanza el método created.
Detached o disconnected: Ocurre cuando un elemento se quita del DOM, se retira del
documento y por tanto desaparece de la página.
Atribute Changed: Ocurre cuando uno de sus atributos cambia de valor, siempre que el atributo
esté siendo observado y por tanto se haya declarado como uno de sus "observedAttributes"
Nota: Estos son los estados del ciclo de vida de los custom elements en Javascript estándar,
aunque algunas librerías basadas en Web Components incorporan otros adicionales.
Existen dos especificaciones de Web Components, una experimental que estuvo vigente durante
cierto tiempo, hasta que el estándar se estabilizó y quedó la especificación definitiva, que es la
que apotaron todos los navegadores. V0 es la especificación inicial, que ahora mismo no aplica
y V1 es la especificación que debemos usar.
Mencionamos esto porque el ciclo de vida de los componentes cambió de la especificación
experimental (V0) a la especificación definitiva (V1), por lo que dependiendo de la antiguedad
de un artículo puedes encontrar que se explica una u otra. De hecho, este artículo explicaba la
especificación experimental y lo hemos actualizado ahora para cubrir la especificación definitiva.
Vamos a comenzar explicando cómo es la especificación definitiva, la que tenemos que usar en
el desarrollo con Web Components. Esta espeficación contiene los métodos siguientes:
Ahora vamos a ver cómo realizar un componente que realiza acciones cuando ocurren cosas en
su ciclo de vida. No importa tanto la funcionalidad del componente como apreciar cómo se va
produciendo la ejecución de los métodos correspondientes a medida que hacemos cosas con el
componente.
Empezamos con algo sencillo para aclarar cuándo se ejecuta el constructor. Primero aclarar que
el constructor es un método tipico de las clases de programación orientada a objetos, pero
también en cierto modo forma parte del ciclo de vida del componente.
Lo relevante del constructor es que se ejecuta cuando el elemento se instancia. Esto quiere decir
que, aunque el elemento solamente se haya declarado como una variable de Javascript, el
constructor se habrá puesto en funcionamiento. Incluso aunque el componente no aparezca en
la página por ningún lugar.
Esto lo podemos ver en el siguiente pedazo de código, donde definimos un componente con su
constructor.
constructor() {
super();
[Link]('Soy el constructor');
}
[Link]('test-lifecycle', TestLifecycle);
[Link]('test-lifecycle');
Es muy importante la llamada a super() en el construtor, antes de hacer cualquier otra cosa, para
que se ejecute el constructor de la clase padre.
Ahora vamos a ver cómo podemos detectar las inserciones en el DOM de este elemento, así
como el momento en el que se elimina del DOM.
// Creamos un elemento
var element = [Link]('test-lifecycle');
// Insertamos en el DOM
[Link](element);
// Eliminamos del DOM
[Link]();
Por último vamos a aprender a realizar acciones cuando un atributo del elemento cambia. Esto
incluye dos pasos importantes:
Para poder detectar cambios en los atributos, éstos tienen que ser observados. Para ello
encontramos una propiedad del estándar que se llama observedAttributes.
Es una propiedad estática, que podemos crear con un getter y que debe contener un array con
todos los nombres de los atributos que deben ser observados.
static get observedAttributes() {
[Link](`Ha cambiado el atributo ${name}, que tenía el valor ${oldValue} y pasa a tener el
valor ${newValue}`);
Para acabar vamos a ver un código de un componente que implementa todos los métodos del
ciclo de vida que hemos visto y su uso con Javascript para crearlo, insertarlo en el DOM, cambiar
un atributo un par de veces y por último retirarlo del DOM.
connectedCallback() {
[Link]('El elemento se ha insertado en el DOM');
}
disconnectedCallback() {
[Link]('El elemento se ha retirado del DOM');
}
// Creamos un elemento
var element = [Link]('test-lifecycle');
// Insertamos en el DOM
[Link](element);
// Cambiamos un atributo que no existía antes
[Link]('dia', 'lunes');
// Volvemos a cambiar el atributo
[Link]('dia', 'martes');
// Eliminamos del DOM
[Link]();
Dado el código anterior, al ejecutarlo aparecerían los siguientes mensajes en la consola de
Javascript del navegador.
Ahora vamos a ver toda otra serie de ejemplos que son muy similares a los que hemos visto en
el artículo hasta ahora, pero que pertenecen a Web Components en su especificación
experimental. Básicamente es lo mismo, pero algún elemento del ciclo de vida ha cambiado de
nombre.
Observarás otro cambio y es que se le están aplicando los métodos del ciclo de vida desde fuera
del componente. Es perfectamente posible, ya que Javascript es muy laxo con respecto a la
visibilidad y acceso a los métodos de las clases.
Puedes ver todos esos estados son como si fueran eventos que ocurren durante la vida de un
componente. Como a los eventos, seremos capaces de asociar funciones manejadoras, que se
encargan de producir comportamientos personalizados para cada suceso. En este caso
llamamos a esas funciones con el término "calback", usado en el estándar como ahora podrás
ver.
Ahora veremos el código del registro de un componente en el que usaremos los diversos
métodos callback del ciclo de vida. Pero para entenderlo te sugerimos la lectura del artículo del
estándar de los Custom Elements, en el que se explicaron ya muchas cosas que aquí vamos a dar
por sabidas.
// Creo un nuevo objeto para registrar un componente, generando un nuevo prototipo
var elemento = [Link]([Link]);
// Defino una función callback para el instante del ciclo de vida "created"
[Link] = function() {
[Link]('se ha creado un elemento');
};
// Defino una función callback para el instante del ciclo de vida "attached"
[Link] = function() {
[Link]('se ha añadido un elemento al DOM');
};
// Defino una función callback para el instante del ciclo de vida "detached
[Link] = function() {
[Link]('se ha retirado un elemento del DOM');
};
// Defino una función callback para el instante del ciclo de vida "attributeCanged"
[Link] = function(attr, oldVal, newVal) {
[Link]('Cambiado ', attr, ' al valor: ', newVal);
};
Solo con que uses un elemento, colocando la etiqueta HTML 'ciclo-de-vida' éste se generaría y
se adjuntaría al DOM, con lo que ya se pondrán en marcha los métodos del ciclo de vida, con sus
correspondientes [Link]().
<ciclo-de-vida></ciclo-de-vida>
Nota: Obviamente, para que ese elemento funcione debe conocerse previamente el elemento,
por lo que el script para registrarlo visto en el punto anterior debería aparecer antes en el código
HTML. (Mira al final el código completo del ejercicio).
Quizás con nuestro ejemplo te sorprenda que no observarás cambios en la página, porque el
elemento del ejemplo no tiene template, pero sí deberías ver los mensajes si abres la consola
Javascript.
- se ha creado un elemento
- se ha añadido un elemento al DOM
Para ver otros métodos del ciclo de vida necesitas el código de algunas funciones Javascript de
manipulación del DOM. Para ello hemos colocado tres botones que invocan tres manipulaciones
diferentes sobre el DOM, que provocarán nuevos mensajes a la consola de Javascript.
Esos eran los tres botones, a los que les colocamos tres manejadores de eventos para realizar
cosas con elementos:
[Link]('cambiaAtr').addEventListener('click', function() {
[Link]('ciclo-de-vida').setAttribute('data-test', 'test-value');
});
[Link]('quitarDOM').addEventListener('click', function() {
[Link]([Link]('ciclo-de-vida'));
});
[Link]('crearElemento').addEventListener('click', function() {
[Link]('ciclo-de-vida');
});
Eso es todo lo que necesitas para practicar con los mecanismos del ciclo de vida de los custom
elements. Ahora para aclarar posibles dudas dejamos el código completo del ejercicio.
Nota: Recuerda que, a pesar que esto sea todo Javascript nativo, solo funcionará para los
navegadores que ya implementan el estándar de los Web Components. Para navegadores que
aún no lo tienen disponible simplemente habría que usar el correspondiente polyfill, del que ya
hemos hablado anteriormente en este manual.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test del ciclo de vida de custom elements</title>
<script>
(function() {
// Creo un nuevo objeto para registrar un componente, generando un nuevo prototipo
var elemento = [Link]([Link]);
// Defino una función callback para el instante del ciclo de vida "created"
[Link] = function() {
[Link]('se ha creado un elemento');
};
// Defino una función callback para el instante del ciclo de vida "attached"
[Link] = function() {
[Link]('se ha añadido un elemento al DOM');
};
// Defino una función callback para el instante del ciclo de vida "detached
[Link] = function() {
[Link]('se ha retirado un elemento del DOM');
};
// Defino una función callback para el instante del ciclo de vida "attributeCanged"
[Link] = function(attr, oldVal, newVal) {
[Link]('Cambiado ', attr, ' al valor: ', newVal);
};
<script>
[Link] = function() {
[Link]('cambiaAtr').addEventListener('click', function() {
[Link]('ciclo-de-vida').setAttribute('data-test', 'test-value');
});
[Link]('quitarDOM').addEventListener('click', function() {
[Link]([Link]('ciclo-de-vida'));
});
[Link]('crearElemento').addEventListener('click', function() {
[Link]('ciclo-de-vida');
});
}
</script>
</body>
</html>
Librerías Javascript hay cientos de ellas. Por suerte o por desgracia sale una nueva por mes!!
Esto ha provocado la aparición de un término "framework fatigue", que define un poco la
situación en la que nos encontramos en el panorama del desarrollo frontend.
En este artículo no quiero provocar todavía más fatiga a los desarrolladores Javascript, sino
poner un poco en relevancia toda una nueva oleada de librerías que, a mi modo de ver, están
haciendo cosas positivas por el hecho de basarse en los estándares.
Por qué es importante que una librería esté basada en todo lo nativo
Cuantas más cosas nativas use una librería o framework para el desarrollo de su funcionalidad
menos código propietario tendrá que ejecutar el cliente web y con ello obtendremos varios
beneficios:
Consumirá menos datos el dispositivo, algo que es importante en conexiones con redes móviles
Consumirá menos tiempo de ejecución, porque no necesitará tanto Javascript para hacer las
cosas
Los puntos anteriores, por supuesto, dependen de la propia librería. Puesto que si la librería usa
estándares pero es muy pesada porque carga cosas innecesarias en una aplicación, o si sus
algoritmos requieren mucho procesamiento, quizás algunas partes como el rendimiento o el
consumo de datos no se cumplan. Pero podemos decir que, si usa lo nativo es mucho más
susceptible de optimizar todas esas parcelas.
Pero además, hay otro punto fundamental que es que todas las librerías basadas en Web
Components son "CROSS FRAMEWORK". Este es un concepto que quizás no se oye tanto, pero
que resulta muy relevante para el momento que nos encontramos.
Cuando elegimos un framework para desarrollar, desde la primera línea de código estamos
incorporando una fuerte dependencia en el proyecto. Esto provoca situaciones que en un futuro
serán embarazosas:
Si el framework se queda obsoleto (no solo que deje de funcionar, sino porque otro framework
mejor aparezca y provoque que el nuestro pase de moda), requerirá construir la aplicación
prácticamente desde cero para poder beneficiarse de los avances en la tecnología.
Las situaciones anteriores no son para nada extrañas en el mundo del desarrollo. Al contrario,
son bastante habituales y cuando estamos desarrollando un proyecto sabemos que a buen
seguro llegará un día que se nos planteen. Es por ello que, cualquier cosa que podamos hacer
para mitigar esos problemas, debería ser vista con buenos ojos.
Todos los motivos anteriores hacen estar firmemente convencido de lo nativo en general y de
Web Components en particular. Pero alguien se puede preguntar ¿Por qué necesito una librería
para desarrollar basado en Web Components?
Lo cierto es que el estándar de Web Components, a día de hoy, no llega tan lejos como llegan
muchas de las librerías o frameworks frontend más habituales. Web Components no ofrece algo
tan útil como el data-binding o la programación reactiva. Claro que todas esas cosas se pueden
incorporar, pero sería a base de tener que escribir mucho código propietario y es justamente
algo que deseamos evitar.
Por eso, si estamos acostumbrados a la experiencia de desarrollo que nos ofrecen frameworks
como Angular o librerías como React, necesitaremos una librería extra para poder ponernos al
mismo nivel.
Sin embargo, las librerías serán generalmente mucho más ligeras y utilizarán muchas más cosas
de lo nativo de Javascript. Por ello, las desventajas de usar una librería serán mucho menores.
Así que, si quieres obtener una experiencia de desarrollo ágil y amistosa y a la vez conseguir
componentes nativos, que funcionan en cualquier aplicación con cualquier framework, te
interesa usar una librería.
Ahora veamos algunas librerías que podremos usar para desarrollar más próximos al estándar y
al Javascript nativo, sin perder eficiencia ni productividad. Son librerías que se basan
principalmente en los estándares, por lo que todo lo que ofrecen lo consiguen comprimir en
muy pocas Kb, en torno a 7Kb solamente, o incluso menos!
LITELEMENT: LitElement es la librería para desarrollo de custom elements creada por el equipo
de Polymer (Google). Es muy cercana al estándar de Web Components y al Javascript nativo, de
hecho tienes que usar lo nativo para la mayoría de las cosas, de ahí su reducido peso. Es
extremadamente rápida, más que cualquier otro framework y librería popular, como React, Vue
y por supuesto Angular.
STENCIL: Esta librería está creada por el equipo de Ionic. Está enfocada en la creación de
interfaces de usuario y de hecho todas las interfaces oficiales que se ofrecen para las
aplicaciones Ionic están basadas en Stencil y por tanto en Web Components. Por supuesto,
puedes usar Stencil para desarrollo de tus componentes, aunque no estés desarrollando
aplicaciones Ionic y podrás usarlas en cualquier framework.
HYPERHTML: Me parece otra librería con un enfoque acertado, ya que usa todo lo posible sobre
Javascript nativo y las nuevas características de ES6 como los Template String Literals. Tiene un
peso muy reducido y un elevado rendimiento.
Quizás los anteriores sean los mayores actores actualmente en el panorama de las librerías
basadas en Web Components. Pero hay mucho más:
POLYMER: Llevamos años hablando de Polymer y no podemos hacer este análisis sin dejar
nombrarlo. Le tenemos que agradecer que haya abierto el camino para la creación del estándar
de Web Components y su popularización. Sin embargo hoy Polymer ya no es una alternativa
recomendable para comenzar un desarrollo. Sigue en mantenimiento, pero es mucho más
pesada que su evolución (LitElement) y ofrece bastante menos rendimiento.
A partir de aquí nos encontramos con muchas otras alternativas, la mayoría son micro-librerías
que pesan en torno de 3KB, cada una con un enfoque particular. Ofrecen una manera
simplificada de crear custom elements y permiten beneficiarnos de las herramientas deseables
para disponer de una experiencia de desarrollo adecuada, como el mencionado data-binding,
manejo del estado, trabajo con templates reactivos y cosas similares.
Atomico que permite crear componentes de manera sencilla, por medio de funciones y hooks.
SlimJS: que se adelanta todavía más en el uso de tecnologías como los decoradores de ES7.
Haunted: que ofrece un API como la de los Hooks de React pero para lit-HTML o HyperHTML.
X-Tag: Es la librería de Mozilla para el desarrollo con Web Components, pero también lleva años
sin actualizaciones.
Como decía al principio, lejos de querer agobiar con tantas alternativas de librerías y
frameworks, lo que quiero resaltar es el hecho de que la comunidad está firmemente
concienciada de que el camino a seguir es el estándar. El surgimiento de tantos proyectos
interesantes lo demuestra.
Por último, también es importante mencionar que las librerías y frameworks más establecidos
en la actualidad, como es el caso de VueJS y Angular, están haciendo esfuerzos para
transformarse y, al menos, ofecer al desarrollador la posibilidad de crear los componentes
basadados en en estándar, en vez de en sus propias abstracciones. No tengo noticias de que
React esté trabajando en el mismo camino. Su justificación es que su librería y el estándar son
productos complementarios, mientras que Web Components es bueno en encapsulación, React
está pensado para data-binding y templates reactivos. Sin embargo, en mi opinión estas
responsabilidades están solapadas y mucho del código de React es innecesario desde que existe
un estándar.
Seguro que nos dejamos más de uno, pero los que hemos agrupado ya son una considerable
lista de proyectos que tratan de sacar lo mejor de Javascript.
Por su peso, muchos de ellos realmente minúsculo, podemos implementarlos con la confianza
de saber que nuestro código va a permanecer muy ligero. Eso sí, no veo mucha necesidad de
mezclarlos entre ellos, ya que todos sirven para hacer las mismas cosas.
A mi personalmente me gustan los que tienen una sintaxis lo más parecida posible a Javascript
y al propio estándar de Web Components. No me gustan tanto los que, por querer simplificar
las cosas a los desarrolladores, proponen un código diferente a cómo haríamos las cosas sin usar
ninguna librería.
En este sentido, estoy seguro que cualquier persona que aprenda LitElement podrá con muy
poco esfuerzo desarrollar web components nativos sin usar librería alguna, pues el código que
se tiene que hacer es extremadamente similar. En este sentido hyperHTML también me parece
muy acertado. Destaqué además en este artículo a Stencil por venir de parte del equipo de Ionic,
aunque el código que se crea es más parecido al de React y menos al estándar, lo que no me
atrae tanto.
Ejemplos de custom elements sencillos y cómo usar la declaración import para incluirlos en una
página web, de modo que se puedan usar.
Este artículo va a presentar un par de ejemplos sencillos de Web Components, muy elementales,
que nos permitan asimilar un poco más las nuevas API para trabajo con este nuevo estándar
desde Javascript.
En el artículo anterior presentamos la especificación import, pero lo que vimos es algo casi
anecdótico, porque realmente un import no sirve para traerse el contenido HTML de un archivo
externo, sino más bien para importar el código de nuevos componentes que podrías usar en
cualquier documento HTML.
En esta ocasión mostraremos un uso más razonable de import, el de traerse el código de dos
custom element creados para la ocasión. En resumen, usaremos las especificaciones:
Custom Elements
HTML Import
Componente dw-date
Este componente simplemente muestra la fecha y hora del instante actual en la página. Se usa
así:
<dw-date></dw-date>
Como comportamiento del componente, alí donde aparezca, se sustituirá por la fecha actual.
Algo así como:
El código del componente tiene esta forma: (con los comentarios y las explicaciones anteriores
del Manual de Web Components estamos seguros que podrás entenderlo)
<script>
//prototipo de elemento, a partir del elemento base
var prototipo = [Link]([Link]);
Componente romper-cadena
Ahora vamos a ver un segundo ejemplo de Web Component sencillo, pero esta vez un poco más
útil. Este elemento permite romper un texto en una longitud en caracteres dada, pero sin
romper las palabras.
El texto de la cadena original será el propio texto que haya en el elemento y además tendrá un
atributo llamado "len" donde se marcará esa longitud máxima de caracteres para el recorte. Si
no es posible romper en esa longitud, porque se rompa una palabra, se entrega la cadena hasta
el espacio en blanco anterior.
<script>
(function() {
function recortar(cadena, len) {
if ([Link] <= len) {
return cadena;
}
var recortada = [Link](0, len);
return [Link](0, [Link]([Link], [Link](' '))) + '...';
}
Ahora llega la parte de los import. Si quieres usar esos componentes en una página los tendrás
que importar. El sistema es bien simple, gracias a la etiqueta IMPORT. Podrás ver el demo
completo de estas dos etiquetas en este código:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Importar un webcomponent</title>
<link rel="import" href="[Link]">
<link rel="import" href="[Link]">
</head>
<body>
<dw-date></dw-date>
<br>
<romper-cadena len="30">Esta cadena se va a romper en la longitud de 30 caracteres
o menos</romper-cadena>
<br>
<romper-cadena len="15">Este elemento me sirve para muchas cosas</romper-
cadena>
</body>
</html>
Como puedes comprobar, después de los correspondientes import, somos capaces de usar las
nuevas etiquetas creadas al registrar los componentes.
Recuerda que es una tecnología estándar, por lo que no necesitas una librería adicional
Javascript para que funcione. Sin embargo, si queremos compatibilidad con navegadores que
aún no implementan este estándar, lo ideal es usar el Polyfill, agregando el script en tu HEAD de
[Link]. Lo puedes hacer directamente desde el CDN:
<script src="[Link]
[Link]"></script>
Esperamos que estos ejemplos te sirvan para seguir avanzando en el aprendizaje de Web
Components, ilustrando con nuevos ejemplos la práctica con esta tecnología. Es interesante ver
las cosas que se pueden conseguir con los custom elements más sencillos y cómo somos capaces
de usarlos en una página web cualquiera.
En el Manual de Web Components hemos abordado diversas especificaciones del estándar que
nos han mostrado por separado las posibilidades de este nuevo modelo de desarrollo
Javascript. Pero la verdad es que estas tecnologías cobran más sentido si se usan en conjunto,
así que vamos a juntarlo todo para experimentar el estándar de la mejor manera.
Usaremos únicamente Javascript estándar, sin apoyarnos en ninguna librería adicional, lo que
se conoce como VanillaJS. Estos ejemplos funcionarán en cualquier navegador, siempre que
incluyas el Polyfill, sin embargo, lo mejor es que los veas en Chrome que es cliente web que
más camino andado tiene para implementar la tecnología.
Nuestro ejercicio consiste en crear un compoente que muestre un mensaje de feedback con
un formato más atractivo estéticamente, que lo que sería un párrafo normal. Algo sencillo para
comenzar, pero que nos permite trabajar con las 4 especificaciones:
• Custom Elements
• Templates
• Shadow DOM
• HTML Import
La etiqueta nueva que vamos a crear se llamará feedback-message. Realmente solo presenta
un mensaje con un estilo especial, que podríamos haber conseguido con una simple clase de
CSS, no obstante como práctica es interesante.
Comenzamos con el archivo del componente. En un único archivo reunimos todo el HTML y el
Javascript necesario para crear un elemento personalizado. Despiezamos sus dos partes
principales:
• El template: donde colocas todo el HTML local que va a tener este componente. Ese
template a menudo estará vacío de contenido y se cargará con Javascript en tiempo de
ejecución. Es nuestro caso. Verás que el template tienen un único párrafo y está vacío.
El contenido lo sacaremos del mismo documento HTML, lo que hay dentro de la
etiqueta del custom element.
• El script: que registrará el componente y le dará su comportamiento especial. En ese
script nos encargamos de hacer diversas tareas laboriosas y de código un tanto largo.
Pero en realidad son pequeñas y simples acciones que están comentadas
perfectamente.
Nota: Para entender bien las diferentes acciones deberías leer los artículos sobre las distintas
especificaciones de Web Components que hemos enlazado antes. Si te parece demasiado
complicado piensa que cuando usas una librería este código se simplifica bastante, llegando a
ser mucho más entendible y sobre todo de un mantenimiento sensiblemente más cómodo.
<template>
<style>
p{
background-color: azure;
font-family: trebuchet ms, tahoma, verdana, arial, sans-serif;
padding: 10px;
}
</style>
<p></p>
</template>
<script>
// Creamos el prototipo de nuestro nuevo elemento
// basándonos en el prototipo del elemento html genérico
var prototipo = [Link]([Link]);
// clono el template
var clone = [Link](templateContent, true);
};
//Registro el componente con el nombre "feedback-message"
[Link]('feedback-message', {
prototype: prototipo
});
</script>
1. El import del código del componente, que deberás poner en cada página que necesite
usarlo
2. Colocar la etiqueta nueva que has creado
Además opcionalmente podrías usar el Polyfill de Web Components, que nos permitirá usarlo
en todos los navegadores modernos.
<!DOCTYPE html>
<html lang="ee">
<head>
<meta charset="UTF-8">
<script
src="../bower_components/webcomponentsjs/[Link]"></script>
<link rel="import" href="[Link]">
<title>Mensaje de Feedback con Web Components y VanillaJS</title>
</head>
<body>
<h1>Un mensaje de Feedbak</h1>
<p>Debajo de este párrafo aparece el mensaje de Feedback generado con un
custom element.</p>
Nota: Si tienes muchos import es una práctica habitual crear un import único y que éste sea el
que haga toda la lista de los muchos import que puedas estar usando.
Otra cosa que encuentras en el HEAD es el Javascript que carga el polyfill de compatibilidad
[Link].
El uso del componente lo tienes más abajo, en la etiqueta nueva que hemos creado al registrar
el componente.
Al ejecutarlo deberías ver el mensaje de feedback con un color de fondo azul y el texto de
color gris. Podrías cambiar el color del texto simplemente cambiando el valor del atributo
"color".
Qué hay del SEO en las aplicaciones y sitios web realizados con Web Components? Librerías
como Polymer, LitElement o Lit ¿Son buenas para tener un correcto posicionamiento en
buscadores?
Hemos rebautizado este artículo como SEO en Web Components ya que el contenido que
explica lo podemos aplicar transversalmente a todas las librerías basadas en Web
Components. Originalmente se escribió con Polymer en la cabeza, porque era la librería
existente en ese momento, pero lo mismo lo podemos aplicar a cualquier librería basada en
Web Components, ya sea Lit, LitElement, Atomico, etc.
En este artículo voy a hablar del posicionamiento web en buscadores (SEO) en aplicaciones y
sitios web realizados con Web Components. Espero que sirvan de ayuda a los interesados,
aunque advierto que es un artículo en base a impresiones y experiencias, así que encontrarás
no solo datos objetivos y rigurosos, sino también opiniones y consejos diversos. Además,
debes tener en cuenta que quizás con el tiempo algunas de las cosas que estoy comentando
evolucionen de distintas maneras.
El presente texto viene como respuesta a un estudiante de los cursos de Polymer de EscuelaIT,
que me preguntaba:
¿Existe alguna forma de que me indexen el contenido de una web hecha con el sistema de
routing de polymer?
Lo primero es avisar que Google sí que indexa páginas que usan el sistema de routing de
Polymer. Este punto lo trataré en último lugar en el presente artículo. Pero te recomiendo leer
mi respuesta completa, en la que he ampliado algo el ámbito de la pregunta y hablaré sobre
SEO en Polymer en general.
Con Polymer puedes hacer custom elements de Web Components, como nueva etiquetas que
extienden el HTML estándar que entienden los navegadores, que podrías usar en cualquier
tipo de sitio. Por tanto, podrías perfectamente usar Polymer en un sitio común, basado en un
CMS que posicione tan bien como WordPress, o cualquier tipo de sitio que esté optimizado
para buscadores.
Esto quiere decir que la discusión sobre si Polymer es bueno o no para el SEO es un poco
ambigua, pues depende de cómo sea el sitio donde estés aplicando Polymer y no de la librería
en sí o de Web Components en general.
En el tema de SEO lo ideal es que el sitio tenga “server side rendering”. O sea, construir la
página del lado del servidor y entregar contenido original en cada URL. Server side rendering
es como funciona una página creada con PHP o cualquier lenguaje del lado del servidor, en la
que el HTML se construye en el servidor y se manda contenido específico de cada página al
cliente. Así es como funciona un CMS por lo general y la mayoría de sitios de la Web, sobre
todo los estáticos.
Sin embargo, las aplicaciones de gestión modernas, basadas en web, servicios, paneles de
control, etc. cada vez están basándose más en el modelo de las páginas conocidas como SPA.
En ellas se usa un sistema de routing basado en Javascript. El navegador se encarga de
procesar la dirección a la que se está accediendo y traer los datos con los que construir por él
mismo el HTML. En estos escenarios ya no tenemos el comportamiento ideal, el mencionado
server side rendering.
Las páginas que usan el routing de Polymer, o cualquier sistema de routing de los frameworks
Javascript con los que se suelen construir las SPA, son siempre en realidad el mismo [Link]
de la home, junto con un Javascript. Las rutas se tratan desde ese Javascript, para mostrar
unos u otros componentes. Como no tienes el contenido original en cada ruta de tu sitio, sino
que ese contenido viene generado desde Javascript, no es tan bueno para SEO.
La primera sería usar una librería basada en Web Components en un sitio común, con
programación del servidor, capaz de producir un HTML único para cada URL. Es justamente lo
que comentaba en el punto anterior de este artículo.
Otra alternativa sería usar con otro framework que sí tenga resuelto el tema del server side
rendering (SSR), como los mencionados antes (Angular, React, etc).
La libería Lit (que es la evolución de LitElement, que a su vez era la evolución de Polymer) ya
tiene solucionada la parte del server side rendering, por lo que podríamos usar esta
renderización del lado del servidor en aplicaciones SPA que usan solamente Web Components.
Usar Angular u otro framework para poder implementar el SSR podría parecer un poco
descabellado, ya que lo que soluciona Web Components se superpone en muchos de los casos
al código específico introducido por Angular o React, por lo que puede parecer poco óptimo
cargar dos librerías distintas que tienen funcionalidades solapadas. Sin embargo hoy resulta
una posibilidad muy viable, ya que en navegadores modernos donde se implementa Web
Components 1.0 el peso que tiene la librería no pasa de unos pocos KB (5KB aproximadamente
en Lit o LitElement).
Por todo ello, no es un problema usar librerías de Web Components junto con otras no
basadas en Web Components. Pero tampoco es algo que necesites, porque todo lo que puedes
hacer con grandes frameworks lo puedes implementar con pequelas librerías o micro-librerías.
Incluso en el caso de usar Lit, la propia librería tiene ya disponible la parte del SSR.
Nota: Ahora el dato no lo recuerdo bien, pero en una conferencia de presentación de Polymer
2.0 decían que estaba en torno a los 5 KB. Claro, que el navegador debe contar con soporte a
Web Components 1.0, y puede que no sea siempre así, pero afortunadamente ahora todos los
navegadores se han puesto de acuerdo con la especificación y es cuestión de muy poco tiempo
que la mayoría de los browsers dispongan de soporte completo a Web Components y así
eviten de cargar el correspondiente Polyfill, que es lo que más ocupa realmente en KB y
tiempo de procesamiento para el arranque de la aplicación.
Puedes probar con herramientas de terceros. No las he probado, pero en este tema la
comunidad está trabajando para hacer algunas soluciones. Por ejemplo tienes Server
Components o artículos de blogs que analizan cómo puedes crear tú mismo el sistema de
renderizado del lado del servidor para tus aplicaciones.
Me gustaría ver pronto soluciones oficiales del propio Google, ya que el propio Polymer es una
apuesta de la empresa del buscador, entiendo que deberían aportar ellos mismos las mejores
soluciones para que las aplicaciones Polymer posicionen de manera muy optimizada.
Como conclusión de este artículo se ha de decir que en realidad Google sí que está indexando
páginas de aplicaciones SPA realizadas usando el sistema de routing de Polymer. Y lo que es
más maravilloso, está teniendo en cuenta incluso datos que llegan desde la base de datos
Firebase.
No sé precisar desde cuándo estamos en esta situación, pero cualquiera de nosotros lo podría
comprobar haciendo una búsqueda por "site:[Link]".
Esa búsqueda te dará una serie de páginas que encuentras en el [Link]. Esa
web está basada en el sistema de routing de Polymer y todos los datos se encuentran en una
base de datos Firebase, por lo que no hay apenas ningún contenido escrito "a pelo" en el
HTML, sino todo viene desde Javascript y del acceso a servicios externos.
Con esto es todo. Creo que habré dado un poco de luz a las dudas de las personas que se
interesan por el SEO en Polymer. Como decía, seguramente en los próximos meses o años
encontremos novedades interesantes y relevantes en cuanto a este importante tema, así que
habrá que estar atentos. Pero el hecho de que Google sí que indexe aplicaciones en Polymer es
sin duda una realidad.