Saltar al contenido

Expresiones y exportaciones en MDX

El cuerpo de un fichero MDX como código ejecutable: insertar expresiones JavaScript entre llaves, definir variables y valores derivados con export const, la relación entre el frontmatter YAML de datos y las exportaciones computadas, y el límite que separa una expresión válida de una sentencia que MDX no admite.

Expresiones en el cuerpo con llaves

La forma más directa de meter cómputo en un documento es la expresión entre llaves. Escribes { seguido de cualquier expresión JavaScript y }, y MDX la evalúa e inserta su resultado en ese punto del texto. Es la misma sintaxis de las plantillas de Astro, ahora disponible en medio de la prosa.

MDX
---title: Estado del proyecto---# {title.toUpperCase()}Documento generado el {new Date().toLocaleDateString('es-ES')}.Quedan {30 - 12} tareas por cerrar de un total de {30}.

La clave está en la palabra expresión: entre las llaves solo cabe algo que produzca un valor. Una operación aritmética, una llamada a método, un acceso a una propiedad, una plantilla de cadena, un ternario: todo eso es expresión y funciona. Lo que no cabe es una sentencia —un if, un for, una declaración— porque una sentencia no devuelve nada que insertar. Esa restricción, que parece limitante, es la misma que rige el JSX y la que te empuja a los patrones funcionales de siempre.

Variables y valores con export const

Para no repetir un cálculo o para dar nombre a un dato, defines variables en la cabecera del documento con export const. Estas declaraciones viven en el ámbito del módulo, así que cualquier expresión del cuerpo puede usarlas, y además —por ser exportadas— quedan disponibles para quien importe el fichero.

MDX
---title: Informe trimestral---export const ventas = 128;export const meta = 150;export const cumplido = Math.round((ventas / meta) * 100);# {title}Se alcanzaron {ventas} de {meta} ventas: un {cumplido} por ciento de la meta.

Nada te obliga a exportarlas: un const a secas también funciona como variable local del módulo. Pero export const es el idioma canónico en MDX por una razón doble: expresa la intención de que ese valor forme parte del contrato del documento, y lo hace accesible desde fuera. Un valor derivado como cumplido muestra el poder del enfoque: se computa una vez, a partir de otros dos, y se reutiliza en la prosa sin que el redactor tenga que recalcularlo a mano ni arriesgarse a que las cifras se desincronicen.

Ese “accesible desde fuera” es literal y merece verse. Como el .mdx compila a un módulo, otro fichero puede importarlo y leer sus valores exportados como leería los de cualquier librería. Junto a esos valores, el módulo expone el componente Content para renderizar el cuerpo y el objeto del frontmatter.

ASTRO
---import { Content, ventas, cumplido } from '../content/informe.mdx';---<p>El informe declara {ventas} ventas y un {cumplido} por ciento cumplido.</p><Content />

Un documento deja así de ser un pozo cerrado del que solo sale HTML: se vuelve una fuente de datos consultable por su propia página. La misma cifra que el texto muestra en su cuerpo puede alimentar una tarjeta de resumen en la plantilla que lo envuelve, sin duplicarla, porque ambas leen el mismo export const.

Frontmatter YAML frente a valores exportados

MDX ofrece dos maneras de asociar datos a un documento, y conviene no confundirlas. El frontmatter YAML —el bloque entre guiones— es para datos estáticos y declarativos: cadenas, números, fechas, listas literales que describen el documento. Las exportaciones con export const son para valores de JavaScript, incluidos los que se computan a partir de imports o de otras variables. YAML no ejecuta; export const sí.

La frontera práctica es de naturaleza, no de gusto. Un title fijo va en el frontmatter, porque es un dato que no necesita calcularse. Un total que sale de sumar una lista importada va en un export const, porque YAML no sabe sumar. Y ambos coexisten sin estorbarse: el frontmatter describe, las exportaciones computan, y el cuerpo del documento consume libremente de las dos fuentes con la misma sintaxis de llaves.

El límite: expresiones, no sentencias

El error más común al empezar con MDX es querer escribir lógica de control entre las llaves. No se puede poner un if ni un for dentro de { }, porque son sentencias y no devuelven valor. La solución es la misma que en JSX: traduces la condición a un ternario o a un &&, y el bucle a un .map() que devuelve un array de nodos.

MDX
---title: Lista---export const tareas = ['diseño', 'código', 'pruebas'];export const urgente = true;{urgente && <strong>Hay trabajo urgente.</strong>}<ul>  {tareas.map((t) => <li>{t}</li>)}</ul>

Ese giro no es una incomodidad que sortear, sino la forma en que MDX te empuja hacia un estilo declarativo. En lugar de decir cómo recorrer la lista con un bucle imperativo, describes qué quieres —un li por cada tarea— y dejas que .map() lo produzca. La ausencia de sentencias no te quita expresividad; te obliga a expresarla como transformación de datos, que es justo el idioma en el que las interfaces se piensan mejor.

No es casualidad que estas reglas coincidan al milímetro con las de las expresiones en una plantilla .astro: son el mismo motor. Lo que aprendiste sobre {expresion}, ternarios y .map() en el template de Astro se transfiere entero a MDX, porque en ambos casos el compilador espera una expresión que produzca un nodo. Esa unidad conceptual es deliberada y ahorra memoria: no hay dos sistemas de plantillas que dominar, hay uno solo que reaparece —en un .astro, dentro de la plantilla; en un .mdx, dentro de la prosa—.