Blog

Experimenting with Partytown

Published: December 22, 2022

A couple weeks back in a Twitter conversation I learned about Partytown.

I was immediately intrigued by the idea and saw great potential, especially on the ecommerce projects that I work on on a daily basis.

Today I spent some time playing with Partytown. In this post I’ll share my process and findings.

Methodology

For my use-case I was looking to quickly test some potential performance optimizations against a remote website that I didn’t have a copy of running locally. The website was running Adobe Commerce (a.k.a. Magento) on the Adobe Commerce Cloud infrastructure.

Running this type of testing is a task that comes up somewhat frequently for me and my current favorite way to do this is using Chrome developer tools local overrides.

Partytown publishes some documentation on how to integrate into plain old HTML although I did find it a bit confusing. Here’s what I wound up doing.

Get a copy of the Partytown code

First we get a copy of the Partytown code

# Make a random temporary folder
mkdir test && cd test

# Install Partytown
npm install @builder.io/partytown

# Use partytown copylib to obtain the code for web publishing
# Partytown wants to use ~partytown as the directory name
# but the ~ in the folder name needs to be escaped and is annoying
node node_modules/@builder.io/partytown/bin/partytown.cjs copylib partytown

Now your partytown directory should look something like this…

partytown
├── debug
│   ├── partytown-atomics.js
│   ├── partytown-media.js
│   ├── partytown-sandbox-sw.js
│   ├── partytown-sw.js
│   ├── partytown-ww-atomics.js
│   ├── partytown-ww-sw.js
│   └── partytown.js
├── partytown-atomics.js
├── partytown-media.js
├── partytown-sw.js
└── partytown.js

Upload the code to the remote server

Per the Partytown documentation, the code needs to be hosted from the origin domain. I attempted to simpy drop my partytown directory into my local overrides folder for the website, however Chrome was complaining that the service worker file wasn’t being loaded with the correct MIME type. To get around this I just uploaded the files to the remote server (maybe there’s a better way to do this?).

On Adobe Commerce Cloud was can drop them into the pub/media folder.

# Zip up the code
zip -r partytown.zip partytown

# scp it up
scp partytown.zip [email protected]:~/pub/media

# SSH in and unzip it
ssh [email protected]
cd pub/media
unzip partytown

Add The Partytown Snippet to the head

Using local overrides inline the snippet into the <head> of the document. This will look something like this.

Note that we have to manually replace /~partytown with /media/partytown.

<script>
/* Partytown 0.7.3 - MIT builder.io */
!function(t,e,n,i,r,o,a,d,s,c,p,l){function u(){l||(l=1,"/"==(a=(o.lib||"/media/partytown/")+(o.debug?"debug/":""))[0]&&(s=e.querySelectorAll('script[type="text/partytown"]'),i!=t?i.dispatchEvent(new CustomEvent("pt1",{detail:t})):(d=setTimeout(w,1e4),e.addEventListener("pt0",f),r?h(1):n.serviceWorker?n.serviceWorker.register(a+(o.swPath||"partytown-sw.js"),{scope:a}).then((function(t){t.active?h():t.installing&&t.installing.addEventListener("statechange",(function(t){"activated"==t.target.state&&h()}))}),console.error):w())))}function h(t){c=e.createElement(t?"script":"iframe"),t||(c.setAttribute("style","display:block;width:0;height:0;border:0;visibility:hidden"),c.setAttribute("aria-hidden",!0)),c.src=a+"partytown-"+(t?"atomics.js?v=0.7.3":"sandbox-sw.html?"+Date.now()),e.body.appendChild(c)}function w(t,n){for(f(),t=0;t<s.length;t++)(n=e.createElement("script")).innerHTML=s[t].innerHTML,e.head.appendChild(n);c&&c.parentNode.removeChild(c)}function f(){clearTimeout(d)}o=t.partytown||{},i==t&&(o.forward||[]).map((function(e){p=t,e.split(".").map((function(e,n,i){p=p[i[n]]=n+1<i.length?"push"==i[n+1]?[]:p[i[n]]||{}:function(){(t._ptf=t._ptf||[]).push(i,arguments)}}))})),"complete"==e.readyState?u():(t.addEventListener("DOMContentLoaded",u),t.addEventListener("load",u))}(window,document,navigator,top,window.crossOriginIsolated);
</script>

Test your optimizations

Before making any changes, use Chrome developer tools and run a lighthouse scan.

Next identify some potential problematic third-party scripts. Add the type="text/partytown" attribute to those scripts in your local override. Then re-run the Lighthouse score to observe the impact.

My findings

I tested this on a client staging site today and had very positive results:

Initial Metrics

Accessibe snippet moved to Partytown

Accessibe + Grin snippets moved to Partytown

Accessibe + Grin + PowerReviews moved to Partytown

Conclusion

I’ve just scratched the surface so far with Partytown, but am very excited about the positive performance improvements it can offer for many websites (especially ecommerce). Hope you found this article helpful!

Magento + OneTrust Cookie Consent - require is not a function

Published: December 20, 2022

Tags:

There’s a lot to be said about implementing OneTrust Cookie Consent and this post doesn’t intend to cover it all. Instead, I’d like to share my experience with the JavaScript errors that occured when adding the OneTrust Cookie Consent scripts to a production Magento instance. Here’s a screenshot of the errors from the developer tools:

Screenshot of errors present in a developer tools

How Magento's JavaScript Block Loader Works

Published: December 11, 2022

Tags:

I’ve been looking at a Magento site where multiple loaders show up in different areas on the cart page. The loaders look something like this:

Screenshot of what the loader looks like

I did a bit of a deep dive into what actually causes these loader to show up. In this post I’ll share my findings.

Getting the Current Fastly VCL via API

Published: September 28, 2022

Tags:

This is just a quick little tip, but something I always have to look up how to do. The Fastly API has an endpoint for fetching the generated VCL for a service. The issue is that the version_id for the serivce must be provided in the request (there’s no way to say “just give me the currently active VCL”).

Preventing Flag Conflicts in Go

Published: July 18, 2022

Tags:

After import-ing a new package into one of my go projects and attempting to run the build, I was presented the following error:

panic: flag redefined: version

In my project, the version flag allows the user to see what version of the tool they have installed (main.version is passed as the current git tag via -ldflags in the build script).

package main

import (
	"flag"
	"fmt"
)

var version string

func main() {
	ver := flag.Bool("version", false, "Get current version")
	flag.Parse()

	if *ver {
		fmt.Println(ver)
	}
}

Presumably, the problem was that the newly imported package also used a flag with the same name.

Troubleshooting mismatched anonymous define

Published: July 9, 2021

If you’re reading this post you’re probably troubleshooting an error like this:

(index):10 Uncaught Error: Mismatched anonymous define() module: function(){return wr}
http://requirejs.org/docs/errors.html#mismatch
    at makeError (require.min.js:formatted:86)
    at intakeDefines (require.min.js:formatted:713)
    at require.min.js:formatted:835
    at nrWrapper ((index):10)

While the RequireJS documentation provides some direction on this error, in practice it can be a nightmare to understand what’s actually happening as the error trace provides no indication as to the underlying code causing the issue.

Fortunately, my colleague found an approach for getting to the actual source of the problem. In this post I’ll share that approach.