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://unpkg.com/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 "https://unpkg.com/atomico";
import { html } from "https://unpkg.com/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 elcustomElements.define()
.La función
html
la importamos de la carpetahtml
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, html } from "https://unpkg.com/atomico";
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 elreturn
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, html, css } from "https://unpkg.com/atomico";
const messageComponent = () => {
return html`<host shadowDom>Contenido de texto</host>`;
}
messageComponent.styles = css`
:host {
background: steelblue;
color: white;
padding: 10px;
}
`;
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 conimport
/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.