Introducing Partytown š: Run Third-Party Scripts From a Web Worker
source link: https://dev.to/adamdbradley/introducing-partytown-run-third-party-scripts-from-a-web-worker-2cnp
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Introducing Partytown š: Run Third-Party Scripts From a Web Worker
Sep 23
ć»6 min read
A fun location for your third-party scripts to hang out
Performance is always top of mind for any website or web app. Itās of no surprise that a page that loads instantly, has no scroll jank, and responds immediately to any interaction, will provide an all around better user-experience.
Even with a fast and highly tuned site following all of the best practices, it's all too common for your performance wins to be erased the moment third-party scripts are added. By third-party scripts we mean code that is embedded within your site, but not directly under your control. A few examples include: analytics, ad pixels, A/B testing, trackers, etc.
When it comes to improving site performance, resources often explain and document tangible improvements with what you can do to your code, but for the most part our hands are tied when it comes to improving third-party code.
Third-Party Script Performance Issues
The elephant in the room is that third-party scripts are often to blame for eating up a large chunk of the main threadās precious resources. Thereās a few tricks to reduce their upfront damaging effects, like waiting until after the page load to run these scripts.
But regardless, theyāre still running hundreds of kilobytes (and commonly, even a few megabytes) of Javascript on your userās main thread! And end-usersā mobile devices have less resources than the machines developers are building the sites on! This can drastically affect Lighthouse scores, Core Web Vitals, search rankings, and even increase bounce rates and reduce user-engagement due to poor user experience.
All of this has surfaced as weāve been building out Qwik for Builder.io. The tldr is that we can make interactive sites load immediately with only HTML and CSS, and only pull in the Javascript you need on-demand. But either way, even with the fastest of the fastest frameworks (or no framework at all), third-party scripts continue to drain site performance. So we got to thinking...
Running Third-Party Scripts Within a Web Worker
Partytown's philosophy is that the main thread should be dedicated to your code, and any scripts that are not required to be in the critical path should be relocated to a web worker. Into a sandboxed location, kinda like...a little town for third-party scripts. Some sort of a...Partytown, if you willā¦
Web workers have been a practical solution that can off-load resource intensive tasks off of the main thread for many years now. The challenge, however, is that workers do not have direct access to main thread APIs, such as window
, document
, or localStorage
. A messaging system can be created between the two worlds, but because postMessage is asynchronous, DOM operations that third-party scripts are packed full of simply wonāt succeed with a traditional messaging system.
For example, hereās a snippet of code found in Google Tag Manager:
var w = document.body.clientWidth;
Thereās nothing special about this code, actually itās pretty darn common. But, notice how it has to be synchronous, and thereās three blocking getters:
- Get
document
- Get
body
- Get
clientWidth
If weāre unable to refactor this code to use promises or callbacks instead, then an asynchronous messaging system wouldnāt allow this to ājust work.ā And I want to emphasize, āunable to refactor this code.ā
The same third-party scripts that are being executed by billions of devices, even as you are reading these lines, cannot just be ārefactored.ā In a perfect world, Iād message Google and say, āHey, you know that analytics code that gazillions of dollars are dependent on? Please refactor it entirely. Thank you.ā Next, Iād have to DM every single service in the world to refactor their code too. Wish me luck, but results may vary.
Take Me To Partytown
Partytown is a lazy loaded 6kb
library that helps relocate resource intensive scripts into a web worker and off of the main thread. Its goal is to help speed up sites by dedicating the main thread to your code, and offloading third-party scripts to a web worker.
But, the most important piece it brings to the table is allowing the web worker to synchronously read from the main thread. If code running within the web worker can call blocking DOM APIs with synchronous return values, then that means we can run, unaltered, third-party scripts in a worker. The third-party code happily executes as intended, but within a different thread as to not take resources away from your code.
Sandboxing and Isolation
Third-party scripts are often a black-box with large amounts of Javascript. What's buried within the obfuscated code is difficult to tell. It's minified for good reason, but regardless it becomes very difficult to understand what third-party scripts are executing on your site and your usersā devices, and on the same thread/context as your app's code.
Partytown, on the other hand, is able to sandbox and isolate third-party scripts within a web worker and allow, or deny, access to main thread APIs. This includes cookies, localStorage, userAgent, etc. Because the code must go through Partytownās proxy in order to access the main thread, Partytown also has the ability to log every read and write, and even restrict access to certain DOM APIs.
Essentially, Partytown lets you:
- Isolate third-party scripts within a sandbox.
- Configure which browser APIs specific scripts can and cannot execute.
- Option to log API calls and arguments in order to give better insight as to what the scripts are doing.
This could be useful for many different use-cases, including:
- Blocking access to
document.cookie
- Providing a standard
navigator.userAgent
- Not allowing scripts to write to
localStorage
- Turning
document.write()
into anoop
function - Block scripts from requesting other scripts
Current Status and Whatās Next
Partytown is still in alpha, it is highly experimental and not ready for production. However, weāve been actively testing it out on a few pages within our production site on Builder.io, and so far so good. Data is being collected as expected and our analytics look unaffected. Our goal is to collect the data now, so that it can be presented in future posts.
In the next post, Iāll be focusing on how the synchronous communication channel works and some of its trade-offs.
Additionally, weāll show how you can start testing Partytown within a React or Next.js project, or really any website or web app. Here's a quick example of how Partytown can be used within a Next.js document, but much more to come in follow up posts:
import { Partytown, GoogleTagManager } from '@builder.io/partytown/react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
export default class MyDocument extends Document {
render() {
return (
<Html>
<Head>
<GoogleTagManager containerId={'GTM-XXXXX'} />
<Partytown />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
If youād like to learn more, or even help test, please come party with us on our Discord channel, or ping me at @adamdbradley. Iād love to ensure Partytown can work with your service or use-case, so please donāt hesitate to start a chat.
Iād also like to thank some awesome people weāve been lucky enough to bounce ideas off of, and help validate if this could work IRL: Addy Osmani, Ilya Grigorik, Kristofer Baxter, Shubhie Panicker, Zach Leatherman, Misko Hevery, Steve Sewell and the entire Builder.io team.
Party on, Wayne!
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK