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
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 significativamente el rendimiento de un sitio. El componente Script de Next.js incluye prácticas recomendadas y valores predeterminados integrados 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 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 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 se deben cargar con anticipación para renderizar la página. Los terceros que no sean necesarios para la renderización inicial deben diferirse para que no bloqueen otros procesamientos en el subproceso principal. Lighthouse tiene dos auditorías para marcar las secuencias de comandos que bloquean la renderización o el subproceso principal.
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 recursos no críticos no bloqueen los recursos críticos.
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 de escritorio. El uso y las recomendaciones pueden variar para cada uno.
- La implementación de muchos terceros puede variar según si se usa un framework o una biblioteca de IU en particular.
- Con frecuencia, se presentan bibliotecas de terceros más recientes.
- Los diferentes requisitos empresariales 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 frameworks y herramientas web de código abierto consiste en proporcionar valores predeterminados sólidos y herramientas con opiniones 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 Core Web Vitals.
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 las 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 recursos de manera eficiente, incluidos los de terceros. Estudiamos datos exhaustivos de HTTP Archive y Lighthouse para descubrir qué terceros bloquean la renderización en mayor medida en diferentes frameworks.
Para abordar el problema de las secuencias de comandos de terceros que bloquean el subproceso principal y que se usan en una aplicación, creamos el componente Script. 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 de manera eficiente las secuencias de comandos de terceros:
Usa el atributo
asyncodefercon 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 se requieren para la carga de página inicial 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>Establece conexiones tempranas con los orígenes requeridos usando 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>Carga diferida de recursos y elementos incorporados de terceros después de que se haya terminado de cargar el contenido principal de la página o cuando el usuario se desplace hacia abajo hasta la parte de la página donde se incluyen.
El componente Script de Next.js
El componente Script 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 especifica la estrategia adecuada, se cargará de forma óptima sin bloquear otros recursos críticos.
El componente Script se basa en la etiqueta HTML <script> y proporciona una opción para establecer la prioridad de carga de las 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 tomar tres valores.
beforeInteractive: Esta opción se puede usar para secuencias de comandos críticas que se deben ejecutar 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 otro JavaScript empaquetado por el usuario. 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.afterInteractive: Esta es la estrategia predeterminada que se aplica y equivale a cargar una secuencia de comandos con el atributo defer. Debe usarse para las secuencias de comandos que el navegador puede ejecutar después de que la página sea interactiva, por ejemplo, las secuencias de comandos de estadísticas. Next.js inserta estas secuencias de comandos en el 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 Script, lo que proporciona un valor predeterminado sólido.lazyOnload: Esta opción se puede utilizar para cargar de forma diferida scripts de baja prioridad cuando el navegador está inactivo. La funcionalidad que proporcionan esas secuencias de comandos no es necesaria inmediatamente después de que la página se vuelve interactiva, por ejemplo, los complementos de chat o de 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 Script, los desarrolladores pueden colocar una secuencia de comandos de terceros en cualquier lugar de la aplicación para los terceros de carga tardía y a nivel del documento para las secuencias de comandos críticas. Esto implica que el componente Script puede ubicarse junto con el componente que usa 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 que se use.
Medición del impacto
Usamos las plantillas de la app de comercio y el blog de inicio 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 frecuente para Google Tag Manager y las incorporaciones de redes sociales se incluyeron en las páginas de estas apps directamente al principio y, luego, a través del componente Script. 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.
En la siguiente comparación, se muestra el progreso visual de ambas versiones del kit de inicio de comercio de Next.js. Como se puede ver, el LCP se produce casi 1 s antes con el componente Script habilitado con la estrategia de carga correcta.
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 async | Componente de secuencia de comandos con strategy = lazyonload para cada una de las cuatro secuencias de comandos |
| Botón Seguir de Twitter con async | |
| Botón Suscribirse de YouTube sin async ni defer | |
| Botón Seguir de LinkedIn sin async ni defer |
Como se ve en el video, el Primer procesamiento de contenido (FCP) se produce a los 0.9 segundos en la página sin el componente Script y a los 0.4 segundos con el componente Script.
Próximos pasos 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 Script.
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 controlar el procesamiento de las 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 IU, fuera del subproceso principal. Las secuencias de comandos que se usan para la asistencia al cliente o el marketing, que, por lo general, no interactúan con la IU, pueden ser buenas candidatas para ejecutarse en un subproceso en segundo plano. Se puede usar una biblioteca de terceros ligera, 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, recomendamos aplazar estas secuencias de comandos en el subproceso principal configurando la estrategia en afterInteractive o lazyOnload. En el futuro, proponemos introducir 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. Agradecemos 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. El CLS se puede minimizar especificando el tamaño del contenedor donde se cargará el elemento incorporado.
El componente Script se puede usar para cargar incorporaciones que pueden causar 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 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 de las siguientes maneras:
- Facilitar la inclusión de etiquetas de secuencia de comandos populares
- Garantizar que el framework use la estrategia más ó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 que las consume. Para reducir el impacto de las secuencias de comandos no esenciales, te recomendamos que las aplaces, lo que hace el componente Script de Next.js de forma predeterminada. Los desarrolladores tienen la garantía 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 Script de Next.js, los desarrolladores de frameworks también pueden considerar compilar estas funciones en otros frameworks. Estamos explorando de forma activa la posibilidad de lanzar un componente similar con el equipo de Nuxt.js. Según los comentarios, también esperamos mejorar aún más el componente Script para abarcar casos de uso adicionales.
Reconocimientos
Agradecemos a Kara Erickson, Janicklas Ralph, Katie Hempenius, Philip Walton, Jeremy Wagner y Addy Osmani por sus comentarios sobre esta publicación.