Volver al blog
astro react portfolio tutorial

Cómo Construí Este Portfolio con Astro

2 min de lectura

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:

  1. Velocidad: UnoCSS es significativamente más rápido
  2. Tamaño: El CSS final es ~6KB vs ~15KB de Tailwind
  3. 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 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:

  1. Dockerfile multi-stage para build optimizado
  2. Traefik como reverse proxy con SSL automático
  3. 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 en menos de 2 segundos
  • Consigue Lighthouse 100 en Performance
  • Es fácil de mantener y actualizar

¿Te interesa crear algo similar? ¡No dudes en contactarme!