Lista de verificación de rendimiento de front-end 2021 (PDF, Apple Pages, MS Word)
Publicado: 2022-03-10Esta guía ha sido amablemente respaldada por nuestros amigos de LogRocket, un servicio que combina la supervisión del rendimiento de frontend , la reproducción de sesiones y el análisis de productos para ayudarlo a crear mejores experiencias para los clientes. LogRocket rastrea métricas clave, incl. DOM completo, tiempo hasta el primer byte, primer retardo de entrada, CPU del cliente y uso de memoria. Obtenga una prueba gratuita de LogRocket hoy.
El rendimiento web es una bestia engañosa, ¿no es así? ¿Cómo sabemos realmente cuál es nuestra posición en términos de rendimiento y cuáles son exactamente los cuellos de botella de nuestro rendimiento? ¿Es JavaScript costoso, entrega lenta de fuentes web, imágenes pesadas o renderizado lento? ¿Hemos optimizado lo suficiente con la sacudida del árbol, la elevación del alcance, la división de código y todos los patrones de carga sofisticados con el observador de intersecciones, la hidratación progresiva, las sugerencias de los clientes, HTTP/3, los trabajadores de servicio y, por Dios, los trabajadores de borde? Y, lo que es más importante, ¿dónde comenzamos a mejorar el desempeño y cómo establecemos una cultura de desempeño a largo plazo?
En el pasado, el rendimiento a menudo era una mera ocurrencia tardía . A menudo pospuesto hasta el final del proyecto, se reduciría a minificación, concatenación, optimización de activos y, potencialmente, algunos ajustes finos en el archivo de config
del servidor. Mirando hacia atrás ahora, las cosas parecen haber cambiado bastante significativamente.
El rendimiento no es solo una preocupación técnica: afecta todo, desde la accesibilidad hasta la usabilidad y la optimización del motor de búsqueda, y cuando se integra en el flujo de trabajo, las decisiones de diseño deben basarse en sus implicaciones de rendimiento. El rendimiento debe medirse, monitorearse y refinarse continuamente , y la creciente complejidad de la web plantea nuevos desafíos que dificultan el seguimiento de las métricas, ya que los datos variarán significativamente según el dispositivo, el navegador, el protocolo, el tipo de red y la latencia ( CDN, ISP, cachés, proxies, firewalls, balanceadores de carga y servidores, todos juegan un papel en el rendimiento).
Entonces, si creamos una descripción general de todas las cosas que debemos tener en cuenta al mejorar el rendimiento, desde el comienzo del proyecto hasta el lanzamiento final del sitio web, ¿cómo sería eso? A continuación, encontrará una lista de verificación de rendimiento de front-end (con suerte imparcial y objetiva) para 2021 : una descripción general actualizada de los problemas que podría necesitar considerar para garantizar que sus tiempos de respuesta sean rápidos, la interacción del usuario sea fluida y sus sitios no agotar el ancho de banda del usuario.
Tabla de contenido
- Todo en páginas separadas
- Preparándose: planificación y métricas
Cultura de rendimiento, Core Web Vitals, perfiles de rendimiento, CrUX, Lighthouse, FID, TTI, CLS, dispositivos. - Establecer metas realistas
Presupuestos de rendimiento, objetivos de rendimiento, marco RAIL, presupuestos de 170 KB/30 KB. - Definición del entorno
Elección de un marco, costo de rendimiento de referencia, paquete web, dependencias, CDN, arquitectura de front-end, CSR, SSR, CSR + SSR, renderizado estático, prerenderizado, patrón PRPL. - Optimizaciones de activos
Brotli, AVIF, WebP, imágenes receptivas, AV1, carga multimedia adaptable, compresión de video, fuentes web, fuentes de Google. - Optimizaciones de compilación
Módulos de JavaScript, patrón de módulo/no módulo, agitación de árboles, división de código, elevación de alcance, paquete web, servicio diferencial, trabajador web, WebAssembly, paquetes de JavaScript, React, SPA, hidratación parcial, importación en interacción, terceros, caché. - Optimizaciones de entrega
Carga diferida, observador de intersecciones, representación y decodificación diferidas, CSS crítico, transmisión, sugerencias de recursos, cambios de diseño, trabajador de servicio. - Redes, HTTP/2, HTTP/3
Grapado OCSP, certificados EV/DV, empaquetado, IPv6, QUIC, HTTP/3. - Pruebas y monitoreo
Flujo de trabajo de auditoría, navegadores proxy, página 404, avisos de consentimiento de cookies de GDPR, diagnóstico de rendimiento CSS, accesibilidad. - Triunfos rápidos
- Descargar la lista de verificación (PDF, Apple Pages, MS Word)
- ¡Nos vamos!
(También puede descargar el PDF de la lista de verificación (166 KB) o descargar el archivo editable de Apple Pages (275 KB) o el archivo .docx (151 KB). ¡Feliz optimización a todos!)
Preparándose: planificación y métricas
Las microoptimizaciones son excelentes para mantener el rendimiento en el buen camino, pero es fundamental tener objetivos claramente definidos en mente: objetivos medibles que influirían en cualquier decisión que se tome a lo largo del proceso. Hay un par de modelos diferentes, y los que se analizan a continuación son bastante obstinados; solo asegúrese de establecer sus propias prioridades desde el principio.
- Establecer una cultura de rendimiento.
En muchas organizaciones, los desarrolladores front-end saben exactamente cuáles son los problemas subyacentes comunes y qué estrategias deben usarse para solucionarlos. Sin embargo, mientras no haya un respaldo establecido de la cultura del desempeño, cada decisión se convertirá en un campo de batalla de departamentos, dividiendo la organización en silos. Necesita la aceptación de las partes interesadas de la empresa y, para obtenerla, debe establecer un estudio de caso o una prueba de concepto sobre cómo la velocidad, especialmente Core Web Vitals , que trataremos en detalle más adelante, beneficia las métricas y los indicadores clave de rendimiento. ( KPI ) que les importan.Por ejemplo, para que el rendimiento sea más tangible, puede exponer el impacto en el rendimiento de los ingresos al mostrar la correlación entre la tasa de conversión y el tiempo de carga de la aplicación, así como el rendimiento de representación. O la tasa de rastreo del bot de búsqueda (PDF, páginas 27–50).
Sin una fuerte alineación entre los equipos de desarrollo/diseño y negocios/marketing, el rendimiento no se mantendrá a largo plazo. Estudie las quejas comunes que llegan al servicio de atención al cliente y al equipo de ventas, estudie los análisis de las altas tasas de rebote y las caídas de conversión. Explore cómo mejorar el rendimiento puede ayudar a aliviar algunos de estos problemas comunes. Ajuste el argumento según el grupo de partes interesadas con el que esté hablando.
Ejecute experimentos de rendimiento y mida los resultados, tanto en dispositivos móviles como en computadoras de escritorio (por ejemplo, con Google Analytics). Le ayudará a construir un caso de estudio personalizado para la empresa con datos reales. Además, el uso de datos de estudios de casos y experimentos publicados en WPO Stats ayudará a aumentar la sensibilidad de las empresas sobre por qué es importante el rendimiento y qué impacto tiene en la experiencia del usuario y las métricas comerciales. Sin embargo, afirmar que el rendimiento importa por sí solo no es suficiente: también debe establecer algunos objetivos medibles y rastreables y observarlos a lo largo del tiempo.
¿Cómo llegar allá? En su charla sobre Creación de rendimiento a largo plazo, Allison McKnight comparte un estudio de caso completo sobre cómo ayudó a establecer una cultura de rendimiento en Etsy (diapositivas). Más recientemente, Tammy Everts ha hablado sobre los hábitos de los equipos de desempeño altamente efectivos tanto en organizaciones pequeñas como grandes.
Al tener estas conversaciones en las organizaciones, es importante tener en cuenta que, al igual que UX es un espectro de experiencias, el rendimiento web es una distribución. Como señaló Karolina Szczur, "esperar que un solo número pueda proporcionar una calificación a la que aspirar es una suposición errónea". Por lo tanto, los objetivos de rendimiento deben ser granulares, rastreables y tangibles.
- Objetivo: ser al menos un 20 % más rápido que su competidor más rápido.
Según la investigación psicológica, si desea que los usuarios sientan que su sitio web es más rápido que el sitio web de su competidor, debe ser al menos un 20% más rápido. Estudie a sus principales competidores, recopile métricas sobre cómo se desempeñan en dispositivos móviles y de escritorio y establezca umbrales que lo ayuden a superarlos. Sin embargo, para obtener resultados y objetivos precisos, primero asegúrese de obtener una imagen completa de la experiencia de sus usuarios mediante el estudio de sus análisis. A continuación, puede imitar la experiencia del percentil 90 para la prueba.Para obtener una buena primera impresión de cómo se desempeñan sus competidores, puede usar Chrome UX Report ( CrUX , un conjunto de datos de RUM listo para usar, una introducción en video de Ilya Grigorik y una guía detallada de Rick Viscomi) o Treo, una herramienta de monitoreo de RUM que funciona con Chrome UX Report. Los datos se recopilan de los usuarios del navegador Chrome, por lo que los informes serán específicos de Chrome, pero le brindarán una distribución bastante completa del rendimiento, lo que es más importante, las puntuaciones de Core Web Vitals, en una amplia gama de sus visitantes. Tenga en cuenta que los nuevos conjuntos de datos de CrUX se publican el segundo martes de cada mes .
Alternativamente, también puede usar:
- Herramienta de comparación de informes Chrome UX de Addy Osmani,
- Speed Scorecard (también proporciona un estimador de impacto en los ingresos),
- Comparación de prueba de experiencia de usuario real o
- SiteSpeed CI (basado en pruebas sintéticas).
Nota : si usa Page Speed Insights o la API de Page Speed Insights (¡no, no está en desuso!), puede obtener datos de rendimiento de CrUX para páginas específicas en lugar de solo los agregados. Estos datos pueden ser mucho más útiles para establecer objetivos de rendimiento para activos como "página de destino" o "lista de productos". Y si está utilizando CI para probar los presupuestos, debe asegurarse de que su entorno probado coincida con CrUX si usó CrUX para establecer el objetivo ( ¡gracias Patrick Meenan! ).
Si necesita ayuda para mostrar el razonamiento detrás de la priorización de la velocidad, o si desea visualizar la disminución de la tasa de conversión o el aumento de la tasa de rebote con un rendimiento más lento, o tal vez necesite abogar por una solución RUM en su organización, Sergey Chernyshev ha creado una calculadora de velocidad UX, una herramienta de código abierto que lo ayuda a simular datos y visualizarlos para transmitir su punto.
A veces, es posible que desee profundizar un poco más, combinando los datos provenientes de CrUX con cualquier otro dato que ya tenga para determinar rápidamente dónde se encuentran las ralentizaciones, los puntos ciegos y las ineficiencias, para sus competidores o para su proyecto. En su trabajo, Harry Roberts ha estado utilizando una hoja de cálculo de topografía de la velocidad del sitio que utiliza para desglosar el rendimiento por tipos de página clave y realizar un seguimiento de las diferentes métricas clave entre ellos. Puede descargar la hoja de cálculo como Hojas de cálculo de Google, Excel, documento de OpenOffice o CSV.
Y si quiere llegar hasta el final, puede ejecutar una auditoría de rendimiento de Lighthouse en cada página de un sitio (a través de Lightouse Parade), con una salida guardada como CSV. Eso lo ayudará a identificar qué páginas específicas (o tipos de páginas) de sus competidores funcionan peor o mejor, y en qué es posible que desee centrar sus esfuerzos. (¡Sin embargo, para su propio sitio, probablemente sea mejor enviar datos a un punto final de análisis!).
Recopile datos, configure una hoja de cálculo, reduzca el 20% y configure sus objetivos ( presupuestos de rendimiento ) de esta manera. Ahora tienes algo medible contra lo que probar. Si tiene en cuenta el presupuesto y trata de enviar solo la carga útil mínima para obtener un tiempo interactivo rápido, entonces está en un camino razonable.
¿Necesita recursos para empezar?
- Addy Osmani ha escrito un artículo muy detallado sobre cómo empezar a presupuestar el rendimiento, cómo cuantificar el impacto de las nuevas funciones y por dónde empezar cuando supera el presupuesto.
- La guía de Lara Hogan sobre cómo abordar los diseños con un presupuesto de rendimiento puede proporcionar consejos útiles para los diseñadores.
- Harry Roberts ha publicado una guía sobre cómo configurar una hoja de cálculo de Google para mostrar el impacto de los scripts de terceros en el rendimiento, utilizando Request Map,
- Performance Budget Calculator de Jonathan Fielding, perf-budget-calculator de Katie Hempenius y Browser Calories pueden ayudar a crear presupuestos (gracias a Karolina Szczur por los avisos).
- En muchas empresas, los presupuestos de desempeño no deben ser aspiracionales, sino más bien pragmáticos, sirviendo como una señal de advertencia para evitar pasar de cierto punto. En ese caso, podría elegir su peor punto de datos en las últimas dos semanas como umbral y continuar desde allí. Presupuestos de desempeño, pragmáticamente le muestra una estrategia para lograrlo.
- Además, haga que tanto el presupuesto de rendimiento como el rendimiento actual sean visibles configurando paneles con gráficos que informen los tamaños de compilación. Hay muchas herramientas que le permiten lograrlo: el panel de SiteSpeed.io (código abierto), SpeedCurve y Calibre son solo algunas de ellas, y puede encontrar más herramientas en perf.rocks.
Una vez que tenga un presupuesto establecido, incorpórelo a su proceso de creación con Webpack Performance Hints y Bundlesize, Lighthouse CI, PWMetrics o Sitespeed CI para hacer cumplir los presupuestos en las solicitudes de extracción y proporcionar un historial de puntuación en los comentarios de relaciones públicas.
Para exponer los presupuestos de rendimiento a todo el equipo, integre los presupuestos de rendimiento en Lighthouse a través de Lightwallet o use LHCI Action para una integración rápida de Github Actions. Y si necesita algo personalizado, puede usar webpagetest-charts-api, una API de puntos finales para crear gráficos a partir de los resultados de WebPagetest.
Sin embargo, la conciencia del rendimiento no debería provenir únicamente de los presupuestos de rendimiento. Al igual que Pinterest, puede crear una regla eslint personalizada que no permita la importación desde archivos y directorios que se sabe que tienen muchas dependencias y que inflarían el paquete. Configure una lista de paquetes "seguros" que se puedan compartir con todo el equipo.
Además, piense en las tareas críticas del cliente que son más beneficiosas para su negocio. Estudie, discuta y defina umbrales de tiempo aceptables para acciones críticas y establezca marcas de tiempo de usuario "Listo para UX" que toda la organización haya aprobado. En muchos casos, los viajes de los usuarios tocarán el trabajo de muchos departamentos diferentes, por lo que la alineación en términos de tiempos aceptables ayudará a respaldar o evitar las discusiones sobre el desempeño en el futuro. Asegúrese de que los costos adicionales de los recursos y características adicionales sean visibles y comprensibles.
Alinear los esfuerzos de rendimiento con otras iniciativas tecnológicas, que van desde nuevas características del producto que se está construyendo hasta la refactorización para llegar a nuevas audiencias globales. Entonces, cada vez que ocurre una conversación sobre un mayor desarrollo, el rendimiento también es parte de esa conversación. Es mucho más fácil alcanzar los objetivos de rendimiento cuando el código base es nuevo o se está refactorizando.
Además, como sugirió Patrick Meenan, vale la pena planificar una secuencia de carga y compensaciones durante el proceso de diseño. Si prioriza desde el principio qué partes son más críticas y define el orden en el que deben aparecer, también sabrá qué se puede retrasar. Idealmente, ese orden también reflejará la secuencia de sus importaciones de CSS y JavaScript, por lo que será más fácil manejarlas durante el proceso de compilación. Además, considere cuál debería ser la experiencia visual en estados "intermedios", mientras se carga la página (por ejemplo, cuando las fuentes web aún no se cargan).
Una vez que haya establecido una sólida cultura de desempeño en su organización, intente ser un 20 % más rápido que antes para mantener las prioridades intactas a medida que pasa el tiempo ( ¡gracias, Guy Podjarny! ). Pero tenga en cuenta los diferentes tipos y comportamientos de uso de sus clientes (que Tobias Baldauf llamó cadencia y cohortes), junto con el tráfico de bots y los efectos de la estacionalidad.
Planificación, planificación, planificación. Puede ser tentador entrar en algunas optimizaciones rápidas de "frutos al alcance de la mano" desde el principio, y podría ser una buena estrategia para ganancias rápidas, pero será muy difícil mantener el rendimiento como una prioridad sin planificar y establecer una empresa realista. -Objetivos de rendimiento personalizados.
- Elija las métricas correctas.
No todas las métricas son igualmente importantes. Estudie qué métricas son más importantes para su aplicación: por lo general, se definirá por la rapidez con la que puede comenzar a renderizar los píxeles más importantes de su interfaz y la rapidez con la que puede proporcionar la capacidad de respuesta de entrada para estos píxeles renderizados. Este conocimiento le dará el mejor objetivo de optimización para los esfuerzos en curso. Al final, no son los eventos de carga o los tiempos de respuesta del servidor los que definen la experiencia, sino la percepción de cuán ágil se siente la interfaz.¿Qué significa? En lugar de centrarse en el tiempo de carga de la página completa (a través de los tiempos de onLoad y DOMContentLoaded , por ejemplo), priorice la carga de la página tal como la perciben sus clientes. Eso significa centrarse en un conjunto de métricas ligeramente diferente. De hecho, elegir la métrica correcta es un proceso sin ganadores obvios.
Según la investigación de Tim Kadlec y las notas de Marcos Iglesias en su charla, las métricas tradicionales podrían agruparse en unos pocos conjuntos. Por lo general, los necesitaremos todos para obtener una imagen completa del rendimiento y, en su caso particular, algunos de ellos serán más importantes que otros.
- Las métricas basadas en la cantidad miden el número de solicitudes, el peso y la puntuación de rendimiento. Bueno para generar alarmas y monitorear cambios a lo largo del tiempo, no tan bueno para comprender la experiencia del usuario.
- Las métricas de hitos utilizan estados durante el tiempo de vida del proceso de carga, por ejemplo, Tiempo hasta el primer byte y Tiempo hasta interactivo . Bueno para describir la experiencia del usuario y el monitoreo, no tan bueno para saber qué sucede entre los hitos.
- Las métricas de procesamiento proporcionan una estimación de la rapidez con la que se procesa el contenido (p. ej., tiempo de inicio de procesamiento , índice de velocidad ). Bueno para medir y ajustar el rendimiento de representación, pero no tan bueno para medir cuándo aparece contenido importante y se puede interactuar con él.
- Las métricas personalizadas miden un evento personalizado en particular para el usuario, por ejemplo, el Tiempo hasta el primer tweet de Twitter y el Tiempo de espera de Pinner de Pinterest. Bueno para describir la experiencia del usuario con precisión, no tan bueno para escalar las métricas y compararlas con la competencia.
Para completar el panorama, generalmente buscamos métricas útiles entre todos estos grupos. Por lo general, los más específicos y relevantes son:
- Tiempo para Interactivo (TTI)
El punto en el que el diseño se ha estabilizado , las fuentes web clave son visibles y el hilo principal está lo suficientemente disponible para manejar la entrada del usuario, básicamente la marca de tiempo cuando un usuario puede interactuar con la interfaz de usuario. Las métricas clave para comprender cuánto tiempo de espera debe experimentar un usuario para usar el sitio sin demoras. Boris Schapira ha escrito una publicación detallada sobre cómo medir TTI de manera confiable. - Primera demora de entrada (FID) o capacidad de respuesta de entrada
El tiempo desde que un usuario interactúa por primera vez con su sitio hasta el momento en que el navegador puede responder a esa interacción. Complementa muy bien a TTI, ya que describe la parte faltante de la imagen: lo que sucede cuando un usuario realmente interactúa con el sitio. Diseñado como una métrica RUM únicamente. Hay una biblioteca de JavaScript para medir FID en el navegador. - Pintura con contenido más grande (LCP)
Marca el punto en la línea de tiempo de carga de la página cuando es probable que se haya cargado el contenido importante de la página. La suposición es que el elemento más importante de la página es el más grande visible en la ventana gráfica del usuario. Si los elementos se representan tanto por encima como por debajo del pliegue, solo la parte visible se considera relevante. - Tiempo total de bloqueo ( TBT )
Una métrica que ayuda a cuantificar la gravedad de cuán no interactiva es una página antes de que se vuelva confiablemente interactiva (es decir, el subproceso principal ha estado libre de tareas que se ejecutan durante más de 50 ms ( tareas largas ) durante al menos 5 s). La métrica mide la cantidad total de tiempo entre la primera pintura y el Tiempo de interacción (TTI), donde el subproceso principal se bloqueó durante el tiempo suficiente para evitar la capacidad de respuesta de entrada. No es de extrañar, entonces, que un TBT bajo sea un buen indicador de un buen desempeño. (gracias, Artem, Phil) - Cambio de diseño acumulativo ( CLS )
La métrica destaca la frecuencia con la que los usuarios experimentan cambios de diseño inesperados ( reflujos ) al acceder al sitio. Examina los elementos inestables y su impacto en la experiencia general. Cuanto menor sea la puntuación, mejor. - Índice de velocidad
Mide la rapidez con la que se rellenan visualmente los contenidos de la página; cuanto menor sea la puntuación, mejor. La puntuación del índice de velocidad se calcula en función de la velocidad del progreso visual , pero es simplemente un valor calculado. También es sensible al tamaño de la ventana gráfica, por lo que debe definir un rango de configuraciones de prueba que coincidan con su público objetivo. Tenga en cuenta que se está volviendo menos importante con LCP convirtiéndose en una métrica más relevante ( ¡gracias, Boris, Artem! ). - tiempo de CPU dedicado
Una métrica que muestra con qué frecuencia y durante cuánto tiempo se bloquea el subproceso principal, trabajando en pintar, renderizar, generar secuencias de comandos y cargar. El tiempo de CPU alto es un claro indicador de una experiencia de janky , es decir, cuando el usuario experimenta un retraso notable entre su acción y una respuesta. Con WebPageTest, puede seleccionar "Capturar línea de tiempo de herramientas de desarrollo" en la pestaña "Chrome" para exponer el desglose del hilo principal a medida que se ejecuta en cualquier dispositivo que use WebPageTest. - Costos de CPU a nivel de componente
Al igual que con el tiempo dedicado a la CPU , esta métrica, propuesta por Stoyan Stefanov, explora el impacto de JavaScript en la CPU . La idea es utilizar el recuento de instrucciones de CPU por componente para comprender su impacto en la experiencia general, de forma aislada. Podría implementarse usando Puppeteer y Chrome. - índice de frustración
Si bien muchas de las métricas presentadas anteriormente explican cuándo ocurre un evento en particular, FrustrationIndex de Tim Vereecke analiza las brechas entre las métricas en lugar de mirarlas individualmente. Examina los hitos clave percibidos por el usuario final, como el título es visible, el primer contenido es visible, visualmente listo y la página parece lista y calcula una puntuación que indica el nivel de frustración al cargar una página. Cuanto mayor sea la brecha, mayor será la posibilidad de que un usuario se sienta frustrado. Potencialmente un buen KPI para la experiencia del usuario. Tim ha publicado una publicación detallada sobre FrustrationIndex y cómo funciona. - Impacto del peso del anuncio
Si su sitio depende de los ingresos generados por la publicidad, es útil realizar un seguimiento del peso del código relacionado con la publicidad. El script de Paddy Ganti construye dos URL (una normal y otra que bloquea los anuncios), solicita la generación de una comparación de video a través de WebPageTest e informa un delta. - Métricas de desviación
Como señalaron los ingenieros de Wikipedia, los datos de cuánta variación existe en sus resultados podrían informarle cuán confiables son sus instrumentos y cuánta atención debe prestar a las desviaciones y los valores atípicos. Una gran variación es un indicador de los ajustes necesarios en la configuración. También ayuda a comprender si ciertas páginas son más difíciles de medir de manera confiable, por ejemplo, debido a scripts de terceros que causan una variación significativa. También podría ser una buena idea realizar un seguimiento de la versión del navegador para comprender los cambios en el rendimiento cuando se implementa una nueva versión del navegador. - Métricas personalizadas
Las métricas personalizadas se definen según las necesidades de su negocio y la experiencia del cliente. Requiere que identifique píxeles importantes , scripts críticos , CSS necesario y activos relevantes y mida la rapidez con que se entregan al usuario. Para eso, puede monitorear Hero Rendering Times o usar Performance API, marcando marcas de tiempo particulares para eventos que son importantes para su negocio. Además, puede recopilar métricas personalizadas con WebPagetest ejecutando JavaScript arbitrario al final de una prueba.
Tenga en cuenta que la primera pintura significativa (FMP) no aparece en la descripción general anterior. Solía proporcionar una idea de la rapidez con la que el servidor genera cualquier dato. FMP largo generalmente indicaba que JavaScript bloqueaba el hilo principal, pero también podría estar relacionado con problemas de back-end/servidor. Sin embargo, la métrica ha quedado obsoleta recientemente, ya que parece no ser precisa en aproximadamente el 20 % de los casos. Fue reemplazado efectivamente por LCP, que es más confiable y más fácil de razonar. Ya no se admite en Lighthouse. Vuelva a verificar las últimas métricas y recomendaciones de rendimiento centradas en el usuario solo para asegurarse de que está en la página segura ( gracias, Patrick Meenan ).
Steve Souders tiene una explicación detallada de muchas de estas métricas. Es importante tener en cuenta que, si bien el tiempo de interacción se mide mediante la ejecución de auditorías automatizadas en el llamado entorno de laboratorio , el retraso de la primera entrada representa la experiencia real del usuario, y los usuarios reales experimentan un retraso notable. En general, probablemente sea una buena idea medir y rastrear siempre ambos.
Según el contexto de su aplicación, las métricas preferidas pueden diferir: por ejemplo, para la interfaz de usuario de TV de Netflix, la capacidad de respuesta de entrada clave, el uso de memoria y TTI son más importantes, y para Wikipedia, las métricas de primeros/últimos cambios visuales y tiempo de CPU son más importantes.
Nota : tanto FID como TTI no tienen en cuenta el comportamiento de desplazamiento; el desplazamiento puede ocurrir de forma independiente ya que está fuera del hilo principal, por lo que para muchos sitios de consumo de contenido, estas métricas pueden ser mucho menos importantes ( ¡gracias, Patrick! ).
- Mida y optimice los Core Web Vitals .
Durante mucho tiempo, las métricas de rendimiento fueron bastante técnicas, centrándose en la vista de ingeniería de qué tan rápido responden los servidores y qué tan rápido se cargan los navegadores. Las métricas han cambiado a lo largo de los años, tratando de encontrar una manera de capturar la experiencia real del usuario, en lugar de los tiempos del servidor. En mayo de 2020, Google anunció Core Web Vitals, un conjunto de nuevas métricas de rendimiento centradas en el usuario, cada una de las cuales representa una faceta distinta de la experiencia del usuario.Para cada uno de ellos, Google recomienda un rango de objetivos de velocidad aceptables. Al menos el 75 % de todas las visitas a la página deben superar el rango bueno para aprobar esta evaluación. Estas métricas ganaron terreno rápidamente, y con Core Web Vitals convirtiéndose en señales de clasificación para la Búsqueda de Google en mayo de 2021 ( actualización del algoritmo de clasificación de Page Experience ), muchas empresas han centrado su atención en sus puntuaciones de rendimiento.
Analicemos cada uno de los Core Web Vitals, uno por uno, junto con técnicas y herramientas útiles para optimizar sus experiencias con estas métricas en mente. (Vale la pena señalar que obtendrá mejores puntajes de Core Web Vitals si sigue los consejos generales de este artículo).
- Pintura con contenido más grande ( LCP ) < 2,5 seg.
Mide la carga de una página e informa el tiempo de procesamiento de la imagen o bloque de texto más grande que está visible dentro de la ventana gráfica. Por lo tanto, LCP se ve afectado por todo lo que está aplazando la representación de información importante, ya sean tiempos de respuesta lentos del servidor, bloqueo de CSS, JavaScript en tránsito (de origen o de terceros), carga de fuentes web, operaciones costosas de representación o pintura, perezosos -imágenes cargadas, pantallas de esqueleto o renderizado del lado del cliente.
Para una buena experiencia, LCP debe ocurrir dentro de los 2,5 segundos desde que la página comienza a cargarse por primera vez. Eso significa que debemos renderizar la primera parte visible de la página lo antes posible. Eso requerirá CSS crítico personalizado para cada plantilla, organizando el orden<head>
y precargando activos críticos (los cubriremos más adelante).La razón principal de una puntuación LCP baja suelen ser las imágenes. Entregar un LCP en <2,5 s en Fast 3G, alojado en un servidor bien optimizado, todo estático sin representación del lado del cliente y con una imagen que proviene de una CDN de imagen dedicada, significa que el tamaño de imagen teórico máximo es de solo alrededor de 144 KB . Es por eso que las imágenes receptivas son importantes, así como la precarga temprana de imágenes críticas (con
preload
).Sugerencia rápida : para descubrir qué se considera LCP en una página, en DevTools puede pasar el cursor sobre la insignia LCP en "Tiempos" en el Panel de rendimiento (¡ gracias, Tim Kadlec !).
- Retardo de la primera entrada ( FID ) < 100 ms.
Mide la capacidad de respuesta de la interfaz de usuario, es decir, cuánto tiempo estuvo ocupado el navegador con otras tareas antes de que pudiera reaccionar a un evento de entrada de usuario discreto como un toque o un clic. Está diseñado para capturar los retrasos que resultan de que el subproceso principal esté ocupado, especialmente durante la carga de la página.
El objetivo es permanecer entre 50 y 100 ms por cada interacción. Para llegar allí, necesitamos identificar tareas largas (bloquea el hilo principal durante > 50 ms) y dividirlas, codificar un paquete dividido en varios fragmentos, reducir el tiempo de ejecución de JavaScript, optimizar la obtención de datos, diferir la ejecución de scripts de terceros. , mueva JavaScript al subproceso de fondo con los trabajadores web y use la hidratación progresiva para reducir los costos de rehidratación en los SPA.Consejo rápido : en general, una estrategia confiable para obtener una mejor puntuación FID es minimizar el trabajo en el subproceso principal dividiendo los paquetes más grandes en paquetes más pequeños y sirviendo lo que el usuario necesita cuando lo necesita, para que las interacciones del usuario no se retrasen. . Cubriremos más sobre eso en detalle a continuación.
- Cambio de diseño acumulativo ( CLS ) < 0.1.
Mide la estabilidad visual de la interfaz de usuario para garantizar interacciones fluidas y naturales, es decir, la suma total de todos los puntajes de cambio de diseño individuales para cada cambio de diseño inesperado que ocurre durante la vida útil de la página. Un cambio de diseño individual ocurre cada vez que un elemento que ya estaba visible cambia su posición en la página. Se puntúa según el tamaño del contenido y la distancia que se movió.
Por lo tanto, cada vez que aparece un cambio, por ejemplo, cuando las fuentes alternativas y las fuentes web tienen métricas de fuente diferentes, o anuncios, incrustaciones o iframes que llegan tarde, o las dimensiones de imagen/video no están reservadas, o CSS tardío obliga a repintar, o los cambios son inyectados por JavaScript tardío: tiene un impacto en la puntuación CLS. El valor recomendado para una buena experiencia es un CLS < 0,1.
Vale la pena señalar que se supone que Core Web Vitals evoluciona con el tiempo, con un ciclo anual predecible . Para la actualización del primer año, es posible que esperemos que First Contentful Paint se promueva a Core Web Vitals, un umbral de FID reducido y un mejor soporte para aplicaciones de una sola página. También podríamos ver que la respuesta a las entradas del usuario después de la carga gana más peso, junto con las consideraciones de seguridad, privacidad y accesibilidad (!).
En relación con Core Web Vitals, hay muchos recursos y artículos útiles que vale la pena consultar:
- La tabla de clasificación de Web Vitals le permite comparar sus puntajes con los de la competencia en dispositivos móviles, tabletas, computadoras de escritorio y en 3G y 4G.
- Core SERP Vitals, una extensión de Chrome que muestra Core Web Vitals de CrUX en los resultados de búsqueda de Google.
- Layout Shift GIF Generator que visualiza CLS con un simple GIF (también disponible desde la línea de comando).
- La biblioteca web-vitals puede recopilar y enviar Core Web Vitals a Google Analytics, Google Tag Manager o cualquier otro punto final de análisis.
- Análisis de Web Vitals con WebPageTest, en el que Patrick Meenan explora cómo WebPageTest expone datos sobre Core Web Vitals.
- Optimización con Core Web Vitals, un video de 50 minutos con Addy Osmani, en el que destaca cómo mejorar Core Web Vitals en un estudio de caso de comercio electrónico.
- El cambio de diseño acumulativo en la práctica y el cambio de diseño acumulativo en el mundo real son artículos completos de Nic Jansma, que cubren prácticamente todo sobre CLS y cómo se correlaciona con métricas clave como la tasa de rebote, el tiempo de sesión o los clics de rabia.
- What Forces Reflow, con una descripción general de las propiedades o los métodos, cuando se solicita/llama en JavaScript, activará el navegador para calcular sincrónicamente el estilo y el diseño.
- CSS Triggers muestra qué propiedades CSS activan Layout, Paint y Composite.
- Reparar la inestabilidad del diseño es un tutorial sobre el uso de WebPageTest para identificar y solucionar problemas de inestabilidad del diseño.
- Cambio de diseño acumulativo, la métrica de inestabilidad de diseño, otra guía muy detallada de Boris Schapira sobre CLS, cómo se calcula, cómo medir y cómo optimizar.
- Cómo mejorar Core Web Vitals, una guía detallada de Simon Hearne sobre cada una de las métricas (incluidas otras Web Vitals, como FCP, TTI, TBT), cuándo ocurren y cómo se miden.
Entonces, ¿son Core Web Vitals las métricas definitivas a seguir ? No exactamente. De hecho, ya están expuestos en la mayoría de las soluciones y plataformas RUM, incluidos Cloudflare, Treo, SpeedCurve, Calibre, WebPageTest (ya en la vista de tira de película), Newrelic, Shopify, Next.js, todas las herramientas de Google (PageSpeed Insights, Lighthouse + CI, Search Consola, etc.) y muchos otros.
Sin embargo, como explica Katie Sylor-Miller, algunos de los principales problemas con Core Web Vitals son la falta de compatibilidad entre navegadores, en realidad no medimos el ciclo de vida completo de la experiencia de un usuario, además es difícil correlacionar los cambios en FID y CLS con resultados de negocio.
Como deberíamos esperar que Core Web Vitals evolucione, parece razonable combinar siempre Web Vitals con sus métricas personalizadas para obtener una mejor comprensión de su posición en términos de rendimiento.
- Pintura con contenido más grande ( LCP ) < 2,5 seg.
- Recopile datos en un dispositivo representativo de su audiencia.
Para recopilar datos precisos, debemos elegir minuciosamente los dispositivos en los que realizar las pruebas. En la mayoría de las empresas, eso significa buscar análisis y crear perfiles de usuario basados en los tipos de dispositivos más comunes. Sin embargo, a menudo, el análisis por sí solo no proporciona una imagen completa. Una parte significativa de la audiencia objetivo podría estar abandonando el sitio (y no regresando) solo porque su experiencia es demasiado lenta y es poco probable que sus dispositivos aparezcan como los dispositivos más populares en análisis por ese motivo. Por lo tanto, realizar una investigación adicional sobre dispositivos comunes en su grupo objetivo podría ser una buena idea.A nivel mundial en 2020, según IDC, el 84,8% de todos los teléfonos móviles enviados son dispositivos Android. Un consumidor promedio actualiza su teléfono cada 2 años, y en el ciclo de reemplazo de teléfonos de EE. UU. es de 33 meses. Los teléfonos promedio más vendidos en todo el mundo costarán menos de $ 200.
Un dispositivo representativo, entonces, es un dispositivo Android que tiene al menos 24 meses de antigüedad , cuesta $200 o menos, funciona con 3G lento, RTT de 400 ms y transferencia de 400 kbps, solo para ser un poco más pesimista. Esto puede ser muy diferente para su empresa, por supuesto, pero es una aproximación lo suficientemente cercana a la mayoría de los clientes. De hecho, podría ser una buena idea buscar en los Best Sellers actuales de Amazon para su mercado objetivo. ( ¡Gracias a Tim Kadlec, Henri Helvetica y Alex Russell por los consejos! ).
¿Qué dispositivos de prueba elegir entonces? Las que encajen bien con el perfil descrito anteriormente. Es una buena opción elegir un Moto G4/G5 Plus un poco más antiguo, un dispositivo Samsung de gama media (Galaxy A50, S8), un buen dispositivo intermedio como un Nexus 5X, Xiaomi Mi A3 o Xiaomi Redmi Note. 7 y un dispositivo lento como Alcatel 1X o Cubot X19, quizás en un laboratorio de dispositivos abiertos. Para realizar pruebas en dispositivos de aceleración térmica más lentos, también puede obtener un Nexus 4, que cuesta alrededor de $ 100.
Además, verifique los conjuntos de chips utilizados en cada dispositivo y no represente demasiado un conjunto de chips : unas pocas generaciones de Snapdragon y Apple, así como Rockchip de gama baja, Mediatek serían suficientes (¡gracias, Patrick!) .
Si no tiene un dispositivo a mano, emule la experiencia móvil en el escritorio probando en una red 3G acelerada (p. ej., 300 ms RTT, 1,6 Mbps de bajada, 0,8 Mbps de subida) con una CPU acelerada (5 veces más lenta). Con el tiempo, cambie a 3G normal, 4G lento (p. ej., 170 ms RTT, 9 Mbps de bajada, 9 Mbps de subida) y Wi-Fi. Para que el impacto en el rendimiento sea más visible, incluso podría introducir 2G Tuesdays o configurar una red 3G/4G acelerada en su oficina para realizar pruebas más rápidas.
Tenga en cuenta que en un dispositivo móvil, deberíamos esperar una desaceleración de 4×–5× en comparación con las máquinas de escritorio. Los dispositivos móviles tienen diferentes GPU, CPU, memoria y diferentes características de batería. Por eso es importante tener un buen perfil de un dispositivo promedio y probar siempre en dicho dispositivo.
- Las herramientas de prueba sintéticas recopilan datos de laboratorio en un entorno reproducible con dispositivos predefinidos y configuraciones de red (por ejemplo, Lighthouse , Calibre , WebPageTest ) y
- Las herramientas Real User Monitoring ( RUM ) evalúan las interacciones de los usuarios de forma continua y recopilan datos de campo (p. ej., SpeedCurve , New Relic ; las herramientas también proporcionan pruebas sintéticas).
- use Lighthouse CI para rastrear las puntuaciones de Lighthouse a lo largo del tiempo (es bastante impresionante),
- ejecute Lighthouse en GitHub Actions para obtener un informe de Lighthouse junto con cada RP,
- ejecutar una auditoría de rendimiento de Lighthouse en cada página de un sitio (a través de Lightouse Parade), con una salida guardada como CSV,
- utilice la calculadora de puntuaciones de Lighthouse y los pesos métricos de Lighthouse si necesita profundizar en más detalles.
- Lighthouse también está disponible para Firefox, pero internamente utiliza la API de PageSpeed Insights y genera un informe basado en un agente de usuario de Chrome 79 sin cabeza.
Afortunadamente, existen muchas opciones excelentes que lo ayudan a automatizar la recopilación de datos y medir el rendimiento de su sitio web a lo largo del tiempo de acuerdo con estas métricas. Tenga en cuenta que una buena imagen de rendimiento cubre un conjunto de métricas de rendimiento, datos de laboratorio y datos de campo:
El primero es particularmente útil durante el desarrollo , ya que lo ayudará a identificar, aislar y solucionar problemas de rendimiento mientras trabaja en el producto. Este último es útil para el mantenimiento a largo plazo, ya que lo ayudará a comprender los cuellos de botella de su rendimiento a medida que ocurren en vivo, cuando los usuarios realmente acceden al sitio.
Al aprovechar las API de RUM integradas, como el tiempo de navegación, el tiempo de recursos, el tiempo de pintura, las tareas largas, etc., las herramientas de prueba sintéticas y el RUM juntos brindan una imagen completa del rendimiento en su aplicación. Puede usar Calibre, Treo, SpeedCurve, mPulse y Boomerang, Sitespeed.io, que son excelentes opciones para monitorear el rendimiento. Además, con el encabezado Server Timing, incluso podría monitorear el rendimiento de back-end y front-end en un solo lugar.
Nota : Siempre es una apuesta más segura elegir aceleradores de nivel de red, externos al navegador, ya que, por ejemplo, DevTools tiene problemas para interactuar con HTTP/2 push, debido a la forma en que está implementado (¡ gracias, Yoav, Patrick !). Para Mac OS, podemos usar Network Link Conditioner, para Windows Traffic Shaper, para Linux netem y para FreeBSD dummynet.
Como es probable que realice pruebas en Lighthouse, tenga en cuenta que puede:
- Configure perfiles "limpios" y "clientes" para realizar pruebas.
Al ejecutar pruebas en herramientas de monitoreo pasivo, es una estrategia común desactivar antivirus y tareas de CPU en segundo plano, eliminar transferencias de ancho de banda en segundo plano y probar con un perfil de usuario limpio sin extensiones de navegador para evitar resultados sesgados (en Firefox y en Chrome).Sin embargo, también es una buena idea estudiar qué extensiones de navegador usan sus clientes con frecuencia y probar también con perfiles de "clientes" dedicados. De hecho, algunas extensiones pueden tener un impacto profundo en el rendimiento (Informe de rendimiento de extensiones de Chrome de 2020) en su aplicación, y si sus usuarios las usan mucho, es posible que desee tenerlo en cuenta por adelantado. Por lo tanto, los resultados del perfil "limpio" por sí solos son demasiado optimistas y pueden aplastarse en escenarios de la vida real.
- Comparta los objetivos de rendimiento con sus colegas.
Asegúrese de que los objetivos de rendimiento sean familiares para todos los miembros de su equipo para evitar malentendidos en el futuro. Cada decisión, ya sea de diseño, marketing o cualquier otra, tiene implicaciones en el rendimiento , y distribuir la responsabilidad y la propiedad entre todo el equipo agilizaría las decisiones centradas en el rendimiento más adelante. Mapee las decisiones de diseño contra el presupuesto de rendimiento y las prioridades definidas desde el principio.
Establecer metas realistas
- Tiempo de respuesta de 100 milisegundos, 60 fps.
Para que una interacción se sienta fluida, la interfaz tiene 100 ms para responder a la entrada del usuario. Más tiempo que eso, y el usuario percibe que la aplicación está retrasada. El RAIL, un modelo de rendimiento centrado en el usuario, le brinda objetivos saludables : para permitir una respuesta de <100 milisegundos, la página debe devolver el control al subproceso principal a más tardar cada <50 milisegundos. La latencia de entrada estimada nos dice si estamos alcanzando ese umbral e, idealmente, debería estar por debajo de los 50 ms. Para puntos de alta presión como la animación, es mejor no hacer nada más donde pueda y el mínimo absoluto donde no pueda.Además, cada cuadro de animación debe completarse en menos de 16 milisegundos, logrando así 60 cuadros por segundo (1 segundo ÷ 60 = 16,6 milisegundos), preferiblemente menos de 10 milisegundos. Debido a que el navegador necesita tiempo para pintar el nuevo marco en la pantalla, su código debería terminar de ejecutarse antes de llegar a la marca de los 16,6 milisegundos. Estamos empezando a tener conversaciones sobre 120 fps (por ejemplo, las pantallas del iPad Pro funcionan a 120 Hz) y Surma ha cubierto algunas soluciones de rendimiento de renderizado para 120 fps, pero probablemente ese no sea un objetivo que estemos viendo todavía .
Sea pesimista en las expectativas de rendimiento, pero sea optimista en el diseño de la interfaz y use el tiempo de inactividad de manera inteligente (marque inactivo, inactivo hasta que sea urgente y reaccionar inactivo). Obviamente, estos objetivos se aplican al rendimiento del tiempo de ejecución, en lugar del rendimiento de carga.
- FID < 100 ms, LCP < 2,5 s, TTI < 5 s en 3G, presupuesto de tamaño de archivo crítico < 170 KB (comprimido con gzip).
Aunque puede ser muy difícil de lograr, un buen objetivo final sería el tiempo para interactuar con menos de 5 años, y para las visitas repetidas, apuntar a menos de 2 años (alcanzable solo con un trabajador de servicio). Apunte a la pintura con contenido más grande de menos de 2,5 segundos y minimice el tiempo de bloqueo total y el cambio de diseño acumulativo . Un retardo de primera entrada aceptable es de menos de 100 ms a 70 ms. Como se mencionó anteriormente, estamos considerando que la línea base es un teléfono Android de $200 (por ejemplo, Moto G4) en una red 3G lenta, emulada a 400ms RTT y 400kbps de velocidad de transferencia.Tenemos dos restricciones principales que dan forma de manera efectiva a un objetivo razonable para la entrega rápida del contenido en la web. Por un lado, tenemos restricciones de entrega de red debido al inicio lento de TCP. Los primeros 14 KB del HTML (10 paquetes TCP, cada uno de 1460 bytes, que suman alrededor de 14,25 KB, aunque no debe tomarse literalmente) es el fragmento de carga útil más crítico y la única parte del presupuesto que se puede entregar en el primer viaje de ida y vuelta ( que es todo lo que obtienes en 1 segundo a 400 ms RTT debido a los tiempos de activación del móvil).
( Nota : como TCP generalmente infrautiliza la conexión de red en una cantidad significativa, Google ha desarrollado TCP Bottleneck Bandwidth and RRT ( BBR ), un algoritmo de control de flujo TCP controlado por retardo. Diseñado para la web moderna, responde a la congestión real, en lugar de pérdida de paquetes como lo hace TCP, es significativamente más rápido, con mayor rendimiento y menor latencia, y el algoritmo funciona de manera diferente ( ¡gracias, Victor, Barry! )
Por otro lado, tenemos restricciones de hardware en la memoria y la CPU debido al análisis de JavaScript y los tiempos de ejecución (hablaremos de ello en detalle más adelante). Para lograr los objetivos establecidos en el primer párrafo, debemos considerar el presupuesto de tamaño de archivo crítico para JavaScript. Las opiniones varían sobre cuál debería ser ese presupuesto (y depende en gran medida de la naturaleza de su proyecto), pero un presupuesto de 170 KB de JavaScript ya comprimido tomaría hasta 1 segundo para analizar y compilar en un teléfono de gama media. Suponiendo que 170 KB se expanda a 3 veces ese tamaño cuando se descomprime (0,7 MB), eso ya podría ser la sentencia de muerte de una experiencia de usuario "decente" en un Moto G4/G5 Plus.
En el caso del sitio web de Wikipedia, en 2020, a nivel mundial, la ejecución del código se ha vuelto un 19 % más rápida para los usuarios de Wikipedia. Por lo tanto, si sus métricas de rendimiento web año tras año se mantienen estables, eso suele ser una señal de advertencia, ya que en realidad está retrocediendo a medida que el entorno sigue mejorando (detalles en una publicación de blog de Gilles Dubuc).
Si desea apuntar a mercados en crecimiento como el Sudeste Asiático, África o India, tendrá que considerar un conjunto muy diferente de limitaciones. Addy Osmani cubre las principales limitaciones de los teléfonos básicos, como pocos dispositivos de alta calidad y bajo costo, la falta de disponibilidad de redes de alta calidad y datos móviles costosos, junto con el presupuesto PRPL-30 y las pautas de desarrollo para estos entornos.
De hecho, Alex Russell de Google recomienda apuntar a 130-170 KB comprimidos con gzip como un límite superior razonable. En escenarios del mundo real, la mayoría de los productos ni siquiera están cerca: el tamaño promedio de un paquete hoy en día es de alrededor de 452 KB, lo que representa un aumento del 53,6 % en comparación con principios de 2015. En un dispositivo móvil de clase media, eso representa entre 12 y 20 segundos para Time -A-Interactivo .
Sin embargo, también podríamos ir más allá del presupuesto del tamaño del paquete. Por ejemplo, podríamos establecer presupuestos de rendimiento en función de las actividades del subproceso principal del navegador, es decir, el tiempo de pintura antes de comenzar a renderizar o rastrear los acaparamientos de CPU de front-end. Herramientas como Calibre, SpeedCurve y Bundlesize pueden ayudarlo a mantener sus presupuestos bajo control y pueden integrarse en su proceso de creación.
Finalmente, un presupuesto de rendimiento probablemente no debería ser un valor fijo . Dependiendo de la conexión de red, los presupuestos de rendimiento deberían adaptarse, pero la carga útil en una conexión más lenta es mucho más "cara", independientemente de cómo se usen.
Nota : Puede sonar extraño establecer presupuestos tan rígidos en tiempos de HTTP/2 generalizado, 5G y HTTP/3 próximos, teléfonos móviles en rápida evolución y SPA florecientes. Sin embargo, suenan razonables cuando nos ocupamos de la naturaleza impredecible de la red y el hardware, que incluye todo, desde redes congestionadas hasta infraestructura de lento desarrollo, límites de datos, navegadores proxy, modo de ahorro de datos y cargos furtivos de roaming.
Definición del entorno
- Elija y configure sus herramientas de compilación.
No prestes demasiada atención a lo que supuestamente está de moda en estos días. Cíñete a tu entorno para construir, ya sea Grunt, Gulp, Webpack, Parcel o una combinación de herramientas. Mientras obtenga los resultados que necesita y no tenga problemas para mantener su proceso de compilación, lo estará haciendo bien.Entre las herramientas de compilación, Rollup sigue ganando terreno, al igual que Snowpack, pero Webpack parece ser la más establecida, con literalmente cientos de complementos disponibles para optimizar el tamaño de sus compilaciones. Esté atento a la hoja de ruta de Webpack 2021.
Una de las estrategias más notables que apareció recientemente es la fragmentación granular con Webpack en Next.js y Gatsby para minimizar el código duplicado. Por defecto, los módulos que no se comparten en todos los puntos de entrada se pueden solicitar para las rutas que no lo utilizan. Esto termina convirtiéndose en una sobrecarga ya que se descarga más código del necesario. Con la fragmentación granular en Next.js, podemos usar un archivo de manifiesto de compilación del lado del servidor para determinar qué fragmentos de salida utilizan los diferentes puntos de entrada.
Con SplitChunksPlugin, se crean varios fragmentos divididos en función de una serie de condiciones para evitar obtener código duplicado en varias rutas. Esto mejora el tiempo de carga de la página y el almacenamiento en caché durante las navegaciones. Enviado en Next.js 9.2 y en Gatsby v2.20.7.
Sin embargo, comenzar con Webpack puede ser difícil. Entonces, si desea sumergirse en Webpack, existen algunos recursos excelentes:
- La documentación de Webpack, obviamente, es un buen punto de partida, al igual que Webpack: The Confusing Bits de Raja Rao y An Annotated Webpack Config de Andrew Welch.
- Sean Larkin tiene un curso gratuito sobre Webpack: The Core Concepts y Jeffrey Way ha lanzado un fantástico curso gratuito sobre Webpack para todos. Ambos son excelentes introducciones para sumergirse en Webpack.
- Webpack Fundamentals es un curso muy completo de 4 horas con Sean Larkin, publicado por FrontendMasters.
- Los ejemplos de Webpack tienen cientos de configuraciones de Webpack listas para usar, clasificadas por tema y propósito. Bonificación: también hay un configurador de configuración de Webpack que genera un archivo de configuración básico.
- awesome-webpack es una lista seleccionada de útiles recursos, bibliotecas y herramientas de Webpack, incluidos artículos, videos, cursos, libros y ejemplos para proyectos Angular, React y sin marco.
- El viaje hacia compilaciones de activos de producción rápida con Webpack es el estudio de caso de Etsy sobre cómo el equipo pasó de usar un sistema de compilación de JavaScript basado en RequireJS a usar Webpack y cómo optimizaron sus compilaciones, administrando más de 13 200 activos en 4 minutos en promedio.
- Los consejos de rendimiento de Webpack son una mina de oro de Ivan Akulov, que presenta muchos consejos centrados en el rendimiento, incluidos los que se centran específicamente en Webpack.
- impresionante-webpack-perf es un repositorio de GitHub de mina de oro con útiles herramientas y complementos de Webpack para el rendimiento. También mantenido por Ivan Akulov.
- Utilice la mejora progresiva como opción predeterminada.
Aun así, después de todos estos años, mantener la mejora progresiva como el principio rector de la implementación y la arquitectura de front-end es una apuesta segura. Primero diseñe y cree la experiencia central y luego mejore la experiencia con funciones avanzadas para navegadores compatibles, creando experiencias resilientes. Si su sitio web se ejecuta rápido en una máquina lenta con una pantalla deficiente en un navegador deficiente en una red subóptima, solo se ejecutará más rápido en una máquina rápida con un buen navegador en una red decente.De hecho, con el servicio de módulos adaptativos, parece que estamos llevando la mejora progresiva a otro nivel, brindando experiencias básicas "ligeras" a dispositivos de gama baja y mejorando con funciones más sofisticadas para dispositivos de gama alta. No es probable que la mejora progresiva desaparezca pronto.
- Elija una base de referencia de rendimiento sólida.
Con tantas incógnitas que afectan la carga: la red, el estrangulamiento térmico, el desalojo de caché, scripts de terceros, patrones de bloqueo del analizador, E/S de disco, latencia de IPC, extensiones instaladas, software antivirus y firewalls, tareas de CPU en segundo plano, restricciones de hardware y memoria, diferencias en el almacenamiento en caché L2/L3, RTTS: JavaScript tiene el costo más alto de la experiencia, junto con las fuentes web que bloquean el procesamiento de forma predeterminada y las imágenes que a menudo consumen demasiada memoria. Con los cuellos de botella de rendimiento alejándose del servidor al cliente, como desarrolladores, tenemos que considerar todas estas incógnitas con mucho más detalle.Con un presupuesto de 170 KB que ya contiene la ruta crítica HTML/CSS/JavaScript, el enrutador, la administración de estado, las utilidades, el marco y la lógica de la aplicación, tenemos que examinar minuciosamente el costo de transferencia de la red, el tiempo de análisis/compilación y el costo del tiempo de ejecución. del marco de nuestra elección. Afortunadamente, hemos visto una gran mejora en los últimos años en la rapidez con la que los navegadores pueden analizar y compilar scripts. Sin embargo, la ejecución de JavaScript sigue siendo el principal cuello de botella, por lo que prestar mucha atención al tiempo de ejecución del script y la red puede tener un impacto.
Tim Kadlec realizó una investigación fantástica sobre el rendimiento de los marcos modernos y los resumió en el artículo "Los marcos de JavaScript tienen un costo". A menudo hablamos sobre el impacto de los marcos independientes, pero como señala Tim, en la práctica, no es raro tener múltiples marcos en uso . Tal vez una versión anterior de jQuery que se está migrando lentamente a un marco moderno, junto con algunas aplicaciones heredadas que usan una versión anterior de Angular. Por lo tanto, es más razonable explorar el costo acumulativo de los bytes de JavaScript y el tiempo de ejecución de la CPU que pueden hacer que las experiencias de los usuarios sean apenas utilizables, incluso en dispositivos de gama alta.
En general, los marcos modernos no dan prioridad a los dispositivos menos potentes , por lo que las experiencias en un teléfono y en una computadora de escritorio a menudo serán dramáticamente diferentes en términos de rendimiento. Según la investigación, los sitios con React o Angular pasan más tiempo en la CPU que otros (lo que, por supuesto, no significa necesariamente que React sea más costoso en la CPU que Vue.js).
Según Tim, una cosa es obvia: "si está utilizando un marco para construir su sitio, está haciendo una compensación en términos de rendimiento inicial , incluso en el mejor de los escenarios".
- Evaluar marcos y dependencias.
Ahora, no todos los proyectos necesitan un marco y no todas las páginas de una aplicación de una sola página necesitan cargar un marco. En el caso de Netflix, "al eliminar React, varias bibliotecas y el código de la aplicación correspondiente del lado del cliente se redujo la cantidad total de JavaScript en más de 200 KB, lo que provocó una reducción de más del 50 % en el tiempo de interactividad de Netflix para la página de inicio sin sesión. ." Luego, el equipo utilizó el tiempo que los usuarios pasaban en la página de destino para precargar React para las páginas posteriores a las que los usuarios probablemente llegarían (siga leyendo para obtener más detalles).Entonces, ¿qué pasa si elimina por completo un marco existente en páginas críticas? Con Gatsby, puede verificar gatsby-plugin-no-javascript que elimina todos los archivos JavaScript creados por Gatsby de los archivos HTML estáticos. En Vercel, también puede permitir la desactivación de JavaScript en tiempo de ejecución en producción para ciertas páginas (experimental).
Una vez que se elige un marco, nos quedaremos con él durante al menos unos años, por lo que si necesitamos usar uno, debemos asegurarnos de que nuestra elección esté informada y bien considerada, y eso se aplica especialmente a las métricas de rendimiento clave que necesitamos. preocuparse.
Los datos muestran que, de forma predeterminada, los marcos son bastante caros: el 58,6 % de las páginas de React envían más de 1 MB de JavaScript, y el 36 % de las cargas de páginas de Vue.js tienen una primera pintura con contenido de <1,5 s. Según un estudio de Ankur Sethi, "su aplicación React nunca se cargará más rápido que aproximadamente 1,1 segundos en un teléfono promedio en la India, sin importar cuánto la optimice. Su aplicación Angular siempre tardará al menos 2,7 segundos en iniciarse. los usuarios de su aplicación Vue deberán esperar al menos 1 segundo antes de poder comenzar a usarla". Es posible que no tenga como objetivo la India como su mercado principal de todos modos, pero los usuarios que accedan a su sitio con condiciones de red subóptimas tendrán una experiencia comparable.
Por supuesto, es posible hacer que los SPA sean rápidos, pero no son rápidos desde el primer momento, por lo que debemos tener en cuenta el tiempo y el esfuerzo necesarios para hacerlos y mantenerlos rápidos. Probablemente será más fácil elegir un costo de rendimiento de referencia ligero desde el principio.
Entonces, ¿cómo elegimos un marco ? Es una buena idea considerar al menos el costo total del tamaño + los tiempos iniciales de ejecución antes de elegir una opción; las opciones ligeras como Preact, Inferno, Vue, Svelte, Alpine o Polymer pueden hacer el trabajo perfectamente. El tamaño de su línea base definirá las restricciones para el código de su aplicación.
Como señaló Seb Markbage, una buena manera de medir los costos iniciales de los marcos es primero renderizar una vista, luego eliminarla y luego volver a renderizar, ya que puede indicarle cómo se escala el marco. El primer renderizado tiende a calentar un montón de código compilado perezosamente, del cual un árbol más grande puede beneficiarse cuando escala. El segundo renderizado es básicamente una emulación de cómo la reutilización del código en una página afecta las características de rendimiento a medida que la página crece en complejidad.
Puede ir tan lejos como para evaluar a sus candidatos (o cualquier biblioteca de JavaScript en general) en el sistema de puntuación de escala de 12 puntos de Sacha Greif explorando características, accesibilidad, estabilidad, rendimiento, ecosistema de paquetes , comunidad, curva de aprendizaje, documentación, herramientas, historial , equipo, compatibilidad, seguridad por ejemplo.
También puede confiar en los datos recopilados en la web durante un período de tiempo más largo. Por ejemplo, Perf Track realiza un seguimiento del rendimiento del marco a escala, mostrando puntuaciones de Core Web Vitals agregadas por origen para sitios web creados en Angular, React, Vue, Polymer, Preact, Ember, Svelte y AMP. Incluso puede especificar y comparar sitios web creados con Gatsby, Next.js o Create React App, así como sitios web creados con Nuxt.js (Vue) o Sapper (Svelte).
Un buen punto de partida es elegir una buena pila predeterminada para su aplicación. Gatsby (React), Next.js (React), Vuepress (Vue), Preact CLI y PWA Starter Kit proporcionan valores predeterminados razonables para una carga rápida lista para usar en hardware móvil promedio. Además, eche un vistazo a la guía de rendimiento específica del marco web.dev para React y Angular ( ¡gracias, Phillip! ).
Y tal vez podría adoptar un enfoque un poco más refrescante para crear aplicaciones de una sola página: Turbolinks, una biblioteca de JavaScript de 15 KB que usa HTML en lugar de JSON para representar las vistas. Entonces, cuando sigue un enlace, Turbolinks busca automáticamente la página, intercambia su
<body>
y fusiona su<head>
, todo sin incurrir en el costo de una carga completa de la página. Puede consultar detalles rápidos y documentación completa sobre la pila (Hotwire).
- ¿Representación del lado del cliente o representación del lado del servidor? ¡Ambas cosas!
Esa es una conversación bastante acalorada. El enfoque final sería configurar algún tipo de arranque progresivo: use la representación del lado del servidor para obtener una primera pintura con contenido rápida, pero también incluya un mínimo de JavaScript necesario para mantener el tiempo de interacción cerca de la primera pintura con contenido. Si JavaScript llega demasiado tarde después del FCP, el navegador bloqueará el hilo principal mientras analiza, compila y ejecuta JavaScript descubierto tarde, por lo tanto, limita la interactividad del sitio o la aplicación.Para evitarlo, siempre divida la ejecución de funciones en tareas asíncronas separadas y, cuando sea posible, use
requestIdleCallback
. Considere la carga diferida de partes de la interfaz de usuario utilizando el soporte deimport()
de WebPack, evitando el costo de carga, análisis y compilación hasta que los usuarios realmente los necesiten ( ¡gracias Addy! ).Como se mencionó anteriormente, Time to Interactive (TTI) nos dice el tiempo entre la navegación y la interactividad. En detalle, la métrica se define mirando la primera ventana de cinco segundos después de que se representa el contenido inicial, en la que ninguna tarea de JavaScript tarda más de 50 ms ( Tareas largas ). Si se produce una tarea de más de 50 ms, la búsqueda de una ventana de cinco segundos comienza de nuevo. Como resultado, el navegador primero asumirá que llegó a Interactive , solo para cambiar a Frozen , solo para eventualmente volver a cambiar a Interactive .
Una vez que llegamos a Interactivo , podemos, ya sea a pedido o según lo permita el tiempo, iniciar partes no esenciales de la aplicación. Desafortunadamente, como notó Paul Lewis, los marcos generalmente no tienen un concepto simple de prioridad que se pueda mostrar a los desarrolladores y, por lo tanto, el arranque progresivo no es fácil de implementar con la mayoría de las bibliotecas y marcos.
Aún así, estamos llegando allí. En estos días hay un par de opciones que podemos explorar, y Houssein Djirdeh y Jason Miller brindan una excelente descripción general de estas opciones en su charla sobre Rendering on the Web y el artículo de Jason y Addy sobre Modern Front-End Architectures. La descripción general a continuación se basa en su trabajo estelar.
- Representación completa del lado del servidor (SSR)
En SSR clásico, como WordPress, todas las solicitudes se manejan completamente en el servidor. El contenido solicitado se devuelve como una página HTML terminada y los navegadores pueden procesarlo de inmediato. Por lo tanto, las aplicaciones SSR no pueden realmente hacer uso de las API DOM, por ejemplo. La brecha entre First Contentful Paint y Time to Interactive suele ser pequeña, y la página se puede representar de inmediato a medida que HTML se transmite al navegador.Esto evita viajes de ida y vuelta adicionales para obtener datos y crear plantillas en el cliente, ya que se maneja antes de que el navegador obtenga una respuesta. Sin embargo, terminamos con un tiempo de reflexión del servidor más largo y, en consecuencia, Tiempo hasta el primer byte y no hacemos uso de las características ricas y receptivas de las aplicaciones modernas.
- Representación estática
Creamos el producto como una aplicación de una sola página, pero todas las páginas se procesan previamente en HTML estático con JavaScript mínimo como paso de creación. Eso significa que con el renderizado estático, producimos archivos HTML individuales para cada URL posible con anticipación, algo que no muchas aplicaciones pueden permitirse. Pero debido a que el código HTML de una página no tiene que generarse sobre la marcha, podemos lograr un tiempo hasta el primer byte consistentemente rápido. Por lo tanto, podemos mostrar una página de destino rápidamente y luego precargar un marco SPA para las páginas posteriores. Netflix ha adoptado este enfoque para reducir la carga y el tiempo de interacción en un 50 %. - Renderización del lado del servidor con (re)hidratación (representación universal, SSR + CSR)
Podemos tratar de usar lo mejor de ambos mundos: los enfoques SSR y CSR. Con la hidratación en la mezcla, la página HTML devuelta por el servidor también contiene un script que carga una aplicación completa del lado del cliente. Idealmente, eso logra una primera pintura con contenido rápida (como SSR) y luego continúa renderizando con (re) hidratación. Desafortunadamente, ese es raramente el caso. Más a menudo, la página parece lista pero no puede responder a la entrada del usuario, lo que produce clics de rabia y abandonos.Con React, podemos usar el módulo
ReactDOMServer
en un servidor Node como Express y luego llamar al métodorenderToString
para representar los componentes de nivel superior como una cadena HTML estática.Con Vue.js, podemos usar vue-server-renderer para representar una instancia de Vue en HTML usando
renderToString
. En Angular, podemos usar@nguniversal
para convertir las solicitudes de los clientes en páginas HTML totalmente procesadas por el servidor. También se puede lograr una experiencia completamente renderizada en el servidor desde el primer momento con Next.js (React) o Nuxt.js (Vue).El enfoque tiene sus desventajas. Como resultado, obtenemos una flexibilidad total de las aplicaciones del lado del cliente al mismo tiempo que brindamos una representación más rápida del lado del servidor, pero también terminamos con una brecha más larga entre la primera pintura con contenido y el tiempo para la interacción y un mayor retraso de la primera entrada. La rehidratación es muy costosa y, por lo general, esta estrategia por sí sola no será lo suficientemente buena, ya que retrasa mucho el tiempo de interacción.
- Streaming del lado del servidor con hidratación progresiva (SSR + CSR)
Para minimizar la brecha entre Time To Interactive y First Contentful Paint, procesamos varias solicitudes a la vez y enviamos contenido en fragmentos a medida que se generan. Por lo tanto, no tenemos que esperar la cadena completa de HTML antes de enviar contenido al navegador y, por lo tanto, mejorar el tiempo hasta el primer byte.En React, en lugar de
renderToString()
, podemos usar renderToNodeStream() para canalizar la respuesta y enviar el HTML en fragmentos. En Vue, podemos usar renderToStream() que se puede canalizar y transmitir. Con React Suspense, también podríamos usar el renderizado asíncrono para ese propósito.En el lado del cliente, en lugar de iniciar toda la aplicación a la vez, iniciamos los componentes progresivamente . Las secciones de las aplicaciones se dividen primero en secuencias de comandos independientes con división de código y luego se hidratan gradualmente (en orden de nuestras prioridades). De hecho, podemos hidratar los componentes críticos primero, mientras que el resto podría hidratarse más tarde. La función de representación del lado del cliente y del lado del servidor se puede definir de manera diferente por componente. Luego, también podemos diferir la hidratación de algunos componentes hasta que estén a la vista, o sean necesarios para la interacción del usuario, o cuando el navegador esté inactivo.
Para Vue, Markus Oberlehner ha publicado una guía sobre cómo reducir el tiempo de interacción de las aplicaciones SSR utilizando la hidratación en la interacción del usuario, así como vue-lazy-hydration, un complemento de etapa inicial que permite la hidratación de los componentes en la visibilidad o la interacción específica del usuario. El equipo de Angular trabaja en la hidratación progresiva con Ivy Universal. También puede implementar la hidratación parcial con Preact y Next.js.
- Representación trisomórfica
Con los trabajadores del servicio en su lugar, podemos usar la representación del servidor de transmisión para navegaciones iniciales/no JS, y luego hacer que el trabajador del servicio asuma la representación de HTML para las navegaciones después de que se haya instalado. En ese caso, el trabajador del servicio renderiza previamente el contenido y habilita las navegaciones de estilo SPA para renderizar nuevas vistas en la misma sesión. Funciona bien cuando puede compartir la misma plantilla y código de enrutamiento entre el servidor, la página del cliente y el trabajador del servicio.
- CSR con representación previa
La renderización previa es similar a la renderización del lado del servidor, pero en lugar de renderizar páginas en el servidor dinámicamente, renderizamos la aplicación en HTML estático en el momento de la compilación. Si bien las páginas estáticas son completamente interactivas sin mucho JavaScript del lado del cliente, la representación previa funciona de manera diferente . Básicamente, captura el estado inicial de una aplicación del lado del cliente como HTML estático en el momento de la compilación, mientras que con la representación previa, la aplicación debe iniciarse en el cliente para que las páginas sean interactivas.Con Next.js, podemos usar la exportación de HTML estático prerenderizando una aplicación en HTML estático. En Gatsby, un generador de sitios estáticos de código abierto que usa React, usa el método
renderToStaticMarkup
en lugar del métodorenderToString
durante las compilaciones, con el fragmento JS principal precargado y las rutas futuras precargadas, sin atributos DOM que no son necesarios para páginas estáticas simples.Para Vue, podemos usar Vuepress para lograr el mismo objetivo. También puede usar prerender-loader con Webpack. Navi también proporciona renderizado estático.
El resultado es un mejor tiempo para el primer byte y la primera pintura con contenido, y reducimos la brecha entre el tiempo para la interacción y la primera pintura con contenido. No podemos usar el enfoque si se espera que el contenido cambie mucho. Además, todas las URL deben conocerse con anticipación para generar todas las páginas. Por lo tanto, algunos componentes pueden renderizarse mediante renderizado previo, pero si necesitamos algo dinámico, tenemos que confiar en la aplicación para obtener el contenido.
- Representación completa del lado del cliente (CSR)
Toda la lógica, el renderizado y el arranque se realizan en el cliente. El resultado suele ser una gran brecha entre Time To Interactive y First Contentful Paint. Como resultado, las aplicaciones a menudo se sienten lentas , ya que toda la aplicación debe iniciarse en el cliente para generar cualquier cosa.Como JavaScript tiene un costo de rendimiento, a medida que la cantidad de JavaScript crece con una aplicación, la división de código agresiva y el aplazamiento de JavaScript serán absolutamente necesarios para controlar el impacto de JavaScript. Para tales casos, una representación del lado del servidor generalmente será un mejor enfoque en caso de que no se requiera mucha interactividad. Si no es una opción, considere usar The App Shell Model.
En general, SSR es más rápido que CSR. Sin embargo, es una implementación bastante frecuente para muchas aplicaciones.
Entonces, ¿del lado del cliente o del lado del servidor? En general, es una buena idea limitar el uso de marcos completamente del lado del cliente a páginas que los requieran absolutamente. Para aplicaciones avanzadas, tampoco es una buena idea confiar solo en el renderizado del lado del servidor. Tanto la representación del servidor como la representación del cliente son un desastre si se hacen mal.
Ya sea que se incline por CSR o SSR, asegúrese de renderizar los píxeles importantes lo antes posible y minimice la brecha entre ese renderizado y el tiempo de interacción. Considere la posibilidad de renderizar previamente si sus páginas no cambian mucho, y posponga el inicio de los marcos si puede. Transmita HTML en fragmentos con renderizado del lado del servidor e implemente una hidratación progresiva para el renderizado del lado del cliente, e hidrátese en la visibilidad, la interacción o durante el tiempo de inactividad para obtener lo mejor de ambos mundos.
- Representación completa del lado del servidor (SSR)
- ¿Cuánto podemos servir de forma estática?
Ya sea que esté trabajando en una aplicación grande o en un sitio pequeño, vale la pena considerar qué contenido podría servirse estáticamente desde un CDN (es decir, JAM Stack), en lugar de generarse dinámicamente sobre la marcha. Incluso si tiene miles de productos y cientos de filtros con muchas opciones de personalización, es posible que desee publicar sus páginas de destino críticas de forma estática y desvincular estas páginas del marco de su elección.Hay muchos generadores de sitios estáticos y las páginas que generan suelen ser muy rápidas. Cuanto más contenido podamos preconstruir con anticipación en lugar de generar vistas de página en un servidor o cliente en el momento de la solicitud, mejor rendimiento lograremos.
En Creación de sitios web estáticos parcialmente hidratados y mejorados progresivamente, Markus Oberlehner muestra cómo crear sitios web con un generador de sitios estáticos y un SPA, mientras se logra una mejora progresiva y un tamaño mínimo de paquete de JavaScript. Markus usa Eleventy y Preact como sus herramientas y muestra cómo configurar las herramientas, agregar hidratación parcial, hidratación perezosa, archivo de entrada del cliente, configurar Babel para Preact y agrupar Preact con Rollup, de principio a fin.
Con el uso de JAMStack en sitios grandes en estos días, apareció una nueva consideración de rendimiento: el tiempo de compilación . De hecho, crear incluso miles de páginas con cada nueva implementación puede llevar minutos, por lo que promete ver compilaciones incrementales en Gatsby que mejoran los tiempos de compilación en 60 veces , con una integración en soluciones de CMS populares como WordPress, Contentful, Drupal, Netlify CMS. y otros.
Además, Next.js anunció la generación estática incremental y anticipada, lo que nos permite agregar nuevas páginas estáticas en tiempo de ejecución y actualizar las páginas existentes después de que ya se hayan creado, volviéndolas a renderizar en segundo plano a medida que ingresa el tráfico. .
¿Necesita un enfoque aún más ligero? En su charla sobre Eleventy, Alpine y Tailwind: Hacia un Jamstack liviano, Nicola Goutay explica las diferencias entre CSR, SSR y todo lo demás, y muestra cómo usar un enfoque más liviano, junto con un repositorio de GitHub que muestra el enfoque. en la práctica.
- Considere usar el patrón PRPL y la arquitectura de shell de la aplicación.
Diferentes marcos tendrán diferentes efectos en el rendimiento y requerirán diferentes estrategias de optimización, por lo que debe comprender claramente todos los aspectos básicos del marco en el que confiará. Al crear una aplicación web, observe el patrón PRPL y la arquitectura de shell de la aplicación. La idea es bastante sencilla: presione el código mínimo necesario para que la ruta inicial se vuelva interactiva y se procese rápidamente, luego use el trabajador de servicio para almacenar en caché y almacenar previamente en caché los recursos y luego cargue las rutas que necesita, de forma asíncrona.
- ¿Ha optimizado el rendimiento de sus API?
Las API son canales de comunicación para que una aplicación exponga datos a aplicaciones internas y de terceros a través de puntos finales . Al diseñar y construir una API, necesitamos un protocolo razonable para permitir la comunicación entre el servidor y las solicitudes de terceros. La transferencia de estado representacional ( REST ) es una opción lógica y bien establecida: define un conjunto de restricciones que los desarrolladores siguen para hacer que el contenido sea accesible de manera eficiente, confiable y escalable. Los servicios web que se ajustan a las restricciones REST se denominan servicios web RESTful .Al igual que con las buenas solicitudes HTTP, cuando los datos se recuperan de una API, cualquier retraso en la respuesta del servidor se propagará al usuario final, lo que retrasará la representación . Cuando un recurso quiere recuperar algunos datos de una API, deberá solicitar los datos del punto final correspondiente. Un componente que representa datos de varios recursos, como un artículo con comentarios y fotos del autor en cada comentario, puede necesitar varios viajes de ida y vuelta al servidor para obtener todos los datos antes de poder procesarlos. Además, la cantidad de datos devueltos a través de REST suele ser mayor de lo que se necesita para representar ese componente.
Si muchos recursos requieren datos de una API, la API podría convertirse en un cuello de botella de rendimiento. GraphQL proporciona una solución eficaz para estos problemas. En sí, GraphQL es un lenguaje de consulta para su API y un tiempo de ejecución del lado del servidor para ejecutar consultas mediante el uso de un sistema de tipos que defina para sus datos. A diferencia de REST, GraphQL puede recuperar todos los datos en una sola solicitud , y la respuesta será exactamente lo que se requiere, sin obtener más o menos datos como suele suceder con REST.
Además, debido a que GraphQL usa un esquema (metadatos que indican cómo se estructuran los datos), ya puede organizar los datos en la estructura preferida, por lo que, por ejemplo, con GraphQL, podríamos eliminar el código JavaScript que se usa para manejar la administración del estado, produciendo un código de aplicación más limpio que se ejecuta más rápido en el cliente.
Si desea comenzar con GraphQL o tiene problemas de rendimiento, estos artículos pueden ser muy útiles:
- Introducción a GraphQL: Por qué necesitamos un nuevo tipo de API por Eric Baer,
- Introducción a GraphQL: la evolución del diseño de API por Eric Baer,
- Diseño de un servidor GraphQL para un rendimiento óptimo por Leonardo Losoviz,
- Rendimiento de GraphQL explicado por Wojciech Trocki.
- ¿Usarás AMP o artículos instantáneos?
Según las prioridades y la estrategia de su organización, es posible que desee considerar el uso de AMP de Google, Instant Articles de Facebook o Apple News de Apple. Puede lograr un buen rendimiento sin ellos, pero AMP proporciona un marco de rendimiento sólido con una red de entrega de contenido (CDN) gratuita , mientras que los artículos instantáneos aumentarán su visibilidad y rendimiento en Facebook.El beneficio aparentemente obvio de estas tecnologías para los usuarios es el rendimiento garantizado , por lo que a veces incluso pueden preferir enlaces AMP-/Apple News/Instant Pages-en lugar de páginas "normales" y potencialmente infladas. Para los sitios web con mucho contenido que manejan una gran cantidad de contenido de terceros, estas opciones podrían ayudar a acelerar drásticamente los tiempos de procesamiento.
A menos que no lo hagan. Según Tim Kadlec, por ejemplo, "los documentos AMP tienden a ser más rápidos que sus contrapartes, pero eso no significa necesariamente que una página tenga un buen rendimiento. AMP no es lo que marca la mayor diferencia desde la perspectiva del rendimiento".
Un beneficio para el propietario del sitio web es obvio: la visibilidad de estos formatos en sus respectivas plataformas y una mayor visibilidad en los motores de búsqueda.
Bueno, al menos así solía ser. Como AMP ya no es un requisito para Top Stories , los editores podrían estar pasando de AMP a una pila tradicional ( ¡gracias, Barry! ).
Aún así, también podría crear AMP web progresivos reutilizando AMP como fuente de datos para su PWA. ¿Abajo? Obviamente, una presencia en un jardín amurallado coloca a los desarrolladores en posición de producir y mantener una versión separada de su contenido, y en el caso de Instant Articles y Apple News sin URL reales (¡gracias Addy, Jeremy!) .
- Elija sabiamente su CDN.
Como se mencionó anteriormente, dependiendo de la cantidad de datos dinámicos que tenga, es posible que pueda "subcontratar" una parte del contenido a un generador de sitios estáticos, empujándolo a un CDN y sirviendo una versión estática desde él, evitando así solicitudes al servidor. De hecho, algunos de esos generadores son en realidad compiladores de sitios web con muchas optimizaciones automáticas provistas de fábrica. A medida que los compiladores agregan optimizaciones con el tiempo, la salida compilada se vuelve más pequeña y más rápida con el tiempo.Tenga en cuenta que las CDN también pueden servir (y descargar) contenido dinámico. Por lo tanto, no es necesario restringir su CDN a activos estáticos. Vuelva a verificar si su CDN realiza compresión y conversión (p. ej., optimización de imágenes y cambio de tamaño en el borde), si brinda soporte para trabajadores de servidores, pruebas A/B, así como también incluye el lado del borde, que ensambla partes estáticas y dinámicas de las páginas. en el borde de la CDN (es decir, el servidor más cercano al usuario) y otras tareas. Además, verifique si su CDN es compatible con HTTP sobre QUIC (HTTP/3).
Katie Hempenius ha escrito una guía fantástica sobre las CDN que brinda información sobre cómo elegir una buena CDN , cómo ajustarla y todos los pequeños detalles que se deben tener en cuenta al evaluar una. En general, es una buena idea almacenar en caché el contenido de la forma más agresiva posible y habilitar funciones de rendimiento de CDN como Brotli, TLS 1.3, HTTP/2 y HTTP/3.
Nota : según la investigación de Patrick Meenan y Andy Davies, la priorización de HTTP/2 se rompe de manera efectiva en muchas CDN, así que tenga cuidado al elegir una CDN. Patrick tiene más detalles en su charla sobre Priorización de HTTP/2 ( ¡gracias, Barry! ).
Al elegir un CDN, puede utilizar estos sitios de comparación con una descripción detallada de sus características:
- Comparación de CDN, una matriz de comparación de CDN para Cloudfront, Aazure, KeyCDN, Fastly, Verizon, Stackpach, Akamai y muchos otros.
- CDN Perf mide la velocidad de consulta de CDN recopilando y analizando 300 millones de pruebas todos los días, con todos los resultados basados en datos RUM de usuarios de todo el mundo. Consulte también la Comparación de rendimiento de DNS y la Comparación de rendimiento de la nube.
- CDN Planet Guides proporciona una descripción general de las CDN para temas específicos, como Servicio obsoleto, Purga, Escudo de origen, Prefetch y Compresión.
- Web Almanac: Adopción y uso de CDN brinda información sobre los principales proveedores de CDN, su administración de RTT y TLS, el tiempo de negociación de TLS, la adopción de HTTP/2 y otros. (Lamentablemente, los datos son solo de 2019).
Optimizaciones de activos
- Utilice Brotli para la compresión de texto sin formato.
En 2015, Google presentó Brotli, un nuevo formato de datos sin pérdidas de código abierto, que ahora es compatible con todos los navegadores modernos. La biblioteca Brotli de código abierto, que implementa un codificador y decodificador para Brotli, tiene 11 niveles de calidad predefinidos para el codificador, con un nivel de calidad más alto que exige más CPU a cambio de una mejor relación de compresión. Una compresión más lenta conducirá en última instancia a tasas de compresión más altas, pero aún así, Brotli se descomprime rápidamente. Sin embargo, vale la pena señalar que Brotli con el nivel de compresión 4 es más pequeño y se comprime más rápido que Gzip.En la práctica, Brotli parece ser mucho más efectivo que Gzip. Las opiniones y las experiencias difieren, pero si su sitio ya está optimizado con Gzip, es posible que espere mejoras de al menos un dígito y, en el mejor de los casos, mejoras de dos dígitos en la reducción de tamaño y los tiempos de FCP. También puede estimar los ahorros de compresión de Brotli para su sitio.
Los navegadores aceptarán Brotli solo si el usuario visita un sitio web a través de HTTPS. Brotli es ampliamente compatible y muchas CDN lo admiten (Akamai, Netlify Edge, AWS, KeyCDN, Fastly (actualmente solo como transferencia), Cloudflare, CDN77) y puede habilitar Brotli incluso en CDN que aún no lo admiten. (con un trabajador de servicio).
El problema es que debido a que comprimir todos los activos con Brotli a un alto nivel de compresión es costoso, muchos proveedores de alojamiento no pueden usarlo a gran escala solo por el enorme costo que genera. De hecho, en el nivel más alto de compresión, Brotli es tan lento que cualquier ganancia potencial en el tamaño del archivo podría verse anulada por la cantidad de tiempo que le toma al servidor comenzar a enviar la respuesta mientras espera para comprimir dinámicamente el activo. (Pero si tiene tiempo durante el tiempo de compilación con compresión estática, por supuesto, se prefieren configuraciones de compresión más altas).
Aunque esto podría estar cambiando. El formato de archivo Brotli incluye un diccionario estático incorporado y, además de contener varias cadenas en varios idiomas, también admite la opción de aplicar múltiples transformaciones a esas palabras, lo que aumenta su versatilidad. En su investigación, Felix Hanau ha descubierto una manera de mejorar la compresión en los niveles 5 a 9 usando "un subconjunto más especializado del diccionario que el predeterminado" y confiando en el encabezado
Content-Type
para decirle al compresor si debe usar un diccionario para HTML, JavaScript o CSS. El resultado fue un "impacto insignificante en el rendimiento (1 % a 3 % más de CPU en comparación con el 12 % normal) al comprimir contenido web a altos niveles de compresión, utilizando un enfoque de uso de diccionario limitado".Además de eso, con la investigación de Elena Kirilenko, podemos lograr una recompresión de Brotli rápida y eficiente utilizando artefactos de compresión anteriores. Según Elena, "una vez que tenemos un activo comprimido a través de Brotli, y tratamos de comprimir contenido dinámico sobre la marcha, donde el contenido se parece al contenido disponible para nosotros con anticipación, podemos lograr mejoras significativas en los tiempos de compresión. "
¿Con qué frecuencia es el caso? Por ejemplo, con la entrega de subconjuntos de paquetes de JavaScript (por ejemplo, cuando partes del código ya están almacenadas en caché en el cliente o con paquetes dinámicos sirviendo con WebBundles). O con HTML dinámico basado en plantillas conocidas de antemano, o fuentes WOFF2 subdivididas dinámicamente . Según Elena, podemos obtener una mejora del 5,3 % en la compresión y una mejora del 39 % en la velocidad de compresión al eliminar el 10 % del contenido, y un 3,2 % de mejores tasas de compresión y una compresión un 26 % más rápida, al eliminar el 50 % del contenido.
La compresión de Brotli está mejorando, por lo que si puede evitar el costo de comprimir dinámicamente los activos estáticos, definitivamente vale la pena el esfuerzo. No hace falta decir que Brotli se puede usar para cualquier carga útil de texto sin formato: HTML, CSS, SVG, JavaScript, JSON, etc.
Nota : a principios de 2021, aproximadamente el 60 % de las respuestas HTTP se envían sin compresión basada en texto, con un 30,82 % comprimiendo con Gzip y un 9,1 % comprimiendo con Brotli (tanto en dispositivos móviles como en computadoras de escritorio). Por ejemplo, el 23,4 % de las páginas de Angular no están comprimidas (a través de gzip o Brotli). Sin embargo, a menudo activar la compresión es una de las victorias más fáciles para mejorar el rendimiento con solo presionar un interruptor.
¿La estrategia? Comprima previamente los activos estáticos con Brotli+Gzip en el nivel más alto y comprima HTML (dinámico) sobre la marcha con Brotli en el nivel 4–6. Asegúrese de que el servidor maneje la negociación de contenido para Brotli o Gzip correctamente.
- ¿Utilizamos la carga de medios adaptativos y sugerencias de clientes?
Viene de la tierra de las noticias antiguas, pero siempre es un buen recordatorio para usar imágenes receptivas consrcset
,sizes
y el elemento<picture>
. Especialmente para los sitios con una gran huella de medios, podemos ir un paso más allá con la carga de medios adaptativa (en este ejemplo, React + Next.js), brindando una experiencia liviana para redes lentas y dispositivos con poca memoria y una experiencia completa para redes rápidas y alta. -dispositivos de memoria. En el contexto de React, podemos lograrlo con sugerencias de clientes en el servidor y ganchos adaptativos de reacción en el cliente.El futuro de las imágenes receptivas podría cambiar drásticamente con la adopción más amplia de las sugerencias de los clientes. Las sugerencias del cliente son campos de encabezado de solicitud HTTP, por ejemplo,
DPR
,Viewport-Width
,Width
,Save-Data
,Accept
(para especificar preferencias de formato de imagen) y otros. Se supone que deben informar al servidor sobre los detalles del navegador, la pantalla, la conexión, etc. del usuario.Como resultado, el servidor puede decidir cómo completar el diseño con imágenes del tamaño adecuado y servir solo estas imágenes en los formatos deseados. Con las sugerencias del cliente, movemos la selección de recursos del marcado HTML a la negociación de solicitud-respuesta entre el cliente y el servidor.
Como señaló Ilya Grigorik hace un tiempo, las sugerencias de los clientes completan la imagen: no son una alternativa a las imágenes receptivas. "El elemento
<picture>
proporciona el control de dirección de arte necesario en el marcado HTML. Las sugerencias del cliente proporcionan anotaciones en las solicitudes de imágenes resultantes que permiten la automatización de la selección de recursos. Service Worker proporciona capacidades completas de gestión de solicitudes y respuestas en el cliente".Un trabajador de servicio podría, por ejemplo, agregar nuevos valores de encabezados de sugerencias de clientes a la solicitud, reescribir la URL y apuntar la solicitud de imagen a un CDN, adaptar la respuesta en función de la conectividad y las preferencias del usuario, etc. para casi todas las demás solicitudes también.
Para los clientes que admiten sugerencias de clientes, se podría medir un 42 % de ahorro de bytes en imágenes y 1 MB+ menos de bytes para el percentil 70+. En Smashing Magazine, también pudimos medir una mejora del 19 al 32 %. Las sugerencias de clientes son compatibles con los navegadores basados en Chromium, pero aún se están considerando en Firefox.
Sin embargo, si proporciona tanto el marcado de imágenes receptivas normales como la etiqueta
<meta>
para Client Hints, entonces un navegador compatible evaluará el marcado de imágenes receptivas y solicitará la fuente de imagen adecuada utilizando los encabezados HTTP de Client Hints. - ¿Usamos imágenes receptivas para las imágenes de fondo?
¡Seguramente deberíamos! Conimage-set
, ahora compatible con Safari 14 y con la mayoría de los navegadores modernos excepto Firefox, también podemos ofrecer imágenes de fondo receptivas:background-image: url("fallback.jpg"); background-image: image-set( "photo-small.jpg" 1x, "photo-large.jpg" 2x, "photo-print.jpg" 600dpi);
Básicamente, podemos servir de forma condicional imágenes de fondo de baja resolución con un descriptor de
1x
e imágenes de mayor resolución con un descriptor de2x
, e incluso una imagen de calidad de impresión con un descriptor de600dpi
. Sin embargo, tenga cuidado: los navegadores no brindan ninguna información especial sobre las imágenes de fondo para la tecnología de asistencia, por lo que, idealmente, estas fotos serían meramente decorativas. - ¿Usamos WebP?
La compresión de imágenes a menudo se considera una ganancia rápida, sin embargo, todavía está muy infrautilizada en la práctica. Por supuesto, las imágenes no bloquean el renderizado, pero contribuyen en gran medida a las bajas puntuaciones de LCP y, muy a menudo, son demasiado pesadas y demasiado grandes para el dispositivo en el que se consumen.Entonces, como mínimo, podríamos explorar el uso del formato WebP para nuestras imágenes. De hecho, la saga WebP estuvo llegando a su fin el año pasado cuando Apple agregó soporte para WebP en Safari 14. Entonces, después de muchos años de discusiones y debates, a partir de hoy, WebP es compatible con todos los navegadores modernos. Por lo tanto, podemos servir imágenes WebP con el elemento
<picture>
y un respaldo JPEG si es necesario (consulte el fragmento de código de Andreas Bovens) o mediante la negociación de contenido (usando encabezados deAccept
).Sin embargo, WebP no está exento de inconvenientes . Si bien los tamaños de archivo de imagen de WebP se comparan con Guetzli y Zopfli equivalentes, el formato no es compatible con la representación progresiva como JPEG, por lo que los usuarios pueden ver la imagen terminada más rápido con un buen JPEG, aunque las imágenes de WebP pueden ser más rápidas a través de la red. Con JPEG, podemos ofrecer una experiencia de usuario "decente" con la mitad o incluso la cuarta parte de los datos y cargar el resto más tarde, en lugar de tener una imagen medio vacía como en el caso de WebP.
Su decisión dependerá de lo que esté buscando: con WebP, reducirá la carga útil y con JPEG mejorará el rendimiento percibido. Puede obtener más información sobre WebP en WebP Rewind talk de Pascal Massimino de Google.
Para la conversión a WebP, puede usar WebP Converter, cwebp o libwebp. Ire Aderinokun también tiene un tutorial muy detallado sobre cómo convertir imágenes a WebP, al igual que Josh Comeau en su artículo sobre la adopción de formatos de imagen modernos.
Sketch es compatible de forma nativa con WebP, y las imágenes de WebP se pueden exportar desde Photoshop utilizando un complemento de WebP para Photoshop. Pero también hay otras opciones disponibles.
Si está utilizando WordPress o Joomla, existen extensiones para ayudarlo a implementar fácilmente la compatibilidad con WebP, como Optimus y Cache Enabler para WordPress y la propia extensión compatible de Joomla (a través de Cody Arsenault). También puede abstraer el elemento
<picture>
con React, componentes con estilo o gatsby-image.¡Ah, enchufe desvergonzado! — Jeremy Wagner incluso publicó un libro Smashing sobre WebP que tal vez desee consultar si está interesado en todo lo relacionado con WebP.
- ¿Utilizamos AVIF?
Es posible que haya escuchado la gran noticia: AVIF ha aterrizado. Es un nuevo formato de imagen derivado de los fotogramas clave del video AV1. Es un formato abierto y libre de regalías que admite compresión con pérdida y sin pérdida, animación, canal alfa con pérdida y puede manejar líneas nítidas y colores sólidos (que era un problema con JPEG), al tiempo que proporciona mejores resultados en ambos.De hecho, en comparación con WebP y JPEG, AVIF funciona significativamente mejor , lo que genera un ahorro de tamaño de archivo promedio de hasta un 50 % con el mismo DSSIM ((des)similitud entre dos o más imágenes usando un algoritmo que se aproxima a la visión humana). De hecho, en su publicación completa sobre la optimización de la carga de imágenes, Malte Ubl señala que AVIF "supera consistentemente a JPEG de una manera muy significativa. Esto es diferente de WebP, que no siempre produce imágenes más pequeñas que JPEG y en realidad puede ser una red. pérdida por falta de apoyo para la carga progresiva".
Irónicamente, AVIF puede funcionar incluso mejor que los SVG grandes, aunque, por supuesto, no debe verse como un reemplazo de los SVG. También es uno de los primeros formatos de imagen que admite soporte de color HDR; ofreciendo mayor brillo, profundidad de bits de color y gamas de colores. El único inconveniente es que actualmente AVIF no admite la decodificación progresiva de imágenes (¿todavía?) y, de manera similar a Brotli, una codificación de alta tasa de compresión actualmente es bastante lenta, aunque la decodificación es rápida.
Actualmente, AVIF es compatible con Chrome, Firefox y Opera, y se espera que pronto sea compatible con Safari (ya que Apple es miembro del grupo que creó AV1).
Entonces, ¿cuál es la mejor manera de publicar imágenes en estos días ? Para ilustraciones e imágenes vectoriales, SVG (comprimido) es sin duda la mejor opción. Para las fotos, usamos métodos de negociación de contenido con el elemento de
picture
. Si se admite AVIF, enviamos una imagen AVIF; si no es el caso, primero recurrimos a WebP, y si WebP tampoco es compatible, cambiamos a JPEG o PNG como respaldo (aplicando las condiciones de@media
si es necesario):<picture> <source type="image/avif"> <source type="image/webp"> <img src="image.jpg" alt="Photo" width="450" height="350"> </picture>
Francamente, es más probable que usemos algunas condiciones dentro del elemento de
picture
:<picture> <source type="image/avif" /> <source type="image/webp" /> <source type="image/jpeg" /> <img src="fallback-image.jpg" alt="Photo" width="450" height="350"> </picture>
<picture> <source type="image/avif" /> <source type="image/webp" /> <source type="image/jpeg" /> <img src="fallback-image.jpg" alt="Photo" width="450" height="350"> </picture>
Puede ir aún más lejos intercambiando imágenes animadas con imágenes estáticas para los clientes que optan por menos movimiento con movimiento
prefers-reduced-motion
:<picture> <source media="(prefers-reduced-motion: reduce)" type="image/avif"></source> <source media="(prefers-reduced-motion: reduce)" type="image/jpeg"></source> <source type="image/avif"></source> <img src="motion.jpg" alt="Animated AVIF"> </picture>
<picture> <source media="(prefers-reduced-motion: reduce)" type="image/avif"></source> <source media="(prefers-reduced-motion: reduce)" type="image/jpeg"></source> <source type="image/avif"></source> <img src="motion.jpg" alt="Animated AVIF"> </picture>
Durante el par de meses, AVIF ha ganado bastante tracción:
- Podemos probar los respaldos de WebP/AVIF en el panel Rendering en DevTools.
- Podemos usar Squoosh, AVIF.io y libavif para codificar, decodificar, comprimir y convertir archivos AVIF.
- Podemos usar el componente AVIF Preact de Jake Archibald que decodifica un archivo AVIF en un trabajador y muestra el resultado en un lienzo,
- Para entregar AVIF solo a navegadores compatibles, podemos usar un complemento PostCSS junto con un script 315B para usar AVIF en sus declaraciones CSS.
- Podemos entregar progresivamente nuevos formatos de imagen con CSS y Cloudlare Workers para modificar dinámicamente el documento HTML devuelto, deducir información del encabezado de
accept
y luego agregar laswebp/avif
, etc., según corresponda. - AVIF ya está disponible en Cloudinary (con límites de uso), Cloudflare admite AVIF en el cambio de tamaño de imagen y puede habilitar AVIF con encabezados AVIF personalizados en Netlify.
- Cuando se trata de animación, AVIF funciona tan bien como
<img src=mp4>
de Safari, superando a GIF y WebP en general, pero MP4 aún funciona mejor. - En general, para animaciones, AVC1 (h264) > HVC1 > WebP > AVIF > GIF, suponiendo que los navegadores basados en Chromium alguna vez admitirán
<img src=mp4>
. - Puede encontrar más detalles sobre AVIF en AVIF para la charla de codificación de imágenes de próxima generación de Aditya Mavlankar de Netflix, y la charla de The AVIF Image Format de Kornel Lesinski de Cloudflare.
- Una gran referencia para todo lo relacionado con AVIF: ha llegado la publicación completa de Jake Archibald sobre AVIF.
¿Entonces es el futuro AVIF ? Jon Sneyers no está de acuerdo: AVIF funciona un 60 % peor que JPEG XL, otro formato gratuito y abierto desarrollado por Google y Cloudinary. De hecho, JPEG XL parece estar funcionando mucho mejor en todos los ámbitos. Sin embargo, JPEG XL aún se encuentra en las etapas finales de estandarización y aún no funciona en ningún navegador. (No se mezcle con el JPEG-XR de Microsoft que viene del buen Internet Explorer 9 veces).
- ¿Están JPEG/PNG/SVG correctamente optimizados?
Cuando esté trabajando en una página de destino en la que es fundamental que una imagen destacada se cargue ultrarrápidamente, asegúrese de que los archivos JPEG sean progresivos y estén comprimidos con mozJPEG (que mejora el tiempo de inicio de procesamiento al manipular los niveles de escaneo) o Guetzli, el código abierto de Google. codificador centrado en el rendimiento perceptivo y utilizando aprendizajes de Zopfli y WebP. El único inconveniente: tiempos de procesamiento lentos (un minuto de CPU por megapíxel).Para PNG, podemos usar Pingo y para SVG, podemos usar SVGO o SVGOMG. Y si necesita obtener una vista previa y copiar o descargar rápidamente todos los activos SVG de un sitio web, svg-grabber también puede hacerlo por usted.
Cada artículo de optimización de imágenes lo indicaría, pero siempre vale la pena mencionar mantener los activos vectoriales limpios y ajustados. Asegúrese de limpiar los activos no utilizados, elimine los metadatos innecesarios y reduzca la cantidad de puntos de ruta en las ilustraciones (y, por lo tanto, en el código SVG). ( ¡Gracias, Jeremy! )
Sin embargo, también hay herramientas útiles en línea disponibles:
- Use Squoosh para comprimir, cambiar el tamaño y manipular imágenes en los niveles de compresión óptimos (con pérdida o sin pérdida),
- Use Guetzli.it para comprimir y optimizar imágenes JPEG con Guetzli, que funciona bien para imágenes con bordes nítidos y colores sólidos (pero puede ser un poco más lento).
- Utilice el Generador de puntos de interrupción de imágenes sensibles o un servicio como Cloudinary o Imgix para automatizar la optimización de imágenes. Además, en muchos casos, el uso exclusivo de
srcset
ysizes
generará beneficios significativos. - Para verificar la eficiencia de su marcado receptivo, puede usar el montón de imágenes, una herramienta de línea de comandos que mide la eficiencia en los tamaños de ventana gráfica y las proporciones de píxeles del dispositivo.
- Puede agregar compresión automática de imágenes a sus flujos de trabajo de GitHub, de modo que ninguna imagen llegue a la producción sin comprimir. La acción usa mozjpeg y libvips que funcionan con PNG y JPG.
- Para optimizar el almacenamiento de forma interna, puede usar el nuevo formato Lepton de Dropbox para comprimir archivos JPEG sin pérdidas en un promedio del 22 %.
- Use BlurHash si desea mostrar una imagen de marcador de posición antes. BlurHash toma una imagen y le da una cadena corta (¡solo 20-30 caracteres!) que representa el marcador de posición para esta imagen. La cadena es lo suficientemente corta como para que se pueda agregar fácilmente como un campo en un objeto JSON.
A veces, la optimización de imágenes por sí sola no es suficiente. Para mejorar el tiempo necesario para iniciar la renderización de una imagen crítica, cargue de forma diferida las imágenes menos importantes y posponga la carga de cualquier script después de que las imágenes críticas ya se hayan renderizado. La forma más segura es la carga diferida híbrida, cuando utilizamos carga diferida nativa y carga diferida, una biblioteca que detecta cualquier cambio de visibilidad desencadenado a través de la interacción del usuario (con IntersectionObserver, que exploraremos más adelante). Adicionalmente:
- Considere precargar imágenes críticas, para que un navegador no las descubra demasiado tarde. Para las imágenes de fondo, si desea ser aún más agresivo que eso, puede agregar la imagen como una imagen normal con
<img src>
y luego ocultarla de la pantalla. - Considere intercambiar imágenes con el atributo de tamaños especificando diferentes dimensiones de visualización de imágenes según las consultas de medios, por ejemplo, para manipular
sizes
para intercambiar fuentes en un componente de lupa. - Revise las inconsistencias en la descarga de imágenes para evitar descargas inesperadas de imágenes de primer plano y de fondo. Tenga cuidado con las imágenes que se cargan de forma predeterminada, pero es posible que nunca se muestren, por ejemplo, en carruseles, acordeones y galerías de imágenes.
- Asegúrese de establecer siempre el
width
y elheight
en las imágenes. Tenga cuidado con la propiedadaspect-ratio
en CSS y el atributo de tamañointrinsicsize
que nos permitirá establecer relaciones de aspecto y dimensiones para las imágenes, de modo que el navegador pueda reservar un espacio de diseño predefinido con anticipación para evitar saltos de diseño durante la carga de la página.
Si se siente aventurero, puede cortar y reorganizar las transmisiones HTTP/2 utilizando trabajadores de Edge, básicamente un filtro en tiempo real que vive en la CDN, para enviar imágenes más rápido a través de la red. Los trabajadores de borde usan flujos de JavaScript que usan fragmentos que puede controlar (básicamente, son JavaScript que se ejecuta en el borde de CDN que puede modificar las respuestas de transmisión), por lo que puede controlar la entrega de imágenes.
Con un trabajador de servicio, es demasiado tarde ya que no puede controlar lo que está en el cable, pero funciona con los trabajadores de Edge. Por lo tanto, puede usarlos sobre archivos JPEG estáticos guardados progresivamente para una página de destino en particular.
¿No es suficiente? Bueno, también puede mejorar el rendimiento percibido de las imágenes con la técnica de múltiples imágenes de fondo. Tenga en cuenta que jugar con el contraste y difuminar detalles innecesarios (o eliminar colores) también puede reducir el tamaño del archivo. Ah, ¿necesitas ampliar una foto pequeña sin perder calidad? Considere usar Letsenhance.io.
Estas optimizaciones hasta ahora cubren solo lo básico. Addy Osmani ha publicado una guía muy detallada sobre la optimización esencial de imágenes que profundiza en los detalles de la compresión de imágenes y la gestión del color. Por ejemplo, podría desenfocar partes innecesarias de la imagen (aplicándoles un filtro de desenfoque gaussiano) para reducir el tamaño del archivo y, eventualmente, incluso podría comenzar a eliminar colores o convertir la imagen en blanco y negro para reducir aún más el tamaño. . Para las imágenes de fondo, exportar fotos de Photoshop con una calidad del 0 al 10 % también puede ser absolutamente aceptable.
En Smashing Magazine, usamos el sufijo
-opt
para nombres de imágenes, por ejemplo,brotli-compression-opt.png
; cada vez que una imagen contiene ese sufijo, todos en el equipo saben que la imagen ya ha sido optimizada.Ah, y no use JPEG-XR en la web: "el procesamiento de decodificación de JPEG-XR del lado del software en la CPU anula e incluso supera el impacto potencialmente positivo del ahorro de tamaño de bytes, especialmente en el contexto de SPA" (no mezclarse con Cloudinary/Google's JPEG XL).
- ¿Los videos están correctamente optimizados?
Cubrimos las imágenes hasta ahora, pero hemos evitado una conversación sobre buenos GIF. A pesar de nuestro amor por los GIF, es realmente el momento de abandonarlos para siempre (al menos en nuestros sitios web y aplicaciones). En lugar de cargar GIF animados pesados que afectan tanto el rendimiento de la representación como el ancho de banda, es una buena idea cambiar a WebP animado (con GIF como alternativa) o reemplazarlos con videos HTML5 en bucle.A diferencia de las imágenes, los navegadores no precargan el contenido de
<video>
, pero los videos HTML5 tienden a ser mucho más livianos y pequeños que los GIF. ¿No es una opción? Bueno, al menos podemos agregar compresión con pérdida a los GIF con Lossy GIF, gifsicle o giflossy.Las pruebas realizadas por Colin Bendell muestran que los videos en línea dentro de las etiquetas
img
en Safari Technology Preview se muestran al menos 20 veces más rápido y se decodifican 7 veces más rápido que el equivalente GIF, además de tener una fracción del tamaño del archivo. Sin embargo, no es compatible con otros navegadores.En la tierra de las buenas noticias, los formatos de video han avanzado enormemente a lo largo de los años. Durante mucho tiempo, esperábamos que WebM se convirtiera en el formato para gobernarlos a todos, y WebP (que es básicamente una imagen fija dentro del contenedor de video WebM) se convertirá en un reemplazo para los formatos de imagen fechados. De hecho, Safari ahora es compatible con WebP, pero a pesar de que WebP y WebM obtuvieron soporte en estos días, el avance realmente no sucedió.
Aún así, podríamos usar WebM para la mayoría de los navegadores modernos:
<!-- By Houssein Djirdeh. https://web.dev/replace-gifs-with-videos/ --> <!-- A common scenartio: MP4 with a WEBM fallback. --> <video autoplay loop muted playsinline> <source src="my-animation.webm" type="video/webm"> <source src="my-animation.mp4" type="video/mp4"> </video>
Pero tal vez podríamos revisarlo por completo. En 2018, Alliance of Open Media lanzó un nuevo formato de video prometedor llamado AV1 . AV1 tiene una compresión similar al códec H.265 (la evolución de H.264) pero a diferencia de este último, AV1 es gratuito. El precio de la licencia H.265 empujó a los proveedores de navegadores a adoptar un AV1 con un rendimiento comparable: AV1 (al igual que H.265) se comprime el doble de bien que WebM .
De hecho, Apple actualmente usa el formato HEIF y HEVC (H.265), y todas las fotos y videos en el último iOS se guardan en estos formatos, no en JPEG. Si bien HEIF y HEVC (H.265) no están correctamente expuestos a la web (¿todavía?), AV1 sí lo está, y está ganando compatibilidad con los navegadores. Por lo tanto, agregar la fuente
AV1
en su etiqueta<video>
es razonable, ya que todos los proveedores de navegadores parecen estar de acuerdo.Por ahora, la codificación más utilizada y admitida es H.264, proporcionada por archivos MP4, por lo tanto, antes de entregar el archivo, asegúrese de que sus MP4 se procesen con una codificación multipaso, borrosa con el efecto frei0r iirblur (si corresponde) y Los metadatos de moov atom se mueven al encabezado del archivo, mientras que su servidor acepta el servicio de bytes. Boris Schapira proporciona instrucciones exactas para que FFmpeg optimice los videos al máximo. Por supuesto, proporcionar el formato WebM como alternativa también ayudaría.
¿Necesita comenzar a renderizar videos más rápido pero los archivos de video aún son demasiado grandes ? Por ejemplo, ¿siempre que tenga un video de fondo grande en una página de destino? Una técnica común que se usa es mostrar el primer cuadro primero como una imagen fija, o mostrar un segmento de bucle corto muy optimizado que podría interpretarse como parte del video y luego, cuando el video esté lo suficientemente almacenado en el búfer, comience a reproducirse. el vídeo real. Doug Sillars tiene una guía escrita detallada para el rendimiento de video de fondo que podría ser útil en ese caso. ( ¡Gracias, Guy Podjarny! ).
Para el escenario anterior, es posible que desee proporcionar imágenes de póster receptivas . De forma predeterminada, los elementos de
video
solo permiten una imagen como póster, lo que no es necesariamente óptimo. Podemos usar Responsive Video Poster, una biblioteca de JavaScript que le permite usar diferentes imágenes de póster para diferentes pantallas, al tiempo que agrega una superposición de transición y un control de estilo completo de los marcadores de posición de video.La investigación muestra que la calidad de la transmisión de video afecta el comportamiento del espectador. De hecho, los espectadores comienzan a abandonar el video si el retraso en el inicio supera los 2 segundos. Más allá de ese punto, un aumento de 1 segundo en la demora da como resultado un aumento de aproximadamente el 5,8 % en la tasa de abandono. Por lo tanto, no sorprende que la mediana del tiempo de inicio del video sea de 12,8 s, con un 40 % de videos que tienen al menos 1 detención y un 20 % de al menos 2 s de reproducción de video detenida. De hecho, las paradas de video son inevitables en 3G ya que los videos se reproducen más rápido de lo que la red puede proporcionar contenido.
Entonces, ¿cuál es la solución? Por lo general, los dispositivos de pantalla pequeña no pueden manejar los 720p y 1080p que estamos sirviendo en el escritorio. Según Doug Sillars, podemos crear versiones más pequeñas de nuestros videos y usar Javascript para detectar la fuente en pantallas más pequeñas para garantizar una reproducción rápida y fluida en estos dispositivos. Alternativamente, podemos usar la transmisión de video. Las transmisiones de video HLS entregarán un video de tamaño adecuado al dispositivo, lo que elimina la necesidad de crear diferentes videos para diferentes pantallas. También negociará la velocidad de la red y adaptará la tasa de bits del video a la velocidad de la red que está utilizando.
Para evitar el desperdicio de ancho de banda, solo podríamos agregar la fuente de video para dispositivos que realmente puedan reproducir bien el video. Alternativamente, podemos eliminar el atributo de
autoplay
de la etiqueta devideo
por completo y usar JavaScript para insertarautoplay
para pantallas más grandes. Además, debemos agregarpreload="none"
en elvideo
para decirle al navegador que no descargue ninguno de los archivos de video hasta que realmente necesite el archivo:<!-- Based on Doug Sillars's post. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ --> <video preload="none" playsinline muted loop width="1920" height="1080" poster="poster.jpg"> <source src="video.webm" type="video/webm"> <source src="video.mp4" type="video/mp4"> </video>
Entonces podemos apuntar específicamente a los navegadores que realmente son compatibles con AV1:
<!-- Based on Doug Sillars's post. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ --> <video preload="none" playsinline muted loop width="1920" height="1080" poster="poster.jpg"> <source src="video.av1.mp4" type="video/mp4; codecs=av01.0.05M.08"> <source src="video.hevc.mp4" type="video/mp4; codecs=hevc"> <source src="video.webm" type="video/webm"> <source src="video.mp4" type="video/mp4"> </video>
Entonces podríamos volver a agregar la
autoplay
sobre un cierto umbral (por ejemplo, 1000px):/* By Doug Sillars. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ */ <script> window.onload = addAutoplay(); var videoLocation = document.getElementById("hero-video"); function addAutoplay() { if(window.innerWidth > 1000){ videoLocation.setAttribute("autoplay",""); }; } </script>
El rendimiento de la reproducción de video es una historia en sí misma, y si desea profundizar en ella en detalle, eche un vistazo a otra serie de Doug Sillars sobre el estado actual del video y las mejores prácticas de entrega de video que incluyen detalles sobre las métricas de entrega de video. , precarga de video, compresión y transmisión. Finalmente, puede verificar qué tan lenta o rápida será su transmisión de video con Stream or Not.
- ¿Está optimizada la entrega de fuentes web?
La primera pregunta que vale la pena hacer es si podemos utilizar las fuentes del sistema de interfaz de usuario en primer lugar; solo debemos asegurarnos de verificar que aparezcan correctamente en varias plataformas. Si no es el caso, es muy probable que las fuentes web que servimos incluyan glifos y características y pesos adicionales que no se están utilizando. Podemos pedirle a nuestra fundición tipográfica que cree subconjuntos de fuentes web o, si usamos fuentes de código abierto, subconjuntos por nuestra cuenta con Glyphhanger o Fontsquirrel. Incluso podemos automatizar todo nuestro flujo de trabajo con la subfuente de Peter Muller, una herramienta de línea de comandos que analiza estáticamente su página para generar los subconjuntos de fuentes web más óptimos y luego inyectarlos en nuestras páginas.La compatibilidad con WOFF2 es excelente, y podemos usar WOFF como respaldo para los navegadores que no lo admiten, o quizás los navegadores heredados podrían recibir fuentes del sistema. Hay muchas, muchas, muchas opciones para la carga de fuentes web, y podemos elegir una de las estrategias de la "Guía completa de estrategias de carga de fuentes" de Zach Leatherman (fragmentos de código también disponibles como recetas de carga de fuentes web).
Probablemente, las mejores opciones a considerar hoy en día son Critical FOFT con
preload
y el método "The Compromise". Ambos usan un renderizado de dos etapas para entregar fuentes web en pasos: primero se requiere un pequeño supersubconjunto para renderizar la página de forma rápida y precisa con la fuente web, y luego cargar el resto de la familia de forma asíncrona. La diferencia es que la técnica "The Compromise" carga el polyfill de forma asincrónica solo si los eventos de carga de fuentes no son compatibles, por lo que no necesita cargar el polyfill de forma predeterminada. ¿Necesitas una victoria rápida? Zach Leatherman tiene un tutorial rápido de 23 minutos y un estudio de caso para ordenar sus fuentes.En general, podría ser una buena idea usar la sugerencia de recursos de
preload
para precargar las fuentes, pero en su marcado incluya las sugerencias después del enlace a CSS y JavaScript críticos. Con lapreload
, hay un rompecabezas de prioridades, así que considere inyectar elementosrel="preload"
en el DOM justo antes de los scripts de bloqueo externos. Según Andy Davies, "los recursos inyectados mediante un script se ocultan del navegador hasta que se ejecuta el script, y podemos usar este comportamiento para demorar cuando el navegador descubre la sugerencia depreload
". De lo contrario, la carga de fuentes le costará en el primer tiempo de renderizado.Es una buena idea ser selectivo y elegir los archivos que más importan, por ejemplo, los que son críticos para la representación o que le ayudarían a evitar reflujos de texto visibles y perturbadores. En general, Zach aconseja precargar una o dos fuentes de cada familia ; también tiene sentido retrasar la carga de algunas fuentes si son menos críticas.
Se ha vuelto bastante común usar el valor
local()
(que se refiere a una fuente local por su nombre) al definir unafont-family
de fuentes en la regla@font-face
:/* Warning! Not a good idea! */ @font-face { font-family: Open Sans; src: local('Open Sans Regular'), local('OpenSans-Regular'), url('opensans.woff2') format ('woff2'), url('opensans.woff') format('woff'); }
La idea es razonable: algunas fuentes populares de código abierto como Open Sans vienen preinstaladas con algunos controladores o aplicaciones, por lo que si la fuente está disponible localmente, el navegador no necesita descargar la fuente web y puede mostrar la fuente local. fuente inmediatamente. Como señaló Bram Stein, "aunque una fuente local coincida con el nombre de una fuente web, lo más probable es que no sea la misma fuente . Muchas fuentes web difieren de su versión de "escritorio". volviendo a otras fuentes, las características de OpenType pueden faltar por completo o la altura de la línea puede ser diferente".
Además, a medida que los tipos de letra evolucionan con el tiempo, la versión instalada localmente puede ser muy diferente de la fuente web, con caracteres que se ven muy diferentes. Entonces, según Bram, es mejor nunca mezclar fuentes instaladas localmente y fuentes web en las reglas
@font-face
. Google Fonts hizo lo mismo al deshabilitarlocal()
en los resultados de CSS para todos los usuarios, excepto las solicitudes de Android para Roboto.A nadie le gusta esperar a que se muestre el contenido. Con el descriptor CSS
font-display
, podemos controlar el comportamiento de carga de la fuente y permitir que el contenido se pueda leer inmediatamente (confont-display: optional
) o casi inmediatamente (con un tiempo de espera de 3 s, siempre que la fuente se descargue correctamente, confont-display: swap
). (Bueno, es un poco más complicado que eso).Sin embargo, si desea minimizar el impacto de los reflujos de texto, podemos usar la API de carga de fuentes (compatible con todos los navegadores modernos). Específicamente, eso significa que para cada fuente, crearíamos un objeto
FontFace
, luego intentaríamos obtenerlos todos y solo luego los aplicaríamos a la página. De esta manera, agrupamos todos los repintados cargando todas las fuentes de forma asincrónica y luego cambiamos de las fuentes alternativas a la fuente web exactamente una vez. Eche un vistazo a la explicación de Zach, a partir de las 32:15, y al fragmento de código):/* Load two web fonts using JavaScript */ /* Zach Leatherman: https://noti.st/zachleat/KNaZEg/the-five-whys-of-web-font-loading-performance#sWkN4u4 */ // Remove existing @font-face blocks // Create two let font = new FontFace("Noto Serif", /* ... */); let fontBold = new FontFace("Noto Serif, /* ... */); // Load two fonts let fonts = await Promise.all([ font.load(), fontBold.load() ]) // Group repaints and render both fonts at the same time! fonts.forEach(font => documents.fonts.add(font));
/* Load two web fonts using JavaScript */ /* Zach Leatherman: https://noti.st/zachleat/KNaZEg/the-five-whys-of-web-font-loading-performance#sWkN4u4 */ // Remove existing @font-face blocks // Create two let font = new FontFace("Noto Serif", /* ... */); let fontBold = new FontFace("Noto Serif, /* ... */); // Load two fonts let fonts = await Promise.all([ font.load(), fontBold.load() ]) // Group repaints and render both fonts at the same time! fonts.forEach(font => documents.fonts.add(font));
Para iniciar una recuperación muy temprana de las fuentes con la API de carga de fuentes en uso, Adrian Bece sugiere agregar un espacio sin interrupciones
nbsp;
en la parte superior delbody
y ocultarlo visualmente conaria-visibility: hidden
y una clase.hidden
:<body class="no-js"> <!-- ... Website content ... --> <div aria-visibility="hidden" class="hidden"> <!-- There is a non-breaking space here --> </div> <script> document.getElementsByTagName("body")[0].classList.remove("no-js"); </script> </body>
<body class="no-js"> <!-- ... Website content ... --> <div aria-visibility="hidden" class="hidden"> <!-- There is a non-breaking space here --> </div> <script> document.getElementsByTagName("body")[0].classList.remove("no-js"); </script> </body>
Esto va junto con CSS que tiene diferentes familias de fuentes declaradas para diferentes estados de carga, con el cambio activado por la API de carga de fuentes una vez que las fuentes se han cargado correctamente:
body:not(.wf-merriweather--loaded):not(.no-js) { font-family: [fallback-system-font]; /* Fallback font styles */ } .wf-merriweather--loaded, .no-js { font-family: "[web-font-name]"; /* Webfont styles */ } /* Accessible hiding */ .hidden { position: absolute; overflow: hidden; clip: rect(0 0 0 0); height: 1px; width: 1px; margin: -1px; padding: 0; border: 0; }
body:not(.wf-merriweather--loaded):not(.no-js) { font-family: [fallback-system-font]; /* Fallback font styles */ } .wf-merriweather--loaded, .no-js { font-family: "[web-font-name]"; /* Webfont styles */ } /* Accessible hiding */ .hidden { position: absolute; overflow: hidden; clip: rect(0 0 0 0); height: 1px; width: 1px; margin: -1px; padding: 0; border: 0; }
Si alguna vez se preguntó por qué, a pesar de todas sus optimizaciones, Lighthouse aún sugiere eliminar los recursos de bloqueo de procesamiento (fuentes), en el mismo artículo, Adrian Bece proporciona algunas técnicas para hacer feliz a Lighthouse, junto con Gatsby Omni Font Loader, una fuente asincrónica de alto rendimiento. Carga y complemento de manejo de Flash Of Unstyled Text (FOUT) para Gatsby.
Ahora, muchos de nosotros podríamos estar usando un CDN o un host de terceros para cargar fuentes web. En general, siempre es mejor autoalojar todos sus recursos estáticos si puede, así que considere usar google-webfonts-helper, una forma sencilla de autohospedar Google Fonts. Y si no es posible, quizás pueda enviar los archivos de fuentes de Google a través del origen de la página.
Sin embargo, vale la pena señalar que Google está trabajando bastante desde el primer momento, por lo que un servidor podría necesitar algunos ajustes para evitar retrasos ( ¡gracias, Barry! )
Esto es bastante importante, especialmente porque desde Chrome v86 (lanzado en octubre de 2020), los recursos entre sitios, como las fuentes, ya no se pueden compartir en la misma CDN, debido a la memoria caché del navegador dividida. Este comportamiento fue predeterminado en Safari durante años.
Pero si no es posible en absoluto, hay una manera de obtener las fuentes de Google más rápidas posibles con el fragmento de código de Harry Roberts:
<!-- By Harry Roberts. https://csswizardry.com/2020/05/the-fastest-google-fonts/ - 1. Preemptively warm up the fonts' origin. - 2. Initiate a high-priority, asynchronous fetch for the CSS file. Works in - most modern browsers. - 3. Initiate a low-priority, asynchronous fetch that gets applied to the page - only after it's arrived. Works in all browsers with JavaScript enabled. - 4. In the unlikely event that a visitor has intentionally disabled - JavaScript, fall back to the original method. The good news is that, - although this is a render-blocking request, it can still make use of the - preconnect which makes it marginally faster than the default. --> <!-- [1] --> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <!-- [2] --> <link rel="preload" as="style" href="$CSS&display=swap" /> <!-- [3] --> <link rel="stylesheet" href="$CSS&display=swap" media="print" onload="this.media='all'" /> <!-- [4] --> <noscript> <link rel="stylesheet" href="$CSS&display=swap" /> </noscript>
La estrategia de Harry es calentar primero de forma preventiva el origen de las fuentes. Luego iniciamos una búsqueda asincrónica de alta prioridad para el archivo CSS. Luego, iniciamos una recuperación asincrónica de baja prioridad que se aplica a la página solo después de que llega (con un truco de hoja de estilo de impresión). Finalmente, si JavaScript no es compatible, recurrimos al método original.
Ah, hablando de Google Fonts: puede reducir hasta el 90 % del tamaño de las solicitudes de Google Fonts declarando solo los caracteres que necesita con
&text
. Además, la compatibilidad con la visualización de fuentes también se agregó recientemente a Google Fonts, por lo que podemos usarla de forma inmediata.Sin embargo, una breve advertencia. Si usa
font-display: optional
, podría ser subóptimo usar también lapreload
, ya que activará esa solicitud de fuente web antes (causando congestión en la red si tiene otros recursos de ruta crítica que deben recuperarse). Utilice lapreconnect
para solicitudes de fuentes de origen cruzado más rápidas, pero tenga cuidado con lapreload
, ya que la precarga de fuentes de un origen diferente provocará conflictos en la red. Todas estas técnicas están cubiertas en las recetas de carga de fuentes web de Zach.Por otro lado, podría ser una buena idea excluirse de las fuentes web (o al menos el renderizado de segunda etapa) si el usuario ha habilitado Reducir movimiento en las preferencias de accesibilidad o ha optado por el Modo de ahorro de datos (consulte el encabezado
Save-Data
) , o cuando el usuario tiene una conectividad lenta (a través de la API de información de red).También podemos usar la consulta de medios CSS
prefers-reduced-data
para no definir declaraciones de fuente si el usuario ha optado por el modo de ahorro de datos (también hay otros casos de uso). La consulta de medios básicamente expondría si el encabezado de la solicitudSave-Data
de la extensión HTTP Client Hint está activado/desactivado para permitir el uso con CSS. Actualmente solo se admite en Chrome y Edge detrás de una bandera.¿Métrica? Para medir el rendimiento de carga de la fuente web, considere la métrica Todo el texto visible (el momento en que todas las fuentes se han cargado y todo el contenido se muestra en las fuentes web), el Tiempo para la cursiva real y el Conteo de flujo de fuente web después del primer renderizado. Obviamente, cuanto más bajas sean ambas métricas, mejor será el rendimiento.
¿Qué pasa con las fuentes variables , podrías preguntar? Es importante tener en cuenta que las fuentes variables pueden requerir una consideración de rendimiento significativa. Nos brindan un espacio de diseño mucho más amplio para las opciones tipográficas, pero tiene el costo de una sola solicitud en serie en lugar de varias solicitudes de archivos individuales.
Si bien las fuentes variables reducen drásticamente el tamaño de archivo combinado general de los archivos de fuentes, esa única solicitud puede ser lenta y bloquear la representación de todo el contenido de una página. Por lo tanto, subdividir y dividir la fuente en conjuntos de caracteres sigue siendo importante. Sin embargo, en el lado bueno, con una fuente variable en su lugar, obtendremos exactamente un reflujo por defecto, por lo que no se requerirá JavaScript para agrupar repintados.
Ahora, ¿qué haría entonces una estrategia de carga de fuentes web a prueba de balas ? Crea subconjuntos de fuentes y prepáralas para el renderizado en 2 etapas, decláralas con un descriptor
font-display
, usa la API de carga de fuentes para agrupar repintados y almacenar fuentes en la memoria caché de un trabajador de servicio persistente. En la primera visita, inyecte la precarga de scripts justo antes de los scripts externos de bloqueo. Si es necesario, puede recurrir al Font Face Observer de Bram Stein. Y si está interesado en medir el rendimiento de la carga de fuentes, Andreas Marschke explora el seguimiento del rendimiento con Font API y UserTiming API.Por último, no se olvide de incluir
unicode-range
para dividir una fuente grande en fuentes más pequeñas específicas del idioma, y use el comparador de estilo de fuente de Monica Dinculescu para minimizar un cambio discordante en el diseño, debido a las discrepancias de tamaño entre el respaldo y el fuentes webAlternativamente, para emular una fuente web para una fuente alternativa, podemos usar los descriptores @font-face para anular las métricas de fuente (demostración, habilitado en Chrome 87). (Tenga en cuenta que los ajustes son complicados con pilas de fuentes complicadas).
¿El futuro parece brillante? Con el enriquecimiento progresivo de la fuente, eventualmente podríamos "descargar solo la parte requerida de la fuente en cualquier página dada, y para las solicitudes posteriores de esa fuente para 'parchar' dinámicamente la descarga original con conjuntos adicionales de glifos según sea necesario en la página sucesiva". puntos de vista", como explica Jason Pamental. La demostración de transferencia incremental ya está disponible y está en proceso.
Optimizaciones de compilación
- ¿Hemos definido nuestras prioridades?
Es una buena idea saber con qué estás tratando primero. Ejecute un inventario de todos sus activos (JavaScript, imágenes, fuentes, scripts de terceros y módulos "caros" en la página, como carruseles, infografías complejas y contenido multimedia), y divídalos en grupos.Configura una hoja de cálculo . Defina la experiencia central básica para navegadores heredados (es decir, contenido central completamente accesible), la experiencia mejorada para navegadores capaces (es decir, una experiencia completa y enriquecida) y los extras (activos que no son absolutamente necesarios y pueden cargarse de forma diferida, como fuentes web, estilos innecesarios, scripts de carrusel, reproductores de video, widgets de redes sociales, imágenes grandes). Hace años, publicamos un artículo sobre "Mejorar el rendimiento de la revista Smashing", que describe este enfoque en detalle.
Al optimizar el rendimiento, debemos reflejar nuestras prioridades. Cargue la experiencia principal de inmediato, luego las mejoras y luego los extras .
- ¿Utiliza módulos JavaScript nativos en producción?
¿Recuerda la buena técnica clásica para enviar la experiencia principal a los navegadores heredados y una experiencia mejorada a los navegadores modernos? Una variante actualizada de la técnica podría usar ES2017+<script type="module">
, también conocido como patrón de módulo/no módulo (también presentado por Jeremy Wagner como servicio diferencial ).La idea es compilar y servir dos paquetes de JavaScript separados : la compilación "normal", la que tiene transformaciones de Babel y rellenos polivalentes y servirlos solo a los navegadores heredados que realmente los necesitan, y otro paquete (la misma funcionalidad) que no tiene transformaciones o polirellenos.
Como resultado, ayudamos a reducir el bloqueo del hilo principal al reducir la cantidad de secuencias de comandos que el navegador necesita procesar. Jeremy Wagner ha publicado un artículo completo sobre el servicio diferencial y cómo configurarlo en su canal de compilación, desde la configuración de Babel hasta los ajustes que deberá realizar en Webpack, además de los beneficios de hacer todo este trabajo.
Las secuencias de comandos del módulo de JavaScript nativo se difieren de forma predeterminada, por lo que mientras se realiza el análisis de HTML, el navegador descargará el módulo principal.
Sin embargo, una nota de advertencia: el patrón de módulo/no módulo puede fracasar en algunos clientes, por lo que es posible que desee considerar una solución alternativa: el patrón de servicio diferencial menos riesgoso de Jeremy que, sin embargo, elude el escáner de precarga, lo que podría afectar el rendimiento de maneras que uno no podría prever. ( ¡gracias, Jeremy! )
De hecho, Rollup admite módulos como formato de salida, por lo que podemos empaquetar código e implementar módulos en producción. Parcel tiene soporte para módulos en Parcel 2. Para Webpack, module-nomodule-plugin automatiza la generación de scripts de módulo/nomodule.
Nota : vale la pena señalar que la detección de funciones por sí sola no es suficiente para tomar una decisión informada sobre la carga útil que se enviará a ese navegador. Por sí solo, no podemos deducir la capacidad del dispositivo de la versión del navegador. Por ejemplo, los teléfonos Android baratos en los países en desarrollo en su mayoría ejecutan Chrome y cortarán la mostaza a pesar de sus capacidades limitadas de memoria y CPU.
Eventualmente, usando el encabezado de sugerencias de cliente de memoria del dispositivo, podremos apuntar a dispositivos de gama baja de manera más confiable. Al momento de escribir, el encabezado solo se admite en Blink (se aplica a las sugerencias del cliente en general). Dado que Device Memory también tiene una API de JavaScript que está disponible en Chrome, una opción podría ser la función de detección basada en la API y recurrir al patrón de módulo/sin módulo si no es compatible ( ¡gracias, Yoav! ).
- ¿Está utilizando la sacudida de árboles, el levantamiento de alcance y la división de códigos?
Tree-shaking es una forma de limpiar su proceso de compilación al incluir solo el código que realmente se usa en producción y eliminar las importaciones no utilizadas en Webpack. Con Webpack y Rollup, también tenemos elevación de alcance que permite que ambas herramientas detecten dónde se puede aplanar el encadenamiento deimport
y convertirlo en una función en línea sin comprometer el código. Con Webpack, también podemos usar JSON Tree Shaking.La división de código es otra característica de Webpack que divide su base de código en "trozos" que se cargan a pedido. No es necesario descargar, analizar y compilar todo el JavaScript de inmediato. Una vez que defina los puntos de división en su código, Webpack puede encargarse de las dependencias y los archivos de salida. Le permite mantener pequeña la descarga inicial y solicitar código a pedido cuando lo solicite la aplicación. Alexander Kondrov tiene una fantástica introducción a la división de código con Webpack y React.
Considere usar preload-webpack-plugin que toma las rutas que divide en código y luego solicita al navegador que las cargue previamente usando
<link rel="preload">
o<link rel="prefetch">
. Las directivas en línea de Webpack también brindan cierto control sobre lapreload
/prefetch
. (Sin embargo, tenga cuidado con los problemas de priorización).¿Dónde definir los puntos de división? Mediante el seguimiento de qué fragmentos de CSS/JavaScript se utilizan y cuáles no. Umar Hansa explica cómo puede usar Code Coverage de Devtools para lograrlo.
Cuando se trata de aplicaciones de una sola página, necesitamos algo de tiempo para inicializar la aplicación antes de poder renderizar la página. Su configuración requerirá su solución personalizada, pero puede estar atento a los módulos y técnicas para acelerar el tiempo de renderizado inicial. Por ejemplo, aquí se explica cómo depurar el rendimiento de React y eliminar problemas comunes de rendimiento de React, y aquí se explica cómo mejorar el rendimiento en Angular. En general, la mayoría de los problemas de rendimiento provienen de la primera vez que se inicia la aplicación.
Entonces, ¿cuál es la mejor manera de dividir el código de manera agresiva, pero no demasiado agresiva? Según Phil Walton, "además de la división de código a través de importaciones dinámicas, [podríamos] también usar la división de código a nivel de paquete , donde cada módulo de nodo importado se coloca en un fragmento según el nombre de su paquete". Phil proporciona un tutorial sobre cómo construirlo también.
- ¿Podemos mejorar la salida de Webpack?
Como Webpack a menudo se considera misterioso, hay muchos complementos de Webpack que pueden ser útiles para reducir aún más la salida de Webpack. A continuación se muestran algunos de los más oscuros que podrían necesitar un poco más de atención.Uno de los interesantes proviene del hilo de Ivan Akulov. Imagine que tiene una función a la que llama una vez, almacena su resultado en una variable y luego no usa esa variable. Tree-shaking eliminará la variable, pero no la función, porque podría usarse de otra manera. Sin embargo, si la función no se usa en ninguna parte, es posible que desee eliminarla. Para hacerlo, anteponga a la llamada de función
/*#__PURE__*/
que es compatible con Uglify y Terser, ¡listo!Estas son algunas de las otras herramientas que Ivan recomienda:
- purgecss-webpack-plugin elimina las clases no utilizadas, especialmente cuando usa Bootstrap o Tailwind.
- Habilite
optimization.splitChunks: 'all'
con split-chunks-plugin. Esto haría que webpack dividiera automáticamente en código sus paquetes de entrada para un mejor almacenamiento en caché. - Establezca la
optimization.runtimeChunk: true
. Esto movería el tiempo de ejecución de webpack a un fragmento separado y también mejoraría el almacenamiento en caché. - google-fonts-webpack-plugin descarga archivos de fuentes, para que pueda servirlos desde su servidor.
- workbox-webpack-plugin le permite generar un service worker con una configuración de precaching para todos sus activos de webpack. Además, consulte Service Worker Packages, una guía completa de módulos que se pueden aplicar de inmediato. O use preload-webpack-plugin para generar
preload
/prefetch
para todos los fragmentos de JavaScript. - speed-measure-webpack-plugin mide la velocidad de compilación de su paquete web y brinda información sobre qué pasos del proceso de compilación consumen más tiempo.
- duplicate-package-checker-webpack-plugin advierte cuando su paquete contiene varias versiones del mismo paquete.
- Utilice el aislamiento del ámbito y acorte los nombres de las clases de CSS de forma dinámica en el momento de la compilación.
- ¿Se puede descargar JavaScript en un Web Worker?
Para reducir el impacto negativo en el tiempo de interacción, podría ser una buena idea descargar JavaScript pesado en un Web Worker.A medida que la base de código siga creciendo, aparecerán cuellos de botella en el rendimiento de la interfaz de usuario, lo que ralentizará la experiencia del usuario. Eso es porque las operaciones DOM se ejecutan junto con su JavaScript en el hilo principal. Con los trabajadores web, podemos mover estas costosas operaciones a un proceso en segundo plano que se ejecuta en un subproceso diferente. Los casos de uso típicos para los trabajadores web son la obtención previa de datos y las aplicaciones web progresivas para cargar y almacenar algunos datos por adelantado para que pueda usarlos más tarde cuando sea necesario. Y podría usar Comlink para agilizar la comunicación entre la página principal y el trabajador. Todavía queda trabajo por hacer, pero estamos llegando allí.
Hay algunos estudios de casos interesantes sobre los trabajadores web que muestran diferentes enfoques para mover el marco y la lógica de la aplicación a los trabajadores web. La conclusión: en general, todavía hay algunos desafíos, pero ya hay algunos buenos casos de uso ( ¡gracias, Ivan Akulov! ).
A partir de Chrome 80, se envió un nuevo modo para trabajadores web con beneficios de rendimiento de los módulos de JavaScript, llamados trabajadores de módulos. Podemos cambiar la carga y ejecución del script para que coincida con
script type="module"
, además, también podemos usar importaciones dinámicas para el código de carga diferida sin bloquear la ejecución del trabajador.¿Cómo empezar? Aquí hay algunos recursos que vale la pena investigar:
- Surma ha publicado una excelente guía sobre cómo ejecutar JavaScript fuera del hilo principal del navegador y también ¿Cuándo debería usar Web Workers?
- Además, consulte la charla de Surma sobre la arquitectura del subproceso principal.
- A Quest to Guarantee Responsiveness de Shubhie Panicker y Jason Miller proporciona información detallada sobre cómo utilizar los trabajadores web y cuándo evitarlos.
- Salir del camino de los usuarios: Menos Jank With Web Workers destaca patrones útiles para trabajar con Web Workers, formas efectivas de comunicarse entre trabajadores, manejar el procesamiento de datos complejos fuera del hilo principal y probarlos y depurarlos.
- Workerize le permite mover un módulo a un Web Worker, reflejando automáticamente las funciones exportadas como proxies asíncronos.
- Si está usando Webpack, podría usar workerize-loader. Alternativamente, también podría usar el complemento de trabajador.
Tenga en cuenta que los Web Workers no tienen acceso al DOM porque el DOM no es "seguro para subprocesos" y el código que ejecutan debe estar contenido en un archivo separado.
- ¿Puede descargar "rutas activas" a WebAssembly?
Podríamos descargar tareas computacionalmente pesadas a WebAssembly ( WASM ), un formato de instrucción binaria, diseñado como un objetivo portátil para la compilación de lenguajes de alto nivel como C/C++/Rust. Su soporte de navegador es notable, y recientemente se ha vuelto viable a medida que las llamadas de funciones entre JavaScript y WASM son cada vez más rápidas. Además, incluso es compatible con la nube perimetral de Fastly.Por supuesto, no se supone que WebAssembly reemplace a JavaScript, pero puede complementarlo en los casos en que observe un consumo excesivo de CPU. Para la mayoría de las aplicaciones web, JavaScript se adapta mejor, y WebAssembly se usa mejor para aplicaciones web de computación intensiva , como los juegos.
Si desea obtener más información sobre WebAssembly:
- Lin Clark ha escrito una serie exhaustiva sobre WebAssembly y Milica Mihajlija ofrece una descripción general de cómo ejecutar código nativo en el navegador, por qué es posible que desee hacerlo y qué significa para JavaScript y el futuro del desarrollo web.
- Cómo usamos WebAssembly para acelerar nuestra aplicación web en 20X (estudio de caso) destaca un estudio de caso de cómo los cálculos lentos de JavaScript se reemplazaron con WebAssembly compilado y aportaron mejoras de rendimiento significativas.
- Patrick Hamann ha estado hablando sobre el papel cada vez mayor de WebAssembly y está desacreditando algunos mitos sobre WebAssembly, explora sus desafíos y podemos usarlo prácticamente en las aplicaciones de hoy.
- Google Codelabs ofrece una Introducción a WebAssembly, un curso de 60 minutos en el que aprenderá cómo tomar código nativo en C y compilarlo en WebAssembly, y luego llamarlo directamente desde JavaScript.
- Alex Danilo ha explicado WebAssembly y cómo funciona en su charla de Google I/O. Además, Benedek Gagyi compartió un caso de estudio práctico sobre WebAssembly, específicamente cómo el equipo lo usa como formato de salida para su base de código C++ para iOS, Android y el sitio web.
¿ Aún no está seguro de cuándo usar Web Workers, Web Assembly, streams o quizás la API JavaScript de WebGL para acceder a la GPU? Acelerar JavaScript es una guía breve pero útil que explica cuándo usar qué y por qué, también con un práctico diagrama de flujo y muchos recursos útiles.
- ¿Servimos código heredado solo para navegadores heredados?
Dado que ES2017 es notablemente compatible con los navegadores modernos, podemos usarbabelEsmPlugin
para transpilar solo las funciones de ES2017+ que no son compatibles con los navegadores modernos a los que se dirige.Houssein Djirdeh y Jason Miller publicaron recientemente una guía completa sobre cómo transpilar y servir JavaScript moderno y heredado, y detallan cómo hacerlo funcionar con Webpack y Rollup, y las herramientas necesarias. También puede estimar cuánto JavaScript puede eliminar en su sitio o paquetes de aplicaciones.
Los módulos de JavaScript son compatibles con todos los navegadores principales, así que use
script type="module"
para permitir que los navegadores con compatibilidad con el módulo ES carguen el archivo, mientras que los navegadores más antiguos podrían cargar compilaciones heredadas conscript nomodule
.En estos días podemos escribir JavaScript basado en módulos que se ejecuta de forma nativa en el navegador, sin transpiladores ni empaquetadores. El encabezado
<link rel="modulepreload">
proporciona una forma de iniciar la carga temprana (y de alta prioridad) de los scripts de módulos. Básicamente, es una forma ingeniosa de ayudar a maximizar el uso del ancho de banda, diciéndole al navegador lo que necesita buscar para que no tenga nada que hacer durante esos largos viajes de ida y vuelta. Además, Jake Archibald ha publicado un artículo detallado con trampas y cosas a tener en cuenta con los módulos ES que vale la pena leer.
- Identifique y reescriba el código heredado con desacoplamiento incremental .
Los proyectos de larga duración tienden a acumular polvo y código obsoleto. Revise sus dependencias y evalúe cuánto tiempo se necesitaría para refactorizar o reescribir el código heredado que ha estado causando problemas últimamente. Por supuesto, siempre es una gran empresa, pero una vez que conoce el impacto del código heredado, puede comenzar con el desacoplamiento incremental.Primero, configure métricas que rastreen si la proporción de llamadas de código heredado se mantiene constante o disminuye, no aumenta. Desaliente públicamente al equipo de usar la biblioteca y asegúrese de que su CI alerte a los desarrolladores si se usa en solicitudes de incorporación de cambios. Los polyfills podrían ayudar en la transición del código heredado a una base de código reescrita que utiliza funciones de navegador estándar.
- Identifique y elimine CSS/JS no utilizados .
La cobertura de código CSS y JavaScript en Chrome le permite saber qué código se ha ejecutado/aplicado y cuál no. Puede comenzar a registrar la cobertura, realizar acciones en una página y luego explorar los resultados de la cobertura del código. Una vez que haya detectado el código no utilizado, busque esos módulos y realice la carga diferida conimport()
(vea el hilo completo). Luego repita el perfil de cobertura y valide que ahora envía menos código en la carga inicial.Puede usar Titiritero para recopilar cobertura de código mediante programación. Chrome también le permite exportar resultados de cobertura de código. Como señaló Andy Davies, es posible que desee recopilar cobertura de código para navegadores tanto modernos como heredados.
Hay muchos otros casos de uso y herramientas para Puppetter que podrían necesitar un poco más de exposición:
- Casos de uso para Puppeteer, como, por ejemplo, diferenciación visual automática o monitoreo de CSS no utilizado con cada compilación,
- Recetas de rendimiento web con Puppeteer,
- Herramientas útiles para grabar y generar guiones de Pupeeteer y Playwright,
- Además, incluso puede grabar pruebas directamente en DevTools,
- Resumen completo de Titiritero por Nitay Neeman, con ejemplos y casos de uso.
Además, purgecss, UnCSS y Helium pueden ayudarlo a eliminar estilos no utilizados de CSS. Y si no está seguro de si se usa un código sospechoso en alguna parte, puede seguir el consejo de Harry Roberts: cree un GIF transparente de 1 × 1 px para una clase en particular y colóquelo en un directorio
dead/
, por ejemplo,/assets/img/dead/comments.gif
.Después de eso, configura esa imagen específica como fondo en el selector correspondiente en su CSS, siéntese y espere unos meses si el archivo aparecerá en sus registros. Si no hay entradas, nadie tenía ese componente heredado representado en su pantalla: probablemente pueda continuar y eliminarlo todo.
Para el departamento I-feel-adventurous , incluso podría automatizar la recopilación de CSS no utilizado a través de un conjunto de páginas al monitorear DevTools usando DevTools.
- Recorta el tamaño de tus paquetes de JavaScript.
Como señaló Addy Osmani, existe una alta probabilidad de que esté enviando bibliotecas de JavaScript completas cuando solo necesita una fracción, junto con polyfills fechados para navegadores que no los necesitan, o simplemente código duplicado. Para evitar la sobrecarga, considere usar webpack-libs-optimizations que elimine métodos no utilizados y polyfills durante el proceso de compilación.Verifique y revise los polyfills que está enviando a los navegadores heredados y a los navegadores modernos, y sea más estratégico al respecto. Eche un vistazo a polyfill.io, que es un servicio que acepta una solicitud de un conjunto de características del navegador y devuelve solo los polyfills que necesita el navegador solicitante.
Agregue también la auditoría de paquetes a su flujo de trabajo habitual. Puede haber algunas alternativas ligeras a las bibliotecas pesadas que agregó hace años, por ejemplo, Moment.js (ahora descontinuado) podría reemplazarse con:
- API de internacionalización nativa,
- Day.js con una API y patrones conocidos de Moment.js,
- fecha-fns o
- Luxón.
- También puede usar Skypack Discover, que combina recomendaciones de paquetes revisadas por personas con una búsqueda centrada en la calidad.
La investigación de Benedikt Rotsch mostró que un cambio de Moment.js a date-fns podría ahorrar alrededor de 300 ms para First paint en 3G y un teléfono móvil de gama baja.
Para la auditoría de paquetes, Bundlephobia podría ayudar a encontrar el costo de agregar un paquete npm a su paquete. size-limit amplía la comprobación básica del tamaño del paquete con detalles sobre el tiempo de ejecución de JavaScript. Incluso puede integrar estos costos con una auditoría personalizada de Lighthouse. Esto también se aplica a los marcos. Al quitar o recortar el adaptador Vue MDC (Componentes de material para Vue), los estilos bajan de 194 KB a 10 KB.
Hay muchas herramientas adicionales para ayudarlo a tomar una decisión informada sobre el impacto de sus dependencias y alternativas viables:
- analizador de paquete webpack
- Explorador de mapas de origen
- Amigo del paquete
- Paquetefobia
- El análisis del paquete web muestra por qué se incluye un módulo específico en el paquete.
- bundle-wizard también crea un mapa de dependencias para toda la página.
- Complemento de tamaño de paquete web
- Costo de importación para código visual
Alternativamente a enviar todo el marco, puede recortar su marco y compilarlo en un paquete de JavaScript sin formato que no requiere código adicional. Svelte lo hace, al igual que el complemento Rawact Babel, que transfiere los componentes de React.js a operaciones DOM nativas en el momento de la compilación. ¿Por qué? Bueno, como explican los mantenedores, "react-dom incluye código para cada posible componente/HTMLElement que se puede renderizar, incluido código para renderizado incremental, programación, manejo de eventos, etc. Pero hay aplicaciones que no necesitan todas estas características (al principio carga de la página). Para tales aplicaciones, podría tener sentido usar operaciones DOM nativas para construir la interfaz de usuario interactiva".
- ¿Usamos hidratación parcial?
Con la cantidad de JavaScript que se usa en las aplicaciones, debemos encontrar formas de enviar la menor cantidad posible al cliente. Una forma de hacerlo, y ya lo cubrimos brevemente, es con una hidratación parcial. La idea es bastante simple: en lugar de hacer SSR y luego enviar la aplicación completa al cliente, solo se enviarían al cliente pequeñas partes del JavaScript de la aplicación y luego se hidratarían. Podemos pensar en ello como múltiples aplicaciones React diminutas con múltiples raíces de renderizado en un sitio web estático.En el artículo "El caso de la hidratación parcial (con Next y Preact)", Lukas Bombach explica cómo el equipo detrás de Welt.de, uno de los medios de comunicación de Alemania, ha logrado un mejor rendimiento con la hidratación parcial. También puede consultar el repositorio de GitHub de próximo rendimiento superior con explicaciones y fragmentos de código.
También podría considerar opciones alternativas:
- hidratación parcial con Preact y Eleventy,
- hidratación progresiva en React GitHub repo,
- hidratación perezosa en Vue.js (repo de GitHub),
- Importe en el patrón de interacción para cargar de forma diferida los recursos no críticos (por ejemplo, componentes, incrustaciones) cuando un usuario interactúa con la interfaz de usuario que lo necesita.
Jason Miller ha publicado demostraciones de trabajo sobre cómo se podría implementar la hidratación progresiva con React, para que pueda usarlas de inmediato: demostración 1, demostración 2, demostración 3 (también disponible en GitHub). Además, puede buscar en la biblioteca de componentes prerenderizados de reacción.
- ¿Hemos optimizado la estrategia para React/SPA?
¿Tiene problemas con el rendimiento de su aplicación de una sola página? Jeremy Wagner ha explorado el impacto del rendimiento del marco del lado del cliente en una variedad de dispositivos, destacando algunas de las implicaciones y pautas que deberíamos tener en cuenta al usar uno.Como resultado, aquí hay una estrategia de SPA que Jeremy sugiere usar para el marco React (pero no debería cambiar significativamente para otros marcos):
- Refactorice los componentes con estado como componentes sin estado siempre que sea posible.
- Preprocesar componentes sin estado cuando sea posible para minimizar el tiempo de respuesta del servidor. Renderizar solo en el servidor.
- Para los componentes con estado con interactividad simple, considere la representación previa o la representación del servidor de ese componente, y reemplace su interactividad con detectores de eventos independientes del marco .
- Si debe hidratar componentes con estado en el cliente, utilice la hidratación perezosa en visibilidad o interacción.
- Para los componentes hidratados de forma diferida, programe su hidratación durante el tiempo de inactividad del subproceso principal con
requestIdleCallback
.
Hay algunas otras estrategias que quizás desee seguir o revisar:
- Consideraciones de rendimiento para CSS-in-JS en aplicaciones React
- Reduzca el tamaño del paquete Next.js cargando polyfills solo cuando sea necesario, usando importaciones dinámicas e hidratación lenta.
- Secretos de JavaScript: Una historia de React, Performance Optimization and Multi-threading, una extensa serie de 7 partes sobre cómo mejorar los desafíos de la interfaz de usuario con React,
- Cómo medir el rendimiento de React y Cómo perfilar las aplicaciones de React.
- Creación de animaciones web para dispositivos móviles en React, una charla fantástica de Alex Holachek, junto con diapositivas y un repositorio de GitHub ( ¡gracias por el consejo, Addy! ).
- webpack-libs-optimizations es un fantástico repositorio de GitHub con muchas optimizaciones útiles relacionadas con el rendimiento específicas de Webpack. Mantenido por Ivan Akulov.
- Mejoras en el rendimiento de React en Notion, una guía de Ivan Akulov sobre cómo mejorar el rendimiento en React, con muchos consejos útiles para hacer que la aplicación sea un 30 % más rápida.
- El complemento React Refresh Webpack (experimental) permite la recarga en caliente que conserva el estado de los componentes y admite ganchos y componentes de funciones.
- Tenga cuidado con los componentes de servidor React de tamaño de paquete cero, un nuevo tipo de componentes propuesto que no tendrá impacto en el tamaño del paquete. El proyecto está actualmente en desarrollo, pero cualquier comentario de la comunidad es muy apreciado (excelente explicación de Sophie Alpert).
- ¿Está utilizando la captación previa predictiva para fragmentos de JavaScript?
Podríamos usar la heurística para decidir cuándo precargar fragmentos de JavaScript. Guess.js es un conjunto de herramientas y bibliotecas que utilizan datos de Google Analytics para determinar qué página es más probable que un usuario visite a continuación desde una página determinada. En función de los patrones de navegación de los usuarios recopilados de Google Analytics u otras fuentes, Guess.js crea un modelo de aprendizaje automático para predecir y obtener previamente el JavaScript que se requerirá en cada página posterior.Por lo tanto, cada elemento interactivo recibe una puntuación de probabilidad de participación y, en función de esa puntuación, un script del lado del cliente decide obtener un recurso con anticipación. Puede integrar la técnica a su aplicación Next.js, Angular y React, y hay un complemento Webpack que también automatiza el proceso de configuración.
Obviamente, es posible que esté solicitando al navegador que consuma datos innecesarios y precarga páginas no deseadas, por lo que es una buena idea ser bastante conservador en la cantidad de solicitudes precargadas. Un buen caso de uso sería obtener previamente los scripts de validación requeridos en el proceso de pago o la obtención previa especulativa cuando una llamada a la acción crítica entra en la ventana gráfica.
¿Necesita algo menos sofisticado? DNStradamus realiza una búsqueda previa de DNS para los enlaces salientes tal como aparecen en la ventana gráfica. Quicklink, InstantClick e Instant.page son pequeñas bibliotecas que automáticamente obtienen enlaces en la ventana gráfica durante el tiempo de inactividad en un intento de hacer que las navegaciones de la página siguiente se carguen más rápido. Quicklink permite precargar rutas de React Router y Javascript; además, tiene en cuenta los datos, por lo que no realiza una búsqueda previa en 2G o si
Data-Saver
está activado. También lo es Instant.page si el modo está configurado para usar la captación previa de ventana gráfica (que es un valor predeterminado).Si desea analizar la ciencia de la captación previa predictiva con todo detalle, Divya Tagtachian tiene una gran charla sobre El arte de la captación previa predictiva, que cubre todas las opciones de principio a fin.
- Aproveche las optimizaciones para su motor de JavaScript de destino.
Estudie qué motores de JavaScript dominan en su base de usuarios, luego explore formas de optimizarlos. Por ejemplo, al optimizar para V8 que se utiliza en los navegadores Blink, el tiempo de ejecución de Node.js y Electron, utilice la transmisión de secuencias de comandos para secuencias de comandos monolíticas.La transmisión de secuencias de comandos permite que las secuencias de comandos
async
odefer scripts
se analicen en un subproceso de fondo separado una vez que comienza la descarga, lo que en algunos casos mejora los tiempos de carga de la página hasta en un 10%. Prácticamente, use<script defer>
en<head>
, para que los navegadores puedan descubrir el recurso temprano y luego analizarlo en el subproceso de fondo.Advertencia : Opera Mini no admite el aplazamiento de secuencias de comandos, por lo que si está desarrollando para India o África, se
defer
el aplazamiento, lo que provocará el bloqueo de la representación hasta que se haya evaluado la secuencia de comandos (¡gracias, Jeremy!) .También puede conectarse al almacenamiento en caché del código de V8, separando las bibliotecas del código que las usa, o al revés, fusionar las bibliotecas y sus usos en una sola secuencia de comandos, agrupar archivos pequeños y evitar las secuencias de comandos en línea. O tal vez incluso use v8-compile-cache.
Cuando se trata de JavaScript en general, también hay algunas prácticas que vale la pena tener en cuenta:
- Conceptos de código limpio para JavaScript, una gran colección de patrones para escribir código legible, reutilizable y refactorizable.
- Puede comprimir datos de JavaScript con la API CompressionStream, por ejemplo, a gzip antes de cargar datos (Chrome 80+).
- Las fugas de memoria de ventana separada y la reparación de fugas de memoria en aplicaciones web son guías detalladas sobre cómo encontrar y corregir fugas de memoria de JavaScript complicadas. Además, puede usar queryObjects(SomeConstructor) desde la consola DevTools ( ¡gracias, Mathias! ).
- Las reexportaciones son malas para la carga y el rendimiento del tiempo de ejecución, y evitarlas puede ayudar a reducir significativamente el tamaño del paquete.
- Podemos mejorar el rendimiento del desplazamiento con detectores de eventos pasivos configurando una bandera en el parámetro de
options
. Por lo tanto, los navegadores pueden desplazarse por la página inmediatamente, en lugar de después de que el oyente haya terminado. (a través de Kayce vascos). - Si tiene oyentes de
scroll
otouch*
, pasepassive: true
a addEventListener. Esto le dice al navegador que no planea llamar aevent.preventDefault()
adentro, para que pueda optimizar la forma en que maneja estos eventos. (a través de Iván Akulov) - Podemos lograr una mejor programación de JavaScript con isInputPending(), una nueva API que intenta cerrar la brecha entre la carga y la capacidad de respuesta con los conceptos de interrupciones para las entradas del usuario en la web, y permite que JavaScript pueda verificar la entrada sin ceder a el navegador.
- También puede eliminar automáticamente un detector de eventos después de que se haya ejecutado.
- Firefox lanzó recientemente Warp, una actualización importante de SpiderMonkey (enviado en Firefox 83), Baseline Interpreter y también hay algunas estrategias de optimización JIT disponibles.
- Siempre prefiera hospedar activos de terceros.
Una vez más, autohospede sus activos estáticos de forma predeterminada. Es común suponer que si muchos sitios usan el mismo CDN público y la misma versión de una biblioteca de JavaScript o una fuente web, los visitantes llegarán a nuestro sitio con los scripts y fuentes ya almacenados en caché en su navegador, lo que acelerará considerablemente su experiencia. . Sin embargo, es muy poco probable que suceda.Por razones de seguridad, para evitar la toma de huellas dactilares, los navegadores han estado implementando el almacenamiento en caché particionado que se introdujo en Safari en 2013 y en Chrome el año pasado. Entonces, si dos sitios apuntan exactamente a la misma URL de recursos de terceros, el código se descarga una vez por dominio y el caché se "aisla" en ese dominio debido a las implicaciones de privacidad ( ¡gracias, David Calhoun! ). Por lo tanto, el uso de una CDN pública no conducirá automáticamente a un mejor rendimiento.
Además, vale la pena señalar que los recursos no viven en la memoria caché del navegador tanto tiempo como cabría esperar, y es más probable que los recursos propios permanezcan en la memoria caché que los recursos de terceros. Por lo tanto, el alojamiento propio suele ser más confiable y seguro, y también mejor para el rendimiento.
- Limite el impacto de los scripts de terceros.
Con todas las optimizaciones de rendimiento implementadas, a menudo no podemos controlar los scripts de terceros que provienen de los requisitos comerciales. Las métricas de los scripts de terceros no se ven influenciadas por la experiencia del usuario final, por lo que, con demasiada frecuencia, un solo script termina llamando a una larga cola de desagradables scripts de terceros, lo que arruina un esfuerzo de rendimiento dedicado. Para contener y mitigar las penalizaciones de rendimiento que traen consigo estos scripts, no es suficiente simplemente diferir su carga y ejecución y calentar las conexiones a través de sugerencias de recursos, es decir,dns-prefetch
opreconnect
.Actualmente, el 57% de todo el tiempo de ejecución del código JavaScript se dedica a código de terceros. El sitio móvil promedio accede a 12 dominios de terceros , con una mediana de 37 solicitudes diferentes (o alrededor de 3 solicitudes realizadas a cada tercero).
Además, estos terceros a menudo invitan a los scripts de terceros a unirse, lo que termina con un gran cuello de botella en el rendimiento, que a veces llega hasta los scripts de terceros en una página. Por lo tanto, auditar regularmente sus dependencias y administradores de etiquetas puede traer sorpresas costosas.
Otro problema, como explicó Yoav Weiss en su charla sobre scripts de terceros, es que en muchos casos estos scripts descargan recursos que son dinámicos. Los recursos cambian entre cargas de página, por lo que no necesariamente sabemos de qué hosts se descargarán los recursos y qué recursos serán.
Aplazar, como se muestra arriba, podría ser solo un comienzo, ya que los scripts de terceros también roban ancho de banda y tiempo de CPU de su aplicación. Podríamos ser un poco más agresivos y cargarlos solo cuando nuestra aplicación se haya inicializado.
/* Before */ const App = () => { return <div> <script> window.dataLayer = window.dataLayer || []; function gtag(){...} gtg('js', new Date()); </script> </div> } /* After */ const App = () => { const[isRendered, setRendered] = useState(false); useEffect(() => setRendered(true)); return <div> {isRendered ? <script> window.dataLayer = window.dataLayer || []; function gtag(){...} gtg('js', new Date()); </script> : null} </div> }
En una publicación fantástica sobre "Reducción del impacto en la velocidad del sitio de las etiquetas de terceros", Andy Davies explora una estrategia para minimizar la huella de terceros, desde la identificación de sus costos hasta la reducción de su impacto.
Según Andy, las etiquetas afectan la velocidad del sitio de dos maneras: compiten por el ancho de banda de la red y el tiempo de procesamiento en los dispositivos de los visitantes y, según cómo se implementen, también pueden retrasar el análisis de HTML. Entonces, el primer paso es identificar el impacto que tienen los terceros, probando el sitio con y sin scripts usando WebPageTest. Con Request Map de Simon Hearne, también podemos visualizar terceros en una página junto con detalles sobre su tamaño, tipo y qué desencadenó su carga.
Preferiblemente, autoalójese y use un solo nombre de host, pero también use un mapa de solicitud para exponer las llamadas de terceros y detectar cuándo cambian los scripts. Puede utilizar el enfoque de Harry Roberts para auditar a terceros y generar hojas de cálculo como esta (consulte también el flujo de trabajo de auditoría de Harry).
Luego, podemos explorar alternativas ligeras a los scripts existentes y reemplazar lentamente los duplicados y los principales culpables con opciones más ligeras. Quizás algunos de los scripts podrían reemplazarse con su píxel de seguimiento alternativo en lugar de la etiqueta completa.
Si no es viable, al menos podemos cargar de forma diferida recursos de terceros con fachadas, es decir, un elemento estático que se parece al tercero incrustado real, pero no es funcional y, por lo tanto, es mucho menos exigente en la carga de la página. El truco, entonces, es cargar la inserción real solo en la interacción .
Por ejemplo, podemos usar:
- lite-vimeo-embed para el reproductor Vimeo,
- lite-vimeo para el reproductor de Vimeo,
- lite-youtube-embed para el reproductor de YouTube,
- react-live-chat-loader para un chat en vivo (estudio de caso y otro estudio de caso),
- marco perezoso para iframes.
Una de las razones por las que los administradores de etiquetas suelen ser de gran tamaño es debido a la gran cantidad de experimentos simultáneos que se ejecutan al mismo tiempo, junto con muchos segmentos de usuarios, URL de páginas, sitios, etc., por lo que, según Andy, reducirlos puede reducir ambos. el tamaño de la descarga y el tiempo que lleva ejecutar el script en el navegador.
Y luego están los fragmentos antiparpadeo. Terceros como Google Optimize, Visual Web Optimizer (VWO) y otros son unánimes en su uso. Estos fragmentos generalmente se inyectan junto con la ejecución de pruebas A/B : para evitar el parpadeo entre los diferentes escenarios de prueba, ocultan el
body
del documento conopacity: 0
, luego agregan una función que se llama después de unos segundos para recuperar laopacity
. . Esto a menudo da como resultado retrasos masivos en el renderizado debido a los costos de ejecución masivos del lado del cliente.Por lo tanto, realice un seguimiento de la frecuencia con la que se activa el tiempo de espera antiparpadeo y reduzca el tiempo de espera. Bloques predeterminados que muestran su página hasta 4 segundos, lo que arruinará las tasas de conversión. Según Tim Kadlec, "Los amigos no dejan que los amigos hagan pruebas A/B del lado del cliente". Las pruebas A/B del lado del servidor en CDN (por ejemplo, Edge Computing o Edge Slice Rerendering) siempre son una opción de mayor rendimiento.
Si tiene que lidiar con el todopoderoso Administrador de etiquetas de Google , Barry Pollard brinda algunas pautas para contener el impacto del Administrador de etiquetas de Google. Además, Christian Schaefer explora estrategias para cargar anuncios.
Cuidado: algunos widgets de terceros se ocultan de las herramientas de auditoría, por lo que pueden ser más difíciles de detectar y medir. Para realizar pruebas de estrés de terceros, examine los resúmenes de abajo hacia arriba en la página de perfil de rendimiento en DevTools, pruebe qué sucede si una solicitud está bloqueada o se agotó el tiempo de espera; para esto último, puede usar el servidor Blackhole de WebPageTest
blackhole.webpagetest.org
que puede señalar dominios específicos en su archivo dehosts
.¿Qué opciones tenemos entonces? Considere el uso de trabajadores de servicio acelerando la descarga del recurso con un tiempo de espera y, si el recurso no ha respondido dentro de un cierto tiempo de espera, devuelva una respuesta vacía para indicarle al navegador que continúe con el análisis de la página. También puede registrar o bloquear solicitudes de terceros que no tengan éxito o no cumplan ciertos criterios. Si puede, cargue el script de terceros desde su propio servidor en lugar de hacerlo desde el servidor del proveedor y cárguelos de forma diferida.
Otra opción es establecer una Política de seguridad de contenido (CSP) para restringir el impacto de los scripts de terceros, por ejemplo, no permitir la descarga de audio o video. La mejor opción es incrustar secuencias de comandos a través de
<iframe>
para que las secuencias de comandos se ejecuten en el contexto del iframe y, por lo tanto, no tengan acceso al DOM de la página y no puedan ejecutar código arbitrario en su dominio. Los iframes se pueden restringir aún más utilizando el atributosandbox
, por lo que puede deshabilitar cualquier funcionalidad que iframe pueda hacer, por ejemplo, evitar que se ejecuten scripts, evitar alertas, envío de formularios, complementos, acceso a la navegación superior, etc.También puede controlar a los terceros a través de la alineación del rendimiento en el navegador con políticas de funciones, una función relativamente nueva que le permite
activar o desactivar ciertas funciones del navegador en su sitio. (Como nota al margen, también podría usarse para evitar imágenes de gran tamaño y sin optimizar, medios sin tamaño, secuencias de comandos de sincronización y otros). Actualmente compatible con navegadores basados en Blink. /* Via Tim Kadlec. https://timkadlec.com/remembers/2020-02-20-in-browser-performance-linting-with-feature-policies/ */ /* Block the use of the Geolocation API with a Feature-Policy header. */ Feature-Policy: geolocation 'none'
/* Via Tim Kadlec. https://timkadlec.com/remembers/2020-02-20-in-browser-performance-linting-with-feature-policies/ */ /* Block the use of the Geolocation API with a Feature-Policy header. */ Feature-Policy: geolocation 'none'
Dado que muchos scripts de terceros se ejecutan en iframes, es probable que deba ser minucioso al restringir sus asignaciones. Los iframes en espacio aislado siempre son una buena idea, y cada una de las limitaciones se puede eliminar a través de una serie de valores
allow
en elsandbox
de espacio aislado. Sandboxing es compatible en casi todas partes, por lo tanto, restrinja los scripts de terceros al mínimo de lo que se les debe permitir hacer.Considere usar un Intersection Observer; eso permitiría que los anuncios se iframed mientras se envían eventos u obtienen la información que necesitan del DOM (por ejemplo, visibilidad de anuncios). Tenga cuidado con las nuevas políticas, como la política de funciones, los límites de tamaño de recursos y la prioridad de CPU/ancho de banda para limitar las funciones web dañinas y los scripts que ralentizarían el navegador, por ejemplo, scripts sincrónicos, solicitudes XHR sincrónicas, document.write e implementaciones obsoletas.
Finalmente, al elegir un servicio de terceros, considere consultar ThirdPartyWeb.Today de Patrick Hulce, un servicio que agrupa todos los scripts de terceros por categoría (análisis, redes sociales, publicidad, alojamiento, administrador de etiquetas, etc.) y visualiza cuánto duran los scripts de la entidad. tardan en ejecutarse (en promedio). Obviamente, las entidades más grandes tienen el peor impacto en el rendimiento de las páginas en las que se encuentran. Simplemente hojeando la página, obtendrá una idea de la huella de rendimiento que debería esperar.
Ah, y no se olvide de los sospechosos habituales: en lugar de widgets de terceros para compartir, podemos usar botones estáticos para compartir en redes sociales (como SSBG) y enlaces estáticos a mapas interactivos en lugar de mapas interactivos.
- Configure los encabezados de caché HTTP correctamente.
El almacenamiento en caché parece ser algo tan obvio que hacer, pero puede ser bastante difícil hacerlo bien. Necesitamos verificar queexpires
,max-age
,cache-control
y otros encabezados de caché HTTP se hayan configurado correctamente. Sin los encabezados de caché HTTP adecuados, los navegadores los configurarán automáticamente al 10% del tiempo transcurrido desdelast-modified
, lo que terminará con un posible almacenamiento insuficiente y excesivo de caché.En general, los recursos deben poder almacenarse en caché durante un tiempo muy corto (si es probable que cambien) o indefinidamente (si son estáticos); solo puede cambiar su versión en la URL cuando sea necesario. Puede llamarlo una estrategia Cache-Forever, en la que podríamos transmitir los encabezados
Cache-Control
yExpires
al navegador para permitir que los activos caduquen solo en un año. Por lo tanto, el navegador ni siquiera solicitaría el activo si lo tiene en el caché.La excepción son las respuestas de la API (por ejemplo
/api/user
). Para evitar el almacenamiento en caché, podemos usarprivate, no store
y nomax-age=0, no-store
:Cache-Control: private, no-store
Use
Cache-control: immutable
para evitar la revalidación de tiempos de vida de caché explícitos prolongados cuando los usuarios presionan el botón de recarga. Para el caso de recarga,immutable
guarda las solicitudes HTTP y mejora el tiempo de carga del HTML dinámico, ya que ya no compiten con la multitud de respuestas 304.Un ejemplo típico en el que queremos usar
immutable
son los activos CSS/JavaScript con un hash en su nombre. Para ellos, probablemente queramos almacenar en caché el mayor tiempo posible y asegurarnos de que nunca se vuelvan a validar:Cache-Control: max-age: 31556952, immutable
Según la investigación de Colin Bendell,
immutable
reduce los redireccionamientos 304 en alrededor de un 50 %, ya que incluso conmax-age
en uso, los clientes siguen revalidando y bloqueando al actualizar. Es compatible con Firefox, Edge y Safari y Chrome todavía está debatiendo el problema.Según Web Almanac, "su uso ha crecido hasta un 3,5 % y se utiliza mucho en las respuestas de terceros de Facebook y Google".
¿Recuerdas el buen viejo mientras se revalida? Cuando especificamos el tiempo de almacenamiento en caché con el encabezado de respuesta
Cache-Control
(p. ej.Cache-Control: max-age=604800
), después de que expiremax-age
, el navegador volverá a buscar el contenido solicitado, lo que hará que la página se cargue más lentamente. Esta ralentización se puede evitar constale-while-revalidate
; básicamente define una ventana de tiempo adicional durante la cual un caché puede usar un activo obsoleto siempre que lo revalide de forma asíncrona en segundo plano. Por lo tanto, "oculta" la latencia (tanto en la red como en el servidor) de los clientes.En junio-julio de 2019, Chrome y Firefox lanzaron la compatibilidad con
stale-while-revalidate
en el encabezado HTTP Cache-Control, por lo que, como resultado, debería mejorar las latencias de carga de páginas posteriores, ya que los activos obsoletos ya no se encuentran en la ruta crítica. Resultado: cero RTT para vistas repetidas.Tenga cuidado con el encabezado de variación, especialmente en relación con las CDN, y tenga cuidado con las variantes de representación HTTP que ayudan a evitar un viaje de ida y vuelta adicional para la validación cada vez que una nueva solicitud difiere levemente (pero no significativamente) de las solicitudes anteriores ( gracias, Guy y Mark ! ).
Además, verifique que no esté enviando encabezados innecesarios (por ejemplo
x-powered-by
,pragma
,x-ua-compatible
,expires
,X-XSS-Protection
y otros) y que incluya encabezados útiles de seguridad y rendimiento (como comoContent-Security-Policy
,X-Content-Type-Options
y otros). Finalmente, tenga en cuenta el costo de rendimiento de las solicitudes CORS en aplicaciones de una sola página.Nota : a menudo asumimos que los activos almacenados en caché se recuperan instantáneamente, pero la investigación muestra que recuperar un objeto del caché puede llevar cientos de milisegundos. De hecho, según Simon Hearne, "a veces, la red puede ser más rápida que el caché, y la recuperación de activos del caché puede ser costosa con una gran cantidad de activos almacenados en caché (no el tamaño del archivo) y los dispositivos del usuario. Por ejemplo: recuperación de caché promedio de Chrome OS se duplica desde ~50ms con 5 recursos en caché hasta ~100ms con 25 recursos".
Además, a menudo asumimos que el tamaño del paquete no es un gran problema y que los usuarios lo descargarán una vez y luego usarán la versión en caché. Al mismo tiempo, con CI/CD empujamos el código a producción varias veces al día, el caché se invalida cada vez, por lo que es importante ser estratégico con respecto al almacenamiento en caché.
Cuando se trata de almacenamiento en caché, hay muchos recursos que vale la pena leer:
- Cache-Control for Civilians, una inmersión profunda en todo el almacenamiento en caché con Harry Roberts.
- Manual básico de Heroku sobre encabezados de almacenamiento en caché HTTP,
- Mejores prácticas de almacenamiento en caché por Jake Archibald,
- Introducción al almacenamiento en caché de HTTP por Ilya Grigorik,
- Manteniendo las cosas frescas con obsoleto mientras se revalida por Jeff Posnick.
- CS Visualized: CORS de Lydia Hallie es una gran explicación sobre CORS, cómo funciona y cómo darle sentido.
- Hablando de CORS, aquí hay un pequeño repaso sobre la política del mismo origen de Eric Portis.
Optimizaciones de entrega
- ¿
defer
para cargar JavaScript crítico de forma asíncrona?
Cuando el usuario solicita una página, el navegador obtiene el HTML y construye el DOM, luego obtiene el CSS y construye el CSSOM, y luego genera un árbol de representación haciendo coincidir el DOM y el CSSOM. Si es necesario resolver algún JavaScript, el navegador no comenzará a mostrar la página hasta que se resuelva, lo que retrasará el procesamiento. Como desarrolladores, tenemos que decirle explícitamente al navegador que no espere y que comience a mostrar la página. La forma de hacer esto para los scripts es con los atributosdefer
yasync
en HTML.En la práctica, resulta que es mejor usar
defer
en lugar deasync
. Ah, ¿cuál es la diferencia de nuevo? Según Steve Souders, una vez que llegan los scriptsasync
, se ejecutan inmediatamente, tan pronto como el script está listo. Si eso sucede muy rápido, por ejemplo, cuando el script ya está en caché, en realidad puede bloquear el analizador HTML. Condefer
, el navegador no ejecuta scripts hasta que se analiza HTML. Entonces, a menos que necesite ejecutar JavaScript antes de comenzar a renderizar, es mejor usardefer
. Además, varios archivos asíncronos se ejecutarán en un orden no determinista.Vale la pena señalar que existen algunos conceptos erróneos sobre
async
ydefer
. Lo que es más importante,async
no significa que el código se ejecutará siempre que el script esté listo; significa que se ejecutará siempre que los scripts estén listos y todo el trabajo de sincronización anterior haya finalizado. En palabras de Harry Roberts: "Si coloca una secuencia de comandosasync
después de las secuencias de comandos de sincronización, su secuencia de comandosasync
será tan rápida como la secuencia de comandos de sincronización más lenta".Además, no se recomienda usar tanto
async
comodefer
. Los navegadores modernos son compatibles con ambos, pero siempre que se usen ambos atributos,async
siempre ganará.Si desea profundizar en más detalles, Milica Mihajlija ha escrito una guía muy detallada sobre cómo construir el DOM más rápido, entrando en los detalles del análisis especulativo, asíncrono y diferido.
- Componentes caros de carga diferida con IntersectionObserver y sugerencias de prioridad.
En general, se recomienda cargar de forma diferida todos los componentes costosos, como JavaScript pesado, videos, iframes, widgets y potencialmente imágenes. La carga diferida nativa ya está disponible para imágenes e iframes con el atributo deloading
(solo Chromium). Bajo el capó, este atributo difiere la carga del recurso hasta que alcanza una distancia calculada desde la ventana gráfica.<!-- Lazy loading for images, iframes, scripts. Probably for images outside of the viewport. --> <img loading="lazy" ... /> <iframe loading="lazy" ... /> <!-- Prompt an early download of an asset. For critical images, eg hero images. --> <img loading="eager" ... /> <iframe loading="eager" ... />
Ese umbral depende de algunas cosas, desde el tipo de recurso de imagen que se obtiene hasta el tipo de conexión efectiva. Pero los experimentos realizados con Chrome en Android sugieren que en 4G, el 97,5 % de las imágenes de la parte inferior de la página que se cargan de forma diferida se cargaron por completo dentro de los 10 ms de volverse visibles, por lo que debería ser seguro.
También podemos usar el atributo de
importance
(high
olow
) en un elemento<script>
,<img>
o<link>
(solo parpadeo). De hecho, es una excelente manera de quitarle prioridad a las imágenes en los carruseles, así como a volver a priorizar las secuencias de comandos. Sin embargo, a veces es posible que necesitemos un poco más de control granular.<!-- When the browser assigns "High" priority to an image, but we don't actually want that. --> <img src="less-important-image.svg" importance="low" ... /> <!-- We want to initiate an early fetch for a resource, but also deprioritize it. --> <link rel="preload" importance="low" href="/script.js" as="script" />
La forma más eficaz de realizar una carga diferida un poco más sofisticada es usar la API Intersection Observer, que proporciona una forma de observar de forma asincrónica los cambios en la intersección de un elemento de destino con un elemento antepasado o con la ventana gráfica de un documento de nivel superior. Básicamente, debe crear un nuevo objeto
IntersectionObserver
, que recibe una función de devolución de llamada y un conjunto de opciones. Luego agregamos un objetivo para observar.La función de devolución de llamada se ejecuta cuando el objetivo se vuelve visible o invisible, por lo que cuando intercepta la ventana gráfica, puede comenzar a realizar algunas acciones antes de que el elemento se vuelva visible. De hecho, tenemos un control granular sobre cuándo se debe invocar la devolución de llamada del observador, con
rootMargin
(margen alrededor de la raíz) ythreshold
(un solo número o una matriz de números que indican a qué porcentaje de la visibilidad del objetivo estamos apuntando).Alejandro García Anglada ha publicado un práctico tutorial sobre cómo implementarlo realmente, Rahul Nanwani escribió una publicación detallada sobre la carga diferida de imágenes de primer plano y de fondo, y Google Fundamentals también proporciona un tutorial detallado sobre la carga diferida de imágenes y videos con Intersection Observer.
¿Recuerdas las lecturas largas de narración dirigida por el arte con objetos en movimiento y pegajosos? También puede implementar una narración de desplazamientos eficaz con Intersection Observer.
Comprueba de nuevo qué más podrías cargar de forma diferida. Incluso las cadenas de traducción de carga diferida y los emoji podrían ayudar. Al hacerlo, Mobile Twitter logró lograr una ejecución de JavaScript un 80 % más rápida a partir de la nueva canalización de internacionalización.
Sin embargo, una advertencia rápida: vale la pena señalar que la carga diferida debería ser una excepción y no la regla. Probablemente no sea razonable cargar de forma diferida cualquier cosa que realmente desee que la gente vea rápidamente, por ejemplo, imágenes de la página del producto, imágenes destacadas o un script necesario para que la navegación principal se vuelva interactiva.
- Carga imágenes progresivamente.
Incluso podría llevar la carga diferida al siguiente nivel agregando la carga progresiva de imágenes a sus páginas. De manera similar a Facebook, Pinterest, Medium y Wolt, primero puede cargar imágenes de baja calidad o incluso borrosas, y luego, a medida que la página continúa cargando, reemplazarlas con las versiones de calidad completa utilizando la técnica BlurHash o LQIP (marcadores de posición de imagen de baja calidad) técnica.Las opiniones difieren si estas técnicas mejoran la experiencia del usuario o no, pero definitivamente mejora el tiempo de First Contentful Paint. Incluso podemos automatizarlo usando SQIP que crea una versión de baja calidad de una imagen como un marcador de posición SVG, o marcadores de posición de imagen degradada con degradados lineales CSS.
Estos marcadores de posición se pueden incrustar en HTML, ya que naturalmente se comprimen bien con los métodos de compresión de texto. En su artículo, Dean Hume ha descrito cómo se puede implementar esta técnica usando Intersection Observer.
¿Retroceder? Si el navegador no es compatible con el observador de intersecciones, aún podemos cargar un polyfill de forma diferida o cargar las imágenes de inmediato. E incluso hay una biblioteca para ello.
¿Quieres ir más elegante? Puede rastrear sus imágenes y usar formas y bordes primitivos para crear un marcador de posición SVG liviano, cargarlo primero y luego pasar de la imagen vectorial del marcador de posición a la imagen de mapa de bits (cargada).
- ¿Aplaza el renderizado con
content-visibility
?
Para un diseño complejo con muchos bloques de contenido, imágenes y videos, la decodificación de datos y la representación de píxeles puede ser una operación bastante costosa, especialmente en dispositivos de gama baja. Concontent-visibility: auto
, podemos indicarle al navegador que omita el diseño de los niños mientras el contenedor está fuera de la ventana gráfica.Por ejemplo, puede omitir la representación del pie de página y las últimas secciones en la carga inicial:
footer { content-visibility: auto; contain-intrinsic-size: 1000px; /* 1000px is an estimated height for sections that are not rendered yet. */ }
Tenga en cuenta que content-visibility: auto; se comporta como desbordamiento: oculto; , pero puede solucionarlo aplicando
padding-left
ypadding-right
en lugar delmargin-left: auto;
,margin-right: auto;
y un ancho declarado. El relleno básicamente permite que los elementos se desborden del cuadro de contenido y entren en el cuadro de relleno sin dejar el modelo de cuadro como un todo y cortarlo.Además, tenga en cuenta que podría introducir algunos CLS cuando finalmente se renderice el contenido nuevo, por lo que es una buena idea utilizar
contain-intrinsic-size
con un marcador de posición del tamaño adecuado ( ¡gracias, Una! ).Thijs Terluin tiene muchos más detalles sobre ambas propiedades y cómo el navegador calcula el
contain-intrinsic-size
, Malte Ubl muestra cómo puede calcularlo y un breve video explicativo de Jake y Surma explica cómo funciona todo.Y si necesita obtener un poco más de granularidad, con CSS Containment, puede omitir manualmente el trabajo de diseño, estilo y pintura para los descendientes de un nodo DOM si solo necesita tamaño, alineación o estilos calculados en otros elementos, o si el elemento está actualmente fuera del lienzo.
- ¿Aplazas la decodificación con
decoding="async"
?
A veces, el contenido aparece fuera de la pantalla, pero queremos asegurarnos de que esté disponible cuando los clientes lo necesiten; idealmente, sin bloquear nada en la ruta crítica, pero decodificando y renderizando de forma asíncrona. Podemos usardecoding="async"
para otorgar al navegador permiso para decodificar la imagen del hilo principal, evitando el impacto del usuario en el tiempo de CPU utilizado para decodificar la imagen (a través de Malte Ubl):<img decoding="async" … />
De forma alternativa, para las imágenes fuera de pantalla, podemos mostrar primero un marcador de posición y, cuando la imagen esté dentro de la ventana gráfica, mediante IntersectionObserver, active una llamada de red para que la imagen se descargue en segundo plano. Además, podemos diferir el procesamiento hasta la decodificación con img.decode() o descargar la imagen si la API de decodificación de imágenes no está disponible.
Al renderizar la imagen, podemos usar animaciones de aparición gradual, por ejemplo. Katie Hempenius y Addy Osmani comparten más información en su charla Speed at Scale: Web Performance Tips and Tricks from the Trenches.
- ¿Genera y sirve CSS crítico?
Para asegurarse de que los navegadores comiencen a mostrar su página lo más rápido posible, se ha convertido en una práctica común recopilar todo el CSS necesario para comenzar a mostrar la primera parte visible de la página (conocida como "CSS crítico" o "CSS en la mitad superior de la página"). ") e incluirlo en línea en el<head>
de la página, reduciendo así los viajes de ida y vuelta. Debido al tamaño limitado de los paquetes intercambiados durante la fase de inicio lento, su presupuesto para CSS crítico es de alrededor de 14 KB.Si va más allá de eso, el navegador necesitará viajes de ida y vuelta adicionales para obtener más estilos. CriticalCSS y Critical le permiten generar CSS crítico para cada plantilla que esté utilizando. Sin embargo, en nuestra experiencia, ningún sistema automático fue mejor que la recopilación manual de CSS crítico para cada plantilla y, de hecho, ese es el enfoque al que hemos regresado recientemente.
A continuación, puede incluir CSS crítico en línea y cargar el resto de forma diferida con el complemento Webpack de critters. Si es posible, considere usar el enfoque de inserción condicional utilizado por Filament Group, o convierta el código en línea en activos estáticos sobre la marcha.
Si actualmente carga su CSS completo de forma asíncrona con bibliotecas como loadCSS, no es realmente necesario. Con
media="print"
, puede engañar al navegador para que obtenga el CSS de forma asíncrona pero se aplique al entorno de la pantalla una vez que se carga. ( ¡gracias Scott! )<!-- Via Scott Jehl. https://www.filamentgroup.com/lab/load-css-simpler/ --> <!-- Load CSS asynchronously, with low priority --> <link rel="stylesheet" href="full.css" media="print" onload="this.media='all'" />
Al recopilar todo el CSS crítico para cada plantilla, es común explorar solo el área "en la mitad superior de la página". Sin embargo, para diseños complejos, podría ser una buena idea incluir la base del diseño también para evitar costos masivos de recálculo y repintado, lo que perjudicaría su puntuación de Core Web Vitals como resultado.
¿Qué sucede si un usuario obtiene una URL que se vincula directamente al medio de la página pero el CSS aún no se ha descargado? En ese caso, se ha vuelto común ocultar contenido no crítico, por ejemplo, con
opacity: 0;
en CSS integrado yopacity: 1
en el archivo CSS completo y mostrarlo cuando CSS esté disponible. Sin embargo, tiene una desventaja importante , ya que es posible que los usuarios con conexiones lentas nunca puedan leer el contenido de la página. Por eso es mejor mantener siempre visible el contenido, aunque no tenga el estilo adecuado.Poner CSS crítico (y otros activos importantes) en un archivo separado en el dominio raíz tiene beneficios, a veces incluso más que en línea, debido al almacenamiento en caché. Chrome abre especulativamente una segunda conexión HTTP al dominio raíz cuando solicita la página, lo que elimina la necesidad de una conexión TCP para obtener este CSS. Eso significa que puede crear un conjunto de archivos CSS críticos (p. ej., Critical- Homepage.css , Critical-Product-Page.css, etc.) y servirlos desde su raíz, sin tener que alinearlos. ( ¡gracias, Felipe! )
Una palabra de precaución: con HTTP/2, el CSS crítico podría almacenarse en un archivo CSS separado y entregarse a través de un servidor push sin inflar el HTML. El problema es que la inserción del servidor era problemática con muchas trampas y condiciones de carrera en todos los navegadores. Nunca fue compatible de manera constante y tuvo algunos problemas de almacenamiento en caché (consulte la diapositiva 114 en adelante de la presentación de Hooman Beheshti).
De hecho, el efecto podría ser negativo e inflar los búferes de la red, evitando que se entreguen marcos genuinos en el documento. Por lo tanto, no fue muy sorprendente que, por el momento, Chrome esté planeando eliminar la compatibilidad con Server Push.
- Experimente reagrupando sus reglas CSS.
Nos hemos acostumbrado al CSS crítico, pero hay algunas optimizaciones que podrían ir más allá. Harry Roberts realizó una investigación notable con resultados bastante sorprendentes. Por ejemplo, podría ser una buena idea dividir el archivo CSS principal en sus consultas de medios individuales. De esa forma, el navegador recuperará CSS crítico con alta prioridad y todo lo demás con baja prioridad, completamente fuera de la ruta crítica.Además, evite colocar
<link rel="stylesheet" />
antes de los fragmentosasync
. Si las secuencias de comandos no dependen de las hojas de estilo, considere colocar las secuencias de comandos de bloqueo sobre los estilos de bloqueo. Si lo hacen, divide ese JavaScript en dos y cárgalo a cada lado de tu CSS.Scott Jehl resolvió otro problema interesante al almacenar en caché un archivo CSS en línea con un trabajador de servicio, un problema común familiar si está utilizando CSS crítico. Básicamente, agregamos un atributo de ID al elemento de
style
para que sea fácil encontrarlo usando JavaScript, luego una pequeña parte de JavaScript encuentra ese CSS y usa la API de caché para almacenarlo en un caché de navegador local (con un tipo de contenido detext/css
) para su uso en páginas posteriores. Para evitar la inserción en páginas posteriores y, en su lugar, hacer referencia externa a los activos almacenados en caché, configuramos una cookie en la primera visita a un sitio. ¡Voila!Vale la pena señalar que el estilo dinámico también puede ser costoso, pero generalmente solo en los casos en que confía en cientos de componentes compuestos renderizados simultáneamente. Entonces, si está usando CSS-in-JS, asegúrese de que su biblioteca CSS-in-JS optimice la ejecución cuando su CSS no tenga dependencias en el tema o los accesorios, y no sobre-componga componentes con estilo . Aggelos Arvanitakis comparte más información sobre los costos de rendimiento de CSS-in-JS.
- ¿Transmite respuestas?
A menudo olvidados y descuidados, los flujos proporcionan una interfaz para leer o escribir fragmentos de datos asincrónicos, de los cuales solo un subconjunto podría estar disponible en la memoria en un momento dado. Básicamente, permiten que la página que realizó la solicitud original comience a trabajar con la respuesta tan pronto como esté disponible la primera parte de los datos, y utilizan analizadores optimizados para transmisión para mostrar progresivamente el contenido.Podríamos crear una transmisión a partir de múltiples fuentes. Por ejemplo, en lugar de servir un shell de interfaz de usuario vacío y permitir que JavaScript lo complete, puede permitir que el trabajador del servicio construya una secuencia donde el shell proviene de un caché, pero el cuerpo proviene de la red. Como señaló Jeff Posnick, si su aplicación web funciona con un CMS que el servidor procesa HTML uniendo plantillas parciales, ese modelo se traduce directamente en el uso de respuestas de transmisión, con la lógica de plantillas replicada en el trabajador del servicio en lugar de su servidor. El artículo The Year of Web Streams de Jake Archibald destaca cómo se puede construir exactamente. El aumento de rendimiento es bastante notable.
Una ventaja importante de la transmisión de la respuesta HTML completa es que el HTML representado durante la solicitud de navegación inicial puede aprovechar al máximo el analizador HTML de transmisión del navegador. Los fragmentos de HTML que se insertan en un documento después de que se haya cargado la página (como es común con el contenido que se completa a través de JavaScript) no pueden aprovechar esta optimización.
¿Soporte de navegador? Todavía estoy llegando con soporte parcial en Chrome, Firefox, Safari y Edge que admiten la API y Service Workers que se admiten en todos los navegadores modernos. Y si vuelve a sentirse aventurero, puede consultar una implementación experimental de solicitudes de transmisión, que le permite comenzar a enviar la solicitud mientras sigue generando el cuerpo. Disponible en cromo 85.
- Considere hacer que sus componentes reconozcan la conexión.
Los datos pueden ser costosos y con una carga útil cada vez mayor, debemos respetar a los usuarios que optan por ahorrar datos mientras acceden a nuestros sitios o aplicaciones. El encabezado de solicitud de sugerencia del cliente Save-Data nos permite personalizar la aplicación y la carga útil para usuarios con restricciones de costo y rendimiento.De hecho, puede reescribir las solicitudes de imágenes de alto DPI a imágenes de bajo DPI, eliminar fuentes web, efectos de paralaje sofisticados, previsualizar miniaturas y desplazamiento infinito, desactivar la reproducción automática de video, empujar el servidor, reducir la cantidad de elementos mostrados y degradar la calidad de la imagen, o incluso cambiar la forma en que entrega el marcado. Tim Vereecke ha publicado un artículo muy detallado sobre estrategias de ahorro de datos que presenta muchas opciones para guardar datos.
¿Quién está usando
save-data
?, te estarás preguntando. El 18% de los usuarios globales de Android Chrome tienen habilitado el Modo Lite (conSave-Data
activado), y es probable que el número sea mayor. Según la investigación de Simon Hearne, la tasa de aceptación es más alta en los dispositivos más baratos, pero hay muchos valores atípicos. Por ejemplo: los usuarios de Canadá tienen una tasa de aceptación de más del 34 % (en comparación con el ~7 % en los EE. UU.) y los usuarios del último buque insignia de Samsung tienen una tasa de aceptación de casi el 18 % a nivel mundial.Con el modo
Save-Data
activado, Chrome Mobile brindará una experiencia optimizada, es decir, una experiencia web con proxy con secuencias de comandos diferidas ,font-display: swap
y carga diferida forzada. Simplemente es más sensato crear la experiencia por su cuenta en lugar de confiar en el navegador para realizar estas optimizaciones.Actualmente, el encabezado solo es compatible con Chromium, en la versión Android de Chrome o a través de la extensión Data Saver en un dispositivo de escritorio. Finalmente, también puede usar la API de información de red para entregar costosos módulos de JavaScript, imágenes y videos de alta resolución según el tipo de red. La API de información de red y, específicamente,
navigator.connection.effectiveType
usan valores deRTT
,downlink
y deeffectiveType
(y algunos otros) para proporcionar una representación de la conexión y los datos que los usuarios pueden manejar.En este contexto, Max Bock habla de componentes conscientes de la conexión y Addy Osmani habla de servicio de módulos adaptativos. Por ejemplo, con React, podríamos escribir un componente que se represente de manera diferente para diferentes tipos de conexión. Como sugirió Max, un componente
<Media />
en un artículo de noticias podría generar:-
Offline
: un marcador de posición con textoalt
, - Modo
2G
/save-data
: una imagen de baja resolución, -
3G
en pantalla no Retina: una imagen de resolución media, -
3G
en pantallas Retina: imagen Retina de alta resolución, -
4G
: un vídeo HD.
Dean Hume proporciona una implementación práctica de una lógica similar utilizando un trabajador de servicio. Para un video, podríamos mostrar un póster de video de manera predeterminada y luego mostrar el ícono "Reproducir", así como el shell del reproductor de video, los metadatos del video, etc. en mejores conexiones. Como alternativa para los navegadores que no son compatibles, podríamos escuchar el evento
canplaythrough
y usarPromise.race()
para agotar el tiempo de carga de la fuente si el eventocanplaythrough
no se activa en 2 segundos.Si desea profundizar un poco más, aquí hay un par de recursos para comenzar:
- Addy Osmani muestra cómo implementar el servicio adaptable en React.
- React Adaptive Loading Hooks & Utilities proporciona fragmentos de código para React,
- Netanel Basel explora los componentes conscientes de la conexión en Angular,
- Theodore Vorilas comparte cómo funciona el servicio de componentes adaptables mediante la API de información de red en Vue.
- Umar Hansa muestra cómo descargar/ejecutar JavaScript costoso de forma selectiva.
-
- Considere hacer que su dispositivo de componentes reconozca la memoria.
Sin embargo, la conexión de red nos da solo una perspectiva en el contexto del usuario. Yendo más allá, también puede ajustar dinámicamente los recursos en función de la memoria disponible del dispositivo, con la API de memoria del dispositivo.navigator.deviceMemory
devuelve la cantidad de RAM que tiene el dispositivo en gigabytes, redondeada a la potencia de dos más cercana. La API también presenta un encabezado de sugerencias de cliente,Device-Memory
, que informa el mismo valor.Bonificación : Umar Hansa muestra cómo aplazar costosos scripts con importaciones dinámicas para cambiar la experiencia en función de la memoria del dispositivo, la conectividad de red y la concurrencia de hardware.
- Caliente la conexión para acelerar la entrega.
Use sugerencias de recursos para ahorrar tiempo endns-prefetch
(que realiza una búsqueda de DNS en segundo plano),preconnect
(que le pide al navegador que inicie el protocolo de enlace de conexión (DNS, TCP, TLS) en segundo plano),prefetch
(que le pide al navegador para solicitar un recurso) ypreload
(que precarga los recursos sin ejecutarlos, entre otras cosas). Bien soportado en los navegadores modernos, con soporte para Firefox pronto.¿Recuerdas
prerender
? La sugerencia de recurso utilizada para solicitar al navegador que construya la página completa en segundo plano para la próxima navegación. Los problemas de implementación fueron bastante problemáticos, desde una enorme huella de memoria y uso de ancho de banda hasta múltiples resultados analíticos registrados e impresiones de anuncios.Como era de esperar, quedó obsoleto, pero el equipo de Chrome lo ha recuperado como mecanismo NoState Prefetch. De hecho, Chrome trata la sugerencia previa a la representación como una captación previa de
prerender
, por lo que todavía podemos usarla hoy. Como explica Katie Hempenius en ese artículo, "al igual que la representación previa, NoState Prefetch obtiene recursos por adelantado ; pero a diferencia de la representación previa, no ejecuta JavaScript ni representa ninguna parte de la página por adelantado".NoState Prefetch solo usa ~45 MiB de memoria y los subrecursos que se obtienen se obtendrán con una prioridad de red
IDLE
. Desde Chrome 69, NoState Prefetch agrega el encabezado Purpose: Prefetch a todas las solicitudes para que se distingan de la navegación normal.Además, tenga cuidado con las alternativas y los portales de procesamiento previo, un nuevo esfuerzo hacia el procesamiento previo consciente de la privacidad, que proporcionará la
preview
insertada del contenido para una navegación fluida.El uso de sugerencias de recursos es probablemente la forma más fácil de aumentar el rendimiento y, de hecho, funciona bien. ¿Cuándo usar qué? Como ha explicado Addy Osmani, es razonable precargar recursos que sabemos que es muy probable que se utilicen en la página actual y para navegaciones futuras a través de múltiples límites de navegación, por ejemplo, paquetes de paquetes web necesarios para páginas que el usuario aún no ha visitado.
El artículo de Addy sobre "Cargar prioridades en Chrome" muestra cómo Chrome interpreta exactamente las sugerencias de recursos, por lo que una vez que haya decidido qué activos son críticos para el procesamiento, puede asignarles una alta prioridad. Para ver cómo se priorizan sus solicitudes, puede habilitar una columna de "prioridad" en la tabla de solicitudes de red de Chrome DevTools (así como en Safari).
La mayoría de las veces en estos días, usaremos al menos
preconnect
ydns-prefetch
, y seremos cautelosos al usarprefetch
,preload
yprerender
. Tenga en cuenta que incluso conpreconnect
ydns-prefetch
, el navegador tiene un límite en la cantidad de hosts que buscará/conectará en paralelo, por lo que es una apuesta segura ordenarlos según la prioridad ( ¡gracias Philip Tellis! ).Dado que las fuentes suelen ser activos importantes en una página, a veces es una buena idea solicitar al navegador que descargue fuentes críticas con
preload
. Sin embargo, verifique dos veces si realmente ayuda al rendimiento, ya que hay un rompecabezas de prioridades al precargar fuentes: dado que lapreload
se considera de gran importancia, puede pasar por alto recursos aún más críticos como CSS crítico. ( ¡gracias, Barry! )<!-- Loading two rendering-critical fonts, but not all their weights. --> <!-- crossorigin="anonymous" is required due to CORS. Without it, preloaded fonts will be ignored. https://github.com/w3c/preload/issues/32 via https://twitter.com/iamakulov/status/1275790151642423303 --> <link rel="preload" as="font" href="Elena-Regular.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" /> <link rel="preload" as="font" href="Mija-Bold.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" />
<!-- Loading two rendering-critical fonts, but not all their weights. --> <!-- crossorigin="anonymous" is required due to CORS. Without it, preloaded fonts will be ignored. https://github.com/w3c/preload/issues/32 via https://twitter.com/iamakulov/status/1275790151642423303 --> <link rel="preload" as="font" href="Elena-Regular.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" /> <link rel="preload" as="font" href="Mija-Bold.woff2" type="font/woff2" crossorigin="anonymous" media="only screen and (min-width: 48rem)" />
Dado que
<link rel="preload">
acepta un atributo demedia
, puede optar por descargar recursos de forma selectiva en función de las reglas de consulta de@media
, como se muestra arriba.Además, podemos usar los atributos
imagesrcset
eimagesizes
para precargar imágenes de héroe descubiertas tardíamente más rápido, o cualquier imagen que se cargue a través de JavaScript, por ejemplo, carteles de películas:<!-- Addy Osmani. https://addyosmani.com/blog/preload-hero-images/ --> <link rel="preload" as="image" href="poster.jpg" image image>
<!-- Addy Osmani. https://addyosmani.com/blog/preload-hero-images/ --> <link rel="preload" as="image" href="poster.jpg" image image>
También podemos precargar el JSON como fetch , para que se descubra antes de que JavaScript lo solicite:
<!-- Addy Osmani. https://addyosmani.com/blog/preload-hero-images/ --> <link rel="preload" as="fetch" href="foo.com/api/movies.json" crossorigin>
También podríamos cargar JavaScript dinámicamente, de manera efectiva para la ejecución diferida del script.
/* Adding a preload hint to the head */ var preload = document.createElement("link"); link.href = "myscript.js"; link.rel = "preload"; link.as = "script"; document.head.appendChild(link); /* Injecting a script when we want it to execute */ var script = document.createElement("script"); script.src = "myscript.js"; document.body.appendChild(script);
Algunas trampas a tener en cuenta: la
preload
es buena para acercar el tiempo de inicio de descarga de un activo a la solicitud inicial, pero los activos precargados aterrizan en la memoria caché que está vinculada a la página que realiza la solicitud. lapreload
bien con la caché HTTP: nunca se envía una solicitud de red si el elemento ya está en la caché HTTP.Por lo tanto, es útil para recursos descubiertos tardíamente, imágenes destacadas cargadas a través
background-image
, insertando CSS crítico (o JavaScript) y precargando el resto del CSS (o JavaScript).Una etiqueta de
preload
puede iniciar una precarga solo después de que el navegador haya recibido el HTML del servidor y el analizador de búsqueda anticipada haya encontrado la etiqueta depreload
. La carga previa a través del encabezado HTTP podría ser un poco más rápida, ya que no debemos esperar a que el navegador analice el HTML para iniciar la solicitud (aunque se debate).Early Hints ayudará aún más, permitiendo que la precarga se active incluso antes de que se envíen los encabezados de respuesta para el HTML (en la hoja de ruta en Chromium, Firefox). Además, las sugerencias de prioridad nos ayudarán a indicar las prioridades de carga de los scripts.
Tenga cuidado : si está utilizando
preload
,as
debe definirse o nada se carga, además, las fuentes precargadas sin el atributocrossorigin
se recuperarán dos veces. Si está utilizandoprefetch
, tenga cuidado con los problemas de encabezado deAge
en Firefox.
- Utilice trabajadores de servicio para el almacenamiento en caché y los respaldos de la red.
Ninguna optimización del rendimiento en una red puede ser más rápida que un caché almacenado localmente en la máquina de un usuario (aunque hay excepciones). Si su sitio web se ejecuta a través de HTTPS, podemos almacenar en caché los activos estáticos en un caché de trabajador de servicio y almacenar respaldos sin conexión (o incluso páginas sin conexión) y recuperarlos de la máquina del usuario, en lugar de ir a la red.Como sugirió Phil Walton, con los trabajadores de servicios, podemos enviar cargas HTML más pequeñas generando nuestras respuestas mediante programación. Un trabajador de servicio puede solicitar solo el mínimo de datos que necesita del servidor (por ejemplo, un contenido HTML parcial, un archivo Markdown, datos JSON, etc.), y luego puede transformar mediante programación esos datos en un documento HTML completo. Entonces, una vez que un usuario visita un sitio y el trabajador de servicio está instalado, el usuario nunca volverá a solicitar una página HTML completa. El impacto en el rendimiento puede ser bastante impresionante.
¿Soporte de navegador? Los trabajadores de servicio cuentan con un amplio apoyo y, de todos modos, el respaldo es la red. ¿ Ayuda a aumentar el rendimiento ? Oh, sí, lo hace. Y está mejorando, por ejemplo, con Background Fetch que también permite cargas/descargas en segundo plano a través de un trabajador de servicio.
Hay una serie de casos de uso para un trabajador de servicio. Por ejemplo, podría implementar la función "Guardar para fuera de línea", manejar imágenes rotas, introducir mensajes entre pestañas o proporcionar diferentes estrategias de almacenamiento en caché según los tipos de solicitud. En general, una estrategia confiable común es almacenar el shell de la aplicación en la memoria caché del trabajador del servicio junto con algunas páginas críticas, como la página sin conexión, la página principal y cualquier otra cosa que pueda ser importante en su caso.
Sin embargo, hay algunas trampas a tener en cuenta. Con un trabajador de servicio implementado, debemos tener cuidado con las solicitudes de rango en Safari (si está utilizando Workbox para un trabajador de servicio, tiene un módulo de solicitud de rango). Si alguna vez te topaste con
DOMException: Quota exceeded.
error en la consola del navegador, luego mira el artículo de Gerardo Cuando 7KB equivalen a 7MB.Como escribe Gerardo: "Si está creando una aplicación web progresiva y está experimentando un almacenamiento de caché inflado cuando su trabajador de servicio almacena en caché activos estáticos servidos desde CDN, asegúrese de que exista el encabezado de respuesta CORS adecuado para recursos de origen cruzado, no almacene en caché respuestas opacas con su trabajador de servicio sin querer, opta por activos de imagen de origen cruzado en el modo
crossorigin
agregando el atributo de origen cruzado a la etiqueta<img>
".Hay muchos recursos excelentes para comenzar con los trabajadores de servicios:
- Mentalidad de trabajador de servicios, que lo ayuda a comprender cómo trabajan los trabajadores de servicios detrás de escena y las cosas que debe comprender al crear uno.
- Chris Ferdinandi proporciona una gran serie de artículos sobre trabajadores de servicios, que explican cómo crear aplicaciones sin conexión y cubren una variedad de escenarios, desde guardar páginas vistas recientemente sin conexión hasta establecer una fecha de caducidad para elementos en un caché de trabajadores de servicios.
- Dificultades y prácticas recomendadas de Service Worker, con algunos consejos sobre el alcance, retrasando el registro de un Service Worker y el almacenamiento en caché de Service Worker.
- Gran serie de Ire Aderinokun sobre "Offline First" con Service Worker, con una estrategia de almacenamiento previo en caché del shell de la aplicación.
- Service Worker: una introducción con consejos prácticos sobre cómo usar Service Worker para disfrutar de ricas experiencias fuera de línea, sincronizaciones periódicas en segundo plano y notificaciones automáticas.
- Siempre vale la pena consultar el libro de cocina fuera de línea de Jake Archibald con una serie de recetas sobre cómo hornear su propio trabajador de servicio.
- Workbox es un conjunto de bibliotecas de trabajadores de servicios creadas específicamente para crear aplicaciones web progresivas.
- ¿Está ejecutando trabajadores de servidores en CDN/Edge, por ejemplo, para pruebas A/B?
En este punto, estamos bastante acostumbrados a ejecutar trabajadores de servicio en el cliente, pero con CDN implementándolos en el servidor, también podríamos usarlos para modificar el rendimiento en el perímetro.Por ejemplo, en las pruebas A/B, cuando HTML necesita variar su contenido para diferentes usuarios, podríamos usar Service Workers en los servidores CDN para manejar la lógica. También podríamos transmitir la reescritura de HTML para acelerar los sitios que usan Google Fonts.
- Optimizar el rendimiento de renderizado.
Cada vez que la aplicación es lenta, se nota de inmediato. Por lo tanto, debemos asegurarnos de que no haya demoras al desplazarse por la página o cuando se anima un elemento, y que esté alcanzando constantemente los 60 cuadros por segundo. Si eso no es posible, al menos hacer que los cuadros por segundo sean consistentes es preferible a un rango mixto de 60 a 15. Use elwill-change
de CSS para informar al navegador qué elementos y propiedades cambiarán.Siempre que esté experimentando, depure los repintados innecesarios en DevTools:
- Mida el rendimiento de representación en tiempo de ejecución. Consulte algunos consejos útiles sobre cómo darle sentido.
- Para comenzar, consulte el curso gratuito de Udacity de Paul Lewis sobre optimización de la representación del navegador y el artículo de Georgy Marchuk sobre pintura del navegador y consideraciones para el rendimiento web.
- Habilite Paint Flashing en "Más herramientas → Representación → Paint Flashing" en Firefox DevTools.
- En React DevTools, marque "Resaltar actualizaciones" y habilite "Registrar por qué se renderizó cada componente",
- También puede usar Why Did You Render, de modo que cuando se vuelva a renderizar un componente, un flash le notificará el cambio.
¿Está utilizando un diseño de mampostería? Tenga en cuenta que es posible que pueda crear un diseño de mampostería solo con la cuadrícula CSS, muy pronto.
Si desea profundizar en el tema, Nolan Lawson ha compartido trucos para medir con precisión el rendimiento del diseño en su artículo, y Jason Miller también sugirió técnicas alternativas. También tenemos un pequeño artículo de Sergey Chikuyonok sobre cómo obtener una animación GPU correcta.
Nota : los cambios en las capas compuestas por GPU son los menos costosos, por lo que si puede activar solo la composición a través de la
opacity
ytransform
, estará en el camino correcto. Anna Migas también brindó muchos consejos prácticos en su charla sobre la depuración del rendimiento de representación de la interfaz de usuario. Y para comprender cómo depurar el rendimiento de pintura en DevTools, consulte el video de auditoría de rendimiento de pintura de Umar. - ¿Ha optimizado para el rendimiento percibido?
Si bien la secuencia de cómo aparecen los componentes en la página y la estrategia de cómo entregamos los activos al navegador son importantes, no debemos subestimar también el papel del rendimiento percibido. El concepto trata los aspectos psicológicos de la espera, básicamente manteniendo a los clientes ocupados o comprometidos mientras sucede otra cosa. Ahí es donde entran en juego la gestión de la percepción, el inicio preventivo, la finalización anticipada y la gestión de la tolerancia.Que significa todo esto? Mientras cargamos activos, podemos tratar de estar siempre un paso por delante del cliente, para que la experiencia se sienta rápida mientras suceden muchas cosas en segundo plano. Para mantener al cliente comprometido, podemos probar pantallas esqueléticas (demostración de implementación) en lugar de cargar indicadores, agregar transiciones/animaciones y básicamente engañar a la UX cuando no hay nada más que optimizar.
En su estudio de caso sobre The Art of UI Skeletons, Kumar McMillan comparte algunas ideas y técnicas sobre cómo simular listas dinámicas, texto y la pantalla final, así como también cómo considerar el pensamiento de esqueleto con React.
Sin embargo, tenga cuidado: las pantallas de esqueleto deben probarse antes de implementarse, ya que algunas pruebas mostraron que las pantallas de esqueleto pueden funcionar peor según todas las métricas.
- ¿Evita cambios de diseño y repintados?
En el ámbito del rendimiento percibido, probablemente una de las experiencias más perturbadoras es el cambio de diseño , o reflujos , causados por imágenes y videos reescalados, fuentes web, anuncios inyectados o secuencias de comandos descubiertas tardíamente que llenan los componentes con contenido real. Como resultado, un cliente podría comenzar a leer un artículo solo para ser interrumpido por un salto de diseño sobre el área de lectura. La experiencia suele ser abrupta y bastante desorientadora: y eso es probablemente un caso de prioridades de carga que deben reconsiderarse.La comunidad ha desarrollado un par de técnicas y soluciones para evitar reflujos. En general, es una buena idea evitar insertar contenido nuevo sobre contenido existente , a menos que suceda en respuesta a una interacción del usuario. Establezca siempre los atributos de ancho y alto en las imágenes, para que los navegadores modernos asignen el cuadro y reserven el espacio de forma predeterminada (Firefox, Chrome).
Tanto para imágenes como para videos, podemos usar un marcador de posición SVG para reservar el cuadro de visualización en el que aparecerán los medios. Eso significa que el área se reservará correctamente cuando también necesite mantener su relación de aspecto. También podemos usar marcadores de posición o imágenes alternativas para anuncios y contenido dinámico, así como preasignar espacios de diseño.
En lugar de imágenes de carga diferida con secuencias de comandos externas, considere usar la carga diferida nativa o la carga diferida híbrida cuando cargamos una secuencia de comandos externa solo si la carga diferida nativa no es compatible.
Como se mencionó anteriormente, siempre agrupe los repintados de fuentes web y la transición de todas las fuentes alternativas a todas las fuentes web a la vez; solo asegúrese de que ese cambio no sea demasiado abrupto, ajustando la altura de línea y el espacio entre las fuentes con font-style-matcher .
Para anular las métricas de fuente para que una fuente alternativa emule una fuente web, podemos usar los descriptores @font-face para anular las métricas de fuente (demostración, habilitado en Chrome 87). (Tenga en cuenta que los ajustes son complicados con pilas de fuentes complicadas).
Para el CSS tardío, podemos asegurarnos de que el CSS crítico para el diseño esté integrado en el encabezado de cada plantilla. Incluso más allá de eso: para páginas largas, cuando se agrega la barra de desplazamiento vertical, desplaza el contenido principal 16px hacia la izquierda. Para mostrar una barra de desplazamiento antes, podemos agregar
overflow-y: scroll
enhtml
para aplicar una barra de desplazamiento en la primera pintura. Esto último ayuda porque las barras de desplazamiento pueden causar cambios de diseño no triviales debido a que el contenido de la parte superior del pliegue se redistribuye cuando cambia el ancho. Sin embargo, debería ocurrir principalmente en plataformas con barras de desplazamiento no superpuestas como Windows. Pero: rompe laposition: sticky
porque esos elementos nunca se desplazarán fuera del contenedor.Si trabaja con encabezados que se vuelven fijos o fijos en la parte superior de la página al desplazarse, reserve espacio para el encabezado cuando se pinee, por ejemplo, con un elemento de marcador de posición o
margin-top
en el contenido. Una excepción deberían ser los banners de consentimiento de cookies que no deberían tener impacto en CLS, pero a veces lo hacen: depende de la implementación. Hay algunas estrategias interesantes y conclusiones en este hilo de Twitter.Para un componente de pestaña que puede incluir varias cantidades de textos, puede evitar cambios de diseño con pilas de cuadrícula CSS. Al colocar el contenido de cada pestaña en la misma área de cuadrícula y ocultar una de ellas a la vez, podemos asegurarnos de que el contenedor siempre tome la altura del elemento más grande, por lo que no se producirán cambios de diseño.
Ah, y por supuesto, el desplazamiento infinito y "Cargar más" también pueden causar cambios de diseño si hay contenido debajo de la lista (por ejemplo, pie de página). Para mejorar CLS, reserve suficiente espacio para el contenido que se cargaría antes de que el usuario se desplace a esa parte de la página, elimine el pie de página o cualquier elemento DOM en la parte inferior de la página que pueda ser empujado hacia abajo por la carga del contenido. Además, precargar datos e imágenes para el contenido de la mitad inferior de la página, de modo que cuando un usuario se desplace hasta ese punto, ya esté allí. También puede usar bibliotecas de virtualización de listas como react-window para optimizar listas largas ( ¡gracias, Addy Osmani! ).
Para asegurarse de contener el impacto de los reflujos, mida la estabilidad del diseño con la API de inestabilidad del diseño. Con él, puede calcular el puntaje de Cambio de diseño acumulativo ( CLS ) e incluirlo como un requisito en sus pruebas, por lo que cada vez que aparece una regresión, puede rastrearla y corregirla.
Para calcular la puntuación de cambio de diseño, el navegador observa el tamaño de la ventana gráfica y el movimiento de elementos inestables en la ventana gráfica entre dos marcos renderizados. Idealmente, la puntuación sería cercana a
0
. Hay una gran guía de Milica Mihajlija y Philip Walton sobre qué es CLS y cómo medirlo. Es un buen punto de partida para medir y mantener el rendimiento percibido y evitar interrupciones, especialmente para tareas críticas para el negocio.Sugerencia rápida : para descubrir qué causó un cambio de diseño en DevTools, puede explorar los cambios de diseño en "Experiencia" en el Panel de rendimiento.
Bonificación : si desea reducir los reflujos y los repintados, consulte la guía de Charis Theodoulou para Minimizar DOM Reflow/Layout Thrashing y la lista de Paul Irish de Qué fuerza el diseño/reflujo, así como CSSTriggers.com, una tabla de referencia sobre las propiedades de CSS que activan el diseño, la pintura y composición.
Redes y HTTP/2
- ¿Está habilitado el grapado OCSP?
Al habilitar el engrapado OCSP en su servidor, puede acelerar sus protocolos de enlace TLS. El Protocolo de estado de certificados en línea (OCSP) se creó como una alternativa al protocolo de Lista de revocación de certificados (CRL). Ambos protocolos se utilizan para comprobar si se ha revocado un certificado SSL.Sin embargo, el protocolo OCSP no requiere que el navegador dedique tiempo a descargar y luego buscar en una lista la información del certificado, lo que reduce el tiempo requerido para un apretón de manos.
- ¿Ha reducido el impacto de la revocación del certificado SSL?
En su artículo sobre "El costo de rendimiento de los certificados EV", Simon Hearne brinda una excelente descripción general de los certificados comunes y el impacto que puede tener la elección de un certificado en el rendimiento general.Como escribe Simon, en el mundo de HTTPS, existen algunos tipos de niveles de validación de certificados que se utilizan para proteger el tráfico:
- La validación de dominio (DV) valida que el solicitante del certificado es propietario del dominio,
- La validación de la organización (OV) valida que una organización es propietaria del dominio,
- Extended Validation (EV) valida que una organización es propietaria del dominio, con una validación rigurosa.
Es importante tener en cuenta que todos estos certificados son iguales en términos de tecnología; sólo difieren en la información y propiedades proporcionadas en dichos certificados.
Los certificados EV son costosos y consumen mucho tiempo, ya que requieren que una persona revise un certificado y garantice su validez. Los certificados DV, por otro lado, a menudo se proporcionan de forma gratuita, por ejemplo, Let's Encrypt, una autoridad de certificación abierta y automatizada que está bien integrada en muchos proveedores de alojamiento y CDN. De hecho, en el momento de escribir este artículo, funciona con más de 225 millones de sitios web (PDF), aunque solo representa el 2,69 % de las páginas (abiertas en Firefox).
Entonces, ¿cuál es el problema entonces? El problema es que los certificados EV no son totalmente compatibles con el grapado OCSP mencionado anteriormente. Si bien el grapado permite que el servidor verifique con la autoridad de certificación si el certificado ha sido revocado y luego agrega ("grapa") esta información al certificado, sin grapar, el cliente tiene que hacer todo el trabajo, lo que genera solicitudes innecesarias durante la negociación de TLS. . En conexiones deficientes, esto podría terminar con costos de rendimiento notables (más de 1000 ms).
Los certificados EV no son una buena opción para el rendimiento web y pueden causar un impacto mucho mayor en el rendimiento que los certificados DV. Para un rendimiento web óptimo, presente siempre un certificado DV grapado de OCSP. También son mucho más baratos que los certificados EV y menos complicados de adquirir. Bueno, al menos hasta que CRLite esté disponible.
Nota : Con QUIC/HTTP/3 sobre nosotros, vale la pena señalar que la cadena de certificados TLS es el único contenido de tamaño variable que domina el conteo de bytes en QUIC Handshake. El tamaño varía entre unos cientos de byes y más de 10 KB.
Por lo tanto, mantener los certificados TLS pequeños importa mucho en QUIC/HTTP/3, ya que los certificados grandes provocarán múltiples protocolos de enlace. Además, debemos asegurarnos de que los certificados estén comprimidos, ya que, de lo contrario, las cadenas de certificados serían demasiado grandes para caber en un solo vuelo QUIC.
Puede encontrar muchos más detalles e indicaciones sobre el problema y las soluciones en:
- Los certificados EV hacen que la Web sea lenta y poco confiable por Aaron Peters,
- El impacto de la revocación del certificado SSL en el rendimiento web por Matt Hobbs,
- El costo de desempeño de los certificados EV por Simon Hearne,
- ¿El apretón de manos QUIC requiere compresión para ser rápido? por Patrick McManus.
- ¿Ya ha adoptado IPv6?
Debido a que nos estamos quedando sin espacio con IPv4 y las principales redes móviles están adoptando IPv6 rápidamente (EE. UU. casi ha alcanzado un umbral de adopción de IPv6 del 50 %), es una buena idea actualizar su DNS a IPv6 para mantenerse a prueba de balas en el futuro. Solo asegúrese de que se brinde soporte de doble pila en toda la red: permite que IPv6 e IPv4 se ejecuten simultáneamente uno al lado del otro. Después de todo, IPv6 no es compatible con versiones anteriores. Además, los estudios muestran que IPv6 hizo que esos sitios web fueran entre un 10 y un 15 % más rápidos debido al descubrimiento de vecinos (NDP) y la optimización de rutas. - Asegúrese de que todos los recursos se ejecuten a través de HTTP/2 (o HTTP/3).
Con Google empujando hacia una web HTTPS más segura en los últimos años, cambiar al entorno HTTP/2 es definitivamente una buena inversión. De hecho, según Web Almanac, el 64% de todas las solicitudes ya se ejecutan a través de HTTP/2.Es importante comprender que HTTP/2 no es perfecto y tiene problemas de priorización, pero se admite muy bien; y, en la mayoría de los casos, es mejor que lo hagas.
Una palabra de precaución: HTTP/2 Server Push se está eliminando de Chrome, por lo que si su implementación se basa en Server Push, es posible que deba volver a visitarlo. En su lugar, podríamos estar mirando Early Hints, que ya están integrados como experimento en Fastly.
Si aún utiliza HTTP, la tarea que más tiempo consumirá será migrar primero a HTTPS y luego ajustar su proceso de compilación para atender la multiplexación y paralelización de HTTP/2. Llevar HTTP/2 a Gov.uk es un estudio de caso fantástico sobre cómo hacer exactamente eso, encontrar una forma de hacerlo a través de CORS, SRI y WPT en el camino. Para el resto de este artículo, asumimos que está cambiando o ya ha cambiado a HTTP/2.
- Implemente correctamente HTTP/2.
Una vez más, la entrega de activos a través de HTTP/2 puede beneficiarse de una revisión parcial de cómo ha estado entregando los activos hasta ahora. Deberá encontrar un buen equilibrio entre empaquetar módulos y cargar muchos módulos pequeños en paralelo. Al final del día, la mejor solicitud sigue siendo no solicitar, sin embargo, el objetivo es encontrar un buen equilibrio entre la primera entrega rápida de activos y el almacenamiento en caché.Por un lado, es posible que desee evitar la concatenación de activos por completo, en lugar de dividir toda la interfaz en muchos módulos pequeños, comprimiéndolos como parte del proceso de compilación y cargándolos en paralelo. Un cambio en un archivo no requerirá que se vuelva a descargar toda la hoja de estilo o JavaScript. También minimiza el tiempo de análisis y mantiene bajas las cargas útiles de las páginas individuales.
Por otro lado, el embalaje sigue siendo importante. Al usar muchos scripts pequeños, la compresión general se verá afectada y aumentará el costo de recuperar objetos del caché. La compresión de un paquete grande se beneficiará de la reutilización del diccionario, mientras que los paquetes separados pequeños no lo harán. Hay trabajo estándar para abordar eso, pero está muy lejos por ahora. En segundo lugar, los navegadores aún no se han optimizado para tales flujos de trabajo. Por ejemplo, Chrome activará las comunicaciones entre procesos (IPC) lineales a la cantidad de recursos, por lo que incluir cientos de recursos tendrá costos de tiempo de ejecución del navegador.
Aún así, puedes intentar cargar CSS progresivamente. De hecho, el CSS integrado ya no bloquea el renderizado para Chrome. Pero hay algunos problemas de priorización, por lo que no es tan sencillo, pero vale la pena experimentar con ellos.
Podría salirse con la suya con la fusión de conexiones HTTP/2, lo que le permite usar la fragmentación del dominio mientras se beneficia de HTTP/2, pero lograr esto en la práctica es difícil y, en general, no se considera una buena práctica. Además, HTTP/2 y la integridad de los subrecursos no siempre funcionan.
¿Qué hacer? Bueno, si utiliza HTTP/2, enviar alrededor de 6 a 10 paquetes parece un compromiso decente (y no es tan malo para los navegadores heredados). Experimente y mida para encontrar el equilibrio adecuado para su sitio web.
- ¿Enviamos todos los activos a través de una única conexión HTTP/2?
Una de las principales ventajas de HTTP/2 es que nos permite enviar activos por cable a través de una sola conexión. Sin embargo, a veces es posible que hayamos hecho algo mal, por ejemplo, tener un problema de CORS o configurar incorrectamente el atributocrossorigin
, por lo que el navegador se vería obligado a abrir una nueva conexión.Para verificar si todas las solicitudes usan una única conexión HTTP/2 o si algo está mal configurado, habilite la columna "ID de conexión" en DevTools → Red. Por ejemplo, aquí, todas las solicitudes comparten la misma conexión (286), excepto manifest.json, que abre una separada (451).
- ¿Sus servidores y CDN son compatibles con HTTP/2?
Diferentes servidores y CDN (todavía) admiten HTTP/2 de manera diferente. Utilice la comparación de CDN para comprobar sus opciones o busque rápidamente el rendimiento de sus servidores y las funciones que puede esperar que sean compatibles.Consulte la increíble investigación de Pat Meenan sobre las prioridades de HTTP/2 (video) y pruebe la compatibilidad del servidor con la priorización de HTTP/2. Según Pat, se recomienda habilitar el control de congestión de BBR y establecer
tcp_notsent_lowat
en 16 KB para que la priorización de HTTP/2 funcione de manera confiable en kernels de Linux 4.9 y posteriores ( ¡gracias, Yoav! ). Andy Davies realizó una investigación similar para la priorización de HTTP/2 en navegadores, CDN y servicios de alojamiento en la nube.Mientras está en él, verifique dos veces si su kernel admite TCP BBR y habilítelo si es posible. Actualmente se usa en Google Cloud Platform, Amazon Cloudfront, Linux (por ejemplo, Ubuntu).
- ¿Está en uso la compresión HPACK?
Si está utilizando HTTP/2, verifique que sus servidores implementen la compresión HPACK para los encabezados de respuesta HTTP para reducir la sobrecarga innecesaria. Es posible que algunos servidores HTTP/2 no admitan completamente la especificación, siendo HPACK un ejemplo. H2spec es una gran herramienta (aunque muy técnicamente detallada) para verificar eso. El algoritmo de compresión de HPACK es bastante impresionante y funciona. - Asegúrese de que la seguridad de su servidor sea infalible.
Todas las implementaciones de navegador de HTTP/2 se ejecutan sobre TLS, por lo que probablemente querrá evitar las advertencias de seguridad o que algunos elementos de su página no funcionen. Vuelva a verificar que sus encabezados de seguridad estén configurados correctamente, elimine las vulnerabilidades conocidas y verifique su configuración de HTTPS.Además, asegúrese de que todos los complementos externos y las secuencias de comandos de seguimiento se carguen a través de HTTPS, que las secuencias de comandos entre sitios no sean posibles y que tanto los encabezados de seguridad de transporte estricta de HTTP como los encabezados de política de seguridad de contenido estén configurados correctamente.
- ¿Sus servidores y CDN son compatibles con HTTP/3?
Si bien HTTP/2 ha aportado una serie de mejoras de rendimiento significativas a la web, también dejó bastante espacio para mejorar, especialmente el bloqueo de cabeza de línea en TCP, que se notó en una red lenta con una pérdida de paquetes significativa. HTTP/3 está resolviendo estos problemas para siempre (artículo).Para abordar los problemas de HTTP/2, IETF, junto con Google, Akamai y otros, han estado trabajando en un nuevo protocolo que recientemente se estandarizó como HTTP/3.
Robin Marx ha explicado HTTP/3 muy bien, y la siguiente explicación se basa en su explicación. En esencia, HTTP/3 es muy similar a HTTP/2 en términos de características, pero en el fondo funciona de manera muy diferente. HTTP/3 proporciona una serie de mejoras: apretones de manos más rápidos, mejor cifrado, flujos independientes más confiables, mejor cifrado y control de flujo. Una diferencia notable es que HTTP/3 utiliza QUIC como capa de transporte, con paquetes QUIC encapsulados sobre diagramas UDP, en lugar de TCP.
QUIC integra completamente TLS 1.3 en el protocolo, mientras que en TCP está superpuesto. En la pila TCP típica, tenemos algunos tiempos de sobrecarga de ida y vuelta porque TCP y TLS necesitan hacer sus propios protocolos de enlace por separado, pero con QUIC ambos pueden combinarse y completarse en un solo viaje de ida y vuelta . Dado que TLS 1.3 nos permite configurar claves de cifrado para una conexión consecuente, a partir de la segunda conexión ya podemos enviar y recibir datos de la capa de aplicación en el primer viaje de ida y vuelta, que se denomina "0-RTT".
Además, el algoritmo de compresión de encabezados de HTTP/2 se reescribió por completo, junto con su sistema de priorización. Además, QUIC admite la migración de conexión de Wi-Fi a red celular a través de ID de conexión en el encabezado de cada paquete QUIC. La mayoría de las implementaciones se realizan en el espacio del usuario, no en el espacio del kernel (como se hace con TCP), por lo que deberíamos esperar que el protocolo evolucione en el futuro.
¿Todo esto haría una gran diferencia? Probablemente sí, especialmente teniendo un impacto en los tiempos de carga en dispositivos móviles, pero también en cómo entregamos los activos a los usuarios finales. Mientras que en HTTP/2, varias solicitudes comparten una conexión, en HTTP/3 las solicitudes también comparten una conexión pero transmiten de forma independiente, por lo que un paquete descartado ya no afecta a todas las solicitudes, solo a una transmisión.
Eso significa que, mientras que con un gran paquete de JavaScript, el procesamiento de los activos se ralentizará cuando una transmisión se detenga, el impacto será menos significativo cuando se transmitan varios archivos en paralelo (HTTP/3). Así que el embalaje sigue siendo importante .
HTTP/3 todavía está en proceso. Chrome, Firefox y Safari ya tienen implementaciones. Algunas CDN ya son compatibles con QUIC y HTTP/3. A fines de 2020, Chrome comenzó a implementar HTTP/3 e IETF QUIC y, de hecho, todos los servicios de Google (Google Analytics, YouTube, etc.) ya se ejecutan en HTTP/3. LiteSpeed Web Server admite HTTP/3, pero ni Apache, nginx ni IIS lo admiten todavía, pero es probable que cambie rápidamente en 2021.
El resultado final : si tiene la opción de usar HTTP/3 en el servidor y en su CDN, probablemente sea una muy buena idea hacerlo. El principal beneficio provendrá de obtener múltiples objetos simultáneamente, especialmente en conexiones de alta latencia. Todavía no lo sabemos con certeza, ya que no se han realizado muchas investigaciones en ese espacio, pero los primeros resultados son muy prometedores.
Si desea profundizar más en los detalles y las ventajas del protocolo, aquí hay algunos buenos puntos de partida para verificar:
- Explicación de HTTP/3, un esfuerzo colaborativo para documentar los protocolos HTTP/3 y QUIC. Disponible en varios idiomas, también en PDF.
- Nivelación del rendimiento web con HTTP/3 con Daniel Stenberg.
- Una guía académica de QUIC con Robin Marx presenta los conceptos básicos de los protocolos QUIC y HTTP/3, explica cómo HTTP/3 maneja el bloqueo de cabeza de línea y la migración de conexiones, y cómo HTTP/3 está diseñado para ser perenne (gracias, Simon !).
- Puede verificar si su servidor se ejecuta en HTTP/3 en HTTP3Check.net.
Pruebas y monitoreo
- ¿Ha optimizado su flujo de trabajo de auditoría?
Puede que no suene como un gran problema, pero tener la configuración correcta al alcance de su mano puede ahorrarle bastante tiempo en las pruebas. Considere usar Alfred Workflow de Tim Kadlec para WebPageTest para enviar una prueba a la instancia pública de WebPageTest. De hecho, WebPageTest tiene muchas características oscuras, así que tómese el tiempo para aprender a leer un gráfico de vista en cascada de WebPageTest y cómo leer un gráfico de vista de conexión de WebPageTest para diagnosticar y resolver problemas de rendimiento más rápido.También puede ejecutar WebPageTest desde una hoja de cálculo de Google e incorporar puntajes de accesibilidad, rendimiento y SEO en su configuración de Travis con Lighthouse CI o directamente en Webpack.
Eche un vistazo a la recientemente lanzada AutoWebPerf, una herramienta modular que permite la recopilación automática de datos de rendimiento de múltiples fuentes. Por ejemplo, podríamos establecer una prueba diaria en sus páginas críticas para capturar los datos de campo de la API CrUX y los datos de laboratorio de un informe Lighthouse de PageSpeed Insights.
Y si necesita depurar algo rápidamente pero su proceso de compilación parece ser notablemente lento, tenga en cuenta que "la eliminación de espacios en blanco y la manipulación de símbolos representa el 95% de la reducción de tamaño en el código minificado para la mayoría de JavaScript, no las transformaciones de código elaboradas". simplemente deshabilite la compresión para acelerar las compilaciones de Uglify de 3 a 4 veces".
- ¿Has probado en navegadores proxy y navegadores heredados?
Probar en Chrome y Firefox no es suficiente. Mire cómo funciona su sitio web en navegadores proxy y navegadores heredados. UC Browser y Opera Mini, por ejemplo, tienen una cuota de mercado significativa en Asia (hasta un 35 % en Asia). Mida la velocidad promedio de Internet en sus países de interés para evitar grandes sorpresas en el futuro. Pruebe con limitación de red y emule un dispositivo de alto DPI. BrowserStack es fantástico para realizar pruebas en dispositivos reales remotos y complementarlo con al menos algunos dispositivos reales en su oficina también; vale la pena.
- ¿Has probado el rendimiento de tus 404 páginas?
Normalmente no lo pensamos dos veces cuando se trata de 404 páginas. Después de todo, cuando un cliente solicita una página que no existe en el servidor, el servidor responderá con un código de estado 404 y la página 404 asociada. No hay mucho de eso, ¿no?Un aspecto importante de las respuestas 404 es el tamaño real del cuerpo de la respuesta que se envía al navegador. Según la investigación de 404 páginas realizada por Matt Hobbs, la gran mayoría de las respuestas 404 provienen de favicons faltantes, solicitudes de carga de WordPress, solicitudes de JavaScript rotas, archivos de manifiesto, así como archivos CSS y de fuentes. Cada vez que un cliente solicita un activo que no existe, recibirá una respuesta 404 y, a menudo, esa respuesta es enorme.
Asegúrese de examinar y optimizar la estrategia de almacenamiento en caché para sus páginas 404. Nuestro objetivo es servir HTML al navegador solo cuando espera una respuesta HTML y devolver una pequeña carga útil de error para todas las demás respuestas. Según Matt, "si colocamos una CDN frente a nuestro origen, tenemos la posibilidad de almacenar en caché la respuesta de la página 404 en la CDN. Eso es útil porque sin ella, golpear una página 404 podría usarse como un vector de ataque DoS, al obligando al servidor de origen a responder a cada solicitud 404 en lugar de permitir que la CDN responda con una versión en caché".
Los errores 404 no solo pueden perjudicar su rendimiento, sino que también pueden costar tráfico, por lo que es una buena idea incluir una página de error 404 en su conjunto de pruebas de Lighthouse y realizar un seguimiento de su puntaje a lo largo del tiempo.
- ¿Ha probado el rendimiento de sus solicitudes de consentimiento de GDPR?
En tiempos de GDPR y CCPA, se ha vuelto común confiar en terceros para brindar opciones para que los clientes de la UE opten por participar o no en el seguimiento. Sin embargo, al igual que con cualquier otro script de terceros, su rendimiento puede tener un impacto bastante devastador en todo el esfuerzo de rendimiento.Por supuesto, es probable que el consentimiento real cambie el impacto de los scripts en el rendimiento general, por lo que, como señaló Boris Schapira, es posible que deseemos estudiar algunos perfiles de rendimiento web diferentes:
- El consentimiento fue completamente denegado,
- El consentimiento fue denegado parcialmente,
- El consentimiento se dio en su totalidad.
- El usuario no ha respondido a la solicitud de consentimiento (o la solicitud fue bloqueada por un bloqueador de contenido),
Normalmente, las solicitudes de consentimiento de cookies no deberían tener un impacto en CLS, pero a veces lo hacen, así que considere usar las opciones gratuitas y de código abierto Osano o cookie-consent-box.
En general, vale la pena analizar el rendimiento de la ventana emergente, ya que deberá determinar el desplazamiento horizontal o vertical del evento del mouse y colocar correctamente la ventana emergente en relación con el ancla. Noam Rosenthal comparte los aprendizajes del equipo de Wikimedia en el artículo Estudio de caso de rendimiento web: vistas previas de páginas de Wikipedia (también disponible como video y minutos).
- ¿Mantiene un CSS de diagnóstico de rendimiento?
Si bien podemos incluir todo tipo de controles para garantizar que se implemente el código que no funciona, a menudo es útil tener una idea rápida de algunas de las frutas más fáciles de resolver que podrían resolverse fácilmente. Para eso, podríamos usar el brillante CSS de diagnóstico de rendimiento de Tim Kadlec (inspirado en el fragmento de código de Harry Roberts que destaca imágenes con carga diferida, imágenes sin tamaño, imágenes de formato heredado y secuencias de comandos síncronas.Por ejemplo, es posible que desee asegurarse de que ninguna imagen de la parte superior de la página se cargue de forma diferida. Puede personalizar el fragmento según sus necesidades, por ejemplo, para resaltar fuentes web que no se utilizan o detectar fuentes de iconos. Una pequeña gran herramienta para garantizar que los errores sean visibles durante la depuración, o simplemente para auditar el proyecto actual muy rápidamente.
/* Performance Diagnostics CSS */ /* via Harry Roberts. https://twitter.com/csswizardry/status/1346477682544951296 */ img[loading=lazy] { outline: 10px solid red; }
- ¿Has probado el impacto en la accesibilidad?
Cuando el navegador comienza a cargar una página, crea un DOM y, si hay una tecnología de asistencia, como un lector de pantalla en ejecución, también crea un árbol de accesibilidad. Luego, el lector de pantalla tiene que consultar el árbol de accesibilidad para recuperar la información y ponerla a disposición del usuario, a veces de forma predeterminada y otras a pedido. Y a veces lleva tiempo.Cuando hablamos de tiempo rápido para interactuar, por lo general nos referimos a un indicador de qué tan pronto un usuario puede interactuar con la página haciendo clic o tocando enlaces y botones. El contexto es ligeramente diferente con los lectores de pantalla. En ese caso, Tiempo rápido para interactuar significa cuánto tiempo pasa hasta que el lector de pantalla puede anunciar la navegación en una página determinada y un usuario del lector de pantalla puede presionar el teclado para interactuar.
Leonie Watson ha dado una charla reveladora sobre el rendimiento de la accesibilidad y, específicamente, el impacto que tiene la carga lenta en los retrasos en los anuncios de los lectores de pantalla. Los lectores de pantalla están acostumbrados a los anuncios rápidos y a la navegación rápida y, por lo tanto, podrían ser incluso menos pacientes que los usuarios videntes.
Las páginas grandes y las manipulaciones de DOM con JavaScript provocarán retrasos en los anuncios del lector de pantalla. Un área bastante inexplorada que podría necesitar algo de atención y pruebas, ya que los lectores de pantalla están disponibles literalmente en todas las plataformas (Jaws, NVDA, Voiceover, Narrator, Orca).
- ¿Está establecido el monitoreo continuo?
Tener una instancia privada de WebPagetest siempre es beneficioso para realizar pruebas rápidas e ilimitadas. Sin embargo, una herramienta de monitoreo continuo, como Sitespeed, Calibre y SpeedCurve, con alertas automáticas le brindará una imagen más detallada de su desempeño. Establezca sus propias marcas de tiempo de usuario para medir y monitorear métricas específicas del negocio. Además, considere agregar alertas de regresión de rendimiento automatizadas para monitorear los cambios a lo largo del tiempo.Considere el uso de soluciones RUM para monitorear los cambios en el rendimiento a lo largo del tiempo. Para herramientas de prueba de carga similares a pruebas unitarias automatizadas, puede usar k6 con su API de secuencias de comandos. Además, consulte SpeedTracker, Lighthouse y Calibre.
Triunfos rápidos
Esta lista es bastante completa y completar todas las optimizaciones puede llevar bastante tiempo. Entonces, si tuviera solo 1 hora para obtener mejoras significativas, ¿qué haría? Reduzcamos todo a 17 frutas maduras . Obviamente, antes de comenzar y una vez que termine, mida los resultados, incluida la pintura con contenido más grande y el tiempo para interactuar en una conexión 3G y por cable.
- Mida la experiencia del mundo real y establezca metas apropiadas. Trate de ser al menos un 20% más rápido que su competidor más rápido. Manténgase dentro de la pintura con contenido más grande < 2,5 s, un retraso de la primera entrada < 100 ms, tiempo para interactuar < 5 s en 3G lento, para visitas repetidas, TTI < 2 s. Optimice al menos para First Contentful Paint y Time To Interactive.
- Optimice imágenes con Squoosh, mozjpeg, guetzli, pingo y SVGOMG, y sirva AVIF/WebP con una imagen CDN.
- Prepare CSS crítico para sus plantillas principales e inclínelo en el
<head>
de cada plantilla. Para CSS/JS, opere dentro de un presupuesto de tamaño de archivo crítico de máx. 170 KB en gzip (0,7 MB descomprimidos). - Recorte, optimice, aplace y cargue de forma diferida los scripts. Invierta en la configuración de su paquete para eliminar redundancias y verifique alternativas ligeras.
- Aloja siempre tus activos estáticos y prefiere alojar siempre activos de terceros. Limite el impacto de los scripts de terceros. Use fachadas, cargue widgets en la interacción y tenga cuidado con los fragmentos antiparpadeo.
- Sea selectivo al elegir un marco. Para las aplicaciones de una sola página, identifique las páginas críticas y sírvalas de forma estática, o al menos prerenderícelas, y use la hidratación progresiva en el nivel de componente y los módulos de importación en la interacción.
- La representación del lado del cliente por sí sola no es una buena opción para el rendimiento. Realice una representación previa si sus páginas no cambian mucho y, si puede, posponga el inicio de los marcos. Si es posible, use la representación del lado del servidor de transmisión.
- Sirva código heredado solo para navegadores heredados con
<script type="module">
y patrón de módulo/no módulo. - Experimente reagrupando sus reglas de CSS y pruebe el CSS en el cuerpo.
- Agregue sugerencias de recursos para acelerar la entrega con
dns-lookup
,preconnect
,prefetch
,preload
yprerender
más rápidos. - Crea subconjuntos de fuentes web y cárgalas de forma asíncrona, y utiliza
font-display
en CSS para una primera representación rápida. - Verifique que los encabezados de caché HTTP y los encabezados de seguridad estén configurados correctamente.
- Habilite la compresión Brotli en el servidor. (Si eso no es posible, al menos asegúrese de que la compresión Gzip esté habilitada).
- Habilite la congestión de TCP BBR siempre que su servidor se ejecute en el kernel de Linux versión 4.9+.
- Habilite el grapado OCSP e IPv6 si es posible. Sirva siempre un certificado DV grapado de OCSP.
- Habilite la compresión HPACK para HTTP/2 y cambie a HTTP/3 si está disponible.
- Caché de activos como fuentes, estilos, JavaScript e imágenes en una caché de trabajador de servicio.
Descargar la lista de verificación (PDF, páginas de Apple)
Con esta lista de verificación en mente, debe estar preparado para cualquier tipo de proyecto de rendimiento frontal. No dude en descargar el PDF listo para imprimir de la lista de verificación, así como un documento editable de Apple Pages para personalizar la lista de verificación según sus necesidades:
- Descargue la lista de verificación PDF (PDF, 166 KB)
- Descargue la lista de verificación en Apple Pages (.pages, 275 KB)
- Descargue la lista de verificación en MS Word (.docx, 151 KB)
Si necesita alternativas, también puede consultar la lista de verificación de front-end de Dan Rublic, la "Lista de verificación de rendimiento web del diseñador" de Jon Yablonski y la FrontendChecklist.
¡Nos vamos!
Algunas de las optimizaciones pueden estar más allá del alcance de su trabajo o presupuesto o pueden ser exageradas dado el código heredado con el que tiene que lidiar. ¡Esta bien! Use esta lista de verificación como una guía general (y, con suerte, completa) y cree su propia lista de problemas que se aplican a su contexto. Pero lo más importante, pruebe y mida sus propios proyectos para identificar problemas antes de optimizarlos. ¡Felices resultados de rendimiento en 2021 para todos!
Muchas gracias a Guy Podjarny, Yoav Weiss, Addy Osmani, Artem Denysov, Denys Mishunov, Ilya Pukhalski, Jeremy Wagner, Colin Bendell, Mark Zeman, Patrick Meenan, Leonardo Losoviz, Andy Davies, Rachel Andrew, Anselm Hannemann, Barry Pollard, Patrick Hamann, Gideon Pyzer, Andy Davies, Maria Prosvernina, Tim Kadlec, Rey Bango, Matthias Ott, Peter Bowyer, Phil Walton, Mariana Peralta, Pepijn Senders, Mark Nottingham, Jean Pierre Vincent, Philipp Tellis, Ryan Townsend, Ingrid Bergman, Mohamed Hussain SH, Jacob Groß, Tim Swalling, Bob Visser, Kev Adamson, Adir Amsalem, Aleksey Kulikov y Rodney Rehm por revisar este artículo, así como a nuestra fantástica comunidad que ha compartido técnicas y lecciones aprendidas de su trabajo en la optimización del rendimiento para que todos las utilicen. . ¡Estás realmente destrozando!