Speed up your JavaScript with Partytown 🥳

Created by human

The problem with third-party scripts

JavaScript is a single-threaded language. Even though it can be non-blocking by using asynchronous calls, it operates on a single thread. This means that if you have some scripts running in a synchronous manner, the next script or the next line will execute after executing the previous one. This is especially noticeable when we use multiple third-party scripts such as analytics, ads, webchats. They are not critical for our business logic but they can block the main thread and drastically increase time to interactive metric. This can negatively impact user experience and the overall score of our performance test by Google Lighthouse or Google Page Speed Insights. If you have ever done audits with these tools, you may have noticed lower scores due to blocking the main thread. It's especially painful when you spent a lot of time optimizing your bundle but third-party scripts kind of destroy your effort. Is there anything we can do to avoid it but still use third-party scripts?

Yes! Let's test the shiny new library Partytown which is made just for this purpose!

Partytown to the rescue!

Partytown is a lightweight library that allows you to speed up sites by dedicating the main thread to your code and offloading third-party scripts to a web worker. It's depicted perfectly in the following picture (source)

Partytown

As you can see, the main thread which is far more important than third-party scripts is now dedicated to your code and the third-party scripts are offloaded to a web worker. This means that the main thread is now free to do other things connected with the business logic of your app.

Example

Even if this package is created for the purpose to offload third-party scripts, you still can use it for whatever script you want. For the purpose of this article, let's simulate some heavy third-party scripts that consume valuable millisecond of the main thread. We will use simple HTML and vanilla JS.

Consider this script inside HTML file:


<div id="text">Hello</div>
<button id="button">Click</button>

<script>
const button = document.querySelector('#button');
const text = document.querySelector('#text');

button.addEventListener('click', () => {
    for (let i = 0; i < 10000000; i++) {
        //empty loop to simulate a long-running process
    }
    text.innerHTML = 'World';
});
</script>

This script changes the text content of some HTML elements after clicking on the button. As you can see, before replacing the text content there is a loop that iterates over 10 million times without doing anything specific but simulates a long-running process. The result is, after clicking on a button, the page is not responsive for a few seconds which means you can't interact with the page.

Let's use Partytown to offload this script to a web worker 🎉.

  1. Let's install the package by running the following command in your terminal:
npm install @builder.io/partytown
  1. Now we have to load Partytown library. Since Partytown is using a service worker, library files must be served from the same origin as your site, and cannot be hosted from a CDN. Each site is different, and how the Partytown lib files are hosted depends on the individual setup. The library provides a simple task that copies the library files to the specified path in your project.

Let's use the following command:

partytown copylib public/~partytown

Now you have your Partytown lib files in the public folder.

  1. Let's now add the following script to your HTML file:
<script src="~partytown/partytown.js"></>

Great! Now we have a Partytown library ready to use 🥳!

  1. All we have to add the following script type to our script tag
type="text/partytown"

And with context:

<div id="text">Hello</div>
<button id="button">Click</button>

<script type="text/partytown">
const button = document.querySelector('#button');
const text = document.querySelector('#text');

button.addEventListener('click', () => {
    for (let i = 0; i < 10000000; i++) {
        //empty loop to simulate a long-running process
    }
    text.innerHTML = 'World';
});
</script>

Now if you click on the button, you will see that even if the loop is still running for a long time, the main thread is not blocked and the page is fully interactive! 🎉 We made it!

Conclusion

Although it's still in beta, Partytown is a really cool library with a lot of potential. It's easy to use and the official docs are well organized and cover all aspects of the concept. Currently, there are multiple wrapper packages dedicated to specific frameworks like next and nuxt, so I'm pretty sure that it will be a great addition to the JavaScript ecosystem. The only downside I see right now is that code editors can't color highlight the script wrapped with <script type="text/partytown"> but I'm pretty sure that It will ship soon.

© Copyright 2024 Michał Kuncio