Cómo construí este portfolio con Astro
Cómo construí este portfolio con Astro
Cuando decidí crear mi nuevo portfolio, tenía claros mis objetivos: rendimiento extremo, animaciones fluidas y facilidad de mantenimiento. Después de evaluar varias opciones, elegí Astro 5 como base.
¿Por Qué Astro?
Astro tiene una filosofía que me encanta: enviar el mínimo JavaScript posible al cliente. Para un portfolio, esto es perfecto porque la mayoría del contenido es estático.
Islands Architecture
Astro usa un concepto llamado “Islands Architecture”. Significa que puedes tener componentes interactivos (React, Vue, Svelte) embebidos en páginas mayormente estáticas.
---
// Esta parte se ejecuta en el servidor
import { Hero } from '@/components/Hero';
import { Projects } from '@/components/Projects';
---
<!-- Hero se carga inmediatamente -->
<Hero client:load />
<!-- Projects solo se hidrata cuando es visible -->
<Projects client:visible />
El stack completo
UnoCSS vs Tailwind
Elegí UnoCSS sobre Tailwind por varias razones:
- Velocidad: UnoCSS es significativamente más rápido
- Tamaño: El CSS final es ~6KB vs ~15KB de Tailwind
- Flexibilidad: Puedo crear shortcuts personalizados fácilmente
// uno.config.ts
shortcuts: {
'btn-primary': 'px-4 py-2 bg-neon-cyan text-black rounded-lg',
'card-glass': 'backdrop-blur-md bg-white/10 border border-white/20'
}
Framer Motion para las animaciones
Las animaciones son sutiles pero importantes. Uso Framer Motion para:
- Transiciones de entrada al scroll
- Efectos hover en cards
- Animaciones de la navegación móvil
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
{children}
</motion.div>
Content Collections para el Blog
Astro tiene un sistema built-in para gestionar contenido llamado Content Collections. Es type-safe y funciona perfecto con MDX.
// src/content/config.ts
const postsCollection = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
date: z.date(),
tags: z.array(z.string()),
}),
});
Deploy en Docker + Traefik
Para el deploy, uso un setup que tengo en un servidor Hetzner:
- Dockerfile multi-stage para build optimizado
- Traefik como reverse proxy con SSL automático
- GitHub Actions para CI/CD
# docker-compose.prod.yml
services:
portfolio:
labels:
- traefik.enable=true
- traefik.http.routers.portfolio.rule=Host(`antonio.romerolabs.dev`)
- traefik.http.routers.portfolio.tls.certresolver=letsencrypt
Resultado
El resultado es un portfolio que carga rápido, saca buena nota en Lighthouse y se mantiene sin dolor. Justo lo que le pides a una web personal.
Actualización de julio de 2026: la web se volvió agéntica
Año y medio después, esta web ya no es la misma. Le cambié la piel entera (fuera el neón cian de rigor, dentro una paleta ámbar de sala de control con IBM Plex) y, sobre todo, le añadí cerebro: un asistente conversacional que corre sobre GLM a través de un proxy propio, con streaming, herramientas que navegan la página y un CV en PDF que se genera al momento en tu navegador.
La moraleja de la actualización es la misma que la del post original: elige una base que no estorbe. Astro me dejó añadir un servicio de chat, un generador de PDF y una capa de identidad visual nueva sin pelearme con el framework ni una sola vez. Si quieres el detalle del asistente, tiene su propio post.
¿Te interesa montar algo parecido? Escríbeme y lo vemos.