¿Qué es Astro.js y cómo usarlo para crear sitios rápidos?
En el mundo del desarrollo web moderno ha entrado en juego desde hace poco un nuevo framework cuyas principales propuestas son su gran rendimiento y velocidad. Estamos hablando de Astro, un framework que, gracias a funcionalidades como sus “Server islands” o a su compatibilidad con otros frameworks está ganando terreno a la hora de elegir una herramienta con la que crear sitios web.
En este artículo te voy a contar en detalle qué es Astro y cómo funciona, y además te voy a enseñar todo lo que necesitas saber para empezar a crear sitios web con este framework. ¡Empezamos!
- ¿Qué es Astro?
- Características principales de Astro
- Cómo crear un proyecto de Astro
- Requisitos mínimos de Astro
- Instalación de Astro
- Estructura de carpetas en Astro
- Comandos básicos en Astro
- Estructura de los archivos .astro
- Páginas y rutas en Astro
- Cómo crear páginas en Astro
- Rutas estáticas y dinámicas con Astro
- Componentes de Astro
- Estructura básica de un componente
- Props de los componentes de Astro
- Slots en los componentes de Astro
- Layouts de Astro
- Estilos CSS en Astro
- Estilos locales y globales
- Importar estilos en Astro
- Integración de Tailwind CSS en Astro
- Scripts en Astro
- Integraciones de Astro con otros frameworks
- Modos SSG y SSR
- Cómo activar el modo SSR (Server Side Rendering) en Astro
- Server Islands o islas de servidor

¿Qué es Astro?
Astro es un framework basado en JavaScript (y que también soporta TypeScript) que sirve para crear sitios web de todo tipo, pero sobre todo está pensado para crear sitios web estáticos basados en el contenido.
Esto no quiere decir que solo se puedan crear sitios estáticos, con Astro puedes crear desde landing pages hasta un blog o incluso un ecommerce. Esto habla mucho de la versatilidad de este framework, que además permite utilizar componentes de otros frameworks como React, Svelte o Vue.
Astro usa internamente Vite, un servidor de desarrollo para front-end que utiliza para compilar y optimizar los archivos finales del sitio web.
Para que los conozcas un poco más en detalle, te voy a hablar a continuación de las principales características de Astro.
Características principales de Astro
- Sistema basado en componentes.
- Cero JavaScript por defecto para garantizar el mejor rendimiento. Por defecto, Astro no va a generar nada de JavaScript, a menos que lo necesites.
- Soporte para TypeScript.
- Compatibilidad con otros frameworks. En Astro puedes utilizar componentes de React, de Vue o Svelte, etc. sin problema.
- Utiliza Vite como motor de desarrollo.
- Compatible con lenguaje Markdown y MDX.
- Modo SSG (Static Site Generation) en el que el HTML de la web se genera al hacer el build y modo SSR (Server Side Rendering) en el que el HTML se genera en el servidor cuando el usuario visita la página.
- Server Islands o islas de servidor gracias a las cuales podemos hacer que solamente determinados componentes de la web sean dinámicos.
Cómo crear un proyecto de Astro
Ahora que ya sabes un poco más acerca de Astro, vamos con lo realmente interesante: empezar a trabajar con Astro. Te voy a guiar paso a paso en el proceso de crear un proyecto con Astro desde cero, desde los requisitos que necesitas hasta el proceso de instalación.
Requisitos mínimos de Astro
La verdad es que no necesitas muchas cosas para empezar a trabajar con Astro, ya que tiene unos requisitos mínimos bastante accesibles:
- Node.js en su versión 18.17.1, 20.3.0 o superior (la versión 19 no está soportada).
- Un editor de código. Yo te recomiendo utilizar Visual Studio Code, que además tiene extensión oficial para Astro.
- Terminal de línea de comandos para poder ejecutar los comandos de Astro (VS Code tiene ya una terminal integrada).
Estos requisitos mínimos son los que están en la documentación oficial de Astro a fecha de publicación de este artículo.
Instalación de Astro
Instalar Astro para empezar a trabajar con él es extremadamente sencillo. Si ya tienes Node JS instalado, tan solo tienes que ejecutar un comando en la consola de comandos y seguir los pasos del asistente de instalación. Pero para que lo veas en detalle, vamos a ver el proceso paso a paso.
- Abre tu terminal, sitúate en la carpeta en la que quieres crear tu proyecto y ejecuta el siguiente comando de instalación de Astro:
npm create astro@latest
- El asistente de instalación de Astro te preguntará dónde quieres crear tu proyecto. Si escribes un nombre, se creará una carpeta con ese nombre y dentro estarán los ficheros de Astro. Si quieres utilizar la misma carpeta en la que estás para crear tu proyecto, escribe simplemente un punto (“.”).
- En el siguiente paso te preguntará si quieres instalar Astro “limpio” o con algún ‘template’ o plantilla. Te ofrece varias opciones:
- ‘A basic, helpful starter project’: para crear un proyecto de Astro con la estructura básica y ejemplos de página, layout y algunos estilos predefinidos. Te recomiendo elegir esta opción al menos la primera vez.
- ‘Use blog template’: una plantilla para crear un blog haciendo uso de Markdown y con ejemplos de páginas y rutas para los post.
- ‘Use docs (Starlight) template: es una plantilla para crear un sistema de documentación con Starlight (como el que utiliza la propia documentación de Astro).
- ‘Use minimal (empty) template: instalación ‘limpia’. Usa esta opción si ya tienes nociones del framework y quieres empezar un proyecto en blanco desde cero.
En mi caso, para explicarte posteriormente cómo funciona Astro, voy a elegir la primera opción. - Lo siguiente que tienes que elegir es si quieres instalar las dependencias de tu proyecto, es decir, los paquetes necesarios para que funcione. Lo habitual es decirle que sí.
- El siguiente paso es elegir si quieres crear un repositorio de Git para tu proyecto. Lo recomendable es que lo hagas.
- Finalmente, se instalará Astro con todas las opciones que has elegido previamente.
Estructura de carpetas en Astro
Cuando el proceso anterior haya terminado, podrás acceder a la carpeta de tu proyecto. Por defecto, la estructura de un proyecto de Astro es algo así (la captura de abajo corresponde a un proyecto de Astro creado con la opción ‘A basic, helpful starter project’):
En la carpeta ‘public’ tendrás tus ‘assets’, los archivos estáticos como imágenes, vídeos, tipografías, etc. En resumen, cualquier archivo que no necesita ser procesado durante el proceso de ‘build’.
En la carpeta ‘src’ tendrás todo el código de tu web. Dentro de esta carpeta pueden existir otras subcarpetas como:
- pages: en este directorio estarán las páginas y rutas de tu sitio web. Cada archivo de esta carpeta será una nueva ruta/página. Pueden ser archivos .astro, .html, .md, .mdx, .js o .ts.
- components: en esta carpeta puedes organizar tus componentes, tanto si son componentes de Astro como si son componentes de otros frameworks. Dentro de la carpeta ‘components’ tienes total libertad para organizar los componentes como prefieras creando más subcarpetas.
- layouts: en Astro los layouts no dejan de ser componentes de Astro que sirven para “envolver” contenido y que sirven para crear plantillas reutilizables en diferentes páginas. Puedes organizar tus layouts en esta carpeta.
Además de estas carpetas ‘public’ y ‘src’ también encontrarás varios archivos de configuración como:
- astro.config.mjs (para configuraciones del propio Astro)
- package.json (archivo de configuración típico de cualquier proyecto de Node)
- tsconfig.json (configuración de TypeScript)
Comandos básicos en Astro
En Astro existen una serie de comandos que puedes ejecutar en la terminal para cosas como arrancar el proyecto en local, para generar una ‘build’ del proyecto con los archivos finales listos para subir a producción, para añadir integraciones, etc.
Te voy a contar los más básicos, pero si necesitas consultar todos los comandos disponibles, puedes hacerlo en el siguiente enlace de la documentación oficial de Astro: https://docs.astro.build/en/reference/cli-reference/
npm run dev
Para arrancar el proyecto en local y poder visualizar los cambios en tiempo real en tu navegador. La URL para trabajar localmente con el proyecto es "http://localhost:4321"
npm run build
Para generar los archivos finales que podrás subir a tu hosting.
npm run preview
Para visualizar el proyecto generado con el comando "npm run build" y comprobar que todo está OK antes de subirlo a producción.
npx astro add [integración]
Con este comando puedes integrar otros servicios o herramientas con Astro. Uno de los casos más típicos es Tailwind, el framework de CSS. En este caso, para integrar Tailwind en Astro tendrías que ejecutar el comando “npx astro add tailwind” y seguir los pasos.
Estructura de los archivos .astro
Antes de empezar a hablar de páginas, rutas, componentes, layouts, etc. es importante pararse a explicar la estructura básica de un archivo con extensión .astro.
Los componentes, layouts y páginas de Astro son archivos con la extensión .astro y tienen una estructura clara:
Por un lado, está el “frontmatter”, que es opcional y siempre va al principio del archivo. El código que va en el “frontmatter” va envuelto entre 3 guiones (“---” … “---”) y se ejecuta del lado del servidor. Se suele utilizar para declarar variables, obtener datos (de una base de datos, de una API…), obtener “props” de Astro, ejecutar lógica condicional, etc.
Y, por otro lado, está el resto del archivo en el que escribiremos nuestro código HTML, estilos CSS o scripts de JavaScript (los cuales se ejecutan del lado del cliente).
— // Este es el frontmatter, donde va código JavaScript o TypeScript — <!-- Aquí va código HTML, CSS y scripts que se ejecutarán del lado del cliente –>
Más adelante, cuando veamos los componentes, layouts, etc. verás ejemplos claros de esta estructura.
Páginas y rutas en Astro
La creación de páginas en Astro es una tarea sencilla, ya que Astro crea las rutas en función de los archivos situados dentro de “src/pages” (enrutamiento basado en archivos). Es decir, cada fichero que se encuentre en ese directorio será una ruta dentro de tu sitio web.
Cómo crear páginas en Astro
En Astro puedes crear páginas dentro de tu proyecto creando los archivos correspondientes en “src/pages”. De esta manera, si creas en esa ruta un archivo “contacto.astro”, existirá una ruta “tuweb.com/contacto”. Esto es lo que se conoce como enrutamiento basado en archivos.
Dentro de tu proyecto de Astro puedes enlazar a páginas que hayas creado utilizando su ruta relativa. Siguiendo el ejemplo anterior de la página de “contacto.astro” podrías crear un enlace a la misma, de la siguiente manera:
<a href=”/contacto”>Contacto</a>
Los formatos de archivo aceptados para crear páginas en Astro son: .astro, .html, .md, .mdx, .js y .ts.
Rutas estáticas y dinámicas con Astro
Las rutas son la manera en la que definimos qué páginas va a tener nuestro sitio web y bajo qué URL estarán disponibles. Como ya te conté antes, Astro utiliza un enrutamiento basado en archivos, de manera que cada archivo que crees en “src/pages” será una ruta.
En Astro existen dos tipos de rutas: rutas estáticas y rutas dinámicas. El ejemplo anterior en el que te expliqué cómo crear una página de contacto creando un archivo “contacto.astro” en “src/pages” es un claro ejemplo de ruta estática.
Sin embargo, hay casos en los que no es viable crear manualmente un fichero por cada ruta. Te pongo un ejemplo para que lo entiendas mejor: imagina que creas una página de “Equipo” en la que tendrás un listado de los miembros de tu empresa, y que cada uno de ellos tendrá su propia página.
Podrías crear dentro de “src/pages” una carpeta “equipo” y dentro de esa carpeta un archivo .astro por cada empleado (david.astro, maria.astro, pepe.astro, etc.). Pero esto tiene dos problemas:
- Tienes que crear a mano un archivo por cada empleado (imagínate hacerlo con 100 empleados…)
- No tienes una plantilla centralizada para la página/ficha de cada empleado.
¿Cómo solucionamos esto en Astro? Muy fácil, con rutas dinámicas. Para el caso del ejemplo, lo que tendrías que hacer es crear un archivo llamado “[empleado].astro” (sí, con los corchetes). De esta manera, “empleado” se convierte en un parámetro que podrás usar dentro de la página. En las rutas, se reemplazará “[empleado]” por el nombre de cada empleado. Yo he usado “[empleado]” para mi ejemplo, pero obviamente puedes usar el nombre que quieras.
Solo nos faltaría definir cuáles van a ser esas rutas, en este caso los nombres de los empleados. Para ello, vamos a usar la funcion “getStaticPaths()” de Astro. Te pongo un ejemplo del contenido que debería llevar tu fichero “[empleado].astro” (ubicado, en el caso de este ejemplo, en “src/pages/equipo/”):
src/pages/equipo/[empleado].astro
--- export function getStaticPaths() { return [ {params: {empleado: 'david'}}, {params: {empleado: 'maria'}}, {params: {empleado: 'pepe'}}, ]; } const {empleado} = Astro.params; --- <h1>Hola, {empleado}</h1>
Esto va a generar, en este caso, 3 rutas:
- /equipo/david
- /equipo/maria
- /equipo/pepe
En cada una se mostrará un H1 con un texto dinámico de “Hola, nombre_del_empleado”. Como solo hemos generado rutas para “david”, “maria” y “pepe”, si intentamos acceder a, por ejemplo, “/equipo/laura” nos dará un error 404. Es importante que sepas que estas páginas se generan en tiempo de compilación (cuando ejecutas el "npm run build").
Después de leer lo anterior, probablemente te haya surgido una duda. ¿Qué pasa si no sé de antemano todos los posibles valores para crear las rutas? Sería el caso, por ejemplo, de un blog en el que utilices el título del post como “slug” en la URL. Como no sabes todos los posibles artículos que va a tener el blog, no te puedes anticipar y crear dichas rutas.
En este caso, lo que tienes que hacer es activar el modo SSR (no te preocupes, más adelante te explico qué es y cómo activar el modo SSR en Astro). Con esto, las rutas se procesarán en tiempo de ejecución (y no de compilación). Esto quiere decir (siguiendo el ejemplo anterior del blog), que cada vez que alguien visite una URL del tipo “/blog/lo_que_sea” se generará esa ruta y se le mostrará la página con el contenido correspondiente.
En este caso, como es lógico, ya no necesitas generar las rutas con getStaticPaths(), por lo que el código necesario para el archivo “[slug].astro” sería algo como esto:
--- const {slug} = Astro.params; --- <h1>El slug de este post es: {slug}</h1>
Componentes de Astro
En el ámbito del desarrollo web, un componente es un bloque de código reutilizable que nos ayuda a dividir y organizar la página en elementos más pequeños e independientes. Puede ser tan grande como un sidebar o una cabecera o tan pequeño como un simple botón.
Los componentes de Astro utilizan la extensión ".astro" y puedes organizarlos dentro de la ruta “src/components”. Como te conté al principio del artículo, uno de los puntos fuertes de Astro es que también puedes utilizar componentes de otros frameworks. En ese caso, la extensión del archivo se corresponderá con el framework al que pertenezca el componente. Por ejemplo, un componente de React llevará la extensión “.jsx”.
En Astro lo habitual es nombrar los componentes con “Pascal Case”, por ejemplo “ProductCard.astro”.
Estructura básica de un componente
Un componente puede ser tan básico como un simple fragmento de HTML o tan complejo como un componente con una lógica determinada, diferentes parámetros, estilos CSS, scripts de JS, etc.
Para explicar la estructura de un componente de Astro, voy a ponerte un ejemplo: voy a crear un componente “card” para mostrar un bloque tipo tarjeta con cierta información.
src/components/Card.astro
<article> <img src="/src/assets/bulbasaur.png" alt="Bulbasaur" /> <h2>Bulbasaur</h2> <p>Tipo: Planta</p> </article> <style> article { background-color: #e5e5e5; border-radius: 0.5rem; border: 2px solid #ccc; padding: 2rem; font-family: Arial, Helvetica, sans-serif; display: flex; flex-direction: column; gap: 0.25rem; } h2, p { margin: 0; text-align: center; } img { width: 100%; max-width: auto; height: 130px; object-fit: contain; margin-bottom: 10px; } </style>
Como ves, es un componente muy básico, con una estructura HTML y unos estilos CSS. Esos estilos, en principio, solamente afectan a este componente (Astro añadirá internamente identificadores únicos a las clases CSS).
Si ahora quisiéramos utilizar este componente en alguna parte de nuestra web, podríamos hacerlo de la siguiente forma:
src/pages/index.astro
--- import Card from "../components/Card.astro"; import Layout from "../layouts/Layout.astro"; --- <Layout> <Card /> </Layout>
Primero hay que importar el componente (dentro del frontmatter) para posteriormente incorporarlo al HTML.
Este componente ya es más o menos reutilizable. Si ponemos muchos "<Card />" se mostrarán varias tarjetas, eso sí, todas iguales con la misma información.
src/pages/index.astro
--- import Card from "../components/Card.astro"; import Layout from "../layouts/Layout.astro"; --- <Layout> <Card /> <Card /> <Card /> <Card /> </Layout>
Props de los componentes de Astro
La gracia de utilizar componentes es que se puedan reutilizar de manera que muestren diferente información. Para eso existen los “props” de Astro.
Los “props” son parámetros o atributos que puede recibir un componente cuando es utilizado y que sirven para personalizarlo. Lo verás más fácil con este ejemplo:
Partiendo de la “card” que ya teníamos, ahora quiero que la imagen, el nombre y el tipo sean dinámicos. La idea es poder utilizar el componente de esta manera y que cada uno muestre la información que le corresponda:
<Card imagen="bulbasaur.png" nombre="Bulbasaur" tipo="Planta" /> <Card imagen="gengar.png" nombre="Gengar" tipo="Fantasma" /> <Card imagen="mewtwo.png" nombre="Mewtwo" tipo="Psíquico" />
El siguiente paso es personalizar el componente “Card.astro” para que reciba esos parámetros y poder así utilizarlos. Nuestro componente “Card” quedaría así:
--- const { imagen, nombre, tipo } = Astro.props; --- <article> <img src={`/src/assets/${imagen}`} alt={nombre} /> <h2>{nombre}</h2> <p>Tipo: {tipo}</p> </article> <style> article { background-color: #e5e5e5; border-radius: 0.5rem; border: 2px solid #ccc; padding: 2rem; font-family: Arial, Helvetica, sans-serif; display: flex; flex-direction: column; gap: 0.25rem; } h2, p { margin: 0; text-align: center; } img { width: 100%; max-width: auto; height: 130px; object-fit: contain; margin-bottom: 10px; } </style>
Como ves, estamos utilizando el objeto “Astro.props” para recibir los parámetros del componente. Luego los utilizamos en el HTML en lugar de la imagen, nombre y tipo que teníamos.
Dentro de un componente puedes añadir otros componentes.
En realidad este es un ejemplo bastante básico, pero se pueden crear componentes que tengan cierta lógica, que consuman datos de una API, que se conecten a una base de datos, etc.
Slots en los componentes de Astro
Los slots son “ranuras” o “huecos” que puede tener un componente para inyectarle contenido desde fuera. Es decir, cuando llamas al componente puedes hacerlo envolviendo cualquier contenido. Mira este ejemplo:
<Card> Aquí puedes meter el contenido que quieras. </Card>
En este caso estamos utilizando el componente con etiquetas de apertura/cierre para envolver otro contenido.
Imagina que queremos utilizar el componente "Card" que hemos creado antes, pero en lugar de la imagen, nombre y tipo queremos que dentro pueda tener cualquier cosa (un texto, 20 párrafos de texto, texto con imágenes, un formulario…). En ese caso no nos serviría utilizar “props”, lo más adecuado sería indicarle al componente que debe tener un hueco o “slot” en el cual va a cargar el contenido que envuelva el componente.
src/components/Card.astro
<article> <slot> </article> <style> article { background-color: #e5e5e5; border-radius: 0.5rem; border: 2px solid #ccc; padding: 2rem; font-family: Arial, Helvetica, sans-serif; display: flex; flex-direction: column; gap: 0.25rem; } </style>
En este caso, hemos mantenido el "<article></article>" pero en su interior ahora hay un <slot /> (y además hemos borrado los estilos que sobraban).
Ahora puedo utilizar el componente Card de esta manera:
src/pages/index.astro
--- import Card from "../components/Card.astro"; import Layout from "../layouts/Layout.astro"; --- <Layout> <Card> <p>Hola, este es un componente Card con un slot.</p> <form> <input type="text" placeholder="Escribe algo..." /> <button type="submit">Enviar</button> </form> </Card> <Card> <ul> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul> <p>Otro ejemplo de Card con slot.</p> <video width="400" controls> <source src="mov_bbb.mp4" type="video/mp4" /> </video> </Card> </Layout>
También puedes asignar un contenido por defecto para el “slot” que se mostrará cuando el componente esté vacío:
src/components/Card.astro
<article> <slot>Este es el contenido por defecto del slot.</slot> </article> <style> article { background-color: #e5e5e5; border-radius: 0.5rem; border: 2px solid #ccc; padding: 2rem; font-family: Arial, Helvetica, sans-serif; display: flex; flex-direction: column; gap: 0.25rem; } </style>
src/pages/index.astro
--- import Card from "../components/Card.astro"; import Layout from "../layouts/Layout.astro"; --- <Layout> <Card></Card> </Layout>
Layouts de Astro
Los layouts son, en esencia, componentes de Astro, pero se diferencian de estos en el propósito para el que son utilizados. Mientras que los componentes se utilizan para encapsular partes reutilizables de la interfaz del sitio web, los layouts se utilizan para encapsular la estructura general de la página. Por ejemplo:
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Inicio - Mi web</title> </head> <body> <header> <nav> <ul> <li><a href="/">Inicio</a></li> <li><a href="/blog">Blog</a></li> <li><a href="/contacto">Contacto</a></li> </ul> </nav> </header> <main> <h1>Mi web</h1> <!-- Resto del contenido de la página --> </main> <footer> <a href="/politica-de-cookies">Política de cookies</a> </footer> </body> </html>
El código anterior podría ser el index de una web, con su head, su body, una cabecera con un menú, un h1, un footer, etc. Cuando crees el resto de páginas del sitio (/blog, /contacto, etc.) muchas de esas partes las querrás reutilizar. Dicho de otra forma, todas las páginas de tu sitio van a compartir esa estructura.
Los layouts sirven para no tener que repetir manualmente esa estructura en todas las páginas. En este caso, el layout podría ser algo como esto:
src/layouts/Layout.astro
--- import Header from "../components/Header.astro"; import Footer from "../components/Footer.astro"; const { title, description } = Astro.props; --- <html lang="es"> <head> <meta charset="utf-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width" /> <title>{title}</title> <meta name="description" content={description} /> </head> <body> <Header /> <main> <slot /> </main> <Footer /> </body> </html>
Y lo usaríamos así cuando creemos una página:
src/pages/index.astro
--- import Layout from "../layouts/Layout.astro"; const title = "Inicio - Mi web"; const description = "Esta es la home de mi sitio web."; --- <Layout title={title} description={description}> <!-- Aquí meteríamos el contenido de la página --> </Layout>
Como ves, no deja de ser un componente de Astro que utiliza un slot y que tiene como “props” un título y una descripción.
Aunque los layouts son componentes de Astro, se organizan en una carpeta diferente, en este caso en “src/layouts”.
Estilos CSS en Astro
En Astro es muy fácil añadir estilos CSS a los componentes, layouts, etc. pero existen varias formas de hacerlo.
Por un lado, puedes utilizar la etiqueta "<style>" dentro de un componente o layout para añadir el CSS que necesites. También puedes importar estilos CSS externos con una regla “import” en el frontmatter.
Veremos ambos casos, pero antes es importante entender la diferencia entre los estilos locales y los estilos globales en Astro.
Estilos locales y globales
Por defecto, los estilos que utilices en tus componentes y layouts tendrán un alcance local. Veamos un ejemplo:
src/components/Button.astro
--- const { href } = Astro.props; --- <a href={href}> <slot /> </a> <style> a { font-family: Arial, Helvetica, sans-serif; text-transform: uppercase; font-weight: bold; text-align: center; text-decoration: none; background-color: crimson; color: white; padding: 1rem 1.5rem; border-radius: 0.25em; cursor: pointer; &:hover { background-color: royalblue; } } </style>
En el ejemplo anterior he creado un componente “Button.astro” y le he aplicado una serie de estilos. Estos estilos tienen un alcance local, lo que quiere decir que solamente van a afectar a este componente (en el proceso de compilación Astro añadirá internamente IDs únicos a estos estilos).
El hecho de que los estilos solo afecten al componente en el que están tiene una gran ventaja, y es que podrás utilizar selectores CSS de baja especificidad (como “a”, “div”, “img”, etc) sin preocuparte de los conflictos entre estilos.
Aunque por defecto los estilos CSS tienen un alcance local, existe la posibilidad de hacer que esos estilos funcionen globalmente. Es decir, que se apliquen en todo el sitio web y no solo en el componente/layout donde estén. Para escribir estilos CSS globales en Astro tan solo necesitas especificarlo de la siguiente forma en el tag <style>:
<style is:global> h1{ background-color: blue; color: white; } </style>
Si el código CSS del ejemplo anterior estuviera dentro de un componente, todos los <h1> de la web (y no solamente los <h1> del componente) se verían afectados por los estilos que se le aplican.
A mayores de los estilos locales y globales, también podemos utilizar un “mix” de ambos utilizando el selector especial “:global()”.
<style> p{ text-decoration: underline; } div :global(p){ color: red; } </style> Si el CSS anterior estuviera dentro de un componente, las etiquetas <p> de ese componente tendrían un subrayado. Pero a mayores, todos las etiquetas <p> que estén dentro de un <div> de toda la web tendrían color rojo.
Importar estilos en Astro
Otra posibilidad a la hora de añadir CSS en Astro es importar las hojas de estilo. Puedes importar hojas de estilo que tengas localmente dentro de tu proyecto de Astro y también puedes importar hojas de estilo de un paquete NPM. En ambos casos, tienes que hacerlo en el frontmatter del archivo de Astro en el que los estés importando.
— import '../styles/forms.css'; // Importar una hoja de estilos local import 'package-name/styles.css'; // Importar una hoja de estilos de un paquete NPM —
A la hora de importar una hoja de estilos de un paquete NPM sigue la documentación del propio paquete al respecto.
Finalmente, también puedes añadir una hoja de estilos utilizando la etiqueta <link> de HTML:
<head> <link rel="stylesheet" href="/styles/forms.css" /> </head>
El orden de cascada de estos 3 métodos de añadir CSS en Astro es:
- Estilos locales
- Estilos importados (en orden de importación)
- Etiquetas <link>
Integración de Tailwind CSS en Astro
Tailwind es uno de los frameworks CSS más conocidos y utilizados en la actualidad. Y como no podía ser de otra manera, Astro nos facilita la vida a la hora de integrarlo, ya que existe un plugin oficial de Tailwind para Vite.
Si lo necesitas puedes echar un vistazo a nuestro artículo sobre qué es Tailwind y cómo utilizarlo.
Para añadir Tailwind CSS en Astro tienes que ejecutar el siguiente comando en tu terminal y seguir los pasos del proceso de instalación:
npx astro add tailwind
Tras seguir los pasos de instalación, el propio instalador te pedirá que importes la hoja de estilos de Tailwind al layout principal.
--- │ import '../styles/global.css' ---
Y listo. Ya ves que instalar Tailwind en Astro es una tarea bastante sencilla y rápida.
Scripts en Astro
En Astro es posible incluir scripts de JavaScript del lado del cliente (es decir, que se ejecutan en el navegador del usuario). Para hacerlo solo necesitas añadir una etiqueta <script> de HTML.
— const { mensaje } = Astro.props; — <p>{mensaje}</p> <script> console.log("Este script se ejecuta en el navegador."); </script>
En el ejemplo anterior he creado un componente muy simple que devuelve un mensaje dentro de una etiqueta <p>. Además, tiene un script que saca un console.log en la consola del navegador del usuario. He puesto un “console.log” para simplificar el ejemplo, pero obviamente puedes escribir scripts mucho más complejos.
Algo muy importante a tener en cuenta es que Astro procesa los scripts que son incluidos así (con una etiqueta <script>). Este procesado implica que:
- Los scripts se insertarán en el “<head>” de la página con el atributo “type=’module’”.
- Si tienes un script en un componente y usas dicho componente varias veces, el script solo se incluirá una vez.
- Puedes utilizar TypeScript.
- Puedes importar módulos de Node.
Pero también puedes añadir scripts y evitar que sean procesados por Astro:
<script is:inline> // Aquí tu código JS </script>
Los scripts que añadas con “is:inline”:
- No aceptan importaciones.
- Si están en un componente que usas varias veces, el script se incluirá todas esas veces.
- Se renderizarán en el HTML tal cual los hayas escrito.
Además de añadir etiquetas “<script>” para escribir tu código JavaScript dentro de ellas, también puedes importar archivos .js que tengas en tu proyecto o externos:
// Para importar un archivo local (ubicado dentro de /src) <script src="../scripts/script.js"></script> // Para importar un archivo externo (o no ubicado dentro de /src) <script is:inline src="https://sitioweb.com/script.js"></script>
Fíjate que para importar scripts externos hay que utilizar la directiva “is:inline” para que Astro no lo procese.
Integraciones de Astro con otros frameworks
Aunque hasta ahora hemos visto cómo crear componentes de Astro, también es posible crear componentes de otros frameworks y usarlos dentro de Astro. Por suerte, existen integraciones oficiales de frameworks como:
- React
- Preact
- Svelte
- Vue
- AlpineJS
- SolidJS
Para explicarte cómo usar un componente de otro framework en Astro voy a tomar de ejemplo React, pero el proceso es similar para el resto.
Si necesitas profundizar sobre el uso de componentes de otros frameworks en Astro echa un ojo a su documentación oficial: https://docs.astro.build/es/guides/framework-components/
Lo primero que debes hacer es instalar la integración oficial ejecutando en tu terminal el comando correspondiente y siguiendo los pasos del asistente de instalación, en este caso:
npx astro add react
Una vez tengas instalada la integración, crear un componente es muy sencillo. Debes hacerlo de la misma forma que cuando creas un componente de Astro, pero utilizando la extensión de archivo que se corresponda con el framework.
En este caso, para crear un componente de React voy a crear un archivo “Contador.jsx” dentro de “src/components”. Usaré el ejemplo típico de React de un contador de clics.
src/components/Contador.jsx
import { useState } from 'react'; export default function Contador() { const [contador, setContador] = useState(0); return ( <div> <p> </p> <button class="bg-slate-500 text-white px-5 py-2.5" onClick={() => setContador(contador + 1)}> Haz clic aquí: Llevas {contador} clics </button> </div> ); }
Ya tenemos el componente de React creado, solo falta incluirlo en alguna página de nuestro sitio web. Para hacerlo seguimos el método habitual que ya hemos visto hasta ahora, con un pequeño detalle que te explico a continuación:
src/pages/Index.astro
— import Contador from "../components/Contador.jsx"; — <Contador client:load />
Como ves, a la hora de añadir el componente he usado la directiva “client:load”. Te explico por qué:
Astro es un framework que en el proceso de compilación genera un HTML estático. En este caso necesitamos un componente que actualice el número de clics cada vez que el usuario pulsa el botón, pero como el HTML ya está generado y es fijo, esto no es posible (el HTML generado es el que es y, por mucho que hagamos clic, no va a cambiar).
Para conseguir esa interactividad tenemos que utilizar una directiva “client” cuando llamamos al componente. Estas directivas permiten definir cuándo se envía el componente al navegador. De esta manera, Astro permite al componente recibir el JavaScript que necesita, en el momento necesario. Esto es lo que se conoce como “hidratar un componente”.
Las directivas “client” que puedes usar son:
- client:load (el JavaScript se enviará al cliente cuando se cargue la página)
- client:visible (el JavaScript se enviará al cliente cuando el componente sea visible al hacer scroll)
- client:only=”nombre_del_framework” (el componente no se renderiza en el servidor, se renderiza en el cliente cuando se cargue la página).
La directiva “client:only” se suele utilizar en casos en los que el componente solo puede ejecutarse en el navegador del cliente (por ejemplo, cuando usas cosas como “window” o “localStorage”). Además, es necesario indicarle el nombre del framework que estás utilizando (en el caso de mi ejemplo, sería ‘client:only=”React”’).
Modos SSG y SSR
Uno de los puntos fuertes de Astro es la rapidez de los sitios web creados con este framework. Esto se debe a que, por defecto, Astro genera HTML estático en el proceso de “build” y que es el que se sirve a los usuarios. Esto es lo que se conoce como SSG o Static Site Generation.
Aun así, esto tiene una desventaja, y es que para sitios dinámicos, con información que cambia con frecuencia o incluso que cambia casi en tiempo real el modo SSG no es el adecuado. Por suerte, en Astro existe otro modo de generar y servir el contenido al usuario: el modo SSR o “Server Side Rendering” (Renderizado del lado del servidor).
En el modo SSR las páginas se generan bajo demanda en el servidor, es decir, en el momento en el que el usuario las visita. Gracias a esto puedes mostrar contenido dinámico sin necesidad de hacer otro “build”. Esto es útil, entre otras cosas, para páginas que cambian con frecuencia, para sistemas de autenticación de usuarios, etc.
Cómo activar el modo SSR (Server Side Rendering) en Astro
Activar el modo SSR en Astro es bastante fácil, pero además necesitarás instalar un adaptador. Veamos todo el proceso.
Para activar el modo SSR en Astro tienes que:
- Configurar el tipo de “output” a “server” (por defecto es “static”) en tu archivo astro.config.mjs
export default defineConfig({ output: 'server', });
- Instalar un adaptador SSR
El adaptador SSR sirve para que Astro sepa cómo desplegar la web en una determinada plataforma. Astro tiene adaptadores oficiales para Cloudflare, Netlify, Node y Vercel e instalarlo es tan fácil como ejecutar el siguiente comando y seguir los pasos del proceso de instalación:// npx astro add nombre_del_servicio // Ejemplo: npx astro add vercel
Si lo necesitas consulta la documentación oficial de Astro sobre los adaptadores SSR: https://docs.astro.build/es/guides/on-demand-rendering/#adaptadores-de-servidor
Con esto, toda tu aplicación web estará en modo SSR, de forma que todas las páginas se renderizarán en el servidor. Aun así, puedes excluir páginas concretas de ser renderizadas en el servidor añadiendo el siguiente código en el frontmatter de la página en cuestión:
— export const prerender = true —
De esta forma, las páginas que contengan el código anterior serán pre renderizadas y se enviarán como HTML estático al navegador del usuario.
Server Islands o islas de servidor
Una de las funcionalidades estrella de Astro son las Server Islands (Islas de servidor), las cuales están disponibles desde la versión 4.12 del framework.
Las Server Islands son componentes de Astro que se renderizan en el servidor y luego son enviados al cliente y sirven para tener partes dinámicas dentro de un HTML estático.
Digamos que tienes una página, cuyo contenido no cambia a excepción de un bloque en el que muestras el nombre del usuario logueado. Si toda la página fuera completamente estática (HTML generado en el “build”), todos los usuarios verían el mismo nombre. Una opción sería activar el modo SSR en todo el sitio, de esta manera la página se construiría con cada petición, pero no tendría mucho sentido hacerlo teniendo en cuenta que la gran mayoría del contenido es siempre el mismo.
Las Server Islands sirven precisamente para solucionar esto. Si hacemos que el componente que muestra el nombre del usuario sea una Server Island, podremos mantener todo el contenido de la página estático a excepción de ese componente. Cuando visitemos la página, se cargará todo el contenido estático y en el servidor se renderizará el componente del nombre de usuario. Cuando esté listo, se enviará al navegador. De esta forma optimizamos al máximo el rendimiento de la web.
Pero vamos al lío: ¿cómo le digo a un componente que debe comportarse como una Server Island? Aunque no te lo creas, es extremadamente sencillo hacerlo.
<Componente server:defer />
Como ves, solo he añadido la directiva “server:defer” al componente. Esto le indica al componente que debe renderizarse en el servidor.
Para utilizar Server Islands no es necesario configurar el “output”, pero si es necesario añadir un adaptador de SSR.
A la hora de utilizar Server Islands puede ser interesante tener un contenido a modo de “fallback” o contenido por defecto. Como el componente se va a renderizar en el servidor, va a tardar (por poco que sea) un poco más en cargarse que el resto del contenido. Esto puede provocar un ligero “parpadeo” que, aunque no es importante, se puede solucionar con un “fallback”:
<Componente server:defer> <span slot=”fallback”>Cargando…</span> </Component>
De esta manera, hasta que el componente termine de renderizarse, veremos el contenido del “fallback”, en este caso un texto de “Cargando…” (pero podría ser cualquier cosa, una imagen, otro componente, etc.).