Builder.io's Partytown with 11ty

Murtuzaali Surti
Murtuzaali Surti

• 3 min read

🏷️ 11ty

🏷️ partytown

Third party analytics scripts are generally included in the head section of HTML. It poses a performance threat because of render blocking nature of those resources.

Although you can use the async or defer attribute to deal with those resources, they are still on the main thread of javascript.

What if you can shift them to a different thread and free the main thread? Yes, you can do it by using partytown, which is nothing but a library which uses web workers to separately execute third party scripts.

Javascript is single-threaded, yet it is capable to execute asynchronous code! How? Well, here's an interactive demo which will help you understand how the event loop and web APIs work when the browser executes javascript!

Diving into how partytown works is out of the scope of this article, but at the surface level, it manages to interact with the DOM synchronously from a web worker.

web worker in partytown

Web workers in partytown

Integrating Partytown with 11ty #

Partytown is framework agnostic, i.e. you can even use it in a simple HTML-only site. For 11ty, you can install the @builder.io/partytown npm package and extract a snippet from the integration submodule which is required to execute partytown.

npm i @builder.io/partytown

Inside eleventy config:

const { partytownSnippet } = require("@builder.io/partytown/integration");

You must include this snippet in your base layout or wherever you want to include partytown. I inserted it by using a shortcode.

eleventyConfig.addShortcode("partytown", () => partytownSnippet());

The shortcode (for nunjucks / liquid) will be:

{% partytown %}

You can use it inside a script element like this:

<script>
    {% partytown %}
</script>

The partytown snippet will now be inline with your HTML.

Next, some static files need to be served from the same origin for partytown to work. These files, by default, must be present in the /~partytown/ directory of your build.

Tip: If you really want to serve lib files from a different directory, you can specify it in the lib config.

Copy required files using addPassthroughCopy in 11ty.

eleventyConfig.addPassthroughCopy({'./node_modules/@builder.io/partytown/lib/*': '~partytown'})
eleventyConfig.addPassthroughCopy({'./node_modules/@builder.io/partytown/lib/debug/*': '~partytown/debug'})

Adding Third Party Script #

For this tutorial, I am using google analytics script but any third party script can be executed with partytown.

First, you need to add an inline partytown config script which will be above any third party scripts declared. A partytown config script specific to google analytics will be:

<script>
    partytown = {
      forward: ['dataLayer.push'],
    };
</script>

Add a type="text/partytown" attribute to all the third party scripts. By doing so, these scripts will be ignored by the main thread and executed on the web worker instead.

<script type="text/partytown" src="<analytics url>"></script>

// other third party inline scripts
<script type="text/partytown">
    // script
</script>

The order of scripts will be as follows:

// partytown config script for google analytics
<script>
    partytown = {
      forward: ['dataLayer.push'],
    };
</script>

// partytown inline script
<script>
    {% partytown %}
</script>

// third party scripts with "type='text/partytown'"
<script type="text/partytown" src="<analytics url>"></script>
<script type="text/partytown">
    // script
</script>

Debugging #

For debugging partytown, you can specify debug: true option in the partytown config script.

partytown = {
    debug: true
}

Enable the verbose level in chrome dev tools' console and you will be able to see the partytown logs.

Takeaway #

Personally, I find the idea of using web workers to execute render blocking third party scripts interesting, partly because it improves performance and partly because it's simple. It does come with some trade-offs though, but so does every other technology.

And not just 11ty, partytown can be integrated with almost any modern frontend framework or library. At the time of writing, partytown is still in beta.

Further Reading 📃


Why I love Markdown

Previous

WebSockets 101

Next