Performance Optimization & Script Loading Priority in Next.js
Explore the impact of defer and async attributes on script loading and execution priority for inline vs. external script resources within Next.js.
In this article, we explore the impact of defer and async attributes on script loading and execution priority for inline versus external script resources within a Next.js application. Understanding script loading priorities is crucial for performance optimization and understanding render blocking consequences.
Traditional script loading priorities have been covered extensively in this article by Google’s Addy Osmani. We decided to see if these criteria and priorities hold true in a Next.js application.
TL;DR: It appears defer attribute still plays a resource execution priority part for traditional script elements within a Next.js app. However, all <Script /> components and script HTML elements that are added within the Next.js app occur after the window/document DOMContentLoaded event.
Testing Methodology & Findings
Scripts loaded through Script component are parsed and executed after the window/document DOMContentLoaded event hence adding defer may only lower the execution priority.
At this point, the Next.js script firing strategies dictates sequence and priority [resource].
To trigger scripts during DOMContentLoaded event (God forbid), you have to use a normal script element in the <Head /> component of the _document.tsx file [resource].
The callback in the onLoad prop of the <Script /> component will not fire for inline scripts.
It will only fire for on load of external resources
Example
2 inline scripts using the Script tag
Both uses the same afterInteractive strategy while one has defer in the Script component and defer in the external resouce script that the inline script will create:
Output of the console logs:
Findings
Because both are just inline scripts, onLoad event never fires.
The inline scripts are parsed and executed in a sequential order even with the defer=true on the first inline <Script /> tag
The external resources are also requested in a sequential order - GTM (Google Tag Manager) followed by Woopra (network request is initiated by the new script elements created by the inline scripts).
However, the execution of the GTM comes after Woopra:
Woopra parsing starts at around 1300ms mark.
GTM parsing starts around 1318ms mark.
Conclusion
Next.js is a highly-performant framework for modern website and web application development. However, out-of-the-box deployment is not guaranteed to produce optimized performance on the front-end. It's critical to understand how scripts are prioritized under the hood. This is just one of the many different considerations to creating a highly optimized and performant Next.js application that we are excellent at.
Need assistance on optimizing the performance of your Next.js app? Feel free to reach out to 9thCO!