Ahora que ya conocemos las bases de los Custom Elements (la parte de WebComponents que permite crear nuestras propias etiquetas), toca comenzar a crear componentes básicos para ir viendo la estructura que podemos seguir para dotarle de funcionalidad. En este artículo vamos a ver como preparar una estructura de carpetas y archivos utilizando WebComponents, como crear nuestro primer componente y las diferentes formas de enlazarlo, tanto desde HTML como desde Javascript.
Quizás, lo primero que deberíamos tener claro es la estructura de carpetas y archivos que vamos a tener para crear nuestros componentes.
En principio, esta «arquitectura» depende mucho de lo que queramos hacer y es muy variable dependiendo de nuestros objetivos, pero vamos a partir de ejemplo sencillo de base, donde src
es la carpeta que contiene nuestro código fuente:
- src
+-- components/
| +-- AppElement.js
+-- index.html
+-- index.js
Partimos de un archivo index.html
(el punto de entrada, el fichero que abre inicialmente el navegador). Dicho archivo HTML puede cargar directamente (como veremos más adelante) el componente AppElement.js
, que se encuentra dentro de la carpeta components/
, o puede cargarlo a través de un fichero index.js
que hace de fichero «centralizador».
Nuevamente, dejar claro que esto es sólo un ejemplo de partida y que esta estructura puede variar mucho dependiendo del proyecto, objetivo y necesidades. Aún así, es un buen ejemplo inicial para comenzar.
Para empezar, vamos a crear el componente básico mínimo necesario para hacerlo funcionar. Como ya hemos visto, esta formado de una clase que debe extender de HTMLElement
, y asociarlo por medio de customElements.define()
con el nombre de una etiqueta HTML (nuestro custom element):
class AppElement extends HTMLElement {
constructor() {
super();
}
}
customElements.define("app-element", AppElement);
Como buena práctica, este fichero suele nombrarse igual que la clase, AppElement.js
y suele colocarse en una carpeta components/
, aunque esto puede depender de la arquitectura utilizada.
Nota: En los casos que el constructor del componente no tenga ninguna lógica (solo incluya el
super()
, como en el ejemplo anterior) podemos ahorrarnos escribir el constructor, ya que es el comportamiento que tiene por defecto.
Como habrás observado, tenemos los archivos index.html
e index.js
, y la carpeta components/
que contiene el archivo AppElement.js
. Sin embargo, no hemos mencionado como están cargados. Se puede hacer de varias formas, vamos a analizarlas:
Una vez tengamos un WebComponent creado, lo que toca es aprender los pasos para cargarlo y utilizarlo. Probablemente, la forma más fácil de hacerlo, es cargándolo desde el HTML de la siguiente forma:
<head>
del documento:<script src="./components/AppElement.js"></script>
<app-element></app-element>
Como ven, rápido y sencillo. Sin complicaciones.
Sin embargo, podríamos preferir cargar el WebComponent desde Javascript en lugar de HTML, ya que puede ser más versátil y flexible en ciertas situaciones. Por ejemplo, si tenemos un gran número de componentes quizás podemos preferir centralizar los import
en un fichero central de Javascript, que pueda ser reutilizado, en lugar de tener varias etiquetas <script>
en varios archivos HTML diferentes.
En ese caso, debemos hacer lo siguiente:
js/
, dependiendo de nuestra arquitectura de carpetas. En cualquier caso, será el equivalente al «main» de muchos lenguajes de programación:<script type="module" src="/js/index.js"></script>
Es muy importante darse cuenta de que es obligatorio utilizar el atributo type
establecido a module
. Con esto le indicamos al navegador que lo que estamos cargando es un fichero Javascript que va a importar módulos ES utilizando la sentencia import
.
Si se nos olvidara añadir el type="module"
a nuestro script, probablemente en la consola Javascript nos aparecerá un error similar al siguiente:
Uncaught SyntaxError: Cannot use import statement outside a module
index.js
tendremos que hacer las importaciones necesarias para cargar el componente y poder utilizarlo posteriormente:import "./components/AppElement.js";
Con esta modalidad de importación, simplemente indicamos a Javascript que incluya y procese el código que contiene dicho fichero Javascript, cargando el componente de una forma análoga a como lo hicimos en el apartado anterior, mediante HTML y una etiqueta <script>
.
Hay una forma híbrida entre las dos anteriores, donde podemos hacer lo siguiente en nuestro archivo index.html
:
<script type="module">
import "./components/AppElement.js";
</script>
Como ves, hemos incluido el contenido del fichero index.js
en el interior de la etiqueta <script>
del index.html
. Aunque esta modalidad funciona, puede que no nos interese si tenemos múltiples ficheros .html
, ya que en esta modalidad, los import
quedan en el interior del fichero .html
y es menos versátil que tenerlo separado en un archivo a parte.
Una vez tengamos nuestro componente cargado y enlazado, existen varias formas de consumirlo (utilizarlo) en nuestra página. Veamos un resumen de cada una de ellas:
La primera y más sencilla ya la hemos visto, simplemente se trata de escribir el nombre de nuestra etiqueta HTML personalizado en el HTML:
<app-element></app-element>
Esta es la forma más básica y común. Sin embargo, no es la única.
Puede interesarnos crear el componente desde Javascript, útil para hacerlo dinámico, usarlo en bucles, condicionales y/o aprovecharnos de toda la potencia de Javascript. En ese caso, tendríamos que hacer lo siguiente:
const appElement = document.createElement("app-element");
document.body.appendChild(appElement);
Hemos hecho lo siguiente:
<app-element>
en memoria, en la variable appElement
.<body>
.Existe una variación de la anterior. Para hacerlo de esta forma, en nuestro fichero AppElement.js
, tendríamos que exportar la clase, para así poder importarla desde otro archivo. Haríamos la siguiente modificación:
export class AppElement extends HTMLElement {
/* ... */
}
Ahora, desde nuestro archivo index.js
, en lugar de hacer una importación directa como la que vimos más atrás, la haríamos de esta forma, importando la clase AppElement
para luego crear una instancia utilizando el new
:
import { AppElement } from "./components/AppElement.js";
const appElement = new AppElement();
document.body.appendChild(appElement);
Obsérvese que en el fichero index.js
hemos importado la clase AppElement
que exportamos en el punto anterior. En el resto del código del fichero podríamos ahora trabajar con ella de forma análoga a como lo hicimos más atrás con .createElement()
.
Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.
Puedes encontrar más sobre mi en Manz.dev