A Next.js package for managing third-party libraries

Houssein Djirdeh
Houssein Djirdeh

In 2021, the Chrome Aurora team introduced theScriptcomponent to improve theloading performance of third-party scripts in Next.js. Since its launch, we'veexpanded its capabilities to make loading third-party resources easier andfaster for developers.

This blog post provides an overview on the newer features we've released, mostnotably the@next/third-partieslibrary, as well as an outline of future initiatives on our roadmap.

Performance implications of third-party scripts

Note: According to the2022 Web Almanac,a third-party is an entity external to the primary site/user relationship, andinvolves aspects of a site not directly controlled by its owner but includedwith their approval.

41% of all third-party requests in Next.js sites are scripts. Unlike other contenttypes, scripts can take a considerable amount of time to download and execute,which can block rendering and delay user interactivity. Data from the ChromeUser Experience Report (CrUX) shows that Next.js sites that load more third-partyscripts have lowerInteraction to Next Paint(INP) andLargest Contentful Paint(LCP) pass rates.

Bar chart that shows a decline in percentage of Next.js achieving good INP and LCP scores in proportion to the number of third-parties loaded
December 2023 CrUX report (110,823 sites)

The correlation observed in this chart does not imply causation. However, localexperiments provide additional evidence that third-party scripts significantlyimpact page performance. For instance, the chart below compares various labsmetrics when a Google Tag Manager container—comprising 18 randomly selectedtags—is added toTaxonomy, a popular Next.js exampleapp.

Bar chart that shows the difference in various lab metrics when a site is loaded with and without Google Tag Manager
WebPageTest (Mobile 4G - Virginia USA)

TheWebPageTest documentationprovides details on how these timings are measured. From a quick glance, it'sclear that all of these lab metrics are impacted by the GTM container. Forexample,Total Blocking Time (TBT)—a useful labproxy that approximates INP—saw a nearly 20-fold increase.

Script component

When we shipped the<Script> component in Next.js, we made sure to introduceit through a user-friendly API that closely resembles the traditional<script>element. By using it, developers can co-locate a third-party script in anycomponent in their application, and Next.js will take care of sequencing thescript after critical resources have loaded.

<!-- By default, script will load after page becomes interactive --><Script src="https://example.com/sample.js" /><!-- Script is injected server-side and fetched before any page hydration occurs --><Script strategy=”beforeInteractive” src="https://example.com/sample.js" /><!-- Script is fetched later during browser idle time --><Script strategy=”lazyOnload” src="https://example.com/sample.js" />

Tens of thousands of Next.js applications—including popular sites such asPatreon,Target, andNotion—use the<Script> component. Despite itseffectiveness, some developers have raised concerns about the followingthings:

  • Where to place the<Script> component in a Next.js app while adheringto the varying installation instructions of different third-party providers(developer experience).
  • Which loading strategy is the most optimal to use for differentthird-party scripts(user experience).

To address both of these concerns, we launched@next/third-parties—aspecialized library offering a set of optimized components and utilitiestailored for popular third-parties.

Developer experience: making third-party libraries easier to manage

Many third-party scripts are used in a significant percentage of Next.js sites, withGoogle Tag Manager being the most popular, used by66% of sites respectively.@next/third-parties builds on top of the<Script>component by introducing higher-level wrappers designed to simplify usage forthese common use cases.

import{GoogleAnalytics}from"@next/third-parties/google";exportdefaultfunctionRootLayout({children}){return(<htmllang="en"><body>{children}</body><GoogleTagManagergtmId="GTM-XYZ"/></html>);}

Google Analytics—another widely used third-party script(52% of Next.js sites)—also has a dedicated component of its own.

import{GoogleAnalytics}from"@next/third-parties/google";exportdefaultfunctionRootLayout({children}){return(<htmllang="en"><body>{children}</body><GoogleAnalyticsgaId="G-XYZ"/></html>);}

@next/third-parties simplifies the process of loading commonly used scripts,but it also extends our ability to develop utilities for other third-partycategories, such as embeds. For instance, Google Maps and YouTube embeds areused in8%and4%of Next.js websites respectively, and we've also shipped components to make themeasier to load.

import{GoogleMapsEmbed}from"@next/third-parties/google";import{YouTubeEmbed}from"@next/third-parties/google";exportdefaultfunctionPage(){return(<><GoogleMapsEmbedapiKey="XYZ"height={200}width="100%"mode="place"q="Brooklyn+Bridge,New+York,NY"/><YouTubeEmbedvideoid="ogfYd705cRs"height={400}params="controls=0"/></>);}

User experience: making third-party libraries load faster

In a perfect world, every widely-adopted third-party library would be fullyoptimized, making any abstractions that improve their performance unnecessary.However, until that becomes a reality, we can try to improve their userexperience when integrated through popular frameworks like Next.js. We canexperiment with different loading techniques, ensure that scripts are sequencedin the right manner, and ultimately share our feedback with third-partyproviders to encourage upstream changes.

Take YouTube embeds, for example. Where some alternative implementations havefar better performance than the native embed. Currently, the<YouTubeEmbed>component exported by@next/third-parties useslite-youtube-embed, which,when demonstrated in a "Hello, World" Next.js comparison, loads considerablyfaster.

GIF that shows page load comparison between the YouTube Embed component and a regular YouTube iframe
WebPageTest (Mobile 4G - Virginia USA)

Similarly, for Google Maps, we includeloading="lazy" as a default attribute forthe embed to ensure that the map only loads when it is a certain distance fromthe viewport. This may seem like an obvious attribute to include—especiallysince the Google Mapsdocumentationincludes it in their example code snippet—but only45% of Next.js sites that embed Google Maps are usingloading="lazy".

Running third-party scripts in a web worker

One advanced technique we're exploring in@next/third-parties is making iteasier to offload the third-party scripts to a web worker. Popularized bylibraries such asPartytown, this can reducethe impact of third-party scripts on page performance substantially byrelocating them entirely off the main thread.

The following animated GIF shows the variations in long tasks and main threadblocking time when applying different<Script> strategies to a GTM containerwithin a Next.js site. Note that, while switching between strategy options onlydelays the timing of when these scripts execute, relocating them to a web workercompletely eliminates their time on the main thread.

GIF that shows differences in main thread blocking time for the different Script strategies
WebPageTest (Mobile 4G - Virginia USA)

In this particular example, moving the execution of the GTM container and itsassociated tag scripts to a web workerreduced TBT by 92%.

It is worth noting that, if not managed carefully, this technique can silentlybreak many third-party scripts, making debugging challenging. In the upcomingmonths, we'll validate if any third-party components offered by@next/third-parties function correctly when run in a web worker. If so, we'llwork towards providing an easy, and optional way, for developers to use thistechnique.

Next steps

In the process of developing this package, it became evident that there was aneed to centralize third-party loading recommendations so that other frameworkscould also benefit from the same underlying techniques used. This led us tobuildThird PartyCapital, a librarythat uses JSON to describe third-party loading techniques, which currentlyserves as the foundation for@next/third-parties.

As our next steps, we'll continue to focus on improving the components providedfor Next.js as well as expand our efforts to include similar utilities in otherpopular frameworks and CMS platforms. We're currently in collaboration with Nuxtmaintainers, and are planning to release similar third-party utilities tailoredto their ecosystem in the near future.

If one of the third-parties you use in your Next.js app is supported by@next/third-parties,install the packageand give it a shot! We would love to hear your feedback onGitHub.

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2024-02-26 UTC.