Creando componentes .astro

Reutilizando partes de una web


Ahora que ya sabemos la estructura de un fichero .astro y crear rutas en la carpeta src/pages/, ya te habrás dado cuenta que en cuanto empieces a crear varias rutas, hay un montón de partes de código que se repiten y que no querrás estar escribiendo una y otra vez, por lo que es necesario reutilizar.

Reutilizando componentes .astro

En Astro (y en la programación en general) es muy importante reutilizar código, para hacerlo todo más simple, más fácil de modificar y evitar repetir la misma información una y otra vez.

Así pues, imagina que tenemos el siguiente fichero src/pages/index.astro:

---
const sitetitle = "Manz.dev";
const title = "Página principal";
const description = "Una larga y detallada descripción de mi página.";
---

<html lang="en">
	<head>
		<meta charset="utf-8" />
		<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
		<meta name="viewport" content="width=device-width" />
		<meta name="generator" content={Astro.generator} />
		<title>{title}</title>
    <meta name="description" content={description} />
	</head>
	<body>
    <header>
      <h1>{sitetitle}</h1>
    </header>

    <nav>
      <a href="/">Home</a>
      <a href="/services/">Services</a>
      <a href="/about/">About me</a>
    </nav>

    <h2>{title}</h2>

    <main>
      <p>Contenido de la página web en cuestión.</p>
    </main>

    <footer>
      <p>© ManzDev Evil Corp. Todos los derechos reservados. Los izquierdos también.</p>
    </footer>

	</body>
</html>

Aunque nuestra página es muy simple aún, ya comienza a costar leerla, porque tiene mucho contenido. Además, si pensamos que también tenemos que crear un src/pages/services/index.astro y un src/pages/about/index.astro, nos daremos cuenta que la parte de los <nav>, el <header>, el <footer> son siempre iguales. además de tener que repetirlos, si tenemos que cambiar uno, habría que cambiarlo en todas las secciones para actualizarlo.

Separando en componentes

Para evitar esto, vamos a separar ese contenido en componentes. Crearemos una carpeta src/components y crearemos tres archivos que llamaremos SiteHeader.astro, SiteNav.astro y SiteFooter.astro. A diferencia de la carpeta src/pages, la carpeta src/components no crea archivos index.html en base a los ficheros .astro, sino que tenemos esa carpeta para añadir contenido que vamos a reutilizar, o simplemente que queremos tener mejor organizado:

Nuestro fichero src/components/SiteHeader.astro será el encabezado de nuestro sitio web y quedaría como se puede ver a continuación:

---
const sitetitle = "Manz.dev";
---

<header>
  <h1>{sitetitle}</h1>
</header>

Por otro lado, nuestro fichero src/components/SiteNav.astro contendrá la zona de navegación y el código quedaría así:

---
---
<nav>
  <a href="/">Home</a>
  <a href="/services/">Services</a>
  <a href="/about/">About me</a>
</nav>

Por último, nuestro fichero src/components/SiteFooter.astro contendrá el pie de página y el código que contiene quedaría así:

---
---
<footer>
  <p>© ManzDev Evil Corp. Todos los derechos reservados. Los izquierdos también.</p>
</footer>

Si nuestro componente se llama SiteFooter.astro, al usarlo deberíamos escribir <SiteFooter />, respetando mayúsculas/minúsculas. En Astro, los componentes están en PascalCase por convención.

Con esto hemos separado en componentes diferentes. La primera parte ya la tenemos hecha.

Reutilizando componentes

Ahora nos queda reutilizarlos en nuestras páginas de src/pages (o incluso en otros componentes). Para ello, basta con importarlos y usarlos, lo que requiere un poquito de Javascript (muy poquito). Nuestro fichero src/pages/index.astro quedaría de la siguiente forma:

---
import SiteHeader from "../components/SiteHeader.astro";
import SiteNav from "../components/SiteNav.astro";
import SiteFooter from "../components/SiteFooter.astro";

const title = "Página principal";
const description = "Una larga y detallada descripción de mi página.";
---

<html lang="en">
	<head>
		<meta charset="utf-8" />
		<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
		<meta name="viewport" content="width=device-width" />
		<meta name="generator" content={Astro.generator} />
		<title>{title}</title>
    <meta name="description" content={description} />
	</head>
	<body>

    <SiteHeader />
    <SiteNav />

    <h2>{title}</h2>

    <main>
      <p>Contenido de la página web en cuestión.</p>
    </main>

    <SiteFooter />
	</body>
</html>

Observa que en la parte superior, hemos importado los componentes creados anteriormente en objetos SiteHeader, SiteNav o SiteFooter. Astro permite utilizar los import de Javascript pero con ficheros .astro e importándolo como si fueran etiquetas HTML que luego puedes utilizar en la zona inferior de HTML, con el nombre que les hayas puesto.

Observa que, al contrario que con las etiquetas HTML normales, las etiquetas HTML de los componentes de astro se pueden autocerrar <SiteHeader /> o cerrar de la forma tradicional <SiteHeader></SiteHeader>.

Siempre que puedas, reutiliza en componentes, para que el código sea más sencillo, especialmente si necesitarás reutilizarlo más adelante. Recuerda también que si comienzas a tener muchos componentes, puedes crear carpetas dentro de src/components y mantener un orden por categorías, estilos o padres de los componentes.

Nota: Probablemente estés pensando que es una molestia tener que repetir toda la estructura <html> con su <head> y demás etiquetas y repetirlas en todas las páginas de src/pages/. Más adelante veremos una forma de simplificarlas con Layouts, pero primero debemos explicar otras cosas.

Mejorando las rutas de import

Al importar nuestros componentes, es posible que comiences a encontrar molesto tener que buscar la ruta de los ficheros, o te equivoques frecuentemente al escribir la ruta, sobre todo cuando usas muchas carpetas anidadas. Por aquí tienes un truco para simplificar estas rutas:

Observa que en los ejemplos anteriores, hemos utilizado rutas relativas al importar los componentes. Estas rutas se basan en buscar el fichero desde la ruta del fichero actual:

// Si estamos en src/components/Component.astro
import SiteHeader from "../components/SiteHeader.astro";

// Si estamos en src/components/Section/NestedComponent.astro
import NestedComponent from "../../components/SiteHeader.astro";

Como puedes ver, a medida que tengamos rutas más complejas con carpetas y subcarpetas, las rutas se volverán más complicadas de leer y mantener.

Una buena forma de simplificar este tema es crear alias de imports. Básicamente, se trata de crear una ruta especial @ que apunte al contenido de la carpeta src. De esta forma, los dos import anteriores se escribirían así:

import SiteHeader from "@/components/SiteHeader.astro";
import NestedComponent from "@/components/SiteHeader.astro";

Ahora no importa donde nos encontremos, siempre empezamos a buscar en src. Para conseguir este funcionamiento, sólo tenemos que cambiar la configuración de nuestro proyecto en el fichero tsconfig.json:

{
  /* ... */
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
    }
  }
}

Tienes más información sobre este tema de rutas en Evitar rutas relativas, ya que esto no es algo de Astro, sino de Typescript (con lo que está construido Astro).

En los primeros temas de este curso utilizaré rutas relativas para no complicar en exceso los ejemplos. No obstante, recomiendo encarecidamente utilizar los alias de rutas.

¿Quién soy yo?

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