Reglas de Presupuesto de Rendimiento
Límites de tamaño de bundle, tiempo-a-interactivo (TTI) y velocidad de fotogramas con propietarios designados para aplicaciones Expo SDK 57 en React Native 0.86. Los presupuestos de rendimiento convierten el subjetivo "se siente lento" en compuertas de fusión y lanzamiento. Asigna propietarios - los presupuestos anónimos se ignoran.
- Establece presupuestos de Nivel 1 durante el inicio del proyecto - ajustar límites después de 200 pantallas es políticamente más difícil que técnicamente.
- Nivel 2 se ejecuta en CI en cada PR que toque dependencias, listas o ruta de inicio.
- Nivel 3 es auditoría manual en dispositivo antes del envío a la tienda y promociones OTA principales.
- Cuando se supera un presupuesto, requiere una excepción ADR o una corrección - las exenciones expiran en el próximo lanzamiento.
- Dispositivo de medición predeterminado: Android de rango medio (por ejemplo, clase Pixel 6a) más un iPhone SE más antiguo - no el Pro Max del líder.
| Métrica | Umbral (inicio) | Rol del propietario |
|---|
| Bundle JS principal (Hermes) | ≤ 4 MB comprimido | Líder de plataforma móvil |
| Descarga total (actualización OTA) | ≤ 8 MB | Ingeniero de versión |
| TTI inicio en frío (pestaña principal) | ≤ 2.5 s en Android de referencia | Líder de equipo de características |
| FPS de desplazamiento (lista principal) | ≥ 55 fps sostenido | Especialista en rendimiento de UI |
| Memoria después de sesión de 10 min | ≤ 350 MB en Android de referencia | Oncall móvil |
Ajusta los números por categoría de aplicación - documenta tus umbrales en docs/performance-budgets.md y vincula desde README.
-
Publica presupuestos escritos antes de congelación de características: MB de bundle, segundos de TTI, pisos de FPS, y techos de memoria - la tabla de inicio anterior es una plantilla, no una ley universal.
- Propietario: Cada métrica tiene una persona designada, no "el equipo".
- Revisión: Trimestral o cuando MAU se duplica.
-
Elige dispositivos de referencia y versiones de SO: Un Android de rango medio y un dispositivo iOS más antiguo - todas las auditorías usan el mismo grupo de hardware.
- CI no puede reemplazar: Laboratorio de dispositivos o rotación de ingeniero para auditoría previa al lanzamiento.
- Rechaza: "Funciona en mi iPhone 16 Pro" como aprobación.
-
Define la medición de TTI: Inicio en frío - primer frame interactivo en la pestaña de ingresos principal (por ejemplo, botón de envío de feed de inicio habilitado).
- Instrumento:
performance.mark en layout raíz y onLayout de pantalla, o React Native Performance API.
- Excluye: Tiempos de dev client y Fast Refresh de presupuestos de producción.
-
Define el alcance del bundle: Bundle Hermes principal + chunks cargados perezosamente antes de TTI - documenta qué divisiones asincrónicas cuentan hacia presupuesto de primer abierto.
- Herramienta:
npx react-native bundle con --verbose o análisis de exportación de Expo.
- OTA: Límite de tamaño de actualización de producción separado del tamaño de instalación.
-
Vincula regresiones a política de reversión: Regresión de bundle o TTI más allá de X% activa consideración de reversión de Reglas de Lanzamiento y OTA.
- X: A menudo 10% relativo o sobrecorrida absoluta fija.
- Comunica: Oncall sabe que los disparadores de rendimiento están junto a disparadores de falla.
-
ADR para excepciones de presupuesto permanentes: Aplicaciones pesadas con mapas sin conexión o video pueden necesitar techos más altos - documenta valor para el usuario y mitigación (carga perezosa, descarga bajo demanda).
-
Verificación de tamaño de bundle Hermes en CI: El script compara el bundle exportado con el umbral - no pasar PR cuando esté por encima del presupuesto sin aprobación de etiqueta perf-budget.
- Propietario: La plataforma móvil mantiene el script en
scripts/check-bundle-size.sh.
- Baseline: Actualiza baseline solo con ADR, no con bumps silenciosos de PR.
-
Revisión de tamaño de dependencia en nativos y adiciones JS: npx expo install nuevo paquete - verifica el costo de importación y el impacto del tamaño de binary nativo.
- Rechaza: Bibliotecas de fecha duplicadas, moment.js, lodash completo.
- Prefiere: Importaciones por función de
date-fns, subconjuntos de lodash-es.
-
Ningún nuevo require sincrónico en ruta de inicio: Difiere módulos pesados con import() en pestañas no críticas - grep require( en app/_layout.tsx y proveedores raíz.
- Olor: Importar biblioteca de gráficos completa en layout raíz.
- Corrección: Importación perezosa a nivel de pantalla con esqueleto.
-
Presupuestos de imagen y fuente: WebP/AVIF donde sea compatible; subconjunto de fuentes vía expo-font - máximo dos familias de fuentes en ruta crítica.
- Propietario: El líder del sistema de diseño aprueba nuevos pesos.
- Rechaza: PNG de fondo de 800 KB cuando existe WebP comprimido.
-
Lint de rendimiento de lista en revisión: FlatList / FlashList requiere keyExtractor, componente renderItem estable, y filas memoizadas - sin hooks dentro de renderItem.
- Ver: Reglas de lint de React Hooks para violaciones de hook en
renderItem.
- Mide: Flashlight o monitor de rendimiento de RN en pantalla de lista más larga.
-
Worklets de Reanimated y gesto se quedan fuera del hilo JS: Las animaciones que pierden fotogramas activan investigación antes de fusión - perfila con react-native-performance.
- Presupuesto: Animaciones de interacción ≤ 300 ms a estado asentado.
- Rechaza:
LayoutAnimation en listas con 500+ filas.
-
TTI inicio en frío en Android de referencia cada RC: Registra mediana de 5 inicios en frío - compara con RC anterior y presupuesto.
- Propietario: El ingeniero de versión registra en el ticket de lanzamiento.
- Bloquea: Promoción RC si TTI regresa > 15% sin exención.
-
FPS de desplazamiento en pantalla de lista principal: Prueba de volteo a través de 50 elementos - piso de fps sostenido (55+) en dispositivo de referencia.
- Herramienta: Superposición de monitor de rendimiento o muestra de Systrace.
- Corrección:
FlashList, componentes de fila más pequeños, correcciones de tamaño de imagen.
-
Instantánea de memoria después de sesión de 10 minutos escrita: Navega pestañas, abre detalle, regresa - heap estable sin suba que indique fugas.
- Propietario: Oncall móvil revisa sospechosos de fuga.
- Nativo: Libera identificadores de
SharedObject de módulos Expo en desmontaje.
-
Tamaño de descarga de actualización OTA antes de publicación en producción: Tamaño de artefacto eas update - advierte cuando esté por encima del presupuesto OTA.
- Comprime: Assets vía pipeline de
expo-asset; deduplica imágenes.
- Reversión: OTA grande se correlaciona con actualizaciones lentas y pérdida de usuarios.
-
Cascada de red en pantalla principal: Paraleliza solicitudes independientes; evita cadenas await serie bloqueando pintura.
- Patrón: Consultas paralelas de TanStack Query en montaje de pantalla.
- Presupuesto: Respuesta de API de contenido first < 800 ms p95 en staging.
-
Verificación spot de batería y térmica: Sesión de navegación de 15 minutos - el dispositivo no debe acelerador severo en Android de referencia.
- Olor: Sondeo de ubicación cada segundo en segundo plano.
- Corrección: Coalesce watchers; usa ubicación de cambio significativo cuando sea posible.
-
Etiqueta de PR de rendimiento: Los cambios que toquen listas, imágenes, inicio, o deps > 50 KB requieren perf-review del propietario del presupuesto.
- Bot: Reglas de etiqueta GitHub desde rutas de CODEOWNERS.
- Educación: Los revisores vinculan a métrica fallida, no vago "optimiza esto".
-
Dashboard semanal: TTI, libre de fallas, muestreo de fps (si RUM disponible), tendencia de tamaño de bundle - visible para producto e ingeniería.
- Propietario: La plataforma móvil publica instantánea en #mobile.
- Alerta: Regresión semana-sobre-semana publicada automáticamente.
-
Verificación de Nueva Arquitectura en actualización: RN 0.86 Nueva Arquitectura puede cambiar características de rendimiento - re-baseline después de bumps de SDK.
- Compara: Mismos dispositivos de referencia antes/después de actualización.
- Documenta: Hallazgos en ADR de actualización de SDK.
-
Feature flags para experimentos de rendimiento: Lanza desplazamiento infinito o nueva pipeline de imagen al 5% antes de OTA completa - observa métricas RUM.
-
Sin tickets de deuda de rendimiento sin métrica: "Hacer la aplicación más rápida" no es un ticket - "Reducir TTI de inicio desde 3.1s a 2.5s en Pixel 6a" es.
- Listo: Mejora medida adjunta a PR.
- Rechaza: Memoización prematura sin perfilación.
-
Apéndice de rendimiento de envío a tienda: El ticket de lanzamiento incluye TTI, tamaño de bundle, resultados de auditoría de FPS, y enlaces ADR de exención - aprobación de QA referencia números.
- Apple: Observa violaciones de hilo principal en Instruments antes de envío a iOS.
- Google: Vitales de Android monitoreados post-lanzamiento.
- Nivel 1 (1-6): Define presupuestos y propietarios - sin números, nada es aplicable.
- Nivel 2 (7-12): Automatiza en CI - atrapa regresiones en tiempo de PR.
- Nivel 3 (13-18): Auditoría de dispositivo - simuladores y iPhones Pro mienten.
- Nivel 4 (19-24): Proceso - mantiene presupuestos vivos pasado el primer sprint.
¿Cuál es un presupuesto razonable de bundle JS para Expo SDK 57?
Muchas aplicaciones de consumidor apuntan a 3-5 MB comprimido de bundle Hermes principal en TTI. Las aplicaciones pesadas (mapas, video) necesitan techos más altos con justificación ADR. Mide tu baseline antes de copiar un número.
¿Por qué medir en Android de rango medio?
Android de gama baja expone tartamudeos, presión de memoria, y almacenamiento lento que los iPhones insignia ocultan. Si pasa en Android de rango medio, iOS usualmente está bien; lo inverso es falso.
¿Cómo mido TTI en React Native?
Marca el lanzamiento de aplicación en _layout.tsx raíz, marca interactivo cuando la pantalla principal termina layout y la puerta de datos se abre. Usa Performance API o eventos de analytics personalizados - excluye compilaciones de dev client.
¿Afecta OTA el presupuesto de bundle?
Sí - cada actualización tiene un presupuesto de tamaño de descarga. Bundles OTA grandes ralentizan actualizaciones y aumentan tasas de falla. Verifica el tamaño del artefacto antes de eas update de producción.
¿FlashList o FlatList?
Por defecto FlashList para listas heterogéneas largas en SDK 57. FlatList está bien para listas estáticas cortas. El propietario del presupuesto revisa cambios de lista en feeds principales.
¿Puede CI medir FPS?
Raramente confiablemente - la auditoría de FPS se mantiene manual o basada en RUM. CI es excelente en tamaño de bundle y verificaciones de dependencia; el laboratorio de dispositivos cubre fotogramas.
¿Qué dispara una reversión de rendimiento?
Definido por equipo - a menudo regresión de TTI > 15%, aumento de falla, o sobrecorrida de bundle vinculada a fallas de inicio. Documenta disparadores en tabla de Reglas de Lanzamiento y OTA.
¿Las imágenes en expo-asset cuentan hacia bundle?
Sí si se empaquetan en tiempo de compilación. Prefiere assets dimensionados apropiadamente, formatos modernos, y CDN remoto para medios raramente usados.
¿Cómo afecta Nueva Arquitectura a los presupuestos?
Fabric puede mejorar rendimiento de desplazamiento de lista pero puede cambiar memoria - re-baseline después de habilitar en RN 0.86. No asumir números idénticos a Arquitectura Antigua.
¿Quién aprueba la exención del presupuesto?
El propietario designado para esa métrica más líder móvil. ADR de exención incluye versión de lanzamiento de vencimiento y plan de mitigación.
¿Deberíamos perfilar en producción?
Sí con RUM de muestreo (rendimiento de Sentry, analytics personalizado) - respeta privacidad, sin PII en eventos de rendimiento. El staging refleja arquitectura de prod para inmersiones profundas.
¿Qué pasa con los benchmarks de Expo Go?
Expo Go incluye overhead extra - nunca uses para aprobación de presupuesto. Usa vista previa o compilaciones perfiladas en producción de EAS en dispositivos de referencia.
¿Cómo atribuyen monorepos el tamaño de bundle?
Mide por exportación de aplicación desde apps/mobile. Los paquetes compartidos cuentan hacia cada aplicación que los importa - aplica límites de paquete para evitar importaciones de bloat accidentales.
Versiones de Stack: Esta página fue escrita para React 19.2.3, React Native 0.86.0, y Expo SDK 57 (expo ~57.0.4).