Optimiza la carga de secuencias de comandos de terceros en Next.js

Comprende la visión detrás del componente de secuencia de comandos de Next.js, que proporciona una solución integrada para optimizar la carga de secuencias de comandos de terceros.

Alrededor del 45% de las solicitudes de sitios web que se publican en dispositivos móviles y computadoras son solicitudes de terceros, de las cuales el 33% son secuencias de comandos. El tamaño, la latencia y la carga de las secuencias de comandos de terceros pueden afectar de forma significativa el rendimiento de un sitio. El componente de secuencia de comandos de Next.js incluye prácticas recomendadas integradas y valores predeterminados para ayudar a los desarrolladores a incorporar secuencias de comandos de terceros en sus aplicaciones y, al mismo tiempo, abordar posibles problemas de rendimiento de forma inmediata.

Secuencias de comandos de terceros y su impacto en el rendimiento

Las secuencias de comandos de terceros permiten a los desarrolladores web aprovechar las soluciones existentes para implementar funciones comunes y reducir el tiempo de desarrollo. Sin embargo, los creadores de estas secuencias de comandos no suelen tener ningún incentivo para considerar el impacto en el rendimiento del sitio web que las consume. Estas secuencias de comandos también son una caja negra para los desarrolladores que las usan.

Las secuencias de comandos representan una cantidad significativa de bytes de terceros que descargan los sitios web en diferentes categorías de solicitudes de terceros. De forma predeterminada, el navegador prioriza las secuencias de comandos según su ubicación en el documento, lo que puede retrasar el descubrimiento o la ejecución de secuencias de comandos fundamentales para la experiencia del usuario.

Las bibliotecas de terceros necesarias para el diseño deben cargarse con anticipación para renderizar la página. Los terceros que no son necesarios para la renderización inicial deben diferirse para que no bloqueen otro procesamiento en el subproceso principal. Lighthouse tiene dos auditorías para marcar las secuencias de comandos que bloquean la renderización o el subproceso principal.

Auditorías de Lighthouse para Elimina los recursos que bloqueen el procesamiento y Minimiza el uso de terceros

Es importante considerar la secuencia de carga de recursos de tu página para que los recursos críticos no se retrasen y los recursos no críticos no los bloqueen.

Si bien existen prácticas recomendadas para reducir el impacto de los terceros, es posible que no todos sepan cómo implementarlas para cada tercero que usan. Esto puede ser complicado por los siguientes motivos:

  • En promedio, los sitios web usan entre 21 y 23 terceros diferentes, incluidas las secuencias de comandos, en dispositivos móviles y computadoras. El uso y las recomendaciones pueden variar para cada uno.
  • La implementación de muchos terceros puede diferir según si se usa un framework o una biblioteca de IU en particular.
  • Las bibliotecas de terceros más nuevas se presentan con frecuencia.
  • Los diferentes requisitos comerciales relacionados con el mismo tercero dificultan que los desarrolladores estandaricen su uso.

Enfoque de Aurora en las secuencias de comandos de terceros

Parte de la colaboración de Aurora con herramientas y frameworks web de código abierto es proporcionar herramientas predeterminadas sólidas y definidas para ayudar a los desarrolladores a mejorar aspectos de la experiencia del usuario, como el rendimiento, la accesibilidad, la seguridad y la preparación para dispositivos móviles. En 2021, nos enfocamos en ayudar a las pilas de frameworks a mejorar la experiencia del usuario y sus métricas de Métricas web esenciales.

Uno de los pasos más significativos para lograr nuestro objetivo de mejorar el rendimiento del framework consistió en investigar la secuencia de carga ideal de las secuencias de comandos de terceros en Next.js. Los frameworks como Next.js tienen una posición única para proporcionar parámetros de configuración predeterminados y funciones útiles que ayudan a los desarrolladores a cargar recursos de manera eficiente, incluidos los de terceros. Analizamos exhaustivamente los datos de Lighthouse y el Archivo HTTP para descubrir qué terceros bloquean la renderización más en diferentes frameworks.

Para abordar el problema del bloqueo de subproceso principal de secuencias de comandos de terceros que se usan en una aplicación, compilamos el componente de secuencia de comandos. El componente encapsula las funciones de secuenciación para proporcionar a los desarrolladores mejores controles para la carga de secuencias de comandos de terceros.

Secuenciación de secuencias de comandos de terceros sin un componente de framework

La orientación disponible para reducir el impacto de las secuencias de comandos que bloquean la renderización proporciona los siguientes métodos para cargar y secuenciar secuencias de comandos de terceros de manera eficiente:

  1. Usa el atributo async o defer con etiquetas <script> que le indiquen al navegador que cargue secuencias de comandos de terceros no críticas sin bloquear el analizador de documentos. Las secuencias de comandos que no son necesarias para la carga inicial de la página o la primera interacción del usuario se pueden considerar no esenciales.

       <script src="https://example.com/script1.js" defer></script>
       <script src="https://example.com/script2.js" async></script>
    
  2. Establece conexiones anticipadas con los orígenes necesarios con preconnect y dns-prefetch. Esto permite que las secuencias de comandos críticas comiencen a descargarse antes.

       <head>
           <link rel="preconnect" href="http://PreconnThis.com">
           <link rel="dns-prefetch" href="http://PrefetchThis.com">
       </head>
    
  3. Carga diferida de recursos y elementos incorporados de terceros después de que se haya terminado de cargar el contenido de la página principal o cuando el usuario se desplaza hacia abajo hasta la parte de la página en la que se incluyen.

El componente de secuencia de comandos de Next.js

El componente de secuencia de comandos de Next.js implementa los métodos anteriores para secuenciar secuencias de comandos y proporciona una plantilla para que los desarrolladores definan su estrategia de carga. Una vez que se especifique la estrategia adecuada, se cargará de forma óptima sin bloquear otros recursos esenciales.

El componente de secuencia de comandos se basa en la etiqueta <script> HTML y proporciona una opción para establecer la prioridad de carga de secuencias de comandos de terceros con el atributo strategy.

// Example for beforeInteractive:
<Script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?features=IntersectionObserverEntry%2CIntersectionObserver" strategy="beforeInteractive" />

// Example for afterInteractive (default):
<Script src="https://example.com/samplescript.js" />

// Example for lazyonload:
<Script src="https://connect.facebook.net/en_US/sdk.js" strategy="lazyOnload" />

El atributo strategy puede tener tres valores.

  1. beforeInteractive: Esta opción se puede usar para secuencias de comandos críticas que deben ejecutarse antes de que la página se vuelva interactiva. Next.js garantiza que esas secuencias de comandos se inserten en el HTML inicial del servidor y se ejecuten antes que otros JavaScript empaquetados por sí mismos. La administración de consentimiento, las secuencias de comandos de detección de bots o las bibliotecas de ayuda necesarias para renderizar contenido importante son buenas opciones para esta estrategia.

  2. afterInteractive: Esta es la estrategia predeterminada que se aplica y equivale a cargar una secuencia de comandos con el atributo aplazar. Se debe usar para las secuencias de comandos que el navegador puede ejecutar después de que la página es interactiva, por ejemplo, las secuencias de comandos de estadísticas. Next.js inserta estas secuencias de comandos en el lado del cliente y se ejecutan después de que se hidrata la página. Por lo tanto, a menos que se especifique lo contrario, Next.js aplaza todas las secuencias de comandos de terceros definidas con el componente de secuencia de comandos, lo que proporciona una configuración predeterminada sólida.

  3. lazyOnload: Esta opción se puede usar para cargar de forma diferida secuencias de comandos de baja prioridad cuando el navegador está inactivo. La funcionalidad que proporcionan estas secuencias de comandos no es necesaria inmediatamente después de que la página se vuelve interactiva (por ejemplo, los complementos de chat o redes sociales).

Los desarrolladores pueden indicarle a Next.js cómo su aplicación usa una secuencia de comandos especificando la estrategia. Esto permite que el framework aplique optimizaciones y prácticas recomendadas para cargar la secuencia de comandos y, al mismo tiempo, garantizar la mejor secuencia de carga.

Con el componente de secuencia de comandos, los desarrolladores pueden colocar una secuencia de comandos de terceros en cualquier lugar de la aplicación para la carga tardía de terceros y a nivel del documento para las secuencias de comandos críticas. Esto implica que el componente de secuencia de comandos puede estar ubicado en la misma ubicación que el componente que usa la secuencia de comandos. Después de la hidratación, la secuencia de comandos se insertará en la parte superior del documento renderizado inicialmente o en la parte inferior del cuerpo, según la estrategia que se use.

Cómo medir el impacto

Usamos las plantillas de la app de comercio y el blog de partida de Next.js para crear dos apps de demostración que ayudaron a medir el impacto de incluir secuencias de comandos de terceros. Los terceros de uso general para Google Tag Manager y las incorporaciones de redes sociales se incluían en las páginas de estas apps directamente al principio y, luego, a través del componente de secuencia de comandos. Luego, comparamos el rendimiento de estas páginas en WebPageTest.

Secuencias de comandos de terceros en una app de comercio de Next.js

Se agregaron secuencias de comandos de terceros a la plantilla de la app de comercio para la demostración, como se indica a continuación.

Antes Después
Google Tag Manager con asíncrono Componente de secuencia de comandos con strategy = afterInteractive para ambas secuencias de comandos
Botón Seguir de Twitter sin async o aplazar
Configuración de la secuencia de comandos y el componente de secuencia de comandos para la demostración 1 con 2 secuencias de comandos.

En la siguiente comparación, se muestra el progreso visual de ambas versiones del kit de partida de comercio de Next.js. Como se ve, el LCP ocurre casi 1 segundo antes con el componente de secuencia de comandos habilitado con la estrategia de carga correcta.

Comparación de tiras de película que muestra una mejora en el LCP

Secuencias de comandos de terceros en un blog de Next.js

Se agregaron secuencias de comandos de terceros a la app de blog de demostración como se indica a continuación.

Antes Después
Google Tag Manager con asíncrono Componente de secuencia de comandos con strategy = lazyonload para cada una de las cuatro secuencias de comandos
Botón Seguir de Twitter con asíncrono
Botón de suscripción de YouTube sin asíncrono ni aplazamiento
Botón Seguir de LinkedIn sin async o diferir
Configuración de la secuencia de comandos y el componente de secuencia de comandos para la demostración 2 con 4 secuencias de comandos.
Video que muestra el progreso de carga de la página de índice con y sin el componente de secuencia de comandos. Hay una mejora de 0.5 segundos en FCP con el componente de secuencia de comandos.

Como se ve en el video, el primer procesamiento de imagen con contenido (FCP) ocurre a los 0.9 segundos en la página sin el componente de secuencia de comandos y a los 0.4 segundos con el componente de secuencia de comandos.

Qué es lo próximo para el componente de secuencia de comandos

Si bien las opciones de estrategia para afterInteractive y lazyOnload proporcionan un control significativo sobre las secuencias de comandos que bloquean la renderización, también estamos explorando otras opciones que aumentarían la utilidad del componente de secuencia de comandos.

Usa trabajadores web

Los trabajadores web se pueden usar para ejecutar secuencias de comandos independientes en subprocesos en segundo plano que pueden liberar el subproceso principal para controlar el procesamiento de tareas de la interfaz de usuario y mejorar el rendimiento. Los Web Workers son más adecuados para descargar el procesamiento de JavaScript, en lugar del trabajo de la IU, del subproceso principal. Las secuencias de comandos que se usan para la asistencia al cliente o el marketing, que suelen no interactuar con la IU, pueden ser buenas candidatas para ejecutarse en un subproceso en segundo plano. Se puede usar una biblioteca de terceros liviana (PartyTown) para aislar esas secuencias de comandos en un trabajador web.

Con la implementación actual del componente de secuencia de comandos de Next.js, te recomendamos que dejes en suspenso estas secuencias de comandos en el subproceso principal configurando la estrategia en afterInteractive o lazyOnload. En el futuro, proponemos presentar una nueva opción de estrategia, 'worker', que permitirá que Next.js use PartyTown o una solución personalizada para ejecutar secuencias de comandos en trabajadores web. Aceptamos los comentarios de los desarrolladores sobre esta RFC.

Minimiza el CLS

Los elementos incorporados de terceros, como anuncios, videos o feeds de redes sociales, pueden causar cambios de diseño cuando se cargan de forma diferida. Esto afecta la experiencia del usuario y la métrica de Cambio de diseño acumulado (CLS) de la página. Para minimizar el CLS, especifica el tamaño del contenedor en el que se cargará la incorporación.

El componente de secuencia de comandos se puede usar para cargar incorporaciones que pueden provocar cambios de diseño. Estamos considerando aumentarlo para proporcionar opciones de configuración que ayuden a reducir el CLS. Esto podría estar disponible dentro del componente de secuencia de comandos o como un componente complementario.

Componentes de wrapper

La sintaxis y la estrategia de carga para incluir secuencias de comandos de terceros populares, como Google Analytics o Google Tag Manager (GTM), suelen ser fijas. Estos se pueden encapsular aún más en componentes de wrapper individuales para cada tipo de secuencia de comandos. Solo estará disponible para los desarrolladores un conjunto mínimo de atributos específicos de la aplicación (como el ID de seguimiento). Los componentes del wrapper ayudarán a los desarrolladores de las siguientes maneras:

  1. Facilita la inclusión de etiquetas de secuencia de comandos populares.
  2. Garantizar que el framework use la estrategia más óptima en segundo plano

Conclusión

Por lo general, las secuencias de comandos de terceros se crean para incluir funciones específicas en el sitio web de consumo. Para reducir el impacto de las secuencias de comandos no críticas, te recomendamos que las difieras, lo que el componente de secuencia de comandos de Next.js hace de forma predeterminada. Los desarrolladores tienen la seguridad de que las secuencias de comandos incluidas no retrasarán la funcionalidad crítica, a menos que apliquen de forma explícita la estrategia beforeInteractive. Al igual que el componente de secuencia de comandos de Next.js, los desarrolladores de frameworks también pueden considerar compilar estas funciones en otros frameworks. Estamos explorando de forma activa la implementación de un componente similar con el equipo de Nuxt.js. En función de los comentarios, también esperamos mejorar aún más el componente de secuencia de comandos para abarcar casos de uso adicionales.

Agradecimientos

Gracias a Kara Erickson, Janicklas Ralph, Katie Hempenius, Philip Walton, Jeremy Wagner y Addy Osmani por sus comentarios sobre esta publicación.