Como construi este blog (y por que debi elegir Nuxt desde el dia 1)
Cronica tecnica de arquitectura de blog: errores de arranque, intento con VitePress, dolor de mantenimiento y refactor build-time con foco en SEO y performance.
Spoiler tecnico: El blog funciona, escala y ya no me quita el sueño. Pero el camino fue un âaprendizaje acelerado con efectos secundariosâ.

Prologo: cuando el entusiasmo le gana al diseño
Esta historia empieza como empiezan muchas historias de software:
- âEsto sale rapido.â
- âLuego lo ordeno.â
- âNo necesito meter otra capa.â
- âOh no.â
Yo queria un portafolio rapido en Vue 3 + Vite, con buen performance y una seccion de blog. Hasta ahi, todo bien.
El problema fue asumir que âblogâ era solo âpintar markdownâ. En realidad era:
- contenido,
- SEO,
- rutas,
- generacion de artefactos,
- performance,
- validaciones,
- y disciplina.
En ese punto, Nuxt ya me estaba viendo desde lejos con cara de: âte lo dijeâ.
Acto 1: la version YOLO del blog
Mi primer impulso fue resolver todo en runtime cliente:
- leer markdown,
- parsearlo,
- resaltarlo con Shiki,
- y rezar para que el bundle no explotara.
Si quieres detectar rapido que algo no va bien, revisa el tamano del chunk. Cuando ves que la pieza de markdown/highlighting crece como si entrenara para una competencia, sabes que hay deuda tecnica.
Leccion: renderizar markdown + highlighting en cliente para un blog tecnico no es gratis.
Acto 2: âmetamos VitePress y yaâ
Aqui fue donde me puse creativo de la manera equivocada. Pense: âSi VitePress resuelve docs/blog, lo encajo en el proyecto y listo.â
No era mala intencion. Si fue mala friccion.
Problemas reales de ese intento:
- Dos modelos mentales conviviendo sin hablarse del todo.
- Acoplamientos raros entre rutas/app y contenido.
- Flujo editorial menos directo para este caso.
- Mantenimiento mas caro para algo que debia simplificar.
Traduccion: quise ahorrar tiempo y termine pagando interes compuesto.

Acto 3: la arquitectura que si se quedo
En lugar de perseguir magia, dividi el problema en capas simples:
content/blog/<locale>/*.mdcomo fuente de verdad.- Scripts de build para generar artefactos consumibles.
- Runtime cliente delgado (sin parsear markdown pesado).
- Rutas y SEO consistentes en SSG.
Estructura real (simplificada)
content/
blog/
es/
*.md
media/
blog/
<slug>/
scripts/
build-blog-content-artifacts.mjs
build-blog-artifacts.mjs
src/features/blog/generated/
blog-index.es.json
blog-posts/es/<slug>.html
blog-routes.json
Flujo de build del blog
Markdown en content/blog/es
-> Build de artefactos
-> indice JSON por locale
-> HTML pre-render por slug
-> rutas SSG publicables
-> listado ligero
-> detalle de post sin parseo runtime
-> prerender estable con vite-ssg

Que gano con esto
- Menos JS en cliente para blog.
- Menos trabajo duplicado entre listado y detalle.
- Menos sorpresas en SEO y rutas.
- Mejor mantenibilidad del contenido.
Practicas que se aplican hoy (y por que importan)
No es solo âque compileâ. Es que se sostenga.
1) Contratos de contenido
- Frontmatter validado por esquema.
langconsistente con carpeta.slugestable.canonicalcorrecto.
Esto evita que un post bonito rompa produccion por un typo silencioso.
2) Seguridad de supply chain
En .npmrc:
ignore-scripts=truesave-exact=truemin-release-age=2
No suena glamuroso. Si suena a dormir tranquilo.
3) Performance con presupuesto
No se optimiza âa ojoâ. Se optimiza con limites:
- budget de JS inicial,
- budget de chunk de detalle de blog,
- validaciones en CI.
Cuando algo se sale, falla. Como debe ser.

4) Separacion de responsabilidades
Cliente:
- renderizar UX.
Build:
- cocinar contenido pesado.
Resultado: el navegador deja de hacer trabajo de cocina industrial.

Fragmentos tecnicos del proyecto
Scripts clave
{
"scripts": {
"build:blog-content-artifacts": "node ./scripts/build-blog-content-artifacts.mjs",
"build:blog-artifacts": "node ./scripts/build-blog-artifacts.mjs",
"build": "npm run build:blog-artifacts && vue-tsc --noEmit && vite-ssg build"
}
}
Carga de artefactos en runtime (idea)
const blogIndexArtifactModules = import.meta.glob(
"/src/features/blog/generated/blog-index.*.json",
{ eager: true, import: "default" }
);
Resultado practico
El detalle de post ya consume HTML generado. No parsea markdown pesado en cliente en cada navegacion.
Y entonces, por que Nuxt desde el dia 1?
Porque varias piezas que yo cosi manualmente, Nuxt te las entrega mas integradas desde el inicio para contenido, rutas y ciclo editorial.
No es que la solucion final actual sea mala. Es que Nuxt me habria dejado invertir mas tiempo en producto y menos tiempo en pegamento.
Referencia clave que hoy pesaria en esa decision:
Cierre
Este blog no nacio perfecto. Nacio util, luego terco, luego mantenible.
Y si este post te evita meter un framework âporque siâ o reescribir media arquitectura en viernes por la noche, mision cumplida.