El desarrollo web ha avanzado mucho desde los primeros días de los sitios web personales estáticos de una sola página. Ahora tenemos una gran cantidad de lenguajes, frameworks y sistemas de gestión de contenidos entre los que elegir, creados para satisfacer todos los nichos imaginables.

Ahí es donde entra Astro, uno de los últimos chicos guays del bloque de frameworks de JavaScript.

Creado por Fred K. Schott y un grupo de colaboradores, Astro se ha convertido rápidamente en uno de los favoritos de la comunidad de desarrolladores. Es un framework todo en uno que funciona como un generador de sitios estáticos.

En este artículo, explicaremos por qué a tantos desarrolladores les gusta Astro y lo eligen frente a otras soluciones. También te explicaremos cómo crear un blog basado en markdown utilizando el framework.

¿Qué Es Astro?

El logotipo de Astro en negro, que muestra
Astro

Astro, o Astro.js, es un popular generador de sitios estáticos concebido para quienes desean crear sitios web ricos en contenido que funcionen con rapidez y fluidez. Su naturaleza ligera, estructura intuitiva y suave curva de aprendizaje lo hacen atractivo para desarrolladores de todos los niveles de experiencia.

A pesar de su pequeño tamaño, Astro viene con potentes herramientas que aumentan drásticamente la flexibilidad de tu sitio, ahorrándote horas en la gestión de contenidos y temas. Además, ofrece a los desarrolladores la opción de trabajar con sus frameworks preferidos a la vez que con Astro — una perspectiva atractiva para los programadores experimentados que ya cuentan con un gran número de favoritos.

Éstas son sólo algunas de las formas en que Astro destaca entre la multitud:

  • Arquitectura en isla: Astro extrae tu interfaz de usuario (IU) en componentes más pequeños y aislados, conocidos como «Islas Astro», que pueden utilizarse en cualquier página. El JavaScript no utilizado se sustituye por HTML ligero.
  • Cero JavaScript (por defecto): Aunque puedes utilizar todo el JavaScript que quieras para crear tus sitios web, Astro intentará desplegar cero JavaScript en producción transcribiendo tu código por ti. Es un enfoque perfecto si lo que te interesa es la velocidad del sitio.
  • SSG y SSR incluidos: Astro comenzó como un generador de sitios estáticos, pero en el camino se convirtió en un framework que utiliza tanto la generación de sitios estáticos (SSG) como la renderización del lado del servidor (SSR, Server-Side Rendering). Y puedes elegir qué páginas utilizarán cada enfoque.
  • Agnóstico en cuanto a frameworks: Al utilizar Astro, puedes utilizar cualquier framework JavaScript que desees, incluso varios frameworks a la vez. (Hablaremos de esto con más detalle más adelante en este artículo)

Además, Astro está preparada para la tecnología edge, lo que significa que puede desplegarse en cualquier lugar, en cualquier momento y con facilidad.

¿Estás listo para saber más? Entonces profundicemos en cómo funciona Astro.

Estructura de Astro

Antes de seguir adelante, es importante entender cómo está configurado Astro para que puedas utilizarlo con eficacia. Echemos un vistazo a la estructura básica de archivos de Astro:

├── dist/
├── src/
│   ├── components/
│   ├── layouts/
│   └── pages/
│       └── index.astro
├── public/
└── package.json

Como puedes ver, la estructura en sí es bastante sencilla. Sin embargo, hay algunos puntos clave que debes recordar:

  • La mayor parte de nuestro proyecto vive en la carpeta src. Puedes organizar tus componentes, diseños y páginas en subcarpetas. Puedes añadir carpetas adicionales para que tu proyecto sea más fácil de navegar.
  • La carpeta public es para todos los archivos que viven fuera del proceso de construcción, como fuentes, imágenes o un archivo robots.txt.
  • La carpeta dist contendrá todo el contenido que quieras desplegar en tu servidor de producción.

A continuación, vamos a profundizar en los principales componentes de Astro: componentes, diseños y páginas.

Componentes

Los componentes son trozos de código reutilizables que pueden incluirse en todo tu sitio web, de forma similar a los shortcodes de WordPress. Por defecto, tienen la extensión de archivo .astro, pero también puedes utilizar componentes que no sean de Astro creados con Vue, React, Preact o Svelte.

A continuación se muestra un ejemplo del aspecto de un componente sencillo: en este caso, una etiqueta div con una clase que contiene un h2:


<div class="kinsta_component">
    <h2>Hello, Kinsta!</h2>
</div>

Y así es como podemos incorporar ese componente a nuestro sitio:

---
import KinstaComponent from ../components/Kinsta.astro
---
<div>
    <KinstaComponent />
</div>

Como se ha demostrado anteriormente, primero tienes que importar el componente. Sólo entonces podrás incluirlo en la página.

Ahora es el momento de añadir algunas propiedades a nuestro componente. Empecemos con una propiedad {title}:

---
const { title = 'Hello' } = Astro.props
---

<div class="kinsta_component">
    <h2>{title}</h2>
</div>

Y así es como se implementaría nuestra propiedad:

---
import KinstaComponent from ../components/Kinsta.astro
---

<div>
    
    <KinstaComponent title="Good day"/>

    
    <KinstaComponent />
 </div>

Sencillo, ¿verdad?

Como probablemente ya te habrás dado cuenta, el verdadero poder de los componentes de Astro reside en su naturaleza global y reutilizable. Te permiten hacer cambios radicales en todo tu sitio editando solo unas pocas líneas de código, lo que puede ahorrarte incontables horas que de otra forma emplearías en realizar tediosas y laboriosas sustituciones de texto.

Diseños

Hablemos ahora de los diseños. Además de su función habitual como estructura de la página, los layouts en Astro también son componentes reutilizables, pero se utilizan como envoltorios de código.

Echa un vistazo a este ejemplo:

---
// src/layouts/Base.astro
const { pageTitle = 'Hello world' } = Astro.props
---

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>{pageTitle}</title>
</head>
<body>
    <main>
        <slot />
    </main>
</body>
</html>

Observa la etiqueta <slot /> aquí. El elemento <slot /> en Astro actúa como marcador de posición para etiquetas y contenido HTML reales.

Veámoslo en acción.

El siguiente código muestra nuestra etiqueta <slot /> sustituida por el código que deseamos, todo ello envuelto por nuestro diseño Base.astro:

---
import Base from '../layouts/Base.astro';
---

<Base title="Hello world">
    <div>
        <p>Some example text.</p>
    </div>
</Base>

Como puedes ver, nuestra etiqueta <slot /> fue sustituida por el HTML que representa, que es:

<div>
    <p>Some example text.</p>
</div>

Los diseños, al igual que los componentes, te permiten reutilizar trozos de código en todo tu sitio, simplificando el reto de actualizar tu contenido y diseño globales.

Páginas

Las páginas son un tipo especial de componente que se encarga del enrutamiento, la carga de datos y la creación de plantillas.

Astro utiliza enrutamiento basado en archivos para generar páginas, en lugar de enrutamiento dinámico. El método basado en archivos no sólo consume menos ancho de banda, sino que también te evita tener que importar tus componentes manualmente.

Aquí tienes un ejemplo de rutas definidas:

src/pages/index.astro => yourdomain.com
src/pages/test.astro => domain.com/test
src/pages/test/subpage => domain.com/test/subpage

Con estas rutas, nuestra página de inicio resultante se mostraría como sigue:


<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>Hello World</title>
</head>
<body>
    <h1>Hello, Kinsta</h1>
</body>
</html>

Pero ya sabemos cómo utilizar los diseños, así que vamos a convertir esto en algo que sea accesible globalmente:

---
import Base from '../layouts/Base.astro';
---

<Base>
    <h1>Hello, Kinsta</h1>
</Base>

Ya está, mucho más limpio.

Hablaremos del enrutamiento en Astro con más detalle más adelante en este artículo, pero por ahora, pasemos a lo divertido: la construcción y personalización del sitio.

Personalizar y Ampliar Astro

¡Es hora de aprender a personalizar tu sitio Astro! Vamos a utilizar colecciones Markdown, enrutamiento, manejo de imágenes y una integración con React para construir y personalizar nuestro sitio estático.

Colecciones Markdown

Con la versión 2.0, Astro introdujo una forma de mantener el contenido Markdown mucho mejor que antes. Gracias a las colecciones, podemos estar seguros de que todos nuestros datos frontmatter están incluidos y tienen el tipo de asociación correcto.

Últimamente, en la versión 2.5, han añadido la posibilidad de gestionar también archivos JSON y YAML como colecciones.

¿Listo para ensuciarte las manos?

En primer lugar, coloca todos tus artículos Markdown en la carpeta src/content/collection_name. Vamos a crear una colección blog para este proyecto, así que en nuestra demostración, la carpeta será src/content/blog.

Ahora es el momento de definir todos los campos frontmatter necesarios en nuestro archivo src/content/config.ts. Nuestro blog necesitará lo siguiente:

  • title (cadena)
  • tags (array)
  • publishDate (hora)
  • image (cadena, opcional)

Así es como se ve todo junto:

import { z, defineCollection } from 'astro:content';

const blogCollection = defineCollection({ 
    schema: z.object({
        title: z.string(),
        tags: z.array(z.string()),
        image: z.string().optional(),
        publishDate: z.date(),
    }),
});

export const collections = {
    'blog': blogCollection,
};

Y esto es lo que contiene nuestro archivo Markdown article-about-astro.md:

---
title: Article about Astro
tags: [tag1, tag3]
publishDate: 2023-03-01
---
## Tamen risit

Lorem *markdownum flumina*, laceraret quodcumque Pachyne, **alter** enim
cadavera choro.

Es cierto que nuestro archivo Markdown no tiene nada de especial. Pero hay algo de magia oculta aquí que se manifestará si cometemos un error tipográfico.

Digamos, por ejemplo, que en lugar de escribir publishDate, escribimos accidentalmente publishData. En caso de un error ortográfico como éste, Astro arrojará un error:

blog → article-about-astro.md frontmatter does not match collection schema.
  "publishDate" is required.

Sorprendente, ¿verdad? Esta ingeniosa función puede ayudarnos a encontrar errores relacionados con el frontmatter en cuestión de segundos.

Lo último que tenemos que añadir es una página que muestre nuestros datos. Vamos a crear un archivo en src/page/blog/[slug].astro con el siguiente código:

---
import Base from '../../layouts/Base.astro';
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
    const blogEntries = await getCollection('blog');
    return blogEntries.map(entry => ({
        params: { slug: entry.slug }, props: { entry },
  }));
}
const { entry } = Astro.props;
const { Content } = await entry.render();
---
<Base>
    <h1>{entry.data.title} </h1>
    <Content />
</Base>

Gracias a getStaticPaths, Astro creará todas las páginas estáticas para cada entrada de la colección de blogs.

Lo único que nos falta ahora es un listado de todos nuestros artículos:

---
import Base from '../../layouts/Base.astro';

import { getCollection } from 'astro:content';
const blogEntries = await getCollection('blog');
---
<Base>
<ul>
    {blogEntries.map(item => <li> <strong><a href={'/blog/' + item.slug}>{item.data.title}</a></strong></li>)}
</ul>
</Base>

Como puedes ver, el uso de colecciones simplifica notablemente esta tarea.

Ahora, vamos a crear una colección de tipos de datos. En primer lugar, debemos abrir de nuevo el archivo src/content/config.ts y añadir una nueva colección de datos:

import { z, defineCollection, referenece } from 'astro:content';

const blogCollection = defineCollection({ 
	type: 'content',
    schema: z.object({
        title: z.string(),
        tags: z.array(z.string()),
        image: z.string().optional(),
        publishDate: z.date(),
	    author: reference('authors')
    }),
});

const authorsCollection = defineCollection({ 
	type: 'data',
    schema: z.object({
        fullName: z.string(),
        country: z.string()
    }),
});


export const collections = {
    'blog': blogCollection,
'authors': authorsCollection,
};

Además de crear una nueva colección, también añadimos la referencia al autor en la blogCollection.

Es hora de crear un nuevo autor. Debemos crear un archivo llamado maciek-palmowski.json en el contenido/autores.json:

{
    "fullName": "Maciek Palmowski",
    "country": "Poland"
}

Lo último que nos queda es coger estos datos en nuestro Post. Para ello, tendremos que utilizar getEntry:

---
import Base from '../../layouts/Base.astro';
import { getCollection, getEntry } from 'astro:content';
export async function getStaticPaths() {
  const blogEntries = await getCollection('blog');
  return blogEntries.map(entry => ({
    params: { slug: entry.slug }, props: { entry },
  }));
}
const { entry } = Astro.props;
const author = await getEntry(entry.data.author);
const { Content } = await entry.render();
---
<Base>
<h1>{entry.data.title}</h1>
<h2>Author: {author.data.fullName}</h2>
<Content />
</Base>

Enrutamiento

Astro tiene dos modos de enrutamiento diferentes. Ya conocimos el primero —enrutamiento estático (basado en archivos) — cuando tratamos anteriormente el tema de las páginas.

Ahora vamos a centrarnos en el enrutamiento dinámico.

Utilizando parámetros de ruta dinámica, puedes ordenar a un archivo de página Astro que automatice la creación de varias páginas con la misma estructura. Esto es útil cuando tienes muchas páginas de un tipo concreto (piensa en biografías de autores, perfiles de usuarios, artículos de documentación, etc.).

En el siguiente ejemplo, trabajaremos en la generación de páginas biográficas para nuestros autores.

En el modo de salida estático por defecto de Astro, estas páginas se generan en el momento de la construcción, lo que significa que debes predeterminar la lista de autores que obtienen un archivo correspondiente. En cambio, en el modo dinámico, las páginas se generan a petición de cualquier ruta que coincida.

Si quieres pasar una variable como nombre de archivo, ponla entre corchetes:

pages/blog/[slug].astro -> blog/test, blog/about-me 

Vamos a profundizar en esto utilizando el código de nuestro archivo src/page/blog/[slug]:

---
import Base from '../../layouts/Base.astro';
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
    const blogEntries = await getCollection('blog');
    return blogEntries.map(entry => ({
        params: { slug: entry.slug }, props: { entry },
  }));
}
const { entry } = Astro.props;
const { Content } = await entry.render();
---
<Base>
    <h1>{entry.data.title}</h1>
    <Content />
</Base>

La ruta getStaticPaths es la responsable de generar todas las páginas estáticas. Devuelve dos objetos:

  • params: Se utiliza para rellenar los corchetes de nuestras URLs
  • props: Todos los valores que pasamos a la página

Y con esto, la generación de tu página está solucionada.

Tratamiento de Imágenes

No podemos hablar de sitios web eficaces sin mencionar los formatos de imagen modernos, los métodos correctos de cambio de tamaño y la carga lenta.

Por suerte, Astro también nos asiste en este aspecto. Gracias al paquete @astrojs/image, podemos introducir todo lo anterior en cuestión de minutos.

Tras instalar el paquete, accedemos a dos componentes: Image y Picture.

El componente Image se utiliza para crear una etiqueta <img /> optimizada. Aquí tienes un ejemplo:

---
import { Image } from '@astrojs/image/components';
import heroImage from '../assets/hero.png';
---

<Image src={heroImage} format="avif" alt="descriptive text" />
<Image src={heroImage} width={300} alt="descriptive text" />
<Image src={heroImage} width={300} height={600} alt="descriptive text" />

Del mismo modo, el componente Picture crea un componente <picture/> optimizado:

---
import { Picture } from '@astrojs/image/components';
import hero from '../assets/hero.png';
---
<Picture src={hero} widths={[200, 400, 800]} sizes="(max-width: 800px) 100vw, 800px" alt="descriptive text" />

SSG vs SSR

Por defecto, Astro se ejecuta como un generador de sitios estáticos. Esto significa que todo el contenido se convierte en páginas HTML estáticas.

Aunque éste es un enfoque perfecto desde muchos puntos de vista (especialmente relacionados con la velocidad), a veces podemos preferir un enfoque más dinámico. Si quieres una página de perfil distinta para cada usuario, por ejemplo, o si tienes miles de artículos en tu sitio, volver a renderizarlo todo cada vez llevaría demasiado tiempo.

Por suerte, Astro también puede funcionar como un framework completamente renderizado en el lado del servidor, o en un modo híbrido entre ambos.

Para activar el SSR en todo el sitio, tenemos que añadir el siguiente código a astro.config.mjs:

import { defineConfig } from 'astro/config';

export default defineConfig({
    output: 'server'
});

Este es el enfoque estándar.

El enfoque híbrido significa que, por defecto, todo se genera dinámicamente, excepto las páginas con export const prerender = true añadido.

Con Astro 2.5, también existe la posibilidad de establecer la renderización estática por defecto y seleccionar las rutas dinámicas manualmente.

Gracias a ellas, podemos, por ejemplo, crear un sitio web totalmente generado estáticamente con páginas dinámicas de inicio de sesión y perfil. Genial, ¿verdad?

Puedes leer más sobre esto en la documentación oficial.

Integrar Otros Frameworks JavaScript

Otra característica asombrosa de Astro te permite llevar contigo tu framework favorito y utilizarlo conjuntamente con Astro. Puedes mezclar Astro con React, Preact, Svelte, Vue, Solid o Alpine (para todas las integraciones, consulta la documentación «Añadir integraciones» de Astro).

Supongamos que queremos utilizar React. En primer lugar, tenemos que instalar la integración ejecutando lo siguiente en npm:

npx astro add react

Ahora que React se ha integrado, podemos crear un componente React. En nuestro caso, será el componente contador en src/components/ReactCounter.tsx:

import { useState } from 'react';

/** A counter written with React */
export function Counter({ children }) {
    const [count, setCount] = useState(0);
    const add = () => setCount((i) => i + 1);
    const subtract = () => setCount((i) => i - 1);

    return (
        <>
            <div className="counter">
                <button onClick={subtract}>-</button>
                <pre>{count}</pre>
                <button onClick={add}>+</button>
                </div>
            <div className="counter-message">{children}</div>
        </>
    );
}

Por último, pero no menos importante, tenemos que colocar el contador en nuestra página con el siguiente código:

---
import * as react from '../components/ReactCounter';
---
<main>
    <react.Counter client:visible />
</main>

Y voilà: Tu componente React se ha integrado perfectamente en tu sitio.

Cómo Desplegar Astro con Kinsta

Ahora es el momento de llevar nuestro sitio Astro a la web. Por suerte, Kinsta es el alojamiento perfecto para un despliegue rápido y sin complicaciones.

Empieza por crear un repositorio GitHub para los archivos de tu sitio. Si no estás listo para usar tus propios archivos, puedes clonar esta plantilla Astro para sitios de inicio que creó nuestro equipo.

Una parte del repositorio de GitHub para el sitio de inicio Astro de Kinsta, que muestra una imagen del logotipo blanco
Repo de GitHub de la plantilla Astro de Kinsta

Una vez que tu repositorio esté listo, inicia sesión en MyKinsta, selecciona Aplicaciones a la izquierda y, a continuación, elige Aplicación en el desplegable morado Añadir servicio.

El panel de MyKinsta se abrió en la sección
Añadir una aplicación en MyKinsta

El último paso consiste en proporcionar a Kinsta los detalles de tu creación y despliegue.

La mayoría de lo que se te preguntará, como el Nombre del proceso y el Método de pago, tendrá respuestas obvias o sencillas. Ten en cuenta que puedes dejar vacío el campo Comando de inicio si lo deseas; Kinsta asignará automáticamente npm start como comando.

Si no estás seguro de cómo responder a cualquier otra pregunta, consulta la documentación de Kinsta para obtener orientación específica para cada campo y ejemplos de despliegue de Astro. También puedes consultar la guía de despliegue de Astro en Kinsta.

Cuando hayas terminado de introducir los detalles de tu construcción, haz clic en el botón Confirmar método de pago para inicializar tu construcción.

¡Y ya está! Ya tienes un sitio estático en producción y en pleno funcionamiento creado con el framework Astro.

Una página oscura con el logotipo de Kinsta en blanco en el centro sobre las palabras
Nuestra página de inicio Astro en vivo

Puedes encontrar tu URL en producción y otros detalles del despliegue en Despliegues en tu cuenta MyKinsta.

La pantalla
Un despliegue Astro con éxito

Resumen

La estructura clara, la sintaxis sencilla y los componentes globales de Astro hacen que crear y ejecutar una aplicación sea realmente fácil. Su naturaleza ligera y el uso dual de enrutamiento estático y dinámico aumentan drásticamente la capacidad de respuesta del sitio, mientras que su capacidad para cooperar con y junto a otros frameworks JavaScript lo hace aún más atractivo para los programadores experimentados.

Si tu objetivo es crear un sitio rico en contenidos que cargue rápidamente, garantice una funcionalidad modular y proporcione una generación tanto estática como dinámica, Astro podría ser la opción adecuada para ti.

Puedes alojar tu sitio web estático con el Alojamiento de Aplicaciones de Kinsta de forma gratuita, y si te gusta, pasa a nuestro plan Nivel Hobby.

¿Qué opinas del generador de sitios estáticos Astro? ¿Lo has utilizado en algún proyecto? Háznoslo saber en la sección de comentarios.

Maciek Palmowski

Maciek es un desarrollador web que trabaja en Kinsta como Development Advocate Analyst (Analista de Desarrollo). Después del trabajo, pasa la mayor parte del tiempo programando, intentando encontrar noticias interesantes para sus newsletters, o bebiendo café.