Los WebComponents han venido para quedarse, y esto es todo lo que debes saber sobre ellos

Hoy en día, casi todo el mundo ha interactuado de una u otra manera con la web: desde personas mayores que abren lenta y metódicamente su lista de llamadas perdidas hasta bebés de pocos meses que lanzan sus dedos contra la pantalla del móvil sin miedo, tocando hasta el último píxel de esa pantalla llena de colores y formas que tanto les atraen.

Todos estamos acostumbrados a ver botones, imágenes, vídeos y textos en una gran variedad de disposiciones (párrafos, tablas, listas, etc.). Cualquier elemento que veamos en una web está formado por uno o varios componentes básicos, que pueden formar estructuras más complejas si los agrupamos o los hacemos colaborar entre sí.

Como desarrolladores, (y si estás leyendo este artículo, probablemente estés relacionado con el mundo del software de una u otra manera), queremos escribir código robusto, mantenible, eficiente… ¡y reutilizable! ¿Cuántas veces hemos tenido que desarrollar algunas piezas, estructuras o elementos que eran muy similares a otras anteriores que ya habíamos desarrollado?

La reutilización es el concepto (además de una buena práctica de desarrollo) que evita que escribamos una y otra vez esos fragmentos de código repetitivos entre aplicaciones con apenas unos cambios (como un color, entre otros), lo que se convierte en una pérdida de tiempo y una mayor cantidad de código a mantener. Desgraciadamente, a pesar de “copiar y pegar”, no se garantiza la coherencia visual entre aplicaciones para esas partes frontales duplicadas.

Cuando el tamaño de un cliente es bastante grande (hablando en términos de software), otra buena práctica es la definición de una biblioteca de UI desde el departamento de UX para gobernar todas las cuestiones visuales. Entre otras ventajas, facilita la reutilización, la coherencia visual y la homogeneización en todos los proyectos del cliente (y este concepto ha evolucionado hacia Sistemas de Diseño -o también conocidos como DS o DSL por su acrónimo en inglés-, pero este tema se introducirá más adelante). El problema surgirá si, por la razón que sea, es necesario cambiar el framework de una aplicación o si hay que desarrollar un proyecto con uno diferente…

Uhm, ¿alguien ha dicho “reescribir toda la librería de UI”? Probablemente…

Los fundamentos de cualquier biblioteca de UI…

 

Sin embargo, la solución de reimplementar la librería completa no es aceptable.

Permitidme viajar brevemente, durante este párrafo, a 20 años atrás. Cuando la web era más joven, cuando cada navegador entendía e interpretaba la web a su manera. La aguerrida comunidad de desarrolladores tenía que desarrollar para uno de ellos (ejem… Internet Explorer, ejem…), y posteriormente, adaptarlo al resto de navegadores, cruzando los dedos y esperando no tener que perder demasiado tiempo adicional (que no dejaba de ser un tiempo estúpido, en el sentido más cariñoso de la palabra). ¿Cuál era el problema? Nuestro código tenía que adaptarse a diferentes navegadores porque soportaban el estándar (JavaScript) de diferentes maneras, así que, nuestras aplicaciones estaban en cierto modo acopladas a los navegadores que queríamos soportar; por ello, las aplicaciones no eran cross-browser. Además, un mal diseño técnico podía llegar a mezclar la lógica de negocio con esa lógica de compatibilización cross-browser-javascript. Hoy en día, afortunadamente, el ecosistema JavaScript ha evolucionado mucho, y ahora es una realidad la plena adopción de nuevas características (como WebWorkers o Custom Elements entre otros) para todos los principales navegadores.
Una vez resuelto el problema original… nos enfrentamos a otro, pero en una capa de abstracción superior: la guerra de los frameworks. Todos nuestros componentes web están tradicionalmente desarrollados o escritos sobre algún framework “de moda”, como AngularJS, Angular, React, Vue… o incluso cualquier otra opción válida de una larga lista de candidatos. ¿Cuál es el nuevo escenario entonces? Ahora, nuestras aplicaciones no están atadas a un navegador… ¡pero sí a un framework! ¿Por qué tenemos que reescribir una y otra vez un componente -como un botón- para cada proyecto (o… ehem… “copiar y pegar”) si el framework es diferente?

Para esto, creo que… ¡es momento de una llamada de emergencia a los Cuatro Fantásticos!

¡Los Cuatro Fantásticos a nuestro rescate! … ¿O no?

 

¡No, no! ¡Esos no! No son los Cuatro Fantásticos a los que me refiero… Son estos:

Aparecieron para resolver algunos problemas recurrentes, como el aislamiento o la reutilización de componentes entre diferentes frameworks -entre otros-. Gracias a la combinación de estas cuatro tecnologías estándar, surgieron los WebComponents, los cuales nos permiten crear componentes reutilizables sin miedo a una colisiones -de variables o de identificadores, por ejemplo-, ya que tienen su propia lógica y/o estilos visuales encapsulados. Además, son agnósticos a cualquier framework web, por lo que no necesitamos nada más que al navegador (si este soporta los estándares, o usando algún polyfill en caso contrario). Los WebComponents puros pueden incluso ejecutarse directamente en el navegador sin necesidad de ninguna librería o framework, ya que aprovechan la tecnología proporcionada nativamente por el navegador.

 

Los estándares de WebComponents

¿Y cuáles son estas -fantásticas- cuatro tecnologías que hemos presentado antes?

  • Custom Elements: dan a los desarrolladores la posibilidad de extender el HTML nativo existente por defecto para crear sus propias etiquetas, ya que hoy en día, esas etiquetas nativas no son suficientes para la creación de nuestras aplicaciones web, por ser muy básicos y limitados. Sin embargo, se benefician del modelo de componentes integrado de la Web, lo que resulta en un código más modular que puede ser reutilizado en muchos contextos diferentes.
  • Shadow DOM: ofrece la encapsulación del marcado (HTML) y de los estilos de los componentes. Es un comportamiento crítico de los WebComponents, ya que garantiza que un componente funcionará en cualquier entorno aunque se esté ejecutando otro código CSS o JavaScript en la página, evitando las colisiones anteriormente mencionadas.
  • HTML Templates: son fragmentos inertes de HTML que se reutilizarán en la aplicación, por ejemplo, para crear una fila de una tabla o una ventana modal. La principal ventaja es que su DOM no será renderizado por el navegador, por lo que no interfiere en el resultado visual, pero puede ser referenciado desde JavaScript para operar con él; es decir, podemos utilizarlo como plantilla o esqueleto para crear contenido en el DOM. Una vez que el contenido de la plantilla se inserta en el DOM, el contenido será renderizado.
  • HTML Imports: los WebComponents se escriben tradicionalmente en HTML, y esta tecnología se utiliza para importar estos archivos de definición a la aplicación principal para utilizarlos en la misma. Este mecanismo es muy similar al de las importaciones de hojas de estilo CSS a través de link-rel. Sin embargo, se propuso un enfoque mejor y más potente (además de que la importación de HTML nunca pasó la fase de borrador en la especificación), y finalmente se implementó como la nueva forma de importar la definición de los WebComponents: ES Imports. Estos ES Imports son la nueva forma de utilizar la instrucción de importación de ES6, donde el principal beneficio es el aislamiento de los elementos globales definidos en un módulo. Para utilizar un elemento definido fuera de un módulo, es necesario exportarlo primero. En el contexto de un componente, los módulos ES6 albergarán toda la definición de cada WebComponent.

Acabamos de hablar de los navegadores y de la compatibilidad… pero, ¿cuál es el soporte ofrecido actualmente por los navegadores? ¿Podríamos escribir y desarrollar WebComponents sin ninguna restricción o limitación?

Desde el 15 de enero, el navegador Edge de Microsoft implementa ya el proyecto Chromium de código abierto, por lo tanto, Edge es ahora totalmente compatible con los estándares web, lo que es una gran noticia para todos, no sólo para la comunidad de desarrolladores, sino también para los usuarios finales.

Vanilla components: puros y nativos

Como hemos dicho anteriormente, los WebComponents están totalmente soportados por los principales navegadores (o incluso alguna versión anterior utilizando la ayuda de los polyfills). Por lo tanto, un WebComponent puede escribirse en JavaScript plano con estos simples pasos:

  1. Crear una clase, donde se colocará la lógica (de negocio o de presentación) del WebComponent. Si el componente es visual, necesitará algún tipo de HTML y/o estilos CSS. Además, el componente podría establecer manejadores de eventos, y que no necesariamente tienen que estar relacionados con eventos de interfaz de usuario (por ejemplo, la respuesta de una petición HTTP).
  2. Registrar el nuevo componente, vinculando o enlazando su nuevo nombre de etiqueta con la definición de la clase (recuerdemos, definición de la clase, no una instancia de la misma).

Obviamente, el primer paso será el más repetido por un desarrollador: escribir el código mínimo necesario para construir un componente. Como los estamos desarrollando sobre JavaScript plano, tenemos que realizar algunas tareas manualmente (lo que sería un proceso demasiado artesanal o repetitivo).

 

A continuación, se muestra a modo de ejemplo cómo podría ser el típico “Hello World”:

 

https://gist.github.com/semagarcia/7df05a274880ca8740c628b6ecb91e2c/raw/9ed2a019c13b01180e9f07d31303b24a33613fac/medium-wc-article–hellow-world.js

La plantilla utilizada por el WebComponent anterior:

 

https://gist.github.com/semagarcia/428a1dfb6c13aaa865a6c7a966f8dbc7/raw/2c80a15cbed38c456a59a65b082ea6537238ef9e/medium-wc-article–hellow-world-template.html

Con los fragmentos anteriores, podremos utilizar nuestro WebComponent en cualquier lugar:

 

https://gist.github.com/semagarcia/688557ad44412effbedf313d9aa56cec/raw/1d811a16428e25b7b5a3a7e23e9e318d0e028d07/medium-wc-article–tag-instantiation.html

Visualmente, el resultado es el siguiente:

Nuestro WebComponent renderizado… simple y sencillo 🙂

Que es el resultado de esto (instancia del WebComponent a través de la etiqueta <my-web-component> tag):

Es muy importante tener en cuenta que el nombre de los WebComponents tiene que incluir un guión en su nombre (significa que el nombre tiene que contener al menos dos palabras). Esto es para evitar posibles colisiones con los nombres de las etiquetas del estándar HTML5 (como img, input, table…).

Cuando el navegador renderiza el HTML y encuentra nuestra etiqueta personalizada “<my-web-component>” busca si la tiene registrada, y en caso afirmativo, utiliza su clase correspondiente para crear una nueva instancia. Si no se encuentra ninguna, el motor la ignorará.

Como desarrolladores, podemos ver algunas acciones manuales y repetitivas en nuestro día a día, como por ejemplo, definir estilos o shadow DOM. Si es repetitivo y manual, esto se podría mejorar y simplificarlo. ¿Cómo? Utilizando una pequeña capa de abstracción donde esas tareas y detalles queden encapsulados y ocultos para los desarrolladores, facilitando dichas tareas. Esta pequeña capa podría llamarse ” WebComponent library” para ayudarnos a definir y crear nuestros WebComponents (entre otras responsabilidades), que serán las piezas fundamentales para “construir” nuestras aplicaciones.

Mejor con una librería

Como hemos explicado anteriormente, no queremos perder tiempo ni esfuerzo. Pero, ¿qué opciones tenemos? ¿Qué bibliotecas existen que merecen ser mencionadas y tenidas en cuenta?

Principales bibliotecas más conocidas:

  • LitElement: ofrece una superclase sencilla de la que extender nuestras propias clases con las que poder crear WebComponents rápidos y ligeros (es la sucesora de la librería Polymer).
  • Angular elements: esta librería permite a los desarrolladores empaquetar componentes Angular para que se comporten como WebComponents.
  • Hybrids: librería para el desarrollo de WebComponents con un enfoque declarativo y funcional basado en objetos planos y funciones puras.
  • SlimJS: librería ligera para la creación de WebComponents que proporciona capacidades ampliadas para los componentes (como el binding) utilizando la herencia de clases nativas de ES6.
  • SvelteJS: es un nuevo enfoque para la construcción de interfaces de usuario.
  • SkateJS: es una abstracción reactiva funcional sobre el estándar de WebComponents como un conjunto de paquetes que permite a los desarrolladores escribir WebComponents pequeños, rápidos y escalables utilizando otras librerías conocidas como Preact o LitHTML.
  • StencilJS: es una toolchain (conjunto de herramientas) para construir design systems reutilizables y escalables, generando WebComponents pequeños, rápidos y completamente basados en el estándar.

Como comentario adicional, mostraremos otro tema interesante y extendido: el tamaño del código que sería necesario escribir. La siguiente imagen compara la “verbosidad” de cada librería, que está relacionada con la sintaxis utilizada:

Obviamente, la implementación con JavaScript puro tiene el código más largo ya que está escrito sin la ayuda de ninguna librería, pero nos da una idea del esfuerzo necesario para obtener el mismo resultado, la abstracción que ofrecen esas librerías y la cantidad de código que necesitaríamos mantener.

En próximos artículos de nuestra serie de frontend profundizaremos en algunos de ellos, ¡estad atentos!

¿Son los WebComponents compatibles con los principales frameworks?

Bien, has decidido lanzarte al mundo de los WebComponents… ¡Genial! ¡Buena elección! Pero, ¿qué grado de compatibilidad ofrecen para integrarse con los principales frameworks?

Cada aplicación es como un rompecabezas (un conjunto de piezas diferentes que funcionan juntas para colaborar en un todo). Cada rompecabezas es típicamente un framework (un marco elegido para desarrollar la aplicación). Cada aplicación tiene sus propios componentes que son específicos de dicho framework (por lo tanto, un componente de Angular no será utilizado dentro de una app de React directamente -o viceversa-). En esta analogía, podemos entender que una pieza de un puzzle no puede ser importada a otro puzzle a menos que realicemos algunas “tareas de adaptación”.

Como decíamos, los WebComponents no necesitan un framework específico para ser utilizados, y los navegadores los entienden directamente sin problema. El motor del navegador es el responsable de renderizarlos. Desde el punto de vista del framework, un WebComponent es como cualquier otro componente estándar de HTML: un elemento definido por una tercera entidad, como podría ser algún otro equipo de desarrollo de la propia empresa -como el equipo de arquitectura-, un proyecto de código abierto liberado por una empresa, la propia comunidad, etc.

La integración entre framework y WebComponent es tecnológicamente posible.

Además, los WebComponents pueden ser (re)utilizados y pueden interoperar con cualquier aplicación (e incluso con cualquier framework) si la comunicación se realiza de acuerdo a unos principios:

Un componente del framework es capaz de interactuar con un WebComponent a través de sus propiedades, atributos y métodos públicos.

 

Input: el flujo de datos va del padre (componente del framework) a su hijo (WebComponent).

https://gist.github.com/semagarcia/f72f1fde05d105e731db669a2b2830d3/raw/7f81d5ef2fb5998658c601b0bcc98c1103e49006/medium-wc-article–input-example.html

Un WebComponent contenido dentro de un componente del framework es capaz de comunicarse con éste a través de eventos estándar (es decir, el WebComponent se comunicará con el componente del framework hacia arriba en el DOM).

Tenemos dos posibilidades para escuchar esos eventos (acciones) del componente hijo.

 

Output: el flujo de datos va desde el hijo (WebComponent) hacia el padre (componente del framework).

https://gist.github.com/semagarcia/8a6f77ce2c3087263e0532b70f625772/raw/5a33b1074115558ddc93958301f421fc5320e632/medium-wc-article–output-example.html

 

OPCIÓN A: Utilizando el método estándar

https://gist.github.com/semagarcia/df4cef7c9349ba3f97cdcfc7443cd035/raw/1ccacd89b7a382b942fc14fb1b243bc465a9a8d7/medium-wc-article–output-option-a.js

 

OPCIÓN B: Utilizando “las reglas“ o mecanismos del framework (en este ejemplo, Angular)

https://gist.github.com/semagarcia/223336c451f940c63ca565264fdbde12/raw/8d0cf2a5a33f941a75b19c49b938095162b2c61d/medium-wc-article–output-option-b.js

Estos inputs y outputs representan la API pública de un WebComponent.

Este comportamiento es la base de las arquitecturas web actuales, basada en eventos (event-driven architecture, EDA). Sin embargo, hay situaciones en las que la integración no es totalmente compatible. Para comprobar las peculiaridades de cada framework, puedes consultar custom-elements-everywhere.

 

Los WebComponents no son sólo una cuestión de desarrolladores

En casi todos los proyectos, el flujo de trabajo para diseñar y desarrollar una nueva aplicación comienza por el equipo de UX. Recogen los requisitos y modelan las necesidades, transformándolas en una interfaz de usuario atractiva, usable y accesible para los usuarios. Durante un largo período, se solía crear un proyecto en Adobe Photoshop y arcaicamente se “dibujaban” ahí las pantallas y los flujos. Después, una simple exportación a PDF generaba el documento que serviría de guía de maquetación para el equipo de desarrollo. Ese fichero estático y simple debía expresar todos los flujos, casos alternativos, interacciones de los componentes…

Desgraciadamente, como era de esperar, había una enorme brecha entre los dos mundos involucrados: UX y Desarrollo, porque entienden el mismo concepto desde puntos de vista diferentes, con representaciones y términos distintos. Las abstracciones son diferentes para cada equipo. Evidentemente, cada uno tiene sus propias peculiaridades, pero entre ellos hay cierto solapamiento, que puede ser fuente de problemas y malentendidos si no conseguimos homogeneizarlos.

Por tanto, la necesidad de un “lenguaje” común adquiere mayor importancia, puesto que representará una especificación de diseño o las directrices de una librería de componentes reutilizables que puedan ser compartidos por toda la compañía (de la misma manera que se reutilizan los WebComponents). Este Sistema de Diseño es mucho más que un PDF estático, y por ello, profundizaremos en ese enfoque en nuestra serie de artículos sobre DSs (¡así que, permanece atento/a!).

Las piezas de una UI son aquellas porciones (más o menos complejas) que tienen importancia por sí mismas, porque son entidades reconocidas y con cierta responsabilidad. Estas piezas elementales -como los botones o los iconos- pueden trabajar juntas (composición) para construir componentes más complejos (tarjeta):

Todos estos componentes (básicos y complejos) se convertirán en las piezas fundamentales para la construcción de interfaces de todos los proyectos de la empresa, asegurando la consistencia de la marca, ya que todos los desarrolladores utilizarán los mismos componentes (y por tanto, mismo comportamiento y experiencia de usuario), sin importar el framework que utilice cada proyecto en particular.

El principal beneficio de un equipo de desarrollo centrado en esta librería de componentes es que todos los cambios estarán centralizados, gobernados, coordinados con el equipo de UX/UI, y gestionados adecuadamente para su evolución. Muchas de estas librerías son diseñadas, desarrolladas y liberadas por empresas importantes y relevantes. A continuación, algunas referencias (no necesariamente de empresas tecnológicas), disponibles públicamente (se puede consultar una lista ampliada aquí):

En el caso de las empresas de software (como IBM, Salesforce o Microsoft, entre otras muchas), cuando ofrecen y publican las directrices de sus Sistemas de Diseño, persiguen un doble objetivo:

  • Hacer más reconocible su marca a través de los patrones, elementos, colores y formas.
  • Asegurar la fidelidad y la coherencia visual en todo el ecosistema, especialmente en las aplicaciones externas desarrolladas por empresas o desarrolladores independientes (por ejemplo, los que escriben un módulo de Salesforce, una aplicación de Microsoft Store, etc.) que se integrarían en sus plataformas.

Otra ventaja de una librería de componentes es que podemos explorar todas las opciones de un componente -también conocidas como variaciones-, al poder ejecutar pequeñas demostraciones para observar su comportamiento. Si pensamos en un botón, podríamos comprobar cómo se comporta cuando está habilitado, deshabilitado, cuando pasamos el ratón por encima, seleccionado, enfocado, activo, primario, secundario… y todas estas propiedades son sólo para un componente. ¿Te imaginas todas las posibilidades que tendría el catálogo de componentes completo?

Además, la publicación del catálogo (incluso sólo para uso interno), permite a toda la empresa comprobar los componentes básicos disponibles junto a sus interacciones, especificaciones actuales, variaciones… y detectar posibles lagunas o nuevas características no implementadas. Todos los diseñadores de UX/UI utilizarán justo esos elementos para diseñar nuevas aplicaciones (a través de una biblioteca/app de diseño, como Sketch o Figma, entre otras).

A su vez, esta librería de componentes es más estable y e independiente porque es un proyecto separado en sí mismo, con sus propias métricas de calidad, controles, pipelines y pubicaciones. Por supuesto, la documentación también está cubierta en este enfoque por muchas herramientas emergentes. Esas herramientas surgen para ayudar en la construcción de ese catálogo de componente anteriormente mencionado (como un visor de demos de cada uno), pero también para comprobar la API pública del componente (propiedades, métodos, eventos…) y “jugar” con el componente sin necesidad de ejecutarlo localmente (lo que es de ayuda para equipos que no son de desarrollo y no tienen tanto conocimiento técnico). Un ejemplo de ellas:

Conclusiones

Los WebComponents han llegado para quedarse, esto es evidente debido a su crecimiento en los últimos años, así como a su evolución, madurez y posibilidades de integración en otros frameworks (gracias a los estándares web).

Podemos resumir los puntos clave que hemos tratado a lo largo del artículo en dos tipos de beneficios:

Breve cuadro de beneficios

Sin embargo, todavía hay algunos temas “espinosos”:

  • Accesibilidad e indexabilidad, debido a la propia encapsulación del componente (shadow DOM), que es un gran beneficio pero también un problema en algunos casos más peculiares.
  • Todavía hay algunas dificultades para el SSR (server-side rendering) con WebComponents, debido al shadow DOM y al pre-renderizado en el lado del servidor. No obstante, algunas librerías de WebComponents están lanzando herramientas para mejorar esta característica, aunque todavía hay mucho trabajo por hacer.
  • Soporte de los navegadores: todos los navegadores principales ya soportan el estándar de los WebComponents, pero algunas versiones antiguas no tienen aún un total soporte. Para ese vacío, existen polyfills que ayudan a aumentar la compatibilidad para evitar que el soporte pueda ser un problema en su adopción o uso en nuevos proyectos.

A pesar de estos puntos, que deberían solucionarse tarde o temprano, los beneficios y la adopción son imparables. La recomendación de los WebComponents nativos y puros puede reducirse a una frase: Embrace the platform!

 

Post publicado originariamente en inglés en Medium: WebComponents have come to stay, and this is what you need to know | gft-engineering (medium.com)

GreenCoding

Con GreenCoding el desarrollo de software se convierte en parte integrante de tu programa de sostenibilidad

Más información