Una mirada práctica al enfoque de compilador para el rendimiento web, contrastando frameworks con mucho runtime y salida en tiempo de compilación, más un marco sencillo para decidir.

Los usuarios raramente describen el rendimiento en términos técnicos. Dicen que la app se siente pesada. Las páginas tardan un instante de más en mostrar algo, los botones responden tarde y acciones simples como abrir un menú, escribir en un buscador o cambiar pestañas se traban.
Los síntomas son familiares: una primera carga lenta (UI en blanco o a medio construir), interacciones con lag (clics que se registran después de una pausa, scroll entrecortado) y spinners largos tras acciones que deberían sentirse instantáneas, como guardar un formulario o filtrar una lista.
Gran parte de esto es coste en tiempo de ejecución. En términos sencillos, es el trabajo que el navegador debe hacer después de que la página carga para que la app sea usable: descargar más JavaScript, parsearlo, ejecutarlo, construir la UI, adjuntar manejadores y luego seguir haciendo trabajo extra en cada actualización. Incluso en dispositivos rápidos hay un límite de cuánto JavaScript se puede hacer pasar por el navegador antes de que la experiencia empiece a notarse lenta.
Los problemas de rendimiento también aparecen tarde. Al principio la app es pequeña: pocas pantallas, datos ligeros, UI simple. Luego el producto crece. Marketing añade trackers, diseño añade componentes más ricos, los equipos añaden estado, características, dependencias y personalización. Cada cambio parece inocuo por separado, pero el trabajo total se acumula.
Por eso los equipos empiezan a prestar atención a ideas de rendimiento centradas en compilación. El objetivo normalmente no es obtener puntuaciones perfectas. Es seguir enviando sin que la app se vuelva más lenta cada mes.
La mayoría de frameworks frontend te ayudan a hacer dos cosas: construir una app y mantener la UI sincronizada con los datos. La diferencia clave es cuándo ocurre la segunda parte.
Con un framework pesado en tiempo de ejecución, más trabajo ocurre en el navegador tras la carga. Envíes un runtime de propósito general que puede manejar muchos casos: rastrear cambios, decidir qué debe actualizarse y aplicar esas actualizaciones. Esa flexibilidad puede ser estupenda para el desarrollo, pero a menudo significa más JavaScript que descargar, parsear y ejecutar antes de que la UI esté lista.
Con optimización en tiempo de compilación, más de ese trabajo se traslada al paso de build. En vez de enviar al navegador un gran conjunto de reglas, la herramienta de build analiza tus componentes y genera código más directo y específico para la app.
Un modelo mental útil:
La mayoría de productos reales están en algún punto intermedio. Los enfoques centrados en compilador siguen enviando algo de código runtime (routing, fetch de datos, animaciones, manejo de errores). Los frameworks con mucho runtime también usan técnicas en build (minificación, code-splitting, server rendering) para reducir el trabajo en el cliente. La pregunta práctica no es qué bando es “correcto”, sino qué mezcla encaja con tu producto.
Rich Harris es una de las voces más claras detrás del pensamiento frontend centrado en compilador. Su argumento es directo: haz más trabajo por adelantado para que los usuarios descarguen menos código y el navegador haga menos trabajo.
La motivación es práctica. Muchos frameworks con mucho runtime envían un motor de propósito general: lógica de componentes, reactividad, diffing, scheduling y helpers que deben funcionar para cualquier app. Esa flexibilidad cuesta bytes y CPU. Incluso cuando tu UI es pequeña puedes pagar por un runtime grande.
Un enfoque de compilador invierte el modelo. En tiempo de build, el compilador mira tus componentes reales y genera el código específico de actualización del DOM que necesitan. Si una etiqueta nunca cambia, se convierte en HTML simple. Si solo cambia un valor, solo se emite la ruta de actualización para ese valor. En lugar de enviar una máquina de UI genérica, envías la salida adaptada a tu producto.
Eso suele dar un resultado sencillo: menos código del framework enviado a los usuarios y menos trabajo en cada interacción. También tiende a notarse más en dispositivos de gama baja, donde la sobrecarga de runtime se hace visible rápidamente.
Aún importan los tradeoffs:
Una regla práctica: si tu UI es mayormente predecible en tiempo de build, un compilador puede generar un resultado muy ajustado. Si tu UI es muy dinámica o basada en plugins, un runtime más pesado puede ser más cómodo.
La optimización en build cambia dónde ocurre el trabajo. Más decisiones se toman durante la compilación y menos trabajo queda para el navegador.
Un resultado visible es menos JavaScript enviado. Bundles más pequeños reducen tiempo de red, tiempo de parseo y el retraso antes de que la página responda a un toque o clic. En teléfonos de gama media eso importa más de lo que muchos equipos esperan.
Los compiladores también pueden generar actualizaciones del DOM más directas. Cuando el build puede ver la estructura de un componente, puede producir código de actualización que toque solo los nodos DOM que realmente cambian, sin tantas capas de abstracción en cada interacción. Esto puede hacer que las actualizaciones frecuentes se sientan más ágiles, especialmente en listas, tablas y formularios.
El análisis en build también puede reforzar tree-shaking y eliminación de código muerto. La ganancia no es solo archivos más pequeños: son menos rutas de código que el navegador tiene que cargar y ejecutar.
La hidratación es otra área donde las decisiones de build pueden ayudar. La hidratación es el paso donde una página renderizada en servidor se vuelve interactiva al adjuntar manejadores y reconstruir suficiente estado en el navegador. Si el build puede marcar qué necesita interactividad y qué no, puedes reducir el trabajo de la primera carga.
Como efecto colateral, la compilación suele mejorar el scope del CSS. El build puede reescribir nombres de clase, eliminar estilos no usados y reducir fugas entre componentes. Eso baja costes sorpresa conforme la UI crece.
Imagínate un dashboard con filtros y una gran tabla de datos. Un enfoque centrado en compilador puede mantener la carga inicial ligera, actualizar solo las celdas que cambiaron tras un clic de filtro y evitar hidratar partes de la página que nunca se vuelven interactivas.
Un runtime más grande no es automáticamente malo. A menudo compra flexibilidad: patrones decididos en tiempo de ejecución, muchos componentes de terceros y flujos de trabajo probados durante años.
Los frameworks pesados brillan cuando las reglas de la UI cambian con frecuencia. Si necesitas routing complejo, layouts anidados, formularios ricos y un modelo de estado profundo, un runtime maduro puede sentirse como una red de seguridad.
Un runtime ayuda cuando quieres que el framework maneje mucho mientras la app corre, no solo mientras se construye. Eso puede hacer a los equipos más rápidos día a día, aunque añada overhead.
Victorias comunes incluyen un gran ecosistema, patrones familiares para estado y fetch de datos, herramientas de desarrollo sólidas, extensión tipo plugin más fácil y onboarding suave si contratas personas que ya conocen el stack.
La familiaridad del equipo es un coste y un beneficio real. Un framework algo más lento que tu equipo pueda usar con confianza puede superar a un enfoque más rápido que requiere reentrenamiento, disciplina estricta o tooling custom para evitar errores.
Muchas quejas de “app lenta” no se deben al runtime del framework. Si tu página espera una API lenta, imágenes pesadas, demasiadas fuentes o scripts de terceros, cambiar de framework no arreglará el problema central.
Un dashboard interno detrás de un login suele sentirse bien incluso con un runtime mayor, porque los usuarios tienen dispositivos potentes y el trabajo lo dominan tablas, permisos y consultas al backend.
“Lo suficientemente rápido” puede ser el objetivo correcto al principio. Si aún estás validando valor de producto, mantén alta la velocidad de iteración, define presupuestos básicos y solo adopta la complejidad de compilador cuando tengas evidencia de que importa.
La velocidad de iteración es tiempo hasta obtener feedback: qué tan rápido alguien puede cambiar una pantalla, ejecutarla, ver qué falló y arreglarlo. Los equipos que mantienen ese bucle corto envían más a menudo y aprenden más rápido. Por eso los frameworks con mucho runtime pueden sentirse productivos al inicio: patrones familiares, resultados rápidos y mucho comportamiento incorporado.
El trabajo de rendimiento ralentiza ese bucle cuando se hace demasiado pronto o de forma demasiado amplia. Si cada PR se convierte en debates de microoptimización, el equipo deja de tomar riesgos. Si construyes una pipeline compleja antes de saber qué es el producto, la gente pasa tiempo peleando con herramientas en lugar de hablar con usuarios.
El truco es ponerse de acuerdo en qué significa “suficientemente bueno” e iterar dentro de ese marco. Un presupuesto de rendimiento te da esa caja. No se trata de perseguir puntuaciones perfectas, sino de límites que protejan la experiencia sin frenar el desarrollo.
Un presupuesto práctico puede incluir:
Si ignoras el rendimiento, normalmente pagas después. Cuando un producto crece, la lentitud queda atada a decisiones de arquitectura, no solo a pequeños ajustes. Un rewrite tardío puede significar congelar features, reentrenar al equipo y romper flujos que antes funcionaban.
El tooling centrado en compilador puede cambiar este tradeoff. Puede que aceptes builds algo más largos, pero reduces el trabajo que hay que hacer en cada dispositivo, en cada visita.
Revisa los presupuestos conforme el producto se consolida. Al principio protege lo básico. Conforme tráfico e ingresos crezcan, aprieta los presupuestos e invierte donde las mejoras muevan métricas reales, no el ego.
Las discusiones sobre rendimiento se enredan cuando nadie acuerda qué significa “rápido”. Escoge un conjunto pequeño de métricas, escríbelas y trátalas como un marcador compartido.
Un set inicial simple:
Mide en dispositivos representativos, no solo en el portátil de desarrollo. Una CPU rápida, caché caliente y servidor local pueden ocultar retrasos que aparecen en un teléfono de gama media sobre datos móviles.
Mantenlo arraigado: elige dos o tres dispositivos que coincidan con usuarios reales y ejecuta el mismo flujo cada vez (pantalla principal, login, una tarea común). Hazlo de forma consistente.
Antes de cambiar de framework, captura una línea base. Toma el build actual, registra los números para los mismos flujos y mantenlos visibles. Esa línea base es tu foto “antes”.
No juzgues el rendimiento por una sola puntuación de laboratorio. Las herramientas de lab ayudan, pero pueden premiar lo equivocado (gran primera carga) y pasar por alto lo que los usuarios reclaman (menús entrecortados, escritura lenta, demoras tras la primera pantalla).
Cuando los números empeoran, no adivines. Revisa qué se envió, qué bloqueó el render y dónde se fue el tiempo: red, JavaScript o API.
Para tomar una decisión sosegada y repetible, trata las decisiones de framework y renderizado como decisiones de producto. El objetivo no es la mejor tecnología, sino el equilibrio correcto entre rendimiento y el ritmo que tu equipo necesita.
Un thin slice debe incluir las partes complicadas: datos reales, auth y tu pantalla más lenta.
Si quieres prototipar ese thin slice rápido, Koder.ai (koder.ai) te permite construir flujos web, backend y móvil por chat y luego exportar el código fuente. Eso puede ayudarte a probar una ruta real temprano y mantener los experimentos reversibles con snapshots y rollback.
Documenta la decisión en lenguaje llano, incluyendo qué te haría revisarla (crecimiento de tráfico, share móvil, objetivos SEO). Eso hace que la elección sea durable cuando el equipo cambie.
Las decisiones de rendimiento suelen fallar cuando los equipos optimizan lo que ven hoy, no lo que los usuarios sentirán en tres meses.
Un error es sobre-optimizar en la primera semana. Un equipo pasa días recortando milisegundos en una página que cambia a diario, mientras el problema real es que los usuarios aún no tienen las features correctas. Al inicio, acelera el aprendizaje primero. Bloquea el trabajo profundo de rendimiento cuando las rutas y componentes se estabilicen.
Otro es ignorar el crecimiento del bundle hasta que duela. Las cosas van bien en 200 KB, luego unas pocas adiciones “pequeñas” y estás enviando megabytes. Un hábito simple ayuda: sigue el tamaño del bundle con el tiempo y trata saltos repentinos como bugs.
Los equipos también tienden a renderizar todo del lado cliente por defecto, incluso cuando algunas rutas son mayormente estáticas (páginas de precios, docs, onboarding). Esas páginas a menudo se pueden servir con mucho menos trabajo en el dispositivo.
Un asesino más silencioso es añadir una gran biblioteca UI por conveniencia sin medir su coste en builds de producción. La conveniencia es válida. Solo sé claro sobre lo que pagas en JS extra, CSS extra y peores interacciones en teléfonos de gama media.
Por último, mezclar enfoques sin límites claros crea apps difíciles de depurar. Si la mitad de la app asume actualizaciones generadas por compilador y la otra mitad depende de magia en runtime, acabas con reglas poco claras y fallos confusos.
Algunas guardas que funcionan en equipos reales:
La mayoría de las veces no es solo la red: es el coste en tiempo de ejecución: el navegador descargando, analizando y ejecutando JavaScript, construyendo la UI y haciendo trabajo adicional en cada actualización.
Por eso una app puede sentirse “pesada” incluso en un portátil potente cuando la carga de JavaScript crece.
Buscan el mismo objetivo (hacer menos en el cliente), pero difieren en el mecanismo.
Significa que el framework puede analizar tus componentes en tiempo de compilación y generar código adaptado a tu app, en lugar de enviar una gran máquina de UI genérica.
El beneficio práctico suele ser bundles más pequeños y menos trabajo de CPU durante las interacciones (clics, mecanografía, desplazamiento).
Empieza por:
Mide en los mismos flujos y dispositivos representativos para comparar builds de forma fiable.
Sí, puede ayudar. Pero primero confirma dónde se va el tiempo: red, CPU de JavaScript, renderizado o backend.
Si tu problema son APIs lentas, imágenes pesadas, muchas fuentes o scripts de terceros, cambiar de framework no arreglará esos cuellos de botella. El framework es una palanca más, no la única.
Elige runtime-heavy cuando necesites flexibilidad e velocidad de iteración:
Si el runtime no es tu cuello de botella, la conveniencia puede valer los bytes extra.
Una regla simple:
Lo habitual es un híbrido: documenta límites claros para evitar mezclar supuestos y causar errores difíciles de depurar.
Usa un presupuesto que proteja la sensación del usuario sin bloquear el envío. Por ejemplo:
Los presupuestos son guardarraíles, no una competición por la puntuación perfecta.
La hidratación es el trabajo de convertir una página renderizada en servidor en algo interactivo: adjuntar manejadores de eventos y reconstruir el estado necesario en el navegador.
Si hidratas demasiado, la primera carga puede sentirse lenta aunque el HTML se muestre rápido. Las herramientas de build pueden reducir la hidratación marcando qué necesita realmente interactividad.
Un buen “thin slice” incluye las partes reales y problemáticas:
Si prototipas ese slice, Koder.ai puede ayudarte a construir el flujo web + backend vía chat y exportar el código para medir y comparar sin hacer un rewrite completo.