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

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

Aproximadamente el 45% de las solicitudes de sitios web publicados en dispositivos móviles y computadoras de escritorio son solicitudes de terceros, de las cuales el 33% son secuencias de comandos. El tamaño, la latencia y la carga de secuencias de comandos de terceros pueden afectar significativamente el rendimiento de un sitio. El componente de secuencias de comandos de Next.js incluye prácticas recomendadas integradas y opciones predeterminadas para ayudar a los desarrolladores a introducir secuencias de comandos de terceros en sus aplicaciones y, al mismo tiempo, abordar posibles problemas de rendimiento desde el primer momento.

Secuencias de comandos de terceros y su impacto en el rendimiento

Las secuencias de comandos de terceros permiten que los desarrolladores web aprovechen 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 utilizan.

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

Las bibliotecas de terceros necesarias para el diseño deben cargarse antes para renderizar la página. Los terceros que no sean necesarios para la renderización inicial se deben postergar 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 que bloquean el subproceso principal.

Auditorías de Lighthouse para eliminar los recursos que bloquean el procesamiento y minimizar el uso de terceros

Es importante tener en cuenta la secuencia de carga de recursos de tu página para que los recursos críticos no se retrasen y los que no son 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 utilicen. Esto puede ser complicado por los siguientes motivos:

  • En promedio, los sitios web utilizan entre 21 y 23 terceros diferentes (incluidas las secuencias de comandos) en los dispositivos móviles y las computadoras de escritorio. El uso y las recomendaciones pueden variar para cada uno.
  • La implementación de muchos terceros puede diferir en función de si se usa un framework o una biblioteca de IU en particular.
  • Se agregan bibliotecas de terceros más nuevas con frecuencia.
  • Los diversos requisitos comerciales relacionados con la misma plataforma de terceros dificultan que los desarrolladores estandaricen su uso.

El enfoque de Aurora en los guiones de terceros

Parte de la colaboración de Aurora con herramientas y frameworks web de código abierto consiste en proporcionar valores predeterminados sólidos y herramientas bien 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 importantes para lograr nuestro objetivo de mejorar el rendimiento del framework implicó investigar la secuencia de carga ideal de secuencias de comandos de terceros en Next.js. Los frameworks, como Next.js, están en una posición única para proporcionar valores predeterminados y funciones útiles que ayudan a los desarrolladores a cargar los recursos de manera eficiente, incluidos los de terceros. Estudiamos minuciosamente los datos de Lighthouse y de HTTP Archive para descubrir qué renderizaciones de bloques de terceros es la más adecuada en diferentes marcos de trabajo.

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

Secuenciar secuencias de comandos de terceros sin un componente de framework

La guía disponible para reducir el impacto de las secuencias de comandos que bloquean el procesamiento 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 las etiquetas <script> que le indican al navegador que cargue secuencias de comandos no críticas de terceros sin bloquear el analizador de documentos. Las secuencias de comandos que no se necesitan para la carga inicial de la página o la primera interacción del usuario pueden considerarse no críticas.

       <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 requeridos mediante 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. Incorporaciones y recursos de terceros de carga diferida una vez que haya terminado de cargarse el contenido de la página principal o cuando el usuario se desplace hacia abajo hasta la parte de la página en la que están incluidos

El componente de la 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 manera óptima sin bloquear otros recursos críticos.

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

// 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 de estrategia 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 en el servidor y se ejecuten antes que otros JavaScript autoagrupados. La administración del consentimiento, las secuencias de comandos de detección de bots o las bibliotecas auxiliares necesarias para renderizar contenido crítico son buenos candidatos 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. Debe usarse para las secuencias de comandos que el navegador puede ejecutar después de que la página es interactiva; por ejemplo, secuencias de comandos de análisis. Next.js inserta estas secuencias de comandos en el lado del cliente, y estas se ejecutan después de que la página se hidrata. Por lo tanto, a menos que se especifique lo contrario, Next.js aplaza todas las secuencias de comandos de terceros definidas con el componente Script, lo que proporciona un valor predeterminado sólido.

  3. lazyOnload: Esta opción se puede usar para realizar una carga diferida de secuencias de comandos de baja prioridad cuando el navegador está inactivo. La funcionalidad proporcionada por esas secuencias de comandos no es necesaria inmediatamente después de que la página se vuelve interactiva, por ejemplo, chat o complementos de redes sociales.

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

Con el componente Script, los desarrolladores pueden colocar una secuencia de comandos de terceros en cualquier lugar de la aplicación para terceros que carguen de forma tardía y en el nivel del documento para secuencias de comandos críticas. Esto implica que el componente Script puede estar ubicado junto al componente usando la secuencia de comandos. Después de la hidratación, la secuencia de comandos se insertará en el encabezado del documento renderizado inicialmente o en la parte inferior del cuerpo, según la estrategia utilizada.

Medición del impacto

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

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

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

Antes Después
Google Tag Manager con valores asíncronos Componente de secuencia de comandos con estrategia = afterInteractive para ambas secuencias de comandos
Botón Seguir de Twitter sin asíncrono ni aplazar
Configuración de secuencias de comandos y componentes de secuencias 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 inicio de comercio de Next.js. Como puedes ver, el LCP ocurre casi 1 s antes con el componente de secuencia de comandos habilitado con la estrategia de carga correcta.

Comparación con una tira de película en la que se muestra una mejora en el LCP

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

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

Antes Después
Google Tag Manager con valores asíncronos Componente de secuencia de comandos con estrategia = carga lenta para cada una de las cuatro secuencias de comandos
Botón Seguir en Twitter con el estado asíncrono
Botón Suscribirse de YouTube sin asíncrono ni aplazar
Botón Seguir en LinkedIn sin asíncrono ni aplazar
Configuración de secuencias de comandos y componentes de secuencias 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 el 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é sigue 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, lo que puede liberar el subproceso principal para que se ocupe de las tareas de procesamiento de la interfaz de usuario y mejorar el rendimiento. Los Web Workers son más adecuados para transferir el procesamiento de JavaScript, en lugar del trabajo de la IU, del subproceso principal. Las secuencias de comandos que se usan para asistencia al cliente o marketing, que no suelen interactuar con la IU, pueden ser buenas candidatas para ejecutarse en un subproceso en segundo plano. Se puede utilizar una biblioteca liviana de terceros (PartyTown) para aislar estas secuencias de comandos en un trabajador web

Con la implementación actual del componente de secuencia de comandos de Next.js, te recomendamos diferir estas secuencias de comandos en el subproceso principal estableciendo la estrategia en afterInteractive o lazyOnload. En el futuro, proponemos incorporar 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 los trabajadores web. Agradecemos los comentarios de los desarrolladores sobre esta RFC.

Minimiza el CLS

Las incorporaciones de terceros, como las de anuncios, videos o feeds de redes sociales, pueden provocar cambios en el diseño cuando se usan cargas diferidas. Esto afecta la experiencia del usuario y la métrica Cambio de diseño acumulado (CLS) de la página. CLS puede minimizarse especificando el tamaño del contenedor en el cual se cargará la incorporación.

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

Componentes de wrapper

La sintaxis y la estrategia de carga para incluir secuencias de comandos populares de terceros, 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 un conjunto mínimo de atributos específicos de la aplicación (como el ID de seguimiento) estará disponible para los desarrolladores. Los componentes de wrapper ayudarán a los desarrolladores con las siguientes tareas:

  1. Incluir etiquetas de secuencias de comandos populares será más fácil.
  2. Garantizar que el framework use la estrategia óptima de forma interna

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 aplace el componente de secuencias de comandos de Next.js 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 manera explícita la estrategia beforeInteractive. Al igual que el componente de secuencias de comandos de Next.js, los desarrolladores de marcos de trabajo también pueden considerar compilar estas funciones en otros frameworks. Estamos explorando activamente conseguir un componente similar con el equipo de Nuxt.js. En función de los comentarios que recibimos, también esperamos mejorar el componente de secuencias de comandos para abarcar casos de uso adicionales.

Agradecimientos

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