10 principios para crear WebComponents de primera
Durante estos 12 años desarrollando para Frontend, pude ver cómo organizar y planificar de antemano puede ser de gran ayuda. El problema al principio fue pensar: ¿qué, después de todo, necesito planificar? Desarrollar una página para una aplicación puede (y debe) ser simple. Sin embargo, para grandes empresas o incluso para el mundo Open Source, planificar algunos aspectos desde el principio es de gran valor y puede ayudarte a no tener que rehacerlo todo al cabo de unos años.
Desde que comencé a trabajar con WebComponents, absorbí ese concepto y me di cuenta de que me habría evitado muchos problemas. Como dije, se ha descubierto mucho a lo largo de los años a través del ensayo y del error. Un requisito tras otro que tenía a mi equipo rascándose la cabeza y pensando: y ahora, no pensamos en ese aspecto cuando creamos ese texto de entrada simple. ¿Cómo cambiar?
Entonces, dado que aprender de los errores de otras personas es más divertido, aquí están mis 10 puntos de lecciones aprendidas.
10 consejos para crear WebComponents
1- Satisfacer una necesidad común
Cuando empezamos a identificar cuáles son los componentes a desarrollar en el proyecto, es habitual pensar en los primeros y más básicos (inputs, dropdown, textarea, etc.), principalmente porque son imprescindibles para cualquier otro uso.
Sin embargo, lo que debe tenerse en cuenta para la acumulación también son los componentes de uso común, como un encabezado que todas las aplicaciones deben desarrollar con un patrón visual o un paso a paso que tiene una barra de progreso para los pasos en los que se hizo clic o incluso una lista con infinito. Desplazarse.
Todos estos son buenos ejemplos porque aparecen en todos los lugares y aplicaciones.
Teniendo en cuenta que los componentes de uso común generalmente no tienen una regla comercial (una que llama a una API en el backend, por ejemplo, es poco probable que se use comúnmente).
2- Crear componentes que solo hagan 1 tarea, pero muy bien hecha
Los WebComponents son maleables. Eso significa que puedes tomar solo una fracción de una página o componente y convertirla en un componente web (a diferencia de los Widgets gigantes y monolíticos que teníamos antes). Ahora, con los microcomponentes ya no necesitamos limitarnos a crear algo enorme con numerosas parametrizaciones que podrían traer detalles que ni siquiera se usaron en la aplicación (cambiar el paquete final de la aplicación y agregar 1 MB de código sin usar). En su lugar, se puede crear un WebComponent para hacer algo mínimo pero muy bueno.
Evaluar si un componente solo está haciendo una cosa no es tan simple, pero tenemos formas de identificarlo:
- El componente debe ser fácil de incluir en una aplicación
Deberías ser capaz de importarlo con solo una línea en la aplicación. Esto indica que no tiene dependencias externas y no necesita nada más para usarlo (si solo necesita una lista para importar un componente, probablemente esté haciendo más de una tarea).
Sin embargo, está bien si hereda la funcionalidad central de otro lugar. Lo importante es que solo tiene una responsabilidad.
- El componente no puede tener conflictos de combinación
Si declaraste algún atributo (propiedad o método) que para usarse haya que desactivar el otro, tal vez tu componente esté haciendo más de una tarea y deba cambiarse, por ejemplo:
-Para usar la propiedad de name, no puedes indicar que la propiedad label provocará rupturas o quiebres.
Esto se aplica a los métodos, porque si existe la regla de que no se puede llamar a un determinado método cuando la propiedad X es verdadera, entonces es posible que tengas que dividir ese componente en dos y compartir una clase entre ellos.
Vayamos a un ejemplo de WebComponent que solo hace una actividad. Ve este header:
Podemos pensar en crear un header que tendrá algunas responsabilidades visuales y dinámicas, como incluir el logotipo de la empresa, mostrar elementos del menú, incluir un texto de entrada para la búsqueda o mostrar un icono de lupa.
Si este componente se piensa desde el principio como solo uno en lugar de cuatro (considero que el logo de la empresa también es un icono), siempre tendremos que pensar en todo cuando haya algún cambio. Y si cambia el componente de entrada, ¿tengo que recordar todos los demás que usan la entrada como dependencia y cambio?
Una propuesta para este encabezado sería ésta:
1 - <my-header>: contenedor que acomodaría a los demás y los organizaría en sus lugares correspondientes, preocupándose únicamente por su capacidad de respuesta y cómo se mostrará todo.
2 - <my-icon>: componenteque tiene los iconos disponibles de la empresa y que pueden o no ser utilizados, tendría expuesto un evento de clic y tus variables para cambiar de color y tamaño.
3 - <my-header-menu>: elemento secundario de my-header, incluido en el nombre para que sea fácil de identificar, que solo puede ser utilizado por el encabezado y no como elemento secundario de ningún otro. Tiene las funcionalidades de hacer clic, pasar el mouse y enfocar.
4 - <my-text>: componente de texto, altamente mutable, acepta como hijo un <my-icon> para mostrarse a la derecha y mira el teclado para emitir un evento en cada entrada. También emite el desenfoque y otros básicos eventos como keyup o keypress.
Ve que cada componente se enfoca en hacer solo una tarea en nuestro header. En lugar de asignarle todas las responsabilidades, esta división permite que los desarrolladores solo obtengan lo que necesitan cuando lo usan.
Piensa que una aplicación quería cambiar el logo o, en lugar de mostrar elementos del menú, quería mostrar los detalles de la página actual o piensa que muchas aplicaciones no necesitarán un campo de búsqueda directamente en el header, ya que no existe una búsqueda general.
3- Sé creativo/a, pero evita el gold plating
En resumen, el gold plating es cuando ofrecemos detalles a nuestro cliente que creemos que serán útiles, pero el cliente aún no los ha pedido (o tal vez no pedirá).
Evitar añadir elementos en el componente desde el principio es una línea muy fina, porque necesitas prever lo básico para que funcione y, al mismo tiempo, no poner un parámetro que tal vez solo se use, incluso si lo consideras súper útil. Mejor crea los conceptos básicos y espera las solicitudes de cambio: un componente recién lanzado todavía tarda en madurar.
4 - Un componente con configuración cero debería ser útil
Un componente tendrá varios estados. Por ejemplo, así podemos crear un datepicker en una aplicación:
El resultado probablemente será un datepicker con una etiqueta, un marcador de posición, una X al final y un valor completo.
Pero, ¿qué pasaría si el desarrollador intentara usarlo de esa manera?
¿Qué se debe mostrar?
¿Debería el datepicker mostrar, al menos, un texto de entrada con un botón para seleccionar la fecha y tal vez mostrar un label predeterminada? ¿O, según la regla, una fecha preestablecida como la fecha de hoy?
Este es el punto. Un componente tiene que ser útil sin ningún tipo de parametrización. Inmediatamente útil. Esto también se denomina prueba de tag simple. Si el desarrollador simplemente abre y cierra la etiqueta del componente creado, ¿obtendrá algo útil?
Algunas reglas que te pueden ayudar:
● Evita requerir atributos. Debes proporcionar buenos valores predeterminados para todos los atributos integrados.
● Evita requerir CSS. Todas las variables CSS también deben tener un valor predeterminado.
● Evita requerir Javascript para ejecutar algo básico al inicio.
● Evita solicitar cambios en la página a aquéllos que usarán la nueva etiqueta.
La regla es: si el desarrollador que va a usar el componente necesita conocer un conjunto de reglas para usarlo, significa que todavía no es un componente de configuración cero.
5 - Crear un componente líquido
Piensa en ti mismo/a creando algo que se combinará con otros componentes para formar una interfaz de usuario. Este es el concepto de composability (componibilidad).
Para dar esta posibilidad de que tu componente se pueda componer con otros, deberás preocuparte por los slots, es decir, la posibilidad de poner algo dentro del tag, por ejemplo:
¿Cómo se manejará el contenido del tag? ¿Tiene sentido que tu componente reciba contenido? ¿Dicho contenido estará en Shadow DOM o Light DOM? ¿Ese tag de contenido, si está dentro de Shadow DOM, no puede incrustar clases CSS externas, o tu componente solo aceptará CSS en línea?
Esto debe tenerse en cuenta desde el principio al utilizar Slot y si aceptas contenidos externos.
Tuve que remover muchos componentes de Shadow DOM por no haberlo planeado desde el principio, lo que los dejaba expuestos a la sobreescritura de CSS.
6- Las CSS variables son tus amigas
Desde el principio, muchas propiedades de CSS no necesitaban corregirse en el código (a menos que fuese parte del Design System de la empresa, ¿el azul y el verde son la marca comercial de la empresa? Corrige entonces esos colores en el CSS para que nadie pueda cambiarlos).
Pero los colores de fondo, los íconos internos, los bordes, la altura y el ancho son generalmente propiedades que los desarrolladores necesitarán. No tengas miedo de crear una lista de propiedades CSS con valores predeterminados definidos, ya que esto ayudará mucho a tu componente en el futuro.
7 - Crear componentes abiertos para cambiar
Este punto depende un poco del framework o herramienta elegida para escribir el WebComponent. El punto es: un componente debe ser heredable para mutar y ser extensible.
Desde el momento en que se puede crear un WebComponent con solo JavaScript, se puede crear un componente con el objetivo de ser heredado. Por ejemplo: podemos crear un Input Text como base para que otros componentes más específicos como un Datepicker, Search o incluso un Textarea puedan aprovechar métodos básicos ya escritos como limpiar, escribir, incluir un icono al final, etc.
Si tu framework/biblioteca permite extender clases, entonces gana productividad y consistencia. Si no, una idea interesante podría ser externar comportamientos comunes en una biblioteca compartida entre estos componentes.
8 - Piensa en pequeño
El tamaño importa en las aplicaciones web. Si un desarrollador piensa en cómo resolver una determinada situación en la aplicación, no puede pensar dos veces antes de utilizar su componente. El efecto que tiene un componente pesado puede ser enorme para una aplicación que ya utilizará varios componentes de terceros al mismo tiempo (o el tuyo una y otra vez).
Entonces, la cantidad de artefactos descargados en la aplicación y el tamaño de cada uno de ellos es importante:
● Opta por imágenes en formatos livianos (Avif > Webp > SVGs. Son mucho mejores que usar los famosos PNG y JPG).
● Evita el uso de bibliotecas (como jQuery o Lodash, por ejemplo): detalles como manipular el DOM o realizar una llamada HTTP se pueden hacer simplemente con JavaScript.
Para ayudarte:
● You might not need jQuery: https://youmightnotneedjquery.com/
● You might not need Lodash: https://youmightnotneed.com/lodash
9- La accesibilidad y la capacidad de respuesta no son un problema
En la medida de lo posible, admite una amplia variedad de usuarios y dispositivos. Además de las muchas herramientas que hoy en día nos ayudan a probar la accesibilidad de un componente, siempre vale la pena entender cómo funcionan las Web Content Accessibility Guidelines (Pautas de Accesibilidad al Contenido Web o WCAG), así como la separación de niveles (y tratar de llegar al menos al nivel AA).
Algunos lectores de pantalla también pueden tener dificultades para leer el contenido dentro de ShadowDOM, así que recuerda exponer el texto y los indicadores de función en tu host WebComponent para que sean fáciles de cambiar y leer.
Los desarrolladores que vayan a usar tu componente necesitarán obtener un resultado receptivo al extraer y emplear tu aplicación, así que ten cuidado con los valores fijos (en píxeles, por ejemplo, puedes definir un texto de entrada con un tamaño de 100 px). Trata siempre de usar valores relativos como porcentajes (un texto de entrada con el 100% del tamaño se comportará con lo definido en la etiqueta superior, dando flexibilidad a quien lo utilice).
Usar media queries también puede ser muy útil para cambiar el aspecto según el tamaño de la pantalla. Muchos componentes (como un header o footer, por ejemplo) deberán ser receptivos para su uso, así que piénsalo desde el principio.
10 - Un poco de técnica: Focus, ShadowDOM, Scoped y Traditional Web
Este consejo lo dejé para el final porque trata de aspectos más técnicos que tuve que aprender con el tiempo y espero que te sirva. Son píldoras pequeñas, pero muy útiles:
Ojo con focus(): ¿qué pasa si el desarrollador que va a usar tu componente te envía un focus()? ¿Cuál es el punto de partida del enfoque? Los WebComponents deben difundir el enfoque en ShadowDOM y depende de ti enviarlo al lugar correcto. También necesitas saber adónde va el foco cuando el usuario presiona la tecla Tab en el teclado. Es posible que debas manipular los índices de tabulación incorporados para que funcionen de la manera que deseas.
ShadowDOM vs Scoped: un componente completamente funcional en ShadowDOM trae numerosas ventajas debido a su encapsulación CSS. Sin embargo, si vas a crear un componente que se encargue de recibir contenido externo (una tarjeta, por ejemplo, esperará que se incluya algo en ella).
Si incluyes este contenido externo mediante un anexo en ShadowDOM, el desarrollador perderá la capacidad de personalizar el contenido en sí, incluso con clases CSS. Piensa entonces que, muchas veces, los componentes más crudos y simples (como tarjetas, paneles o contenedores) estarían mejor con CSS Scoped en lugar de usar ShadowDOM, lo que no traerá ningún beneficio y solo entorpecerá el uso.
Uso de su WebComponent por una Tecnología Web Tradicional (no SPA): Las Tecnologías Web Tradicionales son aquéllas que envían el formulario para que el backend capture todos los datos y los almacene en propiedades (como lo hacen Java, .Net o PHP). El problema es que las entradas dentro de ShadowDOM no son parte de un formulario, por ejemplo:
En el ejemplo anterior tenemos dos entradas: una con name=fullname y la otra con name=age.
Al hacer clic en Send, solo se llamará al método en el back-end myMethod, pero solo se enviará el input fullname, ya que un input dentro de ShadowDOM no participa en el envío del formulario.
Si deseas que tu componente pueda utilizarse por todo tipo de tecnología web (SPA y Web tradicional), debes configurar el parámetro formAssociated en tu componente, que puede ser heredado de HTMLElement.
Puedes ver la configuración aquí.
Eso es todo. Espero que estos 10 puntos te hayan ayudado a pensar y planificar mejor. Ojalá hubiera sabido mucho de esto antes porque me hubiera evitado muchos problemas, pero será un gusto ayudarte a avanzar sin las complicaciones que tuve.
¡Éxito en tus proyectos \o/!
Revelo Content Network da la bienvenida a todas las razas, etnias, nacionalidades, credos, géneros, orientaciones, puntos de vista e ideologías, siempre y cuando promuevan la diversidad, la equidad, la inclusión y el crecimiento profesional de los profesionales en tecnología.