Artículo
De Markdown en runtime a contenido generado en build
Una retrospectiva sobre separar la autoría, la transformación editorial y la entrega de un blog técnico sin cargar ese trabajo en el navegador.
La primera versión de este relato concluía que debía haber elegido otro framework desde el inicio. Era una conclusión demasiado cómoda. El problema real no era Vue contra Nuxt: era haber tratado el contenido editorial como si fuera estado de una aplicación cliente.
Un blog técnico necesita resolver autoría, validación, rutas, HTML, metadatos y recursos. Si todas esas responsabilidades llegan juntas al navegador, el coste no proviene de Markdown por sí solo, sino de haber colocado la frontera del sistema en el lugar equivocado.
Idea central. El navegador debe recibir una página útil. Convertir documentos, validar frontmatter y decidir qué rutas existen corresponde al build cuando el contenido cambia únicamente con una publicación.
El punto de partida
El portafolio anterior era una aplicación Vue construida con Vite. Incorporar el blog parecía una extensión pequeña: leer Markdown, transformarlo y mostrar el resultado dentro de una ruta.
Esa descripción omitía casi todo lo importante. Además del cuerpo había que mantener:
- un índice por idioma;
- títulos, fechas, etiquetas y canonical coherentes;
- rutas prerenderizadas para cada entrada;
- resaltado de ejemplos técnicos;
- borradores ausentes de producción;
- imágenes derivadas y referencias válidas;
- RSS y sitemap alineados con las mismas publicaciones.
La interfaz podía pintar un documento, pero eso no convertía al navegador en el lugar correcto para preparar el documento.
Lo que el runtime no debía resolver
La exploración inicial mezcló carga del archivo, parseo de Markdown y presentación. El efecto más problemático no era una cifra concreta de bundle —no conservo una medición comparable que deba publicar—, sino el acoplamiento: la ruta de lectura dependía de código editorial que no aportaba interacción.
También aparecía duplicación. El índice necesitaba metadatos; el detalle, HTML; el router, la lista de slugs; y SEO, otra representación de los mismos campos. Sin una fase que produjera esos artefactos desde una sola fuente, cada consumidor podía interpretar el contenido de manera distinta.
Mover el trabajo al build no hace rápido un sitio por definición. Sí elimina una clase concreta de trabajo repetido: transformar en cada visita documentos que ya eran conocidos al publicar.
El intento con VitePress
VitePress resolvía correctamente un problema cercano: documentación generada desde Markdown. El intento de integrarlo no falló porque la herramienta fuera inadecuada, sino porque introducía un segundo modelo de aplicación dentro de un portafolio que ya tenía routing, estilos y despliegue propios.
La fricción se volvió visible en tres fronteras:
- quién era responsable de las rutas;
- dónde terminaba la aplicación y comenzaba el sitio editorial;
- qué proceso producía el artefacto que realmente se desplegaba.
Mantener dos ciclos de navegación y presentación habría sido más costoso que extraer una fase editorial pequeña. La decisión fue conservar una sola aplicación y hacer explícita la transformación del contenido.
Los criterios que ordenaron la solución
La arquitectura dejó de discutirse en términos de preferencia por frameworks y se evaluó con contratos observables:
- el Markdown debía seguir siendo la fuente editable;
- un error de frontmatter debía detener el build;
- el navegador no debía parsear Markdown ni iniciar un resaltador global;
- las rutas publicables debían derivarse de la misma consulta que el índice;
- cada URL necesitaba HTML y metadatos útiles sin JavaScript;
- los borradores no podían generar una ruta oculta pero accesible.
Estos criterios permitían comparar alternativas sin convertir una herramienta en la tesis del proyecto.
El pipeline que permaneció
El repositorio anterior terminó con archivos Markdown bajo
content/blog/<idioma>/ y scripts que producían índices JSON, HTML por entrada
y una lista de rutas para el build SSG. La aplicación consumía esos artefactos
en lugar de transformar el documento durante la navegación.
Markdown + frontmatter
↓
validación y render
↓
índice + HTML + rutas
↓
build SSG
↓
archivos estáticos
El pipeline produjo una frontera clara:
- autoría: documentos y recursos editables;
- transformación: validación, render y generación de metadatos;
- entrega: rutas estáticas consumidas por la interfaz;
- navegación: HTML listo, con JavaScript reservado para comportamiento.
No era una solución gratuita. Había scripts propios, contratos de artefactos y pruebas que mantener. A cambio, la complejidad editorial dejaba de estar distribuida entre componentes cliente.
Contratos antes que archivos generados
El valor de la fase de build no estaba en producir más archivos, sino en detectar contradicciones antes del despliegue. El frontmatter validaba campos obligatorios, fechas y canonical. La generación excluía borradores y reunía en un solo lugar los datos consumidos por rutas, RSS y sitemap.
La distinción es importante: un archivo generado sin contrato solo desplaza el error. Un build útil debe fallar cuando una entrada no puede convertirse de forma segura en una página pública.
Lo mismo aplica a rendimiento. Se añadieron presupuestos para observar cambios en la salida, pero no hay una cifra histórica homogénea que permita afirmar un porcentaje de mejora. La conclusión publicable es más limitada: el detalle dejó de necesitar el motor de Markdown en cada navegación y el coste pasó a ser visible en el proceso de publicación.
La lectura retrospectiva desde Astro
El proyecto actual conserva la misma frontera con menos código propio. Las
Content Collections de Astro
cargan y validan las entradas durante el build. La función render() entrega
el componente de contenido y los encabezados, y getStaticPaths() genera
únicamente las rutas que devuelve la consulta pública.
El recorrido ahora es:
- Markdown validado por el esquema de
posts; - consulta única que excluye borradores y ordena por fecha;
- ruta estática que renderiza la entrada;
- layout que genera canonical, Open Graph y
BlogPosting; - HTML navegable sin runtime de interfaz.
Esto no demuestra que Astro sea la elección universal, del mismo modo que la experiencia anterior no demostraba que Nuxt fuera obligatoriamente la correcta. Demuestra algo más útil: para este sitio, un framework orientado a contenido elimina una capa de pegamento que antes se mantenía de forma local.
Costes y límites
Generar contenido en build también tiene consecuencias:
- cada publicación requiere un nuevo build;
- una colección muy grande puede aumentar tiempo y memoria;
- los plugins de Markdown forman parte de la cadena de suministro;
- una previsualización editorial avanzada necesita diseñarse por separado;
- el HTML generado todavía debe revisarse por accesibilidad y peso.
Ninguno de estos límites afecta hoy el carácter estático del sitio, pero evita presentar el patrón como una receta sin contexto.
Decisión que conservaría
No empezaría preguntando qué framework “incluye blog”. Empezaría fijando quién es responsable de cada transformación y qué debe recibir el navegador.
Cuando el contenido es local, cambia al publicar y debe ser legible sin interacción, la frontera más sencilla es:
documento → validación → render de build → HTML estáticoLa lección no es que toda aplicación deba migrar a un generador estático. Es que la arquitectura editorial merece un lugar explícito y no debe aparecer por accidente dentro de la ruta cliente.
La siguiente parte de esta historia está en Un despliegue estático verificable: TLS por fases, lock y rollback.