DEVWorld 2026

Arvin Abedinlou - Decoding Javascript: Loading Performance

22:56 · 07 May 2026 – 08 May 2026 · YouTube

About this talk

In this talk, the speaker discusses optimizing front-end performance for a platform that connects game advertisers to app publishers. They emphasize the importance of loading speed, noting that slow web pages can significantly increase user abandonment rates. The speaker explores several performance aspects, particularly focusing on loading performance, which includes reducing the amount of JavaScript shipped, improving asset delivery, and implementing effective caching strategies. They share insights from their experience migrating from Webpack to Rollup, highlighting the importance of tree shaking and code splitting to minimize the final bundle size. The talk concludes with practical takeaways for developers to enhance user experience and ensure efficient application performance.

Full transcript

Hello everyone. Um I'm Arvin and I'm currently working as front-end engineer at Adjoe. I love coding with TypeScript and JavaScript and whenever I'm not coding you can find me playing volleyball, football, sometimes ping pong and I love cat memes. We'll see them later. Um to put this talk in context, first I have to give you a quick overview of our business, what we do. Um we connect

game advertisers to app publishers looking to monetize their audience. Uh which will help our users to discover new games and earn rewards with playing them. But how do we do that? Uh we do it through our um uh solution called Playtime. How does Playtime works? Our advertisers show the ads to the users. Users will see the ads and play the games and eventually earn the rewards for

playing it. How does it look like for our advertisers? For our advertisers, we have to give them a tool, a dashboard to first of all be able to create these campaigns and then understand what is happening inside each of the campaign and analyze the data. And on the other hand, the users will see our offer wall which is showing the ads for them. So, till now we

have this product which is very powerful but the problem was it wasn't very fast. So, what do I mean when I say it wasn't very fast? According to Akamai, if you don't know Akamai, they are one of the best out there for providing CDN and cloud computing and according to their research, uh if it takes more than 3 seconds for a web page to load, then uh

the risk of abandonment from the user will increase by 50%. What does abandonment uh rate means here? It means the amount of users who came to a platform to doing a specific actions but had to leave the platform without completing that desired action. So, in our case, for our users, uh imagine you are using a business critical tool, not even a simple web page web page application,

what does the risk is here? It's much more because the tool is very complicated, it has so many different steps, and the risk of abandonment may be even higher. And on the other hand, our offer before showing these ads, the risk is even higher because the patience is close to zero. So, our mission here is to create this process of creating these ads and analyzing them as

seamless as possible. behind this clean interface that I showed you, we are handling terabytes of because these advertisers are managing huge advertising budgets, and they want to see all this stuff that is happening inside each campaign instantly, and they don't want to wait even one moment. what do I mean when I say performance? What does it mean, and why is it important? It's a topic important to

both user experience and business success. And when we talk about web page loading, most of the time we think about network speed. But but as we will see, that's just the beginning. The very first moment the user interacts with your web page, and the first byte that they download will set the stage for everything that follows. And this need for speed isn't just a feeling. It's a

critical business metric. And today, we are going to talk about different aspects of it. I can divide it into three different aspects: loading performance, parsing and compilation, and rendering. But because we have only 30 minutes, I'm only going to focus on the first part, loading performance, but I will also share a little bit insight on other topics as well. So, let's just with one question. Uh can

we buy a speed by throwing more hard drives on the client side? I mean, can we buy the speed how we can do it on the back end also on the front end? Anybody has any idea? Give me a thumbs up if you think we can do it. Okay, I I've seen one, but yeah, the answer is no, actually. And that's the reason why we as a

front-end developers are getting paid because we cannot uh just throw more servers, more hard drives, and expect to increase the performance on on the front-end side as we can do it on the back-end side. I mean, we can do it on but we have to buy a MacBook Pro for for all of our users, which is very far from reality. And uh most of the time we

as developers are developing on a fancy MacBook Pro with a fiber internet, uh but on the other hand, our users are on a budget Android phone with congested network and the CPU that is throttling under the heat, and we expect to have the same experience on their hand. Uh and I think that's the reason we always say the performance is empathy, and we have to make sure

we are we are shipping less amount of JavaScript, which is eventually less amount of work for our users. And then we have to understand this code that we are shipping is not running on our machine, but is running on our users' machine. So, everybody convinced performance performance is very important. I could make that point. Let's see some numbers. Uh here I brought a number from HTTP Archive.

It's showing the amount of uh JavaScript bytes that we were shipping 5 years ago comparing to today, uh which is around 800 uh kilobytes, and it's showing the amount is almost double. So, the amount of JS that we are shipping is increasing, and we have to think about a way to optimize this one. So, when we talk about performance, most of the time we think about uh

network transfer, which is the tip of this iceberg, the bundle size. But, in our own profiling, uh uh bundle size and downloading it for our users was only 20% of the time. The rest 80% was happening for parsing, execute execution, and rendering that code. But, there's one important point, which is if we can optimize the tip of this iceberg, which is the bundle size, the amount of

time that we will uh spend for parsing, execute execution, and rendering, all of them will drastically decrease. So, we had at this point we wanted to start this journey of optimizations in our platform. What do you think? which part of this iceberg we aimed for? I've seen one, tip of the iceberg. Yeah, that's genius. We We aimed for the tip of the iceberg. Uh you might say,

"Oh, no, we didn't go with the normal one." But, there were some uh some reasons actually for us to go with the tip of the iceberg, and the reason was we were looking for some immediate numbers and some good uh results to show our managers, and uh starting with the tip of the iceberg was uh the best choice for us. So, let's get started. Uh for optimizing

the loading performance, uh we can divide it into three different levers. First of all, shipping less amount of code. Second one, delivering a smaller. And last one, running lighter. Let's get started with the first one, shipping less code. The whole story began for us uh one day one of my colleagues created this ticket, investigate tree shaking issue. What does tree shaking uh means here? Uh it's the

process of removing the unused code from your final bundle. But, how did we reach to this point? Um at that point, the first chunk of JavaScript that we were shipping to our users was 3.05 megabytes, not gzipped, but it still it was very, very big number. So, it was the first point for us to understand uh okay, maybe something is not going very well on our platform.

To understand next slide a little bit better, I have to give an overview about how our application look like. We have one mono repo and inside that we have two main applications and for serving the common stuff that is happening in these two applications, we have our common modules for example authentication, UI components, utilities and so much more. How did we start it? There are some tools

that you can use them for analyzing your bundle. Back back in the days we were using webpack so webpack model analyzer was the tool that we used, but if you are using other tools like this roll up or anything else, there are also some tools that you can use it for analyzing your What we will what you will see after analyzing your bundle, normally it's some chunks

of some data visualizations that will look like this. This is only one chunk of it which is as you can see on the top is for re-charts and re-charts is the library that we are using for our data visualizations. But there was one point here. This library that you can see was only created in our common module and in our common components and it was imported into

the main app, but it was not even used, but it was part of the final chunk of JavaScript that we were shipping to our users. So, it was a little bit suspicious that maybe something is going wrong, but at this point we still didn't know what is happening. There was also some other cases for us like some of the components that we have written by ourselves. In

this case this component contact form and where it was written, it was written in our common components still was not used only imported as a module inside the main application and this was also part of the final bundle that we were So, we did some more investigation and we understood that the thing that was going wrong was after we did the migration from webpack to Rollup, there

was one attribute called module side effects and by default it's set to true. Uh what does it do when it's set to true? It uh assumes that all the modules that you are importing to your application can have some side effects and because of that side effects, the tree shaking might not work anymore. So all the code that you are importing from all libraries or anything that

you've even written yourself will be will be part of the bundle even if that's not used. So part of the problem was resolved but we still knew knew that there are so much more that we can do. What other things we see? Uh there were so many cases that we were importing some third-party libraries like Sentry and we were importing the whole library. We were not uh

using some specific part of it. So we went a little bit uh deeper inside and we understood, okay, um in most of the cases we don't need the whole package to have the functionalities but uh most probably only some part of it. It's only about uh Sentry here but there are even some bigger third-party libraries that I can assume so many of you are using like Lodash

that maybe you are using couple of functions from it but in some applications uh you're uh importing the whole package. So with fixing all these problems we could save around 18 18% uh in our uh final bundle size which was half a megabyte. Uh but after couple of months that we were shipping so many different features uh and we were not caring about performance that much, this

number again increased to 2.8 megabytes and Gzip this number was around 800 kilobytes. Uh if I want to give a little bit more context to you, the market is standard uh says it should be between 300 to 400 kilobytes. So our case was almost double of that number. So we knew that there is something bigger wrong in the whole structure of the application. And when you look

at our app, you can see on the left side bar we have so many different functionalities that we can serve for our users, but there was one problem inside this app. When the user was visiting our application, no matter which part of this app they wanted to see, we were shipping the whole amount of JavaScript that they need for running the whole application to them, not caring

about which part of it um you are seeing. So, uh there should be a solution for it and we found it, uh which is code splitting. With code splitting, instead of giving the whole amount of JavaScript that you need for running the app, uh you will give the you you will give the key of each of the rooms to the users uh that this amount of code

will be uh downloaded for the users on demand. So, uh they don't need to run even uh they don't even uh even need to download the part of the JS that they are not even going to use. So, everything will be much more efficient for them. And with doing this optimizations, the number that we could save was much bigger. This time we could save around 58% uh

which reached out uh which reached to this number 1.2 MB and gzip was around 400 KB, which was very big win for us. But, that's not the limit. You can even do so many more things with uh code splitting and other techniques. Like one of the example is uh conditionally importing. How does it work? You can put some uh conditional imports based on the user uh preferences

in inside the browser or so many other things that the JS uh won't automatically download for them. Or you can even go further and uh like this example that I brought for you, you can do the import on interaction. If you look at the time that the user starts interacting with our input and you look what will be downloaded for them, uh this uh number that you

can see is not very big. It's only uh, 11 kilobytes. But, even this a small amount of uh, JavaScript won't be downloaded for for the users before they start with the interacting with the components. Number is very small here, but if you imagine you have one huge component that has so much amount of JS. And um, you have this hunch that maybe not all of the users

are using this component, you can uh, set this to be downloaded for the users on demand. And you can save a very good amount of JS doing that. Let's look at our takeaways from this chapter. Uh, be cautious when you are uh, changing your bundler. In our case, we were migrating from webpack uh, to vit, and we only trusted the documentations, and uh, the whole tree shaking

was not working anymore. Slim your dependencies. Most of the time we are using some part of the third-party uh, libraries, but we are still uh, uh, importing the whole package, which is not the best case scenario. And my golden rule, if you can do it later, don't do it now. Be the laziest possible when you are writing your applications. Don't assume all the things that is happening

inside the app should happen instantly. Wait for the user to need it, and then download it for them. With saying that, let's go to the next Delivering a smarter. Um, first of all, I have I have to start with some uh, with some concepts first, and I want to start with bandwidth first. Uh, what does bandwidth means here? Let's imagine this is a normal day of my

life. I'm starting my day with sending some cat memes to my friend, and let all of us imagine this purple part that we can see is the wire connecting two of us together. What does bandwidth means? It is about the amount of cat means that we can stack on top of each other and send all of them at the same time. On the other hand, what is

latency is about the length of this wire that is connecting me and my friend and anything this wire is actually like it means the bandwidth it means the latency is more. So, uh there's also a rule here which is mainly about our case which latency dominates the small files which is JavaScript files in our case or even API request and the reason is the travel time that

needs to happen for downloading this for our users is much more than the bandwidth that actually needs for doing this. How we can resolve this issue? CDNs will come into game and how they resolve this issue. If imagine in our case, I'm I'm standing here in Amsterdam and my friend is in Japan. Without having the CDNs, they have to download the contents that I have from the

server that I uploaded it close to myself, but with CDNs, it will copy the contents that you have in several different locations and every user will download it from the closest server that is around them. So, this one will resolve the issue with length latency, but it can also help with the bandwidth. How it can do it? Every user will download all the contents from the local

X servers. So, as a result, the amount of travel inside the main network will decrease and that will result in less congestion in the main network and that will eventually optimizes also the bandwidth here. So, you remember this small number that we had at the end which was 1.2 megabytes. We still need to ship this amount of JavaScript to our users. When I was saying that we

have to try to minimize this as as much as possible, when you want to ship this amount of JS to your users, you cannot send it as one giant blob. It has It has to be divided into some smaller packets. Each of them can be as big of 16 kilobytes. Uh, and for this example, let's imagine each of them are an envelope. If you want to send

it to our users, how does it work? Uh, first it will start with sending few packets and only if it it gets the thumbs up from the receiver, it will start sending more and more until it finishes. Uh, this process called TCP congestion control. But on the other hand, if it starts sending some of the packets, the road is shaky, some of the packets are lost, then

it doesn't trust the receiver anymore. It will does the handshake one more time, send few packets, again some will be lost, and the process will happen over and over again. That's the reason when you are on an unstable internet connection, it feels much worse than not having internet connection at all. Okay, we talked about the first two chapters, let's go to the last one, And the last

line of our defense is caching. And there are so many different things that we can do for caching to optimize our bundle sizes here. first of all, we can start with caching the API request. We have to make sure all the APIs request that are being triggered inside the applications are being cached for our users. There are so many different libraries that you can use like React

React Query or so many others that does the same thing. But what we have to make sure is that nothing will be repeated and re-downloaded for our users. And next one is the HTTP caching headers. There are also some other options like e-tags that you can use to improve it for your users. And the last one, which is the most important one, is the service worker. Uh

if you're not familiar with service worker, it's a feature from the browser that lets you do the programmable cache. And with doing that, uh you can do so many different things. Like one of them is a pre-fetching all the assets that that the user needs or even downloaded downloading the whole amount of JavaScript that the user needs for running the application. And then you your application can

even run on offline mode. So, it's not optimization. It's resilient for your apps. And after doing all of this, we shouldn't stop because the uh market is uh shifting in so many different ways and like bundler are they are changing every day. You have to make sure that you are analyzing what is happening inside uh your application, how your bundler is working, and understanding if you can

benefit from some of these new tools that are being introduced every day. Or depending on what you want, you can also take a look at some libraries like Next.js or uh Remix that they do the uh serving the HTML files directly progressively so that can also uh help you with optimizing the uh time uh time for first byte that the that the user is downloading. Or even

with uh using the newer version of HTTP, you won't going to have the exact uh control on this. It depends on where you are host uh where you are hosting your files. For example, in our case, we are hosting on AWS and uh most of the requests are being triggered as HTTP/2. And if I want to give you uh an example what was like one of the

main differences from HTTP/1 to HTTP/2, with HTTP/1, uh when the user was downloading the JavaScript, uh when the first one uh was finished was the only time that uh they could start downloading the next file. But with HTTP/2, all the JavaScript files can be downloaded concurrently without even waiting for the first one to be finished. Uh before I uh show you the results, I want to uh

uh, emphasize on this one that uh, all the optimizations that we did for our platform wasn't only on the front end. We also did so many optimizations on the back end part on infrastructure, but I mainly focused on the front end part of it. And as a result of it, we could uh, reach from this loading bar to a dashboard which was super super fast. All the

queries, all the components, everything was being uh, downloaded and rendered instantly for our users. And uh, one of the also biggest wins that we uh, had is actually one of the things that also helped us to have this big win was uh, migrating our database from a very old one to Apache Druid, which was really helpful. But it was like uh, all these optimizations that uh, together

they could uh, give us these results. And the final takeaways. Analyze your bundle. Make sure you are choosing the right tools for analyzing what is happening inside your bundle and understand which libraries are contributing to your final chunk of JavaScript. Ship less amount of code. There are so many different techniques you can use. Uh, one of them is a code splitting or understanding which libraries uh, you're

importing and how you're importing them. Third one, deliver smarter. Uh, make sure you know where are where your uh, users are located and deliver this code as efficient as possible to them. Cache aggressively. Uh, whenever uh, you're seeing one scenario that you can imagine this can be cached for our users and they don't have to download this again, make sure you cache it. first byte is the

first impression. Make it count. Thank you. >> [applause]

From event

DEVWorld 2026

07 May 2026 – 08 May 2026

All event videos
Back to Watch