Unleash the full potential of your website with Partytown! Say goodbye to sluggish pages and low Lighthouse scores caused by clunky third-party scripts. With Partytown, your main thread is dedicated solely to your code, freeing it up to run smoother, faster, and more efficiently than ever before. Empower your website with lightning-fast performance by moving all non-critical scripts to a web worker, where they’ll run seamlessly in the background. Get ready to blast off to the next level of web performance with Partytown!
Improve Your Website's Speed and Efficiency with Partytown

AI Generated Video Summary
Today's Talk discusses improving site speed and efficiency using PartyTown, a tool that runs third-party scripts from a web worker, minimizing their impact on the main UI thread. The inclusion of third-party scripts in webpages should be carefully considered due to their potential impact on performance. Real-world testing is crucial to identify performance issues that may not surface during development. PartyTown offers features like white-listing script capabilities and supports various frameworks for easy integration. It was built by the team at builder.io to ensure websites can scale without sacrificing performance.
1. Introduction to Site Speed and Efficiency
Today we'll discuss improving site speed and efficiency using PartyTown. JavaScript is a major contributor to slow web pages, causing issues like increased interactivity, network payload, DOM manipulation, and thread locking. Faster websites lead to higher conversion rates, supported by case studies. While there's overwhelming advice on optimizing code, third-party scripts are often the biggest culprit for performance problems. These scripts, like Google Analytics and Optimizely, can add HTTP requests, block page rendering, and consume resources. Organizations must balance the benefits of third-party scripts with their performance consequences.
♪♪ Today I'm really excited to be talking about improving your site's speed and efficiency using PartyTown. My name's Adam Bradley. I'm a director of open-source technology at Build.io. Other open-source projects I've been involved in include Ionic and Stencil. And I'm having a lot of fun working on Builder's other open-source project called Quick.
So let's first dive into what the problem is. The short answer is, well, it's JavaScript. JavaScript is one of the biggest contributors to slow web pages. You can often generalize that the more JavaScript you add to a page, the slower it is for the user. Now the reason why JavaScript can slow down a page ranges for many different reasons. But some of the most common issues are coming from the heavy and bloated scripts which includes the increased timed interactivity, the increased network payload, the excessive DOM manipulation that JavaScript files can do, and also how JavaScript can lock up the main thread.
Research shows that the faster the website, the higher the conversion rates, regardless of whatever the conversion metric may be. And there are many well-documented case studies providing evidence to support this claim. And this is just a small sampling of case studies that go in-depth to why performance matters. But let's dig in a little bit more of what we can do to improve performance and ultimately improve your site's conversion rates. Now the web is filled with all sorts of advice on how to improve JavaScript performance, which can be a little bit overwhelming. The numerous optimizations put pressure on the developers, and it focuses often on how to improve your code. However, even with optimal code, there's still performance issues to address. So as you can see here, these are just a very small list of things that often comes up in search results, like this is what you need to do to your code. So remember that part.
However, the biggest culprit of website performance often comes from third-party scripts. Now first-party scripts is your code, the code which you have control of and you can improve. Third-party scripts, however, refer to external code that a website loads from a different domain and server, which the website owner does not have control of, or direct access to, improve. It's code running on your site, on the same window and document, but you do not have control of. Now common example of third-party scripts includes Google Analytics, Google Tag Manager, Optimizely, Hotjar and among many others. Now while third-party scripts are often used to provide valuable functionality and data collection, they also come with many issues. They can add additional HTTP requests which can lead to longer page load times, or block the rendering of the main page, which can result in a poor user experience. Third-party scripts can also be resource-intensive, using valuable CPU and memory resources, which can also lead to slower page load times, especially on mobile devices. Now despite all of these issues, organizations often have valid reasons to include third-party scripts, as the data they provide help inform business decisions across the entire organization. However, it's important to weigh the benefits against the potential performance consequences of loading too many third-party scripts.
2. Impact of Third-Party Scripts
It's important to carefully weigh the inclusion of third-party scripts in your webpage. Recent studies show an increasing number of third-party scripts loaded on mobile devices. The more first-party scripts a website has, the more likely they are to add third-party scripts for added functionality and data collection. Developers must consider the impact of third-party scripts on performance and evaluate their use.
So it's important to carefully weigh which ones you should and should not include in your webpage. Now recent studies have shown that the number of third-party scripts loaded on a mobile device is increasing. According to the HTTP Archive, the media mobile device requests 10 third-party scripts and 9 first-party scripts, which is a significant increase from previous years, and the trend is only expected to continue. And when you go to the 90th percentile, mobile pages are requesting 34 third-party scripts and 33 first-party scripts. So the more first-party scripts a website has, the more likely they are to add third-party scripts to provide the added functionality and collect more data. So it's important for developers to consider the impact of third-party scripts on a webpage performance and carefully evaluate their use.
3. Measuring Performance and Real-World Testing
Lighthouse is a great tool for measuring performance during development, but real user metrics are needed for production environments. Tools like PageSpeed Insights, webpagetest.org, and speedcurve.com provide valuable insights into user experience and help optimize performance. Testing websites under real-world conditions is crucial to avoid performance issues that may not surface during development.
Now, Lighthouse measures performance using lab data from predefined networks and devices, making it a great tool for measuring performance during development. However, when it comes to measuring website performance on a production environment, it's recommended to use tools that incorporate real user metrics. These tools provide a more accurate representation of how users experience your website and can help identify performance issues that may not be visible in lab tests.
One such tool that utilizes both lab data and real-world data collected from users is PageSpeed Insights. And other great tools include webpagetest.org and speedcurve.com. By utilizing these, developers can gain valuable insights into how users experience their website and make informed decisions about how to optimize for performance.
One of the most common problems in measuring website performance is that issues may not surface during development. This is because developers typically test websites on high-end devices with high-end internet connections, which may not be representative of end-users who'll be accessing your website in production. For example, during development, a website performance may appear to be lightning-fast when tested on a MacBook Pro with a local network. But this does not translate to actual end-users who are likely to be accessing your site from mid-market phones while on the go and out in the wild. This can result in a lower performing website that is vastly different than the one that was tested on during development. In order to avoid this issue, it's important to test websites under a variety of conditions that more closely mirrors the real world.
4. The Impact of Third-Party Scripts on Performance
Three-party scripts compete with your code for resources on the main thread, resulting in slower website performance. Web workers provide a possible solution, but they cannot access the window or document of the main thread. Communication between the main thread and the web worker is asynchronous, making it challenging to use web workers to avoid performance issues caused by third-party scripts. PartyTown solves this problem by allowing third-party scripts to run from a web worker, minimizing their impact on the main UI thread and improving UI performance.
Now, three-part scripts can have a negative impact on website performance in various ways. One of the most significant issues is that they compete with your code for resources on the main thread. These scripts have the same level execution priority as your code, and you have to equally share access to the window and document objects. This means that when your code is executing, it is competing with the other third-party scripts for the same resources. Unfortunately, your code is not given any priority over third-party scripts, which leads to a situation where scripts are equally fighting on the main thread, resulting in slower website performance.
Moreover, the competition for resources often contributes to layout thrashing, which further slows down the website. When running performance analyst tools, it's evident that third-party scripts are often the most significant performance killers as they can significantly impact the overall user experience. But this is the state that we're in. It's not as simple as opting out of running third-party scripts because in many cases, it's a requirement of your organization. And remember, you don't have control over these third-party scripts, you can't modify them. And additionally, you can't prioritize your code to run faster than their code, since they all compete for the same resources on the same main thread.
Now, a possible and powerful solution could be to use web workers to help improve performance issues caused by third-party scripts. As we know, third-party scripts compete for resources on the main thread with your code and can slow down the entire website. So if we were to run the code in a separate background thread, we could unblock the main thread and help improve performance. But while it may seem like a simple solution, it's not always that practical. The challenge is that we cannot modify or improve another service's code. One challenge in using web workers to run third-party scripts is that workers are unable to access the window or document of the main thread. This is because these globals are not present in the worker environment, which can be problematic since many third-party scripts rely on window and document to execute numerous DOM operations. Although it's possible to communicate between the main thread and the worker thread, the transfer of data is often, or is, asynchronous. And even if you were to create an abstraction layer for the communication, you would still need a promise or callback to send the data. Furthermore, since third-party scripts code cannot be modified, it's not feasible to ask the service provider to rewrite their code to enable asynchronous DOM operations.
So to summarize, web workers would be an ideal solution for executing third-party scripts. However, it's important to keep in mind that modifying their code is not possible. Additionally, any interaction between the main thread and the web worker is asynchronous. So in reality, it's a challenge to use web workers as a way to avoid performance issues caused by third-party scripts. This is where PartyTown comes in. It addresses the problem of third-party scripts affecting the performance of the main UI thread. It allows these scripts to run from a web worker, leaving the main thread free to handle your code. By doing so, PartyTown minimizes the chances of third-party scripts blocking the main thread and impacting the UI performance. Now with PartyTown, you can write third-party scripts from a web worker and ensure the main thread is dedicated to your code and minimize any negative impact in third-party scripts of the UI performance.
5. Improving Performance with PartyTown
A web worker can reduce the bottleneck on the main thread by offloading third-party scripts to execute in a background thread. PartyTown improves webpage performance by running third-party scripts from a web worker, allowing the main thread to focus on your code. The performance improvement provided by PartyTown varies based on factors like the number of third-party scripts and their operations. Changing the type attribute of the script element to 'text/PartyTown' allows PartyTown to skip script execution on the main thread and run it in a web worker. This flexibility makes PartyTown easy to integrate into any web page without requiring additional tools or build steps. However, it's important to note that a web worker is isolated from the main thread and does not have access to window or document objects.
Here's a generalized diagram of how a web worker is able to reduce the bottleneck on the main thread. On the left, both your code and their code compete for the same resources. On the right, your code is free to use the main thread and their code is offloaded to execute in a background thread. By running third-party scripts in a background, the main thread can now be fully dedicated to your code.
Now determining the performance improvement provided by PartyTown is not straightforward as it varies based on several factors. In short, it depends on the number of third-party scripts used on the site and what operations they're doing. There is no one-size-fits-all answer. So for instance, in a test example where this page itself does nothing, it scores 100 without any issues. However, if we were to add a few third-party scripts, the page's performance goes down to 77. Again, this page does absolutely nothing and should be easily scoring 100. But when those same scripts run from PartyTown, the page performance goes back to 100. This demonstrates the difference PartyTown can make in improving a simple webpage. So imagine the impact it can do when a large amount of JavaScript is being used on an average website.
So how does PartyTown actually work? Well, it all starts with the common script element and its use of the type attribute. For instance, if the type attribute is set to text JavaScript or the newer type of module, the browser will execute the script on the main thread. Additionally, the script tag will also execute the code if it doesn't have a type attribute at all. So none of this is too shocking, right? It's the normal script element. Without the type attribute, it knows to execute the code. If you use a recognizable type attribute, again, it'll execute the code on the main thread. But what if we were to change the type attribute to a value that the browser doesn't recognize, such as, let's say, text slash PartyTown? Then the browser completely skips over the script and does not execute it. As far as the browser is concerned, it's just another empty div that does absolutely nothing. So next, PartyTown is able to use a query selector to find all of the scripts that the browser already skipped over and didn't execute, but instead, we want to run those scripts inside of a Web Worker. So the first example shows a common script element being executed on the main thread. The second example shows how adding text slash PartyTown will instead move the same code to be ran from a Web Worker. This also allows the developer to pick and choose which script should and should not run within the Web Worker. There's no loader, preprocessor, or build step required to make the system work. And since we're only changing an HTML attribute, it's not tied to a specific technology like Webpack, React, PHP or whatever. And because it's not built for one tool, it also makes it easy to integrate into any web page. Now it's important to remember that a Web Worker is isolated from the main thread and does not have access to window or document. If we attempt to execute code that relies on these objects, such as Document.title, from within a Web Worker, it will result in an error since a Web Worker has no knowledge of these objects.
6. Executing Third-Party Scripts on Web Worker
Third-party scripts often rely on synchronous operations and access global objects only available on the main thread. Python utilizes proxies to intercept and forward DOM operations from the Web Worker to the main thread, allowing third-party scripts to execute seamlessly. Communication between the main thread and the Web Worker is asynchronous, but Python proxies DOM operations to the main thread, ensuring synchronous execution. This approach solves the challenge of running third-party scripts on the Web Worker and provides a consistent experience.
If we were to run this code, the browser would be like, what the heck is this thing called Document? I have no idea what that is. And third-party scripts are often loaded with DOM operations just like this. These operations must be able to function without any issues, since we cannot modify how the third-party scripts were initially written. Thus, it becomes necessary to find a solution that allows the scripts to run seamlessly without interfering with the performance of the main UI thread.
We recognize that third-party scripts access global objects only available on the main thread, but are not available on the worker thread. As a result, Python utilizes proxies to intercept and forward any DOM operations from the Web Worker to the main thread. By doing so, Python allows a Web Worker to indirectly access the main thread's window and document objects. Now, the proxy acts as a middleware that intercepts the DOM-related requests made by the third-party scripts running on the Web Worker and forwards them to the main thread. The main thread processes these requests and returns the corresponding values back to the worker thread. This approach ensures Python is able to maintain a seamless, consistent experience for the third-party script code, regardless of whether it's running on the main thread or the worker thread.
Now, as previously mentioned, communication between the main thread and the Web Worker is asynchronous. This is because the threads run on separate execution contexts. However, this poses a challenge for Python, especially when it comes to running third-party scripts. Now, third-party scripts are often written with the assumption that they're running on the main thread and, as such, they heavily rely on synchronous operations. These operations may include accessing the DOM, modifying styles, reading cookies among many other things. For Python to work effectively, it needs to be able to ensure that these operations work exactly the same way as they would if as if they were executed on the main thread. Now, instead of trying to replicate the entire DOM on the WebWorker, Python will proxy any DOM operations to the main thread, execute the command there, and return the value back to the WebWorker. This allows third-party scripts to execute normally without any modification and with the same level of performance as they would on the main thread. Now, by doing so, Python ensures that third-party scripts can work despite the asynchronous nature of communication between the threats.
So here's a straightforward example of a third-party script code running document.title. When their script calls document.title, it's a blocking call and the getter is expecting a value. It's not expecting the getter to return a promise. It's expecting a string value of document.title. This is actually the biggest challenge that Python has to solve. As we talked about earlier, no matter what we do, sending messages between the main thread and the worker thread requires an asynchronous task. Basically, we have to use a PostMessage API and listen for those messages from the opposite thread, which is entirely asynchronous. This is the other important piece of the puzzle, which allows the web worker to communicate with the main thread synchronously. In this diagram, the worker thread calls a getter expecting a value, but our proxy will fire off a synchronous XHR request, which is intercepted by the service worker so that it can talk to the main thread. And in the end, the synchronous XHR request returns the getter value. And according to the third-party script running from the web worker, this was one synchronous blocking task.
7. PartyTown Features and Common Issues
PartyTown allows white-listing script capabilities, offers a debug build for better inspection, and supports atomics and shared-array buffers for faster communication. However, using shared-array buffers may cause practical issues. It's important to test third-party scripts for compatibility with PartyTown and collaborate with vendors to make it work. The most common issue is proxying HTTP requests, which may require a reverse proxy for correct coarse headers.
And because of this architecture, there's some cool things we can also do. It can allow us to white-list what a script can and cannot do. For example, reading navigator.userAgent or reading document.cookies could return an empty string. Or it could be used for event calls like the dreaded document.write function call. And another cool feature from this is that PartyTown also comes with a debug build, which helps developers better inspect what third-party scripts are even doing. Now, depending on your config, you can decide what types of calls should be logged so that you can better see what's happening. And you can see the values passed to and received from every command of every single third-party script, which traditionally is pretty hard to do.
So far we've talked about how PartyTown uses service workers to intercept requests, but this is actually the fallback. By default, it uses atomics and shared-array buffers when available, which also has some benefits of offering 10x faster communication between the different threads. The downside, however, is that the document must opt-in to using shared-array buffers using HTTP response headers from the server. So this can be kind of difficult to implement, but also once implemented, once these response headers kick in, it's not practical for most sites to have this setting turned on as many things such as images and scripts might stop working. Since we've only had a short amount of time to go over all this, I encourage you to take a look at the PartyTown docs to find out more about atomics and how to use them on your site.
It's also worth noting that nothing is without tradeoffs and PartyTown is no different. These are just some of the few gotchas that happen that we commonly see with PartyTown. Some of them is the confusion of how you send events from the main thread over to the web worker or cores issues that happen when certain third-party scripts do not provide a correct cores header that you need to set up to proxy responses. Other ones would be that the third-party scripts' UI updates are way too intensive and the communication between two different threads can't keep up. And you see a little bit of jankiness between the two. So basically what I'm saying is not all third-party scripts just work. It really depends on what that script is doing and it comes down to the developers to test out if this is a good candidate for PartyTown or not. And also, we need a lot of help from vendors. So if you're trying to get your site or your service to work with PartyTown, we would love to get more interaction with or working with the different services to get this working on their service.
So here, I'd like to talk about the most common issue that we see with PartyTown and that would be proxying HTTP requests. So, often third-party scripts are added to a page by including the script tag in the body. When using this traditional approach, the script's HTTP response does not require coarse headers. However, because PartyTown requests the scripts from within a web worker, it's having to use Fetch, not the script tag. So then the script's response does require the correct coarse headers. Now, many third-party scripts do provide the correct coarse headers, but not all do. For services that do not add the correct headers, then a reverse proxy to another domain must be used in order to provide the coarse headers. So next, I really encourage you to take a look at the doc's website. Again, PartyTown isn't tied to one framework, so it can be used from any one of them or no framework at all.
8. Integrating PartyTown and Builder.io
The PartyTown site provides easy integration into existing projects. It supports Next.js, Gatsby, React, Angular, Astro, and more. Users are encouraged to try PartyTown, test it on their websites, and provide feedback. PartyTown is open source and MIT-licensed. It was built by the team at builder.io while developing Qwik, a framework focused on resumability. The goal is to ensure websites can scale without sacrificing performance, whether using first-party or third-party scripts. Take a look at Qwik and Builder, and explore the PartyTown website for more information and integration options.
But the PartyTown site also documents the easiest way to integrate it into your existing projects. This includes both Next.js and Gatsby have a way to run their scripts using a worker strategy solution, which, you guessed it, is just PartyTown. But there's also integrations for any React app, Angular, Astro, and many more. And if you don't see your favorite framework there, then please, our doc site would love to get a pull request from you addin' it there.
So please, try out PartyTown, test it out on your website, and let us know how it goes. It's open source and MIT-licensed, but we would also love to have your help testing out the many different third-party script scenarios that exist out in the wild. And PartyTown itself is built and maintained by our team at builder.io. Really, the entire project came up as we were building Qwik, which is a framework around the idea of using resumability rather than hydration. Qwik deserves many of its own presentations, but in short, it's no matter how fast we make Qwik, websites still have an unsolved problem of using third-party scripts. And that's why builder.io has invested in both open-source projects like these. We wanna make sure that our sites are able to build and continue to scale without sacrificing performance, no matter if it's a first-party script code or third-party script code.
So I encourage you to take a look at both Qwik and Builder. That's all I have for now. There's so, so much more to talk about with Pariah Town, so I encourage you to go to the website, learn more about it, see how you can get it integrated into your website yourself. Let us know if you have any issues that come up, and please, give it a shot. Let us know how it goes.
Comments