Hablamos mucho de plugins de caché, CDN, imágenes en WebP. Rara vez hablamos de la decisión, previa a todas ellas, que determina el resto: el tema. Antes de una sola línea de contenido, tu tema fija lo que un navegador tendrá que descargar, analizar, compilar y ejecutar para pintar la página. Y entre todas sus decisiones técnicas, una pesa más que las demás sobre la velocidad: la forma en que entrega su JavaScript.
Hay dos familias. Los temas que dividen su código en piezas pequeñas cargadas a demanda, y los temas que amontonan todo en un solo bloque, el famoso main.js, theme.js o bundle.min.js que gobierna el menú, el slider, el lightbox, las pestañas, los formularios, las animaciones de scroll y las llamadas AJAX. Esta segunda familia te encierra en un techo de rendimiento bajo. Aquí tienes el porqué, y cómo detectarlo antes de comprometerte.
Optimizar finamente es poder dividir
Una buena optimización de front-end nunca es un único interruptor. Es un trabajo quirúrgico: conservar lo que se ve de inmediato, posponer el resto, eliminar lo que no se usa en absoluto. En concreto, en una página bien optimizada queremos poder:
- Cargar lo estrictamente mínimo para que la parte superior de la página (el ATF, above the fold) se pinte y sea interactiva lo antes posible.
- Retrasar todo lo que no se necesita de inmediato (un carrusel de pie de página, un chat, un widget para compartir) hasta la primera interacción o el primer scroll.
- No cargar en absoluto lo que no aparece en la página actual (el script de la galería en una página que no tiene galería).
Estas tres palancas comparten un requisito previo: el código debe ser divisible. Solo puedes retrasar una pieza si existe como pieza. Solo puedes descartar un script condicional si se encoló de forma condicional. Toda la finura reside ahí. Un tema monolítico elimina el requisito previo. Ya no hay piezas, hay un bloque.
Anatomía de un monolito
Abre la pestaña Network de un sitio, filtra por JS, y mira el peso del archivo más grande que entrega el tema. En un tema monolítico verás un único archivo que concentra lo esencial:
acme-theme/assets/js/main.min.js 287 KB <- everything
jquery.min.js 89 KB
jquery-migrate.min.js 13 KBEse archivo no hace una sola cosa. Hace veinte. Y sobre todo, están conectadas entre sí en el mismo scope, la misma clausura, la misma cadena de dependencias de jQuery. El menú desplegable comparte su init con el slider del hero, que comparte el suyo con el módulo de testimonios, que depende de un plugin de scroll, que depende de jQuery, que depende de jQuery Migrate. Quita un ladrillo y los demás se caen.
Aquí es donde la estrategia de optimización choca contra el muro. Retomemos nuestras tres palancas. Retrasarlo todo: puedes posponer el bloque entero hasta la primera interacción, pero entonces la primera interacción (un simple clic en el menú hamburguesa) paga, de golpe, la descarga, el análisis, la compilación y la ejecución de los 287 KB completos. El usuario hace clic, y nada responde mientras el hilo principal digiere un carrusel que no le sirve de nada. Moviste el problema, no lo resolviste. No retrasar nada: el bloque se ejecuta en la carga, infla el TBT (Total Blocking Time), retrasa la interactividad, y si toca el DOM por encima del pliegue, degrada el LCP. Dividir con finura: imposible, no hay nada que dividir. Es todo o nada.
El coste real es el análisis, no la descarga
Un malentendido tenaz: "300 KB de JS comprimido, no pasa nada, no es nada de descargar." La descarga no es el problema principal. El JavaScript tiene un coste que las imágenes no tienen: hay que analizarlo, compilarlo y ejecutarlo en el hilo principal, justo el que debe responder a las interacciones del usuario.
Un byte de imagen se decodifica en un hilo secundario. Un byte de JS potencialmente bloquea la interactividad. En un móvil de gama media, analizar y ejecutar 300 KB de JS de aplicación se mide en cientos de milisegundos, no en peso de red. Y un monolito te hace pagar ese coste íntegro, por código que, el 80 % del tiempo, no tiene nada que ver con la página en pantalla.
"Pero un solo archivo es mejor para HTTP/2, ¿no?"
Una objeción legítima, y merece una respuesta honesta en lugar de un desprecio. Sí, históricamente, reducir el número de peticiones era buena práctica, y sí, concatenar tenía sentido sobre HTTP/1.1. Pero dos cosas cambiaron. Primero, HTTP/2 y HTTP/3 multiplexan: varios archivos pequeños en paralelo ya no cuestan el precio de las peticiones secuenciales de antaño. El argumento de "menos peticiones" ha perdido gran parte de su fuerza.
Después, y este es el punto decisivo, el coste real del JS no es la petición, es la ejecución. Diez scripts pequeños de los que solo ejecutas dos cuestan mucho menos que uno solo grande que ejecutas por entero. La granularidad no está para hacer más peticiones, está para ejecutar menos código. Ese es un beneficio distinto, y sobrevive perfectamente a HTTP/2.
Tres casos concretos
Caso A: el carrusel fantasma
Un tema todo en uno carga su bundle completo en cada página, carrusel incluido. Pero el carrusel solo existe en la página de inicio.
En las 40 páginas de artículos del blog, ese código se descarga, se analiza, se compila, y nunca se usa. La pestaña Coverage de Chrome lo confirma: del 60 al 80 % del archivo está marcado como "unused".
Un tema modular simplemente no habría encolado ese script fuera de la página de inicio.
Caso B: el menú tomado como rehén
Un sitio quiere retrasar su JavaScript no crítico. Problema: el menú hamburguesa móvil y el lightbox de la galería viven en el mismo archivo.
Retrasa el archivo y rompes el menú, el elemento más crítico del above-the-fold en móvil. No lo retrases y el lightbox, inútil en la carga, se queda en la ruta crítica.
El acoplamiento prohíbe la única decisión que tendría sentido: menú ahora, lightbox después.
En un tema así, el síntoma clásico es un menú hamburguesa que solo se abre al segundo toque. El método general para encontrar qué script ha roto un retraso está en nuestra guía sobre el retraso de JavaScript.
Caso C: el contraejemplo que funciona
Un tema bien construido encola un pequeño script de navegación (unos pocos KB, sin dependencia de jQuery) para el menú, y carga el script de la galería solo en las páginas que contienen una galería, con un defer.
El menú es instantáneo. La galería se carga por separado, se retrasa sin romper nada, y desaparece por completo de las páginas que no la tienen.
Aquí la plataforma de optimización tiene con qué trabajar: puede operar con grano fino porque el tema le dejó asideros.
// Menú: mínimo, sin jQuery, siempre necesario
wp_enqueue_script( 'acme-nav', $uri.'/nav.js', array(), null, true );
// Galería: solo donde de verdad hay una galería, diferida
if ( has_block( 'core/gallery' ) ) {
wp_enqueue_script( 'acme-gallery', $uri.'/gallery.js', array(), null, true );
}Cómo detectar un monolito antes de comprometerte
Puedes auditar un tema en unos minutos, sobre su demo, sin siquiera instalarlo.
- Pestaña Network, filtro JS. Mira el archivo más grande que entrega el tema. Un único archivo que pesa 150 KB o más, presente en todas las páginas, es una señal de alarma. Varios archivos de tamaño modesto es una buena señal.
- Pestaña Coverage (en DevTools, "Coverage"). Recarga la página y lee el porcentaje "Unused". Si el script grande muestra un 60 % o más de código sin usar en una página interior, el tema carga demasiado, en todas partes, sin condiciones.
- La prueba de la página desnuda. Compara el JS cargado en la página de inicio y en una página de contacto minimalista. Si es exactamente el mismo bundle, el tema no carga nada de forma condicional. Lo vuelca todo, todo el tiempo.
- La dependencia de jQuery. Un tema que apila jQuery, jQuery Migrate y un montón de plugins de jQuery en una sola cadena es casi siempre monolítico de espíritu, incluso cuando divide sus archivos. Esas dependencias se dan la mano y se niegan a ser divididas.
- Leer el código, si es accesible. Mira cómo se registran los scripts. Un único
wp_enqueue_scriptglobal sin ninguna condición de página o componente lo dice todo. Un tema serio encola sus scripts cerca de los componentes que los usan, y bajo condiciones.
Qué hace bueno a un tema, en cuanto a JS
- Assets granulares: varios scripts específicos en lugar de un solo bloque.
- Carga condicional: un script está presente solo en las páginas que usan su componente.
- Baja dependencia de jQuery, idealmente JavaScript nativo para los ladrillos críticos como el menú.
- Aplazable por naturaleza: el código puede posponerse sin romper el above-the-fold, porque el above-the-fold no depende de él.
- Nada inútil ejecutado en la carga para la parte superior de la página.
- Hooks limpios, que permiten a una plataforma de optimización eliminar, retrasar o reemplazar una pieza sin efectos secundarios.
Ninguno de estos puntos trata del "peso" del tema en el sentido de marketing. Todos tratan de la divisibilidad. Esa es la métrica real.
En resumen
Optimizar un sitio es tomar decisiones finas, página por página, componente por componente: este ahora, aquel después, este tercero nunca. Esas decisiones dan por hecho que el tema entregó su código en piezas que puedes manejar por separado. Un tema monolítico no entrega piezas, entrega un único bloque soldado, y te condena al todo o nada.
Una plataforma de optimización puede hacer mucho incluso en ese caso: servir una caché, aplazar en bloque lo que se puede aplazar, aligerar imágenes, estabilizar el layout. Pero no puede deshacer un acoplamiento escrito en el código del tema. El techo se fijó aguas arriba, en el momento en que se eligió el tema.
Mantys Core hace su trabajo más afilado en temas granulares, y aun así ayuda en los monolíticos:
En un tema divisible, mantiene el above-the-fold al mínimo y retrasa el resto hasta la interacción o el scroll, página por página.
Elimina el CSS y el JS que la página actual nunca usa, y aplaza lo que se puede aplazar.
En un monolito, sigue cacheando, estabilizando el layout y aplazando en bloque, pero el tema fija el techo.
Elegir un tema divisible es elegir un techo más alto. Todo lo que viene después se compone a partir de ahí.
Comentarios
¿Atascado con un problema parecido? Describa su configuración y lo que observa. Leemos cada comentario y respondemos.
Todavía no hay comentarios. Comparta el primero su caso.