Parte: 12 — Juegos web y HTML5 · Fuente: web.dev — Fast load times y MDN Web Docs — HTTP compression ⏱️ Duración estimada: 60 min · Nivel: Intermedio
En la web, la primera batalla no es el gameplay: es lograr que el juego cargue rápido. Un usuario abandona en segundos si ve una pantalla en blanco descargando 40 MB. La optimización web ataca dos frentes: reducir el peso (bundle de código, texturas, audio) y mejorar la estrategia de carga (diferir lo no esencial, comprimir en tránsito, cachear). El objetivo es minimizar el time-to-play: el tiempo desde que se abre la URL hasta que se puede jugar.
En esta clase medimos el peso y el tiempo de carga de un build web, aplicamos técnicas concretas —compresión gzip/brotli, carga diferida, atlas de texturas— y comparamos el antes y el después con números reales tomados de las herramientas del navegador. Aprenderás a razonar sobre cada kilobyte que envías al jugador.
Al finalizar, el alumno podrá:
| # | Tema | Por qué importa |
|---|---|---|
| 1 | Time-to-play | La métrica que decide si el jugador se queda. |
| 2 | Peso del bundle | Menos JS/WASM = arranque más rápido. |
| 3 | Peso de los assets | Imágenes y audio suelen dominar el total. |
| 4 | Atlas de texturas | Menos peticiones y mejor compresión. |
| 5 | Compresión gzip/brotli | Reduce bytes en tránsito sin tocar el asset. |
| 6 | Carga diferida | Cargar solo lo necesario para empezar. |
| 7 | Streaming de assets | Traer niveles/sonidos bajo demanda. |
| 8 | Caché | Evitar volver a descargar lo ya bajado. |
Cache-Control y nombres con hash evitan re-descargas.Usaremos las DevTools del navegador (pestaña Network y Lighthouse) para medir, y un servidor local que soporte compresión. Puedes servir con http-server (Node) activando gzip/brotli, o usar herramientas como vite build que ya minifican. Para atlas de texturas hay empaquetadores como TexturePacker o free-tex-packer (web).
Instala un servidor con compresión para las pruebas:
npm install -g http-server
Referencias: guía de rendimiento en https://web.dev/explore/fast y compresión HTTP en https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Compression.
Mediremos un build, lo optimizaremos y compararemos.
Sirve tu build web actual y mide la línea base. Abre DevTools → Network, marca "Disable cache", recarga y anota: número de peticiones, peso total transferido (Transferred) y tiempo de Load.
Corre Lighthouse (DevTools → Lighthouse → Analyze) en modo Performance y guarda la puntuación y el "Total Blocking Time" como referencia.
Comprime imágenes. Convierte los PNG grandes a formatos modernos y ajusta calidad. Con sharp (Node) por ejemplo:
npx sharp-cli -i "assets/*.png" -o assets-web --format webp --quality 80
Crea un atlas. Agrupa los sprites sueltos en una sola textura y su JSON de coordenadas. Esto reduce peticiones y aprovecha mejor la compresión. Carga el atlas y recorta cada sprite por sus coordenadas en vez de pedir 30 archivos.
Activa compresión en el servidor. http-server sirve .gz automáticamente si existen; genera las versiones comprimidas:
# Genera .gz y .br junto a cada asset de texto/código
find dist -type f \( -name "*.js" -o -name "*.json" -o -name "*.wasm" \) \
-exec gzip -k9 {} \; -exec brotli -k {} \;
http-server dist -g -b # -g gzip, -b brotli
import() dinámico:// Se descarga solo cuando el jugador entra al nivel 2
async function cargarNivel2() {
const { crearNivel2 } = await import("./niveles/nivel2.js");
return crearNivel2();
}
Configura caché. Sirve los assets con hash en el nombre (juego.a1b2c3.js) y cabeceras de caché largas, de modo que el navegador no vuelva a descargarlos entre visitas.
Vuelve a medir con Network y Lighthouse tras estos cambios. Registra los mismos números que en los pasos 1-2 y calcula la mejora: cuántos KB y cuántos milisegundos ahorraste. Documenta el antes/después en una pequeña tabla.
bundle.js sin comprimir, con gzip y con brotli.import() un módulo pesado y verifica en Network que solo se descarga al usarlo.Cache-Control: max-age=31536000 a los assets con hash y explica por qué es seguro.Toma un build web (propio o de ejemplo) y redúcele el peso transferido al menos un 30% aplicando al menos tres técnicas (compresión de imágenes, atlas, gzip/brotli, carga diferida o caché), documentando en una tabla el antes/después de: peso total transferido, número de peticiones y tiempo de carga.
Criterio de aceptación: la tabla muestra métricas reales tomadas de DevTools antes y después; la reducción de peso transferido es ≥ 30%; se nombran y justifican las técnicas aplicadas; el juego sigue funcionando igual tras optimizar (nada roto por diferir o comprimir).
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
| El peso no baja pese a comprimir | El servidor no envía Content-Encoding. Verifica que sirve .gz/.br y las cabeceras. |
| Sprites cortados o desplazados tras el atlas | Coordenadas mal leídas del JSON. Revisa origen y tamaño de cada frame. |
| El juego rompe al diferir un módulo | Se usó antes de que import() resolviera. Espera la promesa antes de invocarlo. |
| Assets viejos tras un deploy | Caché agresiva sin hash en el nombre. Usa nombres con hash para invalidar. |
| Lighthouse da resultados distintos cada vez | Ruido de red/CPU. Mide varias veces y en modo incógnito sin extensiones. |
❓ ¿gzip o brotli? Brotli suele comprimir mejor texto y código (JS, JSON, WASM) que gzip, a costa de algo más de CPU al comprimir. Genera ambas versiones y deja que el navegador elija según Accept-Encoding.
❓ ¿El atlas siempre conviene? Casi siempre para sprites 2D: reduce peticiones y cambios de textura en GPU. Ojo con atlas gigantescos que superen el tamaño máximo de textura del dispositivo; divídelos si hace falta.
❓ ¿Qué diferencia hay entre carga diferida y streaming? La carga diferida pospone recursos completos hasta que se necesitan; el streaming trae un mismo recurso por partes (por ejemplo, texturas progresivas o audio por chunks). Ambas mejoran el TTP.
❓ ¿Comprimir imágenes con pérdida no baja la calidad? Sí, un poco, pero a calidad 75-85 suele ser imperceptible en juego y ahorra mucho. Compara visualmente y ajusta; para arte con bordes nítidos considera formatos sin pérdida o WebP lossless.
Clase 223 - Networking web: WebSockets y WebRTC