Saltar al contenido

Prism como alternativa: cliente frente a servidor y rendimiento

Astro también soporta Prism como resaltador: markdown.syntaxHighlight puede valer 'prism' y existe el componente <Prism /> de @astrojs/prism, con tokens por clase y una hoja de estilos externa en lugar de estilos en línea. Aclarar el intercambio Shiki frente a Prism, y el eje ortogonal y más profundo de resaltar en el servidor frente a hacerlo en el cliente, con su modelo de coste, cierra el nivel con criterio de arquitectura.

<Prism /> y el resaltado con Prism

Cambiar el resaltador de Markdown a Prism es una línea en la configuración: syntaxHighlight: 'prism'. A diferencia de Shiki, Prism no escribe colores en línea; emite tokens con clases —.token.keyword, .token.string—, de modo que los colores viven en una hoja de estilos aparte que tú debes incluir. Sin ese CSS, el código sale con la estructura de tokens marcada pero sin color.

JS
// astro.config.mjsimport { defineConfig } from 'astro/config';export default defineConfig({  markdown: {    syntaxHighlight: 'prism',  },});

Con ese ajuste, todas las vallas de Markdown pasan a resolverse con Prism en lugar de Shiki. El componente <Prism />, por su parte, funciona con independencia de esa opción global, igual que <Code /> lo hacía con Shiki: uno gobierna el Markdown, el otro se invoca donde lo necesites.

ASTRO
---import { Prism } from '@astrojs/prism';---<Prism lang="js" code={`const x = 1;`} />

Para que ese resaltado tenga color hay que incluir una hoja de estilos de tema de Prism —una de las muchas que su ecosistema ofrece— en el head de la página o en un layout compartido.

ASTRO
---// en un layout compartido---<link rel="stylesheet" href="/estilos/prism-tomorrow.css" />

Prism es un proyecto veterano y omnipresente: durante años fue el resaltador por defecto de incontables sitios, y su catálogo de temas y complementos es enorme. Esa madurez es parte de su atractivo, junto con lo liviano de su salida. La contrapartida es esa dependencia externa: el color ya no viaja con el bloque, sino en una hoja aparte que hay que cargar, mantener y no olvidar, justo la pieza que Shiki elimina al escribir el color en línea.

Prism resuelve sus gramáticas con expresiones regulares, no con gramáticas TextMate, lo que lo hace más ligero pero menos preciso: en lenguajes con sintaxis incrustada o construcciones ambiguas, acierta menos que Shiki. Su HTML, en cambio, es más compacto, porque una clase corta pesa mucho menos que un style en línea repetido en cada token. El intercambio es claro: Prism entrega marcado ligero a cambio de una hoja de estilos y algo de precisión; Shiki entrega precisión y cero CSS a cambio de un HTML más pesado.

Shiki o Prism: el intercambio dentro del servidor

Dentro de la rama “resaltar en el servidor”, la elección entre Shiki y Prism se resuelve mirando qué te duele más. Si el peso del HTML domina tu presupuesto —páginas con muchísimo código, donde los estilos en línea de Shiki inflan el documento, y más aún con temas duales que duplican las variables—, Prism con su marcado por clases puede salir a cuenta. Si en cambio te importa la fidelidad exacta con tu editor, la cobertura de lenguajes difíciles y no querer mantener una hoja de estilos de tema, Shiki es la elección natural, y por eso es el valor por defecto.

Un par de ejemplos aterriza la decisión. Un sitio de documentación técnica, cuya página media es medio texto y medio código, se beneficia de la precisión de Shiki: el lector espera que el color coincida con su editor, y la ausencia de una hoja de tema es una pieza menos que mantener. Un blog con algún bloque de código ocasional, en cambio, apenas notará la diferencia de precisión y sí agradecerá un HTML más liviano si el rendimiento está muy ajustado. La elección no es ideológica: depende de cuánto código lleva tu página y de cuánto pesa cada byte en tu contexto.

Conviene no exagerar el coste de Shiki. Su tokenización con Oniguruma en WebAssembly no es gratis y, en sitios con muchos bloques, se nota en el tiempo de build; pero es un coste que pagas una vez, en tu máquina, y que Astro amortigua con caché. El HTML más pesado importa solo cuando el código domina la página; para la mayoría de los sitios, la precisión y la ausencia de CSS de tema pesan más que unos kilobytes de estilos en línea.

Hay además una consideración de arranque. El motor WebAssembly de Shiki y la carga de sus gramáticas tienen un coste inicial que se amortiza a lo largo de la compilación: en proyectos pequeños es imperceptible, en enormes se nota al principio del build. Prism, más liviano, arranca antes. Pero de nuevo ese gasto es de tu máquina y de una sola vez por build, no del visitante, así que rara vez debe inclinar la decisión frente a la precisión o el peso del HTML, que sí se cobran en cada visita. La regla se mantiene: optimiza lo que paga el visitante, no lo que paga tu servidor de integración continua.

¿Cliente o servidor? Cuándo cada uno

Aquí está la pregunta que de verdad decide el rendimiento, y es independiente de si usas Shiki o Prism. Resaltar en el servidor —lo que hemos hecho durante todo el nivel— tiene sentido siempre que el código se conozca antes de la petición: contenido estático, ejemplos de documentación, fragmentos escritos a mano. El cálculo corre una vez, el resultado se reutiliza en cada visita, y el navegador no gasta nada.

Resaltar en el cliente solo tiene sentido cuando el código no se conoce hasta que el navegador está vivo: un editor de código en directo donde el usuario teclea, un fragmento generado por el propio usuario y mostrado al instante, contenido traído por una API y renderizado dentro de una isla interactiva, o funciones que exigen ejecución en el navegador. En esos casos no hay build ni servidor que pueda adelantarse, porque la entrada aún no existía; entonces, y solo entonces, envías un resaltador al cliente y pagas su coste.

Cuando ese caso llega, lo que envías importa tanto como la decisión de enviarlo. Un resaltador de cliente carga su motor y, con él, las gramáticas de los lenguajes que vayas a resaltar y el tema elegido. Shiki ofrece para esto una construcción de grano fino, donde importas solo el núcleo y las gramáticas concretas que uses en lugar del paquete entero, precisamente para que el coste inevitable sea el mínimo posible. La disciplina, en la rama del cliente, es esa: si no puedes evitar enviar un resaltador, envía el más pequeño que resuelva tu caso, y cárgalo de forma diferida para que no bloquee la primera pintura de la página.

En el modelo de Astro, ese resaltado de cliente vive dentro de una isla: un componente de framework marcado con una directiva client: que lo hidrata en el navegador. El resaltador se carga ahí, junto a la lógica del editor, y solo ahí; el resto de la página sigue siendo HTML estático sin JavaScript.

ASTRO
---import EditorEnVivo from '../components/EditorEnVivo.jsx';---<EditorEnVivo client:load />

Así, incluso cuando el resaltado baja al cliente, su coste queda acotado a la porción que de verdad lo necesita, en lugar de contaminar todo el documento. Un editor incrustado como CodeMirror o Monaco trae su propio resaltado pensado para texto que cambia con cada pulsación; y si quieres la fidelidad de Shiki en vivo, su construcción de grano fino permite montar el resaltador en esa misma isla. El patrón no cambia: el resaltado se vuelve parte de la lógica interactiva de una isla concreta, con su coste asumido a conciencia porque no existe alternativa.

Rendimiento: qué paga quién

El modelo de coste lo aclara todo. Resaltar en el servidor concentra el gasto en un único pago —CPU del build o del render— y entrega HTML que sirve a infinitos visitantes sin recalcular; el navegador solo pinta. Resaltar en el cliente reparte el gasto entre todos los visitantes: cada dispositivo descarga el motor y sus gramáticas, y ejecuta el resaltado en cada visita, con su coste en ancho de banda, en tiempo hasta ser interactivo y hasta en batería. La conclusión práctica se ordena sola: por defecto, resalta en el servidor; recurre al cliente únicamente cuando el código sea genuinamente dinámico en tiempo de ejecución, y aun entonces, minimiza lo que envías.

Merece la pena poner cifras al intercambio. El HTML de Shiki es más pesado que el de Prism —estilos en línea por token frente a clases cortas—, pero ambos se miden en kilobytes de texto que se comprimen bien y se sirven una vez. Un resaltador de cliente, en cambio, se mide en decenas o cientos de kilobytes de JavaScript que hay que descargar, analizar y ejecutar en cada dispositivo. La asimetría es de órdenes de magnitud, y siempre a favor del servidor: incluso el HTML más inflado de Shiki resulta más barato para el visitante que el resaltador de cliente más ajustado. Esa es, en el fondo, la razón por la que Astro elige resaltar en el servidor por defecto y por la que tú deberías desviarte de esa opción solo con una razón de peso.