ManzDev
Perfil de Manz Dashboard de actividad
HTML5 Etiquetas HTML
CSS CSS vanilla
PostCSS Transformador CSS
Javascript Javascript ES2020+
NPM Node Package Manager
WebComponents Componentes web
Terminal Terminal de GNU/Linux
VueJS Framework VueJS 3
Automatizadores Empaquetadores Javascript
Youtube Canal de Youtube
Twitch Canal de Twitch
Telegram Canal de Telegram
Discord Servidor de Discord

Introducción: ¿Qué es Atomico?

Atomico es una excelente librería creada por Matias Trujillo, que permite crear WebComponents siguiendo un enfoque de programación funcional, que destaca por su simpleza y sencillez. Entre las características principales de esta librería podemos enfatizar las siguientes:

  • Se enfoca en utilizar sólo funciones. Evita la complejidad de usar clases, this, etc...
  • Se centra en el uso de hooks, inspirado en la librería React.
  • Utiliza un Virtual DOM (vDOM) específico para WebComponents.

Si tenemos claros los conceptos principales de WebComponents, nos resultará extremadamente sencillo (¡y muy productivo!) trabajar con la librería de componentes Atomico.

Estructura inicial

Aunque podemos escribir en una terminal npm init @atomico y dejar que un asistente nos guíe en la creación de la estructura (scaffolding) de carpetas del proyecto, en esta guía vamos a hacerlo manualmente para comprender mejor los pasos que se realizarán:

-- project-name/
     |-- index.html
     |-- index.js
     |-- components/
           |-- MessageComponent.js

Observa que la carpeta project-name contiene un fichero index.html que va a hacer referencia a un archivo Javascript index.js. También tendremos una carpeta components que contiene un archivo Javascript MessageComponent.js.

En el archivo index.html tendremos algo similar a esto:

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <script type="module" src="./index.js"></script>
</head>
<body>

  <message-component></message-component>

</body>
</html>

Ten en cuenta que la etiqueta <script> hace referencia al fichero index.js, pero lo cargamos con un atributo especial llamado type="module". Este atributo permite a navegadores modernos cargar un archivo Javascript que contiene uno o varios import para cargar módulos Javascript.

Además, también observa que utilizamos la etiqueta HTML <message-component> que es el WebComponent de ejemplo que vamos a crear con Atomico.

Por último, en el archivo index.js tendremos el siguiente código:

import "./components/MessageComponent.js";

Esta línea importará el componente MessageComponent y lo cargará en el navegador, para que pueda reconocer las etiquetas <message-component>. Veremos esto un poco más adelante.

Instalación de Atómico

Para utilizar Atómico en nuestra aplicación o sitio web, la opción que se suele usar habitualmente es instalar la librería utilizando npm, como un paquete de producción. Por lo tanto, desde una terminal escribimos lo siguiente:

npm install atomico

Con esto se añadirá la librería atomico a la lista de dependencias en el package.json. Una vez hecho este paso, comenzaremos a crear nuestro componente, que en nuestro caso se encuentra en el fichero MessageComponent.js, dentro de la carpeta components.

La primera línea de este fichero Javascript será la siguiente:

import { c } from "atomico";

Existen opciones alternativas para evitar utilizar npm, como podría ser utilizar un CDN como JSDelivr o unpkg desde una etiqueta <script>. Otra opción quizás más interesante es SkyPack, el cuál permite utilizar el CDN en los import, en lugar de realizar los clásicos bare imports de NPM, que buscan el paquete atomico en la carpeta node_modules.

import { c } from "https://cdn.skypack.dev/atomico";

Tanto en la primera como la segunda alternativa estamos importando la función c(), que es una de las características de Atómico que se utiliza para cargar componentes, como veremos en el siguiente apartado.

Crear componentes con Atomico

Crear un componente con Atomico es extremadamente sencillo. Observa el siguiente ejemplo donde creamos una función messageComponent que será nuestro componente. En su interior podemos escribir la lógica del componente, y finalmente, debe devolver el template del componente, es decir, el código HTML del mismo:

import { c } from "atomico";
import { html } from "atomico/html";

function messageComponent() {
  /* ... */
  return html`<host>Contenido de texto</host>`;
}

customElements.define("message-component", c(messageComponent));

Observa que hay tres características importantes de Atomico que estamos usando en este ejemplo:

  • La función c() la importamos del núcleo de Atomico, y la utilizamos en la última línea, para envolver la función que utilizamos como componente en el customElements.define().

  • La función html la importamos de la carpeta html de Atomico, y la utilizaremos para devolver una plantilla HTML construida para utilizar en componentes Atomico.

  • En el interior de dicha plantilla HTML, utilizaremos la etiqueta <host> para hacer referencia al componente.

Además, ten en cuenta que también podemos traducir la función clásica de Javascript en una función flecha (arrow function), algo que quizás nos resulte más simple y fácil de escribir:

<message-component></message-component>

<script type="module">
import { c } from "https://cdn.skypack.dev/atomico";
import { html } from "https://cdn.skypack.dev/atomico/html";

const messageComponent = () => html`<host>Contenido de texto</host>`;

customElements.define("message-component", c(messageComponent));
</script>

Ten en cuenta que si la función flecha incluye más de una sentencia, tenemos que englobar el cuerpo de la función con llaves {} e indicar el return de forma explícita.

Componentes y CSS con Atomico

Ahora que sabemos crear un componente básico, vamos a completarlo un poco más. Importaremos las funciones css y useStyleSheet para añadir estilos CSS a nuestro componente Atomico.

En primer lugar, observa que he creado un objeto styles que contiene el código CSS del componente. Ten en cuenta que estamos envolviendo este código con la función css. Por otro lado, la explicación de :host la tienes en CSS Scoping.

<message-component></message-component>

<script type="module">
import { c } from "https://cdn.skypack.dev/atomico";
import { html } from "https://cdn.skypack.dev/atomico/html";
import { css, useStyleSheet } from "https://cdn.skypack.dev/atomico/css";

const styles = css`
  :host {
    background: steelblue;
    color: white;
    padding: 10px;
  }
`;

const messageComponent = () => {
  useStyleSheet(styles);
  return html`<host shadowDom>Contenido de texto</host>`;
}

customElements.define("message-component", c(messageComponent));
</script>

Una vez creados estos estilos en el objeto styles, en el interior de la función messageComponent donde tenemos nuestro componente, y antes de devolver la plantilla HTML, utilizaremos useStyleSheet() para indicarle que utilice los estilos del componente.

Remarcar que sería posible crear múltiples objetos de estilos CSS y pasarlos como múltiples parámetros a useStyleSheet, aplicándolos todos. Esto nos podría permitir incluso separar los estilos en ficheros diferentes e importarlos con import / export si nos resultara interesante.

Para que estos estilos funcionen correctamente, necesitaremos utilizar un Shadow DOM. Esta característica nos ayudará a que el CSS no se salga del componente y no se aplique por error en otros lugares. Para ello, añadiremos el atributo shadowDom en la etiqueta <host> del componente Atomico.

En los siguientes artículos veremos como definir props y comenzar a utilizar hooks para crear componentes mucho más flexibles y versátiles.



Manz
Publicado por Manz

Docente, divulgador informático y Streamer de código. Amante del CSS y de la plataforma web en general. Autor de Emezeta.com tiempo atrás. Ha trabajado como profesor en la Universidad de La Laguna y es director del curso de Programación web FullStack y FrontEnd de EOI en Tenerife. En sus ratos libres, busca GIF de gatos en Internet.