Partytown with Adam Bradley - JSJ 550

Today we talk with Adam Bradley, the Director of Technology at Builder.io. He previously worked at Ionix as a creator of Ionic Framework, a mobile UI interface builder for web applications, and StencilJS which powers Ionix. Currently he works on both Qwik and Partytown at Builder.io. In today’s episode we dive into Partytown, discussing the unique ways it improves website performance. When there are so many third-party scripts injected into the average website, you can quickly lose control of speed. We learn how Partytown addresses this with a remote web worker, and how it still gets the data it needs synchronously.

Special Guests: Adam Bradley

Show Notes

Today we talk with Adam Bradley, the Director of Technology at Builder.io. He previously worked at Ionix as a creator of Ionic Framework, a mobile UI interface builder for web applications, and StencilJS which powers Ionix. Currently he works on both Qwik and Partytown at Builder.io.

In today’s episode we dive into Partytown, discussing the unique ways it improves website performance. When there are so many third-party scripts injected into the average website, you can quickly lose control of speed. We learn how Partytown addresses this with a remote web worker, and how it still gets the data it needs synchronously.

On YouTube

Sponsors


Links


Picks

Transcript

Charles_Wood:
Hey everybody and welcome back to another episode of JavaScript Jabber. This week on our panel we have Steve Edwards.
 
Steve:
Hello from cloudy and cool Portland.
 
Charles_Wood:
We also have Dan Shappir.
 
Dan_Shappir:
Hi from sunny Tel Aviv
 
Charles_Wood:
I'm Charles Max Wood from Top End Devs, and this week we have a special guest and that is Adam Bradley. Adam, thank you for having a name, I can say, and welcome to the podcast.
 
Adam_Bradley:
Thanks, and I should say I'm from beautiful Madison, Wisconsin.
 
Charles_Wood:
Oh, nice. I
 
Adam_Bradley:
Yes.
 
Charles_Wood:
have a brother that lived out there for a while and he loved it, so. Do you wanna give us just a brief introduction, who you are,
 
Adam_Bradley:
Sure.
 
Charles_Wood:
kind of where you've been, what you do, why you're
 
Adam_Bradley:
Sure,
 
Charles_Wood:
famous?
 
Adam_Bradley:
yeah, absolutely. I don't know about famous, but absolutely. So previously I worked at Ionic. So I helped create the Ionic framework, which is a mobile UI interface builder for different web applications. And through that, I've been able to create a lot of different applications. So I've been able to create a lot of different applications for
 
Charles_Wood:
Mmm.
 
Adam_Bradley:
different applications. And I've been able to create a lot of different applications for different applications. And I've been able to create a lot
 
Charles_Wood:
Yeah,
 
Adam_Bradley:
of different applications for different applications.
 
Charles_Wood:
good guys over there, Max and Mike. We've had
 
Adam_Bradley:
Absolutely.
 
Charles_Wood:
them on the show before.
 
Adam_Bradley:
Mac, Mike, Ben. Yeah, so I was
 
Dan_Shappir:
Thanks for watching!
 
Adam_Bradley:
employee number three there. So I had
 
Charles_Wood:
Oh
 
Adam_Bradley:
a
 
Charles_Wood:
wow.
 
Adam_Bradley:
lot of fun helping to create that. And in doing that, we created Stencil, which is actually what powers Ionic.
 
Charles_Wood:
Mm-hmm.
 
Adam_Bradley:
And so that was a framework that's using web components to create each of the leaf components for Ionic so that we can then have Ionic fit inside of any single framework, React, Angular, what have you. And so that went really, really well. that stuff. And today I'm at Builder.io. I'm working on quick and party time.
 
Charles_Wood:
Very cool. So, yeah, we've got you on to talk about Party Town.
 
Adam_Bradley:
Thanks for watching!
 
Charles_Wood:
And I kind of like to start at the high level like what it does, but can you also do that in a way that kind of explains to people why they would want to use it?
 
Adam_Bradley:
Sure. Yeah, so with today's websites, there's, well,
 
Dan_Shappir:
you
 
Adam_Bradley:
any website, there's a performance issue of the more JavaScript you add, the slower the page is going to be. And so there is no shortage of documentation explaining to people what they should do, how to make their websites faster, how to optimize your bundles, how to lazy load components. So there's all this information on what you do to your code to help speed up your application. So let's say that we did every single recommendation. We do everything possible. and we get our own React app working as fast as possible. Let's say it scores 100 out of 100 locally. Then we deploy it. The real problem hits when the real world starts adding analytics to your, or basically third-party scripts to your website. So let's say that you do have the fastest website possible. You don't have a JavaScript problem. Once you start adding all these different third-party scripts, which I believe the average is at least 20 third-party scripts, there's a HTTP archive stat showing that the median
 
Charles_Wood:
Oh
 
Adam_Bradley:
20,
 
Charles_Wood:
wow.
 
Adam_Bradley:
30-part scripts on a webpage. As you keep adding these, that's what's really slowing down your site. And so any e-commerce site, again, that could be a very fast website, just with what you built on your machine. As different departments are adding more and more scripts, that's really, really slowing down your site. And I think a lot of developers have experienced this. They've seen that like, hey, I was scoring great. What happened to my performance of this site? And that's like, oh, it's the 20, 30 different scripts that are each, you know, 30, bytes, you've got almost three megabytes of someone else's JavaScript running on your main thread, eating up all the resources. They're not synced up together. They're all fighting for paint to the window. They're all actually, I've seen quite a bit of them having like a set interval as reading the DOM. And so all of this junk is being added to your site because you gave it access to do that. And so that's kind of the big problem that we're at right now. I'm thinking that All of these scripts access to the main thread, the same one that you're trying to share, but we have zero control of what they do and how they do it. It's just kind of a free for all, and they can eat up as many resources as you want, which is what your app should be using rather than theirs.
 
Dan_Shappir:
I think it's worthwhile to clarify or even define exactly what is meant by third-party scripts. I assume that most of our listeners do know what it is, but you know maybe a few do not. So it's important to stress that third-party scripts are scripts that you inject into your website, but are provided from a different domain, and it's a domain that's not controlled by you. So it's not your scripts. Analytics, Google Tag Manager, the Facebook stuff, and there are so many more. Something from Twitter or something. Yeah, just the list goes on and on. And it's important to note that these are not like, you know, scripts from like external libraries that you might incorporate via NPM into your code. Those are bundled into your code and they're effectively first-party scripts even if you didn't write them. Third-party scripts are wholly controlled by someone else. So I think that's an important point to make. And another point I think that's important is kind of what I consider to be a certain deficiency, perhaps, of the entire web platform, that you literally have no control over what these scripts can do within the context of your own web page. That means that once you have a script tag that brings down a script, that script can effectively do within your web page anything that your scripts can do within that web page. It has like total freedom and you can't really limit what it decides to do. If it wants to like consume your all your memory, all your CPU, modify the DOM in whichever which way, well it can do all that stuff and it is what it is.
 
Adam_Bradley:
Yeah, absolutely. That's a great clarification. And it comes down to like you did give access to this script to run on your users' machines. And so they can do whatever they want. If you add one third-party script, you probably not see the problem. Like if you add only Google Analytics, there's a slight, you know, dent in your performance. It's the problem of adding 20 or 30. That's where it really comes in. And then they're all again, they're not synced. They're all kind of doing their own thing. They all want to, you know, make their service be the best one. of dom reasons they need to do. And basically it just turns into this big cat fight on the main thread of resources.
 
Steve:
Yeah.
 
Adam_Bradley:
Meanwhile, you have an application you're trying to get people to use.
 
Dan_Shappir:
Thanks for watching!
 
Steve:
Right. I remember I used to, uh, probably about 10 years ago, I was working for a large nonprofit and running, uh, four different sites and these happened to be Drupal sites and the bane of my existence was ad scripts that we had to have
 
Adam_Bradley:
Yeah.
 
Steve:
in. We had to have all 30 of our scripts for running ads on the websites. Cause that was a large part of how the organization made money and got income as a nonprofit. And I can remember, you know, getting questions about performance and I would basically take all the scripts out and just run the site by itself. And it was so fast.
 
Adam_Bradley:
Yep.
 
Steve:
And then as soon as we started running third party scripts, everything just slowed down to a crawl. And I pointed, I might show it examples. Look, here's it. You know, this is running without ads. This is what it is. And they're like, sorry, we got to have them.
 
Charles_Wood:
Yeah.
 
Steve:
And at that point, you know, we tried everything we could think of, whether it was, um, you know, loading the JavaScript at the end of the page, you know, putting it at the tail end of the page so that it didn't load to We tried so many things and it was just took up way too much of my time
 
Adam_Bradley:
Yeah.
 
Steve:
and was
 
Charles_Wood:
Yeah.
 
Steve:
miserable.
 
Charles_Wood:
Well, it's interesting because, for example, with the
 
Steve:
you
 
Charles_Wood:
Facebook pixels, just to throw that one out there, right? A lot of tracking is done for the marketing folks, and it turns out that you kind of need that in order to do Facebook ads properly and attribute purchases and things like that. So a lot of times we kind of look at it and we think the but they do provide legitimate business reasons to put them on there. You know, some of them are like, you know, the intercom chat or things like that in there as well. But yeah, I mean, you know, Google Analytics, you know, I mean, I'm talking about this from the podcast and the things, right? And I'm getting ready to sell courses and stuff like that. And so, you know, if I want to buy Facebook ads, Facebook ads system before I start buying ads. Google Analytics, my sponsors want to know how many times people are going to see their ads. It is
 
Adam_Bradley:
Yeah.
 
Charles_Wood:
exactly what we're talking about, but yeah, it does impact the performance and things like that, and that sucks.
 
Adam_Bradley:
Yeah,
 
Dan_Shappir:
Yeah, you're running... Oh, sorry. Go
 
Adam_Bradley:
and
 
Dan_Shappir:
for it.
 
Adam_Bradley:
that's kind of been a hard requirement that we have with Parton was that it's easy to say, like, well, if you want to improve your performance, get rid of the analytics, get rid of the three-part scripts, duh, why don't you do that? But again, just as what you're saying, the reality is the business makes that decision. The business has reasons. They use all this data to make business decisions. And so you can't just say, well, don't remove the three-part scripts. Maybe on your personal blog you can. as a large e-commerce site that has millions, billions of dollars dependent on this data, you can't just remove it. And so that's kind of the hard requirement with Parton was that we can't say, don't use this. And we can't alternate, change the third-party script code. It's given to us from a different server. We can't just decide to, well, let's try to improve something or improve its performance somehow. It's like, well, that's not how it can work. It's a half megabyte of JavaScript, someone else's JavaScript on a different domain. We can't control that. those two things, it kind of made Priton a challenge. It was like, well, how do we improve
 
Dan_Shappir:
Thanks for watching!
 
Adam_Bradley:
these someone else's scripts and someone else's domain that's running on the side of your website? And that's kind of where Priton came in.
 
Dan_Shappir:
I want to mention two more things. So first of all, yet more examples of, you know, Chuck, you gave some examples of, and more. Like again, if you're using the Facebook Pixel, you're probably running campaigns within Facebook. You want to know which campaigns are effective and which aren't. Similarly with Google, you want to know if you're doing SEO campaigns, you know, your pay, or pay-per-click. You want to know what works and what doesn't. You know, the organization absolutely needs this information. There's literally no way you can go to the marketing department or the martech or whatever and tell them, no, you know, I'm removing your scripts. In fact, it's gone the other way because it seems like, you know, the marketing people were so sick and tired of having to argue with the developers all the time about, you know, adding the pixels that they needed that they kind of did an end run around us with where
 
Charles_Wood:
Mm-hmm.
 
Dan_Shappir:
effectively they have this
 
Adam_Bradley:
Yeah.
 
Dan_Shappir:
like meta script which can download which can load more scripts so now they just embed that one third party script as it were into the site but through that script they can add whatever else they want and in most cases that I've seen the developers in the organization don't even know which third party scripts are being loaded into the website. Moreover
 
Adam_Bradley:
Yeah, absolutely.
 
Dan_Shappir:
these scripts are not loaded during development. So during development, everything seems great, or even in the staging environment, everything looks wonderful because the scripts aren't even there, and then they're
 
Charles_Wood:
Mm-hmm.
 
Dan_Shappir:
loaded in the production environment and you're screwed.
 
Adam_Bradley:
Yeah, that's pretty accurate portrayal of what happens. So again, like in development, you can have a extremely fast scoring 100 out of 100 Lighthouse, push it live and then all of a sudden you're scoring a 19. You know, and so that's, that's not far fetched at all.
 
Charles_Wood:
Alright, so how do I get Facebook off my lawn then?
 
Adam_Bradley:
Yeah, so really the big trick that Pariton applies is trying to run all of this code. So again, let's say you've got two megabytes of someone else's JavaScript running on the main thread. You want to dedicate the main thread to your code. So to your 100 kilobytes of awesome application is just dedicated to the main thread. Well, that three megabytes, let's put into a web worker. Let's put it somewhere else to run. And that's kind of been, you know, something that's been practical for over a decade now, like since I think IE 10, they've had web workers. And so it's absolutely been practical. How come this hasn't been done earlier? How come people haven't been using web workers much more? And it comes down to, well, the web worker doesn't have access to the DOM or the window. And so the web worker cannot, you cannot do document.title is usually my simplest example. There's no way for the web worker to say, what's the document.title of this webpage? Because there's no such thing as a DOM in that environment. It's an entirely different world. For it to do that, it needs to send a message to the main thread, which is like, hey, main thread, what's the document title? Main thread's like, it's whatever, sends it back. And that messaging between the two, that's asynchronous. And that's really the big problem of why this hasn't been done earlier. Because it's asynchronous, because there's this moment in between, and there's no callback, no promises, anything like that, all of these scripts don't count on that. All of these scripts are counting on document.titleD immediately, synchronously, respond with a string. And it's not just document.title, it's all of the APIs. It's expecting to be on the main thread. It's expecting that the moment that they do element.getAttribute is going to immediately get that data back. And that's the problem. That's why, because it's someone else's code and someone else's servers, we can't just change how that works. We can't change like, well, let's make this a getTitle to be asynchronous with the callback because all of a sudden we've changed their three megabytes of code, it's going to break, it's not going to work anymore. And that's the problem. it comes in is it's able to run this code the same in a different world into a web worker. But the moments that it does need that data synchronously is that it uses this trick to then like post to the main thread to say, hey, get me document that title, synchronously. And that's the trick.
 
Dan_Shappir:
Before we dive in into how you manage to accomplish this magic, because for me, what you've done is literally black magic, I do want to expand a little bit again for our listeners about web workers. Like you
 
Charles_Wood:
Mm-hmm.
 
Dan_Shappir:
said, they're nothing new. But unfortunately, they're not so widely used precisely because of those various restrictions that exist on them, like their inability to directly access and the difficulty in moving information between the various workers and the main thread. So, as we know, in the past decades, computers aren't really getting faster anymore. And if you're looking at the various mobile devices, and most of the browsing these days is done for mobile devices, the endpoint devices are actually potentially getting slower, because people are moving from faster desktops to slower mobile devices. are more and more cores. So if you can offload the processing off of the main thread to a different thread, then you're taking advantage of a separate core and you can execute multiple things in parallel effectively without the slowdown. Unfortunately, the browser was created in the days of single cores, and it was created primarily as a kind of a single thread thing, hence the whole concept of the main thread so much of the browser's work running the JavaScript, doing the rendering and additional stuff. So like you said, the concept of Web Workers was introduced as a way of offloading JavaScript computation off of the main thread, but it precisely suffers from the limitation that you described of no access, no direct access to the DOM. Effectively, if it wants to communicate with the DOM, it needs to send an asynchronous message to JavaScript that message does whatever service it needs for it, and then sends the information back also asynchronously. And the final thing I want to mention is that, another kind of unfortunate, well, both unfortunate and fortunate decision that I think we can attribute to Brendan Eich was that he made both JavaScript and the DOM wholly synchronous. I think it's an unfortunate decision on one hand, That's not really the way that such systems need to work. And it greatly limits how the browser operates. On the other hand, had he made it asynchronous on the get-go, probably would have been too complicated for most web
 
Adam_Bradley:
Yeah.
 
Dan_Shappir:
developers to comprehend. And potentially, the web would never have gotten off the ground. But be that as it may, the DOM, like you said, is primarily synchronous. You access a property, you read the title, or you write to the title. In an ideal world, all of these things would have had an await in front of them, but that's not how the web works. And like
 
Adam_Bradley:
Thanks for watching!
 
Dan_Shappir:
you said, all those third-party scripts were created to run in the main thread. They make direct access to the DOM. It would have been lovely if Facebook, for example, modified their pixel not to work that way, and maybe eventually they will, but currently they don't. And despite this fact, you guys somehow managed to take this code that makes direct synchronous access to the DOM and move it to run in a worker. What I want to understand first of all is, let's say, first of all, how do I do it? Meaning if I already have a website that uses third-party scripts, what do I need to do to get And the second thing would be how do you do it? How do you accomplish this magic? So let's start with what I need to do to get it
 
Adam_Bradley:
Sure. So basically there needs to be a, what I'm calling, you know, a party town snippet. Basically a little bit of code, just like you'd add like Google Tag Man or something like that. This little bit of snippet that goes at the head of the script, or head of your document, that just kind of has a registry that you can set it all up. And so that snippet needs to be added to the head. It's synchronous. It's not a separate request. It's just, you know, a couple bytes of code that's added to the head. And then the next thing is like any script that you want Each script element can have a type attribute. So normally you don't have it at all or it has type, you know, text slash application or type module. And what that does is it tells the browser, if there's no type attribute at all, it says, you know, execute the script. If you give it something that the browser doesn't recognize, if you give it something like text slash party town, the browser sees this attribute and this script element and it's like, I have no idea what you're talking about. I'm just gonna skip over this. any of the content side of here, because I don't know what kind of content lives inside of here. And so that's kind of the first trick that Pariton does, is it allows you to keep your code identical. However you were adding those scripts before, or today, is whether you're using React or using WordPress, somehow that script element is showing up into your document. The only change you have to do is add the type attribute of text slash Pariton. So again, that tells it to don't execute me, just leave me be. And then the second phase is that when loads, it's all done and everything's cooled off. That's when Part-Town is like, okay, now it's my time to work. Let's go find all those scripts that didn't execute. Let's find where they are, you know, do a query selector for that script type, tech slash Part-Town, and let's tell the main thread or tell the web worker to start executing these scripts. And so that's the first step of what it is. And again, like one of the requirements was with Part-Town is that it's not like a React project, it's not a Drupal project, it's just as low levels it can get We do have wrappers for different frameworks, but for the most part, it's just like, add that attribute somehow, whatever way you would add an attribute to your existing code, and then part-time will know how to query, select it for that, and continue.
 
Dan_Shappir:
That's very cool. So effectively, like you said, the two steps of adding Party Town to my website is A, add the Party Town script tag, and B, modify the script tag of all the third party scripts that are directly embedded in my web page in the HTML. Add the type text slash Party Town on their script tags. That's it.
 
Adam_Bradley:
Yep, and the other step was to make sure that the library files are there, because there is a directory of, till the party town directory that needs to have, and because we're using service workers, service work requirement is that it needs to be on the same origin, so you can't use party town through like a CDN. It needs to be, those files need to be on your same origin,
 
Dan_Shappir:
Hmm.
 
Adam_Bradley:
is one thing it needs to do. But yeah, that's basically the setup, and that allows you to also decide to pick and choose, Like, I only want, let's say you've got 10 scripts on your page, I only want to do just this one. Or you could even, you know, some people that are starting to experiment with Part-Town, they'll say, like, on just the About Us page, and for just this script, why don't we add the attribute to see how it's working in production? Because you kind of pointed out earlier how, you know, production environments and staging environments are usually two entirely different things when it comes to the three-part scripts. And so one way to do that is to, you know, test on, A, B testing on certain pages and things like that. it allows you to not have to have some sort of webpack plugin that does all sorts of magic, you know, that just takes over control of all of your scripts because realistically you're adding them your own way. And so with your own way, you can decide, I want to add this type attribute for this one particular condition.
 
Dan_Shappir:
As an aside, I would say that because of, you know, related to what you just said, that staging is effectively different than production is the reason that I think that staging environments are mostly useless. There's usually no real point in actually even having a staging environment. So not a permanent one at least, you know, you might spin up a temporary staging environment to test something, but usually I don't see any point in staging environments.
 
Adam_Bradley:
Well, especially with third party scripts, that's been the
 
Dan_Shappir:
Exactly.
 
Adam_Bradley:
kind of the, the, the difficult, very difficult part with party town is someone says, does this work? No, it does a service X work with party town. And it's like, well, first off, I have no idea. There's thousands and thousands of different scripts and each one of them can be doing billions of different things inside the code. Like there's no, you know, there's no easy answer to say yes or no, it's going to work in there. Um, and then the next thing is, uh, we can test on some QA website and the QA code might have like, no, if QA. do nothing and then else, you know, oh, we're in production, let's do all the, the actual magic. And so there's, it's almost every script has this, has somewhere, some conditional of it, like if local hosts do nothing. Um, and so that's the other really hard part is like, you don't, you can't really test your three per scripts unless it's in production and I don't know that that's not a, you know, it's, it's not a part time problem. It's, you know, it's kind of a, everybody's issue. Like it's an unsolved problem. I think when it comes to three per scripts.
 
Dan_Shappir:
Like my previous R&D manager, the VP of R&D at WIC said, you've got to be brave about those things. Have guts. Test in production.
 
Charles_Wood:
Ha ha ha

Adam_Bradley:
Yeah. Well, you kind of have no option.
 
Dan_Shappir:
Yeah.
 
Adam_Bradley:
I'd love alternatives. Yeah.
 
Dan_Shappir:
You just need to make sure that you have good monitoring and the ability to roll back
 
Adam_Bradley:
Yeah.
 
Dan_Shappir:
really quickly and effectively, and test in production.
 
Adam_Bradley:
Yeah. And it's not, you know, and I'll fully admit, you know, I'm a web developer too. I'll probably admit that like it's not the best idea to just throw something on the about us page and cross your fingers. But again, like what are your alternatives? Because the third price, the, you know, Google analytics doesn't actually run any of this production code and thus it's in production. So
 
Dan_Shappir:
Which brings me to another question. So as I mentioned before, you have Google Tag Manager as this kind of third party script manager, as it were. Effectively, Google
 
Adam_Bradley:
Yeah.
 
Dan_Shappir:
Tag Manager, which means that it's loaded directly by the script tag in the HTML, but it then loads additional scripts itself.
 
Charles_Wood:
Mm-hmm.
 
Dan_Shappir:
Does Google Tag Manager work with Party Town? it does, does the scripts that it loads automatically run within that WebWorker?
 
Adam_Bradley:
Yeah, that certainly is a scenario that is an issue where because Pyrton runs the Google Tag Manager in WebWorker, any additional scripts that that script adds continues to stay inside of the WebWorker. But there might be a case where a certain script should never run inside of WebWorker, it needs to run inside the main thread. And so that's the challenge today is that Pyrton will by default continue to run everything inside of the WebWorker. the escape hash, I think in our config, I'm looking at the site right now, where you can load scripts on main thread. And that config was added fairly recently for this scenario of like, the default is basically run these 10 Google Tag Manager scripts that the marketing team added. But this one particular one, you know, whatever.com, we want that one to run in the main thread. And so that config allows that.
 
Dan_Shappir:
Why would you want to run specific scripts in the main thread?
 
Adam_Bradley:
I don't know. There's plenty of scenarios where something just doesn't, will never work inside of a web worker. Certain, well, even Canvas, Canvas will work inside of a web worker because it still can communicate. But there's plenty of certain scenarios that don't work. Like I think video buffering is one that's been an issue in the past. Usually if they can start a video, it can play it, everything works fine. But if it's buffering constantly between the two, But again, it's hard to say the one true answer of why you'd want to run something in the main thread. The other, probably the most common reason would be that there's some bug inside of Pyrtown that didn't allow a special API to work as it
 
Dan_Shappir:
Hmm.
 
Adam_Bradley:
was supposed to. And
 
Dan_Shappir:
So
 
Adam_Bradley:
that's
 
Dan_Shappir:
basically,
 
Adam_Bradley:
kind of, again, it's kind of escape hatch.
 
Dan_Shappir:
yeah. So, okay, cool. So yeah. So like you said, it's an escape hatch. So if somebody comes to you and says, hey, I'm using party town and, and script X out of that million third party scripts that exist in the world doesn't seem to work correctly. You know, you might decide to look at it or not. But while you are there, at least have an escape hatch for the interim.
 
Adam_Bradley:
Yeah. Yeah. And yeah, that's really been the big goal with Parton is that it's not like recreating the DOM. So you got like, so think of JS DOM, which is what a Node.js project, because Node.js is in the browser. It's just a JavaScript runtime. And so there's a project out there called JS DOM, which plenty of us use in a Node environment to recreate the DOM. Well, that's about two megabytes of JavaScript, all common JS. And so if I wanted to recreate the DOM, and run that inside of there, I'd have a two megabyte file inside of your browsers, which completely defeats the purpose of what we were trying to do with trying to speed up your scripts by having less scripts. And so instead, the big trick is that Party Town is essentially saying, these are all the APIs that I see are on the main thread. Let's just kind of make proxies for them on the WebWorker.
 
Charles_Wood:
Thank you.
 
Adam_Bradley:
And so it kind of just quickly looks through all the different prototypes. It's like, oh, these are things. And it forwards those things onto the WebWorker. And so then when the WebWorker proxy gets hit by that DOM API, it's like, oh yeah, I saw this is on the main thread. Let's go get the information from the main thread. And so
 
Charles_Wood:
So effectively,
 
Adam_Bradley:
with that.
 
Charles_Wood:
you've written some middleware that passes the messages back and forth.
 
Adam_Bradley:
Yeah, I think so. Yeah, just a fancy proxy, right? Because we don't want to recreate the entire DOM because it will be forever chasing something different. And the other cool one that is kind of fun to see work just organically is certain features are on Chrome, but they're not in Firefox or Safari. And so because of this feature of it's like, well, we see what APRs are available on the main thread, and we just tell the web worker to recreate those. Then the same type of polyfills are feature isn't available on Safari, whatever if statement that they have for that feature detection, it skips over it naturally. So Safari can't do X, Chrome can. It knows how to avoid the two and do the same thing that would have done the main thread.
 
Dan_Shappir:
And this scanning is done dynamically. That means that you look at the actual scripts that get loaded and figure out from the actual script text which APIs you need to effectively polyfill or simulate and only create those. That's the way that it works.
 
Adam_Bradley:
No, it actually on the initial startup is when it loops through the entire window, a prototype of like what's on window and then window has a
 
Charles_Wood:
Did you all
 
Adam_Bradley:
node.
 
Charles_Wood:
freeze?
 
Adam_Bradley:
What's that?
 
Charles_Wood:
I think my connection froze.
 
Adam_Bradley:
Okay. No, yeah,
 
Steve:
No,
 
Adam_Bradley:
it just, it gets out of inf-
 
Steve:
I didn't hear Adam there for a couple of seconds either.
 
Adam_Bradley:
Okay, I skipped out.
 
Charles_Wood:
Okay.
 
Steve:
Yeah.
 
Adam_Bradley:
All better now?
 
Steve:
Now you're fine. Yeah.
 
Adam_Bradley:
Okay, yeah, so it basically, no, it scans through the, on startup, it scans through the prototypes of what's on the main thread. And really as kind of just a big string, it sends it over to the web worker, which is like, hey, these are the things that exist. Recreate these proxies.
 
Dan_Shappir:
So it doesn't scan the scripts it scans your browser effectively.
 
Adam_Bradley:
Right. Like
 
Dan_Shappir:
Oh
 
Adam_Bradley:
the browser
 
Dan_Shappir:
cool
 
Adam_Bradley:
that that user is using at that time. Could be Firefox, could be, you know, mobile Safari, whatever it's using, it's going to tell the web worker, you're like, redo this, the same API.
 
Dan_Shappir:
and you do the kind of recursive descent from the window
 
Adam_Bradley:
Yep.
 
Dan_Shappir:
object, something like that.
 
Adam_Bradley:
Yep. And that's usually where a lot of the fixes have to happen. If there's for some crazy special reason, something didn't get polyfilled correctly, that's where it takes time to look into, why didn't this work? And so if you look at our site, there's quite a few platform tests of just like anything and everything that the platform should do. It should work identically. So the idea being that if we make sure that every single DOM works, really not like recreate how it works, but just like information flows exactly how it's supposed to, then if we can recreate exactly how the DOM is supposed to work in WebWorker, then all of the scripts should work. And so there's usually something, one or two things that didn't flow through correctly. And that's where the bugs lie, is trying to figure out why the proxy didn't do what it was supposed to do.
 
Dan_Shappir:
you
 
Adam_Bradley:
And so again, those tests, and we got all sorts of playwright tests that are trying to recreate, you know, if you said href, it's supposed to do this. You know, so we know what it's supposed to do. On the main thread, absolutely the same thing should happen in the WebWorker, Sorry.
 
Dan_Shappir:
So now let's get to your magic, because I get how you create those proxy objects inside the worker that represent the actual DOM by scanning the DOM and then sending the information of the DOM shape into the worker and creating proxy objects based on that. And then access is made to those proxy objects, either method whatever, but if it was just a naive implementation, that would result in you needing to send an asynchronous message to the main thread to do the work or to get the information or set the information. And that would have been great if all the third-party scripts would have used a wait on all the property accesses and method accesses and whatever. But they don't because they assume that they're running in the main thread and everything is synchronous. that.
 
Adam_Bradley:
Yeah, so that was the next big challenge. And so there's been, you know, everyone's like, criticism of just like, well, isn't it still doing the exact same amount of work? Like, what's the big deal? Now you just have this overhead of posting messages back and forth. But the big difference is that all of that logic, first off, all the memory usage, all the logic, all the script is running two different threads. So there's a big benefit there. None of that's fighting for your main thread, or the other main thread. The other thing is that all that logic is executing, of that web worker. It's not like every single line that it executes, it has to go to the main thread. It stays pretty much within that web worker most of the time. And then occasionally, it needs to get information synchronously. And that's where it then occasionally goes to the main thread. And I say occasionally, you're still going to see a lot of network requests of what's going on. And so, all right, so here's the big trick, the big magic that is going to have to be an asynchronous request to a different thread. There's nothing we can do about that. And so really there's two ways that we can do that and that's through one, through Atomics and we can talk about that later. And I would say the Atomics is the correct way. And then the other way is I'll label more as a trick is the Service Worker synchronous XHR request that we use. And so a synchronous XHR request, if you remember from the olden days, is that that was just, you never use that. synchronous XHR requests because that's going to lock up your user's browser. It's being deprecated, if not already removed from the main APIs. It's highly never use that type of API that you would see all over the place. And for good reason, because when people did use synchronous XHR requests, let's say that you clicked a button and then it needs to do some request information and come back, everything would lock up during that time. And so then that's where we were all trained, to get information so that you can have a little spinning loader while you're downloading the data. And yes, I believe that's being deprecated from the main thread. So then when you hear about that being used for Pyrtown, that's usually the first response is like, wait, you're not supposed to use synchronous XHT requests. Well, that's different for the WebWorker because a WebWorker is pretty much largely based on having synchronous requests and being able to freeze up that thread. So the biggest example would be import scripts function, the global function that it has. widely why they used in almost any web worker to synchronously load different CDN information, especially if you think of something like StackBlitz or Cloud, I was like, Code Sandbox, things like that. They all rely on the use of how import scripts work synchronously. And so that is not something that's gonna be deprecated. And the fact that a web worker is able to pause execution while something is happening. trick is like, well, that's one way that we can make the web worker stop for a moment and get something synchronicity. And so what we're doing is that when we access document.title or something accesses document.title, we create this magic proxy called document. And on it, it has this property called title. We don't know what it does. And I'm thinking as a web worker here, I have no clue what document.title is. to call. Inside of that proxy that we call, it then does this synchronous XHTL request to Proxytown URL, which is a scoped URL that doesn't actually hit the network. And which is if you look at any site that's got a part on running it, you will see a bunch of network requests for Proxytown. It's kind of misleading because they're not actually prox network requests. They're not hitting the real network. It looks like they are through Chrome DevTools. but they're not. And so I wish they weren't there because they are being intercepted. They are being, you know, just handled locally within the browser. But with that request, we then have the service worker is able to basically convert the synchronous request into an asynchronous one. So the service worker has an onFetch method and the onFetch method then goes like, okay, you want to get document.title. Let's post it to the main thread, ask.net title. Main thread finally gets back to me, you know, a millisecond later, that initial request that the WebWorker had. So then by the time the WebWorker executes, it might've been one millisecond, but according to the WebWorker, it was synchronous and it happened immediately. I don't know if that was way too much or
 
Dan_Shappir:
No,
 
Adam_Bradley:
if
 
Charles_Wood:
Hehehe
 
Adam_Bradley:
there's any.
 
Dan_Shappir:
that's great. I think, like I mentioned before, a lot of web developers, people working the front end, don't really have experience with threads. If you were talking to Java developers, for example, threads would be obvious. Everything is threads. And the whole idea when you're working with threads is that you block threads. And that's how threads are usually used. Not the main thread. UI thread, but the various other threads that you have. You need them to do something. They need some information. They block until that information is received. And once it's there, they can continue, because the main thread is still there to continue processing user inputs. And effectively, that's the model that you get with web workers. By offloading computation, it could be a lengthy computation that would block the main thread. a synchronous XHR that would block the main thread. So effectively, what you're saying is that you've used a synchronous XHR coupled with your custom service worker to implement a blocking API on top of web workers. So the web workers are blocked. The main thread, obviously, is not. That still works with post messages between the service worker
 
Adam_Bradley:
Yep.
 
Dan_Shappir:
and the main thread. until the response arrives that WebWorker is blocked. And consequently, the third-party scripts which expect things to be synchronous, you know, they are. They just potentially take a long time to respond, but what do you care?
 
Adam_Bradley:
Yeah. And that's where Parry Town is really ideal for third-party scripts that are largely asynchronous. When a button is clicked, it then kind of batches up this button was clicked, is at this location. We've got enough information. Let's send a fetch over to the main service that this button was clicked. And so that's kind of the ideal. Google Analytics is a great example of this, where it's kind of just a background task that can be asynchronous.
 
Charles_Wood:
Hmm.
 
Adam_Bradley:
blocking application, right? You don't want to run, that's asked a lot too, it's like, if Party Town is so great, why don't I run my application? And it's like, well, that's the opposite of what you want to do. Because we're just trying to move off all of these, you know, bloated scripts to slowly go into somewhere else. And they can go slower, right? Like that's fine. Now that also scares people. It's like, well, now they're going to execute a little bit slower. It's like, yeah, but that's fine because they're already just listening for events and then slowly posting to their service. And when I say slowly, you know, two, three milliseconds slower than what it would have been if it was in the main thread. And so that also kind of speaks to, is like all that weight that you were waiting on before is now not, you know, messing up the main thread. And so now when you click, you have free resources to do everything inside of your application, your React Angular application, and the WebWorker code can slowly go just a touch slower, which is fine, in my opinion, for those scripts.
 
Dan_Shappir:
I have to ask, where did this idea come from? I mean,
 
Adam_Bradley:
Yeah.
 
Dan_Shappir:
to me, it borders on genius. I mean, the concept of taking, of implementing a synchronous dom inside a web worker and creating synchronicity, using blocking XHR to a service worker, what can I say? I would never have thought of that.
 
Adam_Bradley:
Hehehe
 
Dan_Shappir:
Like, how did this come about?
 
Adam_Bradley:
Yeah, no, it definitely came out of like a necessity of, so we're also building QUIC, which is a framework, kind of a next generation framework that allows us to be extremely, extremely fast by not executing JavaScript and lazily, prefetching code on demand and things like that. So anyways, without going into further detail about QUIC is that we basically came to the realization is like we can make QUIC the fastest framework in the entire world, but no matter what we do, we still have these third-party script problems. And so at Builder, have a lot of customers that are certain to use Quick and certain to use, and they use Builder quite a bit, use Builder for their applications. And the same thing comes down to is like, a lot of them are e-commerce customers and they get their site running fast, but they still have the same problem. And so Quick, I kind of feel, only solves half the problem of having bloated, you know, your own bloated JavaScript application. And so we kind of solve that problem. I'm just like, you can make your application a lot faster now. But is you're still going to add three megabytes of someone else's script on your main thread. It's still going to fight the problem. So that's where it kind of came down to is like, all right, quick-solving half the problem. We still have this other problem. What are the possible ways that we could speed this up? And that's where you kind of listed all the requirements. Like, well, we can't change a code. It's on someone else's server. So we can modify that. We can't tell people to not include it because again, back to the business decisions, you need this data. down to, well, WebWorker, WebWorker is the perfect answer. Why don't we use that? And then it's like, well, this is why we don't can't use it. It's because it needs document that title synchronously. And so that's where it, it just kind of kept going down this path of just like, well, why can't we do this? Why can't we do this? Can we do this? And so eventually get to like, okay, the real problem of all this is synchronous access to the DOM from WebWorker. How do we solve that? And so the two ways I could think of were, um, atomics and, uh, synchronous XHR.
 
Charles_Wood:
So what are atomics?
 
Adam_Bradley:
So Atomics is fairly new to JavaScript. And I'm not a Java developer, Python developer, so I can't speak too smart about Atomics. So maybe someone else here can. But it's fairly new to the JavaScript world where you're able to basically lock a thread, such as the Web Worker, and then communicate with the main thread and then unlock it. And so we actually do employ this. There is a build, or there is a, it's already working today actually, is using Atomics to communicate. And so, and it's actually 10 times faster, it's a smaller build, nothing but great things to be said about Atomics. And I also think it's the correct way, like what you were saying earlier, Dan, of just like, that's how you would program something with multiple threads. That said, so how come we don't use it, how come it's not the default? It actually is the default, I take that back. It's just that no one is able to use it for the most part because the reality is you need to enable some headers the response headers of the document to enable atomics. And I haven't documented what those headers were, I forget what they are now. But these headers essentially say like, hey, you're only allowed to run certain scripts, images, everything on the main, or you're only allowed to run them from these domains. Anything else from a different domain is not gonna work. And so on your private blog, on your own, you know, a tiny website that might be fairly feasible, you know, the Pariton site is a good example of that. much going on for it. It doesn't have CDN images. It just has Google Analytics, which we have hooked up correctly. But the reality is if a traditional website, you know, it's a normal e-commerce site, if you enable Atomics, you're pretty much going to have everything broken. You're going to have all your images broken. You're going to have all your scripts not loading. And that's because of the Spectre, I think, vulnerability that was out a couple of years ago. It kind of all comes back to
 
Charles_Wood:
Mm-hmm.
 
Adam_Bradley:
that. Dan, do you know more about the Spectre vulnerability at all?
 
Dan_Shappir:
Yeah, so Spectre kind of killed the shared array buffer. The whole concept of atomics
 
Adam_Bradley:
Yeah.
 
Dan_Shappir:
is that you have shared memory that multiple threads can access simultaneously. One of the key limitations when you compare web workers in JavaScript to the threads that you have in Java or in C++ or environments like those all the threads run in the same memory space. So they have direct access to the same objects, the same arrays with the same structures and whatnot. In JavaScript with workers, each worker has its own memory space. You can send stuff from one worker to the other asynchronously via post mechanism, but you can't have like two workers or the main thread in a worker that say the same array simultaneously. And there was an attempt to enable that. So there was, so they introduced as part of the standard this thing called shared array buffer, I think it's called.
 
Adam_Bradley:
Yep.
 
Dan_Shappir:
Yeah, that's the
 
Adam_Bradley:
Yep.
 
Dan_Shappir:
name where you can basically create this kind of an array, send it to that worker. block of memory can be accessed simultaneously from both from let's say two workers or the main thread and a worker and it enables much more Efficient exchange of information between the two when you need that sort of a thing The but like you said it and when you have that sort of thing then you need to synchronize access to it So you you know you want to be careful of let's say not having two workers right to the same place in the array simultaneously and you create all sorts of race conditions and stuff like that. So they created atomics as a means to synchronize access to that shared array. And again, those would be really familiar to anybody coming from a threaded programming language like Java. But like you said, it turned out that there is a problem that Spectre basically enabled Again, I'm trying to remember the exact details.
 
Adam_Bradley:
timing attacks.
 
Dan_Shappir:
Yeah, timing attacks basically would be able to sniff out. I probably need to do a quick check to be reminded again. But it basically leveraged shared arrays to overcome browser security models. So the quick solution that they had was to basically rip out this entire functionality out of the browsers. So effectively, they added APIs into the browsers, but quickly retracted everything before anybody could really get familiar with them because of these security vulnerabilities. And now they're trying to kind of introduce them back in a sort of a safe way. I'll do a quick check about exactly what Spectre actually did exactly. But you can keep on going. So basically, you're saying that if you to atomics, you use atomics, but generally you don't, so you don't use atomics.
 
Adam_Bradley:
Yeah, so the default really is, there's a global variable on window. I think it's a cross isolated origin or something like that. When that's true, it means that Atomics will work. And to make that true is that the document has to have the response headers of saying that I should find what the titles are, but they basically don't allow any other scripts to run except the ones that are on this domain, which is a good thing, right? to like this security vulnerability. And so, so for my own blog and for the Parton Doc site, that works just fine. But if you're amazon.com, you're not going to enable that because all of your scripts and images will stop working. Um, and so that's the problem right now. So again, like I kind of think that Atomics was the Atomics and Strata array buffer were the correct answer. And I wish that was the, the, the one that worked for everybody. Um, but the reality is like, it then goes to the fallback of the service worker now when you use Part-Time.
 
Charles_Wood:
So, my next question is, because it sounds like, yeah, you just, what, NPM install party town or
 
Adam_Bradley:
Yep.
 
Charles_Wood:
can you load it from a CDN?
 
Adam_Bradley:
No, you can't. That's one of
 
Charles_Wood:
Okay.
 
Adam_Bradley:
the, because it's a service worker, a service worker has to run on your domain.
 
Charles_Wood:
Okay.
 
Adam_Bradley:
So that was, and that's all documented on the site, but there are integrations that make it easier to run in like an Astro and Beautify and React, basically all of them. Most of the frameworks
 
Charles_Wood:
Sorry.
 
Adam_Bradley:
have some sort of integration, but those are all just wrapper components to just add the copy of those files to the correct directory and to add the attribute that you want to.
 
Dan_Shappir:
A question
 
Charles_Wood:
Right,
 
Dan_Shappir:
about
 
Charles_Wood:
and then
 
Dan_Shappir:
that.
 
Charles_Wood:
the... Oh, go ahead.
 
Dan_Shappir:
So you said, so given, I think we've discussed it in the past, but it's actually also worthwhile bringing it up here in the podcast. You know, a lot of websites these days have their own service worker. And now you're saying that you need to have the party town running within that website in the primary domain needs to have a service worker. So don't, you know, doesn't that create a conflict between the service workers? service workers or something like
 
Adam_Bradley:
Yeah,
 
Dan_Shappir:
that.
 
Adam_Bradley:
great question. And so that was another requirement. It's like, we can't take over the user's service worker, or I guess the websites. And so that's why all of the library files just see that they're under tilde slash part time, which if you have a directory called tilde slash part time, I apologize that we're taking over that directory, but that directory basically is like, anything, any requests that happens inside of this scoped directory are the ones that this service worker will handle. Everything else has nothing to do with. continues to allow your traditional service workers all your requests, they are completely oblivious that there is such a thing as a Pyrtown service worker. But if you have an iframe inside of the, that's being executed from within taild slash Pyrtown AMX requests, that's the one that would get intercepted. And so that's where the service worker scripts are being intercepted from that request.
 
Dan_Shappir:
Speaking about iframes, if I have banner ads on the website, which usually are iframes, that use usually iframes to embed the ad, is it able to mitigate that as well or what happens in that context?
 
Adam_Bradley:
Um, yes, I'm trying to remember how that works. Actually, iframes was about 90% of the problem when it comes to the runtime. Like trying to get those to work because each one has, it has its very own window. Each one has to communicate with each other with a post message and stuff. And so getting that to all work was quite a challenge. But in general, yes, they're able to, you can add scripts like, like I think the Twitter embed was one of the hardest ones. It's got for a tweet, it's how many characters, right? of code and I think it's like four or five different iframes that are added for an embedded tweet. Don't believe me, look at it. It's crazy that that's what's required to embed a Hover Mini character tweet. But nonetheless, that's how it works. And so, Parton is able to continue to execute those inside of a WebWorker doing that.
 
Dan_Shappir:
By the way, that's something that I have to bring up. I mean, with all due respect to Party Town, at the end of the day, if all you want to do is embed the text of a specific tweet, just
 
Adam_Bradley:
Yes.
 
Dan_Shappir:
copy the tweet.
 
Adam_Bradley:
Yes, I agree. And I think there's
 
Charles_Wood:
Yeah.
 
Adam_Bradley:
plenty of projects out there that do allow you to just, it just turns it into the HTML and CSS. I've seen a couple, you know, like webpack plugins and stuff that are able to just convert or even markdown plugins, convert it into a normal HTML and CSS, which is such a better idea than tracking all the other stuff.
 
Dan_Shappir:
Another terrible
 
Charles_Wood:
Yep.
 
Dan_Shappir:
example, by the way, is YouTube, embedded YouTube videos.
 
Adam_Bradley:
Yeah.
 
Dan_Shappir:
They're like, it's a half a megabyte compressed JavaScript that gets downloaded, whether or not you actually press the play on the video. I know that Paul Irish from Google actually created this kind of a proxy for the YouTube video player that only downloads it when you actually start interacting with it, something like that. just because of that of that issue which seems
 
Adam_Bradley:
Yeah.
 
Dan_Shappir:
kind of funny since you know youtube belongs to google you might have thought that maybe they would have sold it themselves but you know they didn't so paul did
 
Adam_Bradley:
Yeah, a lot of those, I mean, because I've gotten a lot of the bugs that I come across, it comes down to me like de-minifying code, you know, using prettier on the source code and kind of stepping through like, what the heck is this stuff doing? And it's amazing the stuff that I've seen inside of these scripts. And the biggest violator that I've seen quite often is that they'll have a set interval somewhere, you know, every a hundred milliseconds do a scan of every single DOM element and read what the text is and keep doing that over and over again. no way for us to ever know that that was happening. You know, there's no way to know that this is what all your scripts are doing anyways. And so that's also kind of what Parton, I don't think I have it documented enough on the site, but like you're able to kind of see every interaction that's happening. You're able to say like any, you know, let's say you want to block anyone from reading document.cookie, because you're going through your proxy, because they are sitting inside of the web worker, they're not inside of the main thread, and they have to go through your code. That's where like, hey, if you're accessing document cookie, let's just respond with an empty string. You know, according to their codes, like, oh, cool. It's just an empty string. But you're able to kind of like sandbox that. And the same thing is like, if you want to monitor what set interval is doing,
 
Dan_Shappir:
you
 
Adam_Bradley:
or you want to see like all of the access that's happening, you can console log them, you can prevent them and do anything that you want. And it is pretty amazing. It's no wonder why the more scripts you add, the slower your site becomes when you see kind of what they're doing internally. Like there's a lot going on that half megabyte
 
Dan_Shappir:
So
 
Adam_Bradley:
of
 
Dan_Shappir:
you can,
 
Adam_Bradley:
script.
 
Dan_Shappir:
so you could, for example, or maybe you actually do slow down that interval, even though they're doing it after every 100 milliseconds, you slow it down to every 10 seconds or something
 
Adam_Bradley:
You
 
Dan_Shappir:
like
 
Adam_Bradley:
could.
 
Dan_Shappir:
that.
 
Adam_Bradley:
Yeah, you absolutely could. I mean, that's one thing that it does do as an optimization is that setters are actually all batched. So let's say that you do get attribute, whatever, attribute. And that's going to be synchronous. Like, we need to get that information. So that has to go there. It comes back. And then we've got 100 lines of setting style code. We've got set the red color, set background, whatever. They're all sets, set attribute. blocking because it hasn't actually, you know, even if it's the main thread, it's not really kind of blocking yet because nothing's been applied. And so it can do all that. And then the moment that it hits a getter is when it just says, Oh, I have to be blocking now. So now let's send all those 100 setters that we, that we applied and the getter on one batch. And so that actually helped out the performance quite a bit of, you know, batching all the setters together.
 
Dan_Shappir:
unless they thrash the DOM, which is a problem in the main
 
Adam_Bradley:
Yeah.
 
Dan_Shappir:
thread as well. By the way, for those who don't know what thrashing the DOM means, it means that you're interleaving getters and setters, which forces the browser to apply every setter immediately in order to return the correct value for the upcoming getter. And you really
 
Adam_Bradley:
And
 
Dan_Shappir:
want
 
Adam_Bradley:
that's,
 
Dan_Shappir:
to avoid doing that.
 
Adam_Bradley:
yeah, and they absolutely do all sorts of thrashing there. And that's also where I say like, even if one's doing thrashing that's bad, if they're all doing it, that's why performance is horrible. It's because they're all kind of doing their own thing. They don't care about what the other ones are doing. They don't know what the other ones are doing. And so that is one optimization for good or bad. I think for good, what Part-Time does is that those interactions are within a request animation frame. So it does kind of throttle them. It does put them into a nice flow. So it doesn't do the layout thrashing. And so again, running that script in a web worker is gonna be a little bit slower, but also is that such a bad thing? We are slowing down these scripts from thrashing it down. We are slowing them down from destroying your performance. So,
 
Dan_Shappir:
And
 
Adam_Bradley:
yeah.
 
Dan_Shappir:
what do you do with event handlers? I know that obviously third-party scripts register to various event handlers. You gave examples of button clicks, but it could also be various window events. So when they register, you kind of create your own stub on the main thread and then post that event information back to the worker? What do you actually do?
 
Adam_Bradley:
Yep, so let's say we had a onClick on window. That got registered inside of a WebWorker. So it's a fake window. There's no such thing as an onClick there. So what we really do is just create this ID of like, hey, ID, you know, function one was called. And then it goes over to the main thread and creates the real onClick handler. And it says like, but all it does is say like, function one was called by the user, right? And so then it just kind of sends it back to the to the worker thread. It's like function one was called And then the worker's like, oh yeah, I know what code that's supposed to execute. And so that's kind of how it does, is it just kind of has an ID map of the two worlds.
 
Dan_Shappir:
But you do need to serialize the entire event object in that case.
 
Adam_Bradley:
Yes, yes.
 
Dan_Shappir:
OK.
 
Adam_Bradley:
And so like even a DOM element is just kind of serialized into IDs where we're able to look up the ID again. So like we're not trying, we're not, we don't serialize like the text content and HTML, like none of that stuff gets passed over. As I just said that like the onclick of ID or button five was clicked, you know? And so it just sends that information back and forth. And so like when the main thread is like, oh, or when the web worker is just like, well, button. That's when it's another request back to it.
 
Dan_Shappir:
So I have a suggestion for you. Maybe you've already implemented it. If the third party scripts ask to register to the unload event, register it instead to the page hide event, or something like that, or visibility hidden. Because unload gets in the way of the bfcache, which is an entire discussion in and of its own. But by switching it over, you probably and you let the website use the BFcache for faster reloading. So that's something
 
Adam_Bradley:
Hmph.
 
Dan_Shappir:
you should look at as well. Suggestion.
 
Adam_Bradley:
BF Cash, what's that?
 
Dan_Shappir:
BFcache is a relatively new feature in Chrome. Turns out it's been a while in Safari. It's just called BFcache from back forward cache. It means that when you navigate away from a website, the browser actually, if it can, keeps of the memory of that website. And then if you come back, instead of reloading the website, it just takes that memory snapshot and resumes from there. So it is if you
 
Adam_Bradley:
Thanks for watching!
 
Dan_Shappir:
never left the website. So it kind of loads instantly after a back. So let's say you click the link in a website. You went somewhere. And then you decide, OK, I want to go back to where I was. You click the Back button. reloading that original website, you instantly are there. It's as if you never left. And that's enabled in Safari, in Chrome these days. And it's really a speeded up a lot of web navigation. And you kind of get it for free. The users don't even know that it's happening. The
 
Adam_Bradley:
Yeah.
 
Dan_Shappir:
interesting thing, though, is that certain things prevent BFcache from working. things is an unload event handler. So Google actually has
 
Adam_Bradley:
Interesting.
 
Dan_Shappir:
a best practice recommendation of not using the unload event handler. Unfortunately, some third party scripts still do. So even if you don't, the third party scripts may. And they would actually get in the way of the BF cache and prevent you from using BF cache. By the way, there's even in the DevTools, DevTools to check whether your website is or isn't compatible with BFcache. And if it isn't, it will tell you why. And that reason might be because you're using Unload, the Unload Event Handler.
 
Adam_Bradley:
interesting. Yeah, and I wouldn't hold it past any of those scripts. So they pretty much, you know, they have to code to the lowest common denominator. So they always, you know,
 
Charles_Wood:
Mm-hmm.
 
Adam_Bradley:
code to like IE8, you know.
 
Dan_Shappir:
Yeah, so I know for a fact that the Facebook Pixel, FB Event or whatever it's called was using it. I think Facebook might have actually fixed that, but if they were using it, I'm sure others are using it as well.
 
Charles_Wood:
Yep.
 
Adam_Bradley:
Yeah.
 
Charles_Wood:
Now we're kind of getting toward the end of our scheduled time. And I wanted to ask, is anybody using this to speed up their sites? Right. Is this out in the wild somewhere where somebody's
 
Dan_Shappir:
We are
 
Charles_Wood:
knocking
 
Dan_Shappir:
looking
 
Charles_Wood:
it
 
Dan_Shappir:
at
 
Charles_Wood:
out of the
 
Dan_Shappir:
it.
 
Charles_Wood:
park?
 
Dan_Shappir:
Next insurance is in
 
Adam_Bradley:
It's-
 
Dan_Shappir:
the process of integrating it.
 
Adam_Bradley:
It's certainly interesting because if you look at the NPM downloads, it does very, very well. I think it's in the hundreds of thousands weekly. But it's hard to get websites to say that they're using it. And I guess that makes sense. Everyone has their private data, private repos. This is for business decisions. It's not really the usage of it. It really isn't an open source thing. You know, using it as open source, but telling people that you're using it isn't. data from a lot of website users out there to say like, yes, we've enabled it. And yes, our conversion rates went up or no, it made no difference at all. So that's one thing I'd love to ask the community is like getting help there is. Is yeah, it looks great in Lighthouse scores. It shows that it's a faster Lighthouse says everything's great. But I'd love to get some real data of saying like our conversion went up 5%, you know, like be since we enabled it, you know, something went a lot faster. Um, that's the hard part to get it. Like, I guess other people to, uh, come forward with.
 
Dan_Shappir:
So I have another
 
Charles_Wood:
Okay.
 
Dan_Shappir:
suggestion for you in this context. There is this open source project called the Webalizer,
 
Adam_Bradley:
Yeah.
 
Dan_Shappir:
which identifies which technologies are used in a web page. So you can go into that. It's an open source project and make sure that Webalizer identifies Party Town as a technology being
 
Adam_Bradley:
Yeah.
 
Dan_Shappir:
used in a page. The benefit of that is that the HTTP archive to analyze and identify which technologies are being used in webpages that are in its database. So once you've done that, you will be able to actually run queries on the HTTP archive to see which websites are actually using Party Town
 
Adam_Bradley:
Yeah,
 
Dan_Shappir:
and
 
Adam_Bradley:
that's
 
Dan_Shappir:
see
 
Adam_Bradley:
an amazing
 
Dan_Shappir:
their performance
 
Adam_Bradley:
idea.
 
Dan_Shappir:
relative to websites in general. Now, obviously, and maybe even look at their history, over time.
 
Adam_Bradley:
Yeah, no, that's an amazing idea. And that's, that's really, you know, people ask me again, like how, how much faster will my site get? Like, I don't have that data. I know I can tell you that Lighthouse will go faster, but that's also kind of why we label it as beta. It's like we, we're, we don't have the data that proves this makes a massive, massive, massive difference.
 
Dan_Shappir:
Yeah, you'll
 
Adam_Bradley:
So.
 
Dan_Shappir:
be able to actually segment the Google Cracks data based on whether or not Party Town is using the site or not. So I think that would be an interesting type of analysis to
 
Adam_Bradley:
Yeah.
 
Dan_Shappir:
run. You should probably contact Rick Viscomey from Google about that. I think he'll be happy to help you with that.
 
Adam_Bradley:
Yeah, that'd be awesome. Yeah.
 
Charles_Wood:
One other way of asking this is, I guess, what kinds of changes have you seen in Lighthouse scores? Because I'm assuming you've tested this in your own stuff.
 
Adam_Bradley:
Yeah. Yeah. I think on a site that has quite a few third-party scripts, you see 40, 50 is pretty common improvement
 
Charles_Wood:
Oh wow.
 
Adam_Bradley:
of Lighthouse score. But that's also, it's hard to say, well, it depends because like, do you
 
Charles_Wood:
Yeah.
 
Adam_Bradley:
have 30 scripts or do you have one script? And so when they have one script, it's like, oh, I made a one point difference. Big deal.
 
Charles_Wood:
Facebook Pixel counts as 30 scripts.
 
Adam_Bradley:
Yeah, I mean, yeah, and so, and then also, what is that script doing? I'm only
 
Charles_Wood:
Right.
 
Adam_Bradley:
adding one three-part script, but it could be a two megabyte, you know, full story or something.
 
Charles_Wood:
Yep. Cool. Well, let's go ahead and get to pics. Did I cut someone off when I asked my question?
 
Dan_Shappir:
No, all good.
 
Charles_Wood:
Okay. All right. Let's, let's go ahead and do picks. Cause that's kind of where we're at as far as the time goes. Um, before we do that, Adam, if people want to, uh, check in with you, see what you're working on, um, you know, learn more about builder, about, uh, party town, where, where do they go?
 
Adam_Bradley:
Yeah, probably Twitter. Adam D. Bradley on Twitter is where I like to hang out. Usually somewhat quiet, but very responsive to DMs and any direct messages. I'm on there quite a bit. So, so yeah, feel free to contact me there. And then also on both the GitHub for part of town and quick. And I guess in discord for builder IO is where I'm actively chatting to.
 
Dan_Shappir:
I also like to mention that we mentioned Builder.io and Quik several times in this podcast. We've actually had both Steve and Mishko from Builder to talk about Builder.io and to talk about Quik. And in fact, the discussion about Quik was so great that we're actually going to have Mishko again to talk about even more about Quik. So people can
 
Adam_Bradley:
Okay.
 
Dan_Shappir:
check our back episodes to find that excellent content.
 
Charles_Wood:
Mm-hmm. All right, well, let's do our picks. Steve, do you want to start us off with picks?
 
Dan_Shappir:
Chuck, I think that I asked to go
 
Charles_Wood:
Oh
 
Dan_Shappir:
first.
 
Charles_Wood:
yeah, you did.
 
Dan_Shappir:
Yes.
 
Charles_Wood:
Dan, do you want to start us off with picks?
 
Dan_Shappir:
So my first pick will actually be the reason why I'm a bit pressed for time, is that right now the W3C TPAC conference or virtual conference is ongoing. This is, or unconference, this is where the various working groups within the W3C, the know how the web platform is evolving, adding new APIs, addressing various issues with existing APIs. And in general, we're not talking about specific frameworks. This is not about React or Vue or Angular. This is about the browser itself, the various protocols that underlie the browser, and so forth. I'm a participant in the Web Performance Working Group. It's really interesting discussions. I think that really anybody can listen into the conversations So just look for w3c t-pac. That's TP AC and And that's it. So it's ongoing right now and I'm heading right back there after we're done So that would be my first pick my second pick is as usual the ongoing war in Ukraine Even though it seems like the Ukrainians are making headway against the Russians that this is going to shorten the war, unfortunately. And it does mean that the pain and suffering is still ongoing. So as usual, if there's anything you can do to help the Ukrainian people in any way whatsoever, please, please, please do. And those would be my picks for today. And bye everybody. And thank you Adam for coming on our show and telling us about Party Town. Bye everybody.
 
Adam_Bradley:
Yep. See ya.
 
Charles_Wood:
All right, Steve, what are your picks?
 
Steve:
One quick clarification from Dan stuff. That was T-pack and not two pack for you rap fans. But anyway, moving on to the dad jokes of the week. Let's see, an aunt question. How do you tell a male aunt apart from a female aunt? They're all female. Otherwise they'd be called uncle. Thank you. So what do you call it when you stab a milkshake with a straw? Shakespeare. Get it? to shake and you're spearing it. Anyway, sorry, I was ruined when I described them. And then finally, those of you Office Space fans might really appreciate this one. I was confused when my printer started playing music until I realized that the paper was jamming. I was confused when my printer started playing music until I realized that the paper was jamming. I was confused when my printer started playing music until I realized that the paper was jamming. I was confused when my printer started playing music until I realized that the paper was jamming. PC load letter for those of you who don't remember. Anyway, those are my picks.
 
Charles_Wood:
All right.
 
Steve:
Chuck's going over here. Oh my God, I'm so glad that's over.
 
Charles_Wood:
Hahaha
 
Adam_Bradley:
Thanks for watching!
 
Steve:
Meanwhile, Adam is laughing just so that you can't
 
Adam_Bradley:
It's
 
Steve:
see.
 
Adam_Bradley:
good
 
Steve:
For
 
Adam_Bradley:
stuff,
 
Steve:
those
 
Adam_Bradley:
no.
 
Steve:
of you who can't see.
 
Adam_Bradley:
I'm a huge fan of dad jokes.
 
Charles_Wood:
All
 
Adam_Bradley:
I...
 
Charles_Wood:
right, so I'm gonna throw out a few picks here. I usually pick a board game and this week will be no exception, but let me... Let me get the info together real quick. So I can't remember the name of the game and I was gonna look it up beforehand and I didn't. So we'll just edit this, but. Irish Gauge. All right, so I'm gonna pick a game called Irish Gauge. And if you've played, it's a train game. And so I played it with a bunch of my friends and it's kind of a mix between like Ticket to Ride and Settlers of Catan. So you're... and monopoly. Anyway, so what you wind up doing is you play the game and you're buying stock in railroads and then you're building the railroad. So your turn, you can either auction off the stock. You can put down up to three points worth, I guess, of rail line. or you can call for dividends. And if you call for dividends, then the railroads all pay out. So you generally want to call for dividends when it's going to be of highest advantage to you and not your opponents, right? Because when you call for dividends, everybody who has stock in a railroad gets paid. So, you know, and so there's a little bit of strategy bid on or pay for a stock. There's some strategy as far as how you put down the rails because if you're the first one in the space, it costs you less. And in some spaces, you can't double up and you collect dividends according to the type and size of the city that your train runs through. And so anyway, it sounds more complicated than it is the instructions are all on one sheet actually, front and back. So that's all it takes. You know, I've played some other games where they have like a manual on how to play it basically. And so this one's fairly simple that way. It's just a matter of, you know, figuring out what order and when and, you know, how that works. It has a weight of 2.36 on BoardGameGeek, right? So, you know, it's definitely within the realm of kind of the casual gamer who just wants to play games with, you know, with a family. It's simple enough to where I think most of my teenagers could play it. I have a 13 year old, I think she'd be fine. I think my 11 year old could play it. My six year old, no. But anyway, there are two other games that are kind of follow-ons to this game. I haven't played them yet. And they get a little bit more complicated. Anyway, this place, three to five people. And yeah, it was really fun. This is definitely a game I wanna go buy.
 
Adam_Bradley:
What
 
Charles_Wood:
So
 
Adam_Bradley:
was the name of it?
 
Charles_Wood:
it's called Irish Gage. I'll put a
 
Adam_Bradley:
There's
 
Charles_Wood:
link
 
Adam_Bradley:
Kate.
 
Charles_Wood:
to Board Game Geek in the chat. But anyway, I think it took us about an hour to play it. So yeah, anyway,
 
Adam_Bradley:
Cool.
 
Charles_Wood:
so yeah, so those are my picks. And oh, well, I was gonna pick a few other things. So shameless self-promotion, I am putting together a book club. So if you want to do developer books, I've been podcasting in programming space for like 14 years. And so I tend to know a lot of the people who have authored a lot of the books that you've probably wanted to read. And so I don't know if we're going to do like clean coders and get Bob Martin to show up or, you know, do you want to Kent Beck's books or, you know, but I've met or know, you know, Michael Feathers or Martin Fowler, you know. So we'll probably line up some of these books and see what we can do. I think it'd be fun to do Gang of Four with the Gang of Four. I don't know how likely that is. shows too over the last several years. So anyway, I'm just going to put it out there that that's probably what we're going to do. Depending on the length of the book and the amount of content, you know, how easy we can get through it, we will either go one month or two months on the books. And I'm setting up a discourse forum so we can discuss it and then we'll have weekly calls. And so you can jump on the call or you can just watch That way I can invite four, five, six, eight, however many people into the discussion at a time, I'll facilitate it, share my insights if I feel like it, and then kind of work through it, but I'm hoping that I can get the authors on too. And so we can ask them questions or talk through some of the ideas or maybe spend 10 minutes, 20 minutes listening to them and then spend the rest of the time talking about what we got out of it. Anyway, I'm pretty excited about it. I'm looking at charging like 17 bucks a month to be part of it and just make that go. I do have another thing that I'm putting together and this is one that I just keep getting asked. Generally it's from people who want to kind of figure out what the next step is in their career. They're not sure what to learn. They're not sure how to stay current on things. with their skills at work because work adopted view two and now view three is out. Or they're on an old version of React and haven't updated. Or their back end is a technology that isn't as widely used anymore. And so I'm putting together basically a how to stay current course that walks you through how to know what to keep up on. where to get resources, how to approach learning from videos, podcasts, blog posts, books, you name it, courses. You have the tools to go out and upgrade your tech skills as they come along. Then if something comes out like, say, Party Town, then if it's on your radar and it's something that you should be picking up as the next phase in your career, can make a difference where you're working right now, then you'd see it pop up, you'd go and check it out, you'd evaluate, yes, this is something I need to learn, and then you'd go get the resources together to learn it. And so I'm putting that together as well. It's gonna be the first course on top-end devs, top-end devs.com slash courses. So you can go check both of those out. And then I postponed JavaScript remote conference, it's gonna be in November now instead of October. so that I can get people on a mailing list and stuff like that and make sure that everybody has a solid experience with it. So anyway, those are the other things that I'm going to pick. I just switched things back over to ActiveCampaign. I used it for a while. I didn't realize how many features were in it, but I'm getting coached by a friend of mine who uses it pretty heavily. And I've been pulling all of the information that we have back into that. And I really like it. and a CRM. And so I'm just gonna shout out about that just because it's been an awesome tool. And I'm probably gonna be putting together an email list of people who want to get notified when we're having a conference or a meetup or when we're looking for guests for the shows so that they know, hey, I ought to submit something in order to be a part of this. So anyway, that's what I've got this week. Do you have some pics this week?
 
Adam_Bradley:
Yeah, I was just looking at the MPM downloads of UVU, which is a testing runner. And so I don't think it's really obscure anymore. Like I started using it in the last two years. It's a basic kind of a replacement for Jest, and
 
Charles_Wood:
Mm-hmm.
 
Adam_Bradley:
I'm a huge, huge fan of it. But again, like now that I say that, I think quite a few other people are big fans of it either. So I don't think it's too big of a crazy pick. But no, we've migrated a lot of, are all of quick and part time to use UVU,
 
Charles_Wood:
So nice.
 
Adam_Bradley:
faster than Jest, really enjoy using it. And so basically anything by Luke Edwards, such as like POCA and serve the other node HTTP server, we also use. So awesome, awesome developer. He makes some really lightweight, fast products and so are soft open source projects. So anything he creates, use it. And then I think the other one that we've been using quite a bit is Playwright, just kind of the our replacement for Puppeteer, mainly because it's more tailored to testing. And so we use it widely for all of our tests in both Paratown and inQuik.
 
Steve:
Yeah, with
 
Charles_Wood:
In
 
Steve:
the
 
Charles_Wood:
this
 
Steve:
last
 
Charles_Wood:
neck
 
Steve:
name
 
Charles_Wood:
of the
 
Steve:
like
 
Charles_Wood:
woods.
 
Steve:
Edwards, it's hard to lose.
 
Charles_Wood:
In this neck of the woods, UVU is Utah Valley University. So
 
Adam_Bradley:
Okay.
 
Charles_Wood:
I was like,
 
Adam_Bradley:
Yeah,
 
Charles_Wood:
they have a package?
 
Adam_Bradley:
of course, and it's for testing.
 
Charles_Wood:
Yeah, right, right. Yeah, use the testing center.
 
Adam_Bradley:
Yes.
 
Charles_Wood:
Steve can hit do the rim shot there. Anyway, but yeah.
 
Adam_Bradley:
Thanks for watching!
 
Charles_Wood:
All right, we're gonna go ahead and wrap up, but thanks for coming, this was awesome.
 
Adam_Bradley:
Cool, thanks for having me, this was fun.
 
Charles_Wood:
Yeah, absolutely. I encourage people to go check it out. And until next time, folks, Max out.
 
Steve:
Adios.
 
Adam_Bradley:
See ya.
 
Charles_Wood:
All right.
Album Art
Partytown with Adam Bradley - JSJ 550
0:00
1:16:33
Playback Speed: