~/ctrl-z blog

Hola mundo: así está construido este blog

Astro, MDX, Tailwind CSS, Expressive Code y Pagefind: el stack completo de este blog y por qué elegí cada pieza.

Bienvenido a este blog. Como primera entrada, nada mejor que explicar cómo está construido y el por qué cada tecnología.

El stack

  • Astro — genera HTML estático puro. Cero JavaScript por defecto en el cliente.
  • MDX — Markdown con superpoderes: puedo usar componentes dentro de los artículos.
  • Tailwind CSS 4 — estilos utilitarios con la nueva configuración basada en CSS.
  • Expressive Code — bloques de código con resaltado, marcos de terminal y botón de copiar.
  • Pagefind — búsqueda local que se indexa en el build; no hay servidor ni terceros.
  • RSS + sitemap — generados automáticamente en cada build.

¿Por qué un sitio estático?

La razón principal es la seguridad: no hay base de datos, no hay panel de administración expuesto, no hay PHP que parchear. La superficie de ataque se reduce a servir archivos.

astro.config.mjs
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import sitemap from '@astrojs/sitemap';
import expressiveCode from 'astro-expressive-code';
export default defineConfig({
site: 'https://devblog.example.com',
integrations: [expressiveCode(), mdx(), sitemap()],
});

Publicar es un comando

Cada entrada es un archivo .mdx. Para crear una nueva basta con:

Terminal window
npm run new -- "Título de mi nueva entrada"

El esquema de la colección valida el frontmatter con Zod, así que un error de tipado rompe el build en vez de llegar a producción:

src/content.config.ts
const blog = defineCollection({
loader: glob({ pattern: '**/[^_]*.mdx', base: './src/content/blog' }),
schema: z.object({
title: z.string().max(120),
description: z.string().max(200),
pubDate: z.coerce.date(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
}),
});

En próximas entradas iré profundizando en cada pieza. ¡Gracias por leer!