TCP Overhead

In case you are not aware, I write software for a company called BoomTown. It’s a not-so-startup in Charleston, SC. We offer a CRM for real-estate agents and manage their front-end websites. I’m on the front-end/consumer facing side of the house, and if you were to put all of our domains into one domain then, we’d be one of the most visited sites on the internet. If you’ve ever searched for a house in the USA or Canada, you’ve probably visited one of our sites before.

We handle a ton of traffic… we use Docker daily. In fact, Docker gets our new devs up and running in less than 30 minutes which is saying a lot. We use WordPress, React, Backbone, C# and Scala. It’s a ton of fun (I’m mostly massaging WordPress, React and Backbone … but my love language is C#)

In order to package up all our assets for production, we use a tool called WebPack. WebPack does some really neat things under the hood, including a thing called ‘code splitting’ aka, “layers”, “rollups”, or “fragments” if you’re coming from similar tools.

This allows us to defer downloading assets that are unlikely to be used immediately (or at all in the case of a desktop user who doesn’t need an off-canvas menu). However, a few weeks ago, we asked ourselves: “What is the cost to our users by doing this? When should we be doing it, and when should we not?”

I spent most of my day today answering those exact same questions. To get started, I need to get some facts. What does a split point cost, especially under bad network conditions? So, I drummed up a little calculator. Given the original size (without splitting), the size of the same file after splitting, and the size of the split out modules, what is the impact on site performance?

A real life example: An original size of 1,126kb, it takes around 26s to download over a bad connection. That’s a long time… So, what if we split out something that’s not needed right away? Say, an off-canvas menu. That will bring our initial load down to 1,095kb and 26s to download. The size of the chunk that got broken off is 27kb (30kb got cut out of the original size) which takes 800ms +/- 100ms. That seems like a pretty good tradeoff. Webpack starts downloading it as soon as it is able to and we don’t have too much to lose there.

Now, let’s try splitting out something smaller. This time we break off a 14kb chunk, which takes about 600ms +/- 100ms and saves us no time on the main chunk.

What about if we break off something larger? Say 63kb, which takes about 1.5s to download and shaves off about the same from the main chunk.

The interesting thing about this: the smaller the chunk, the more the user has to pay for it. They have to wait the same amount of time to download the main chunk, and then wait more time for the other chunks to download, taking up valuable download threads.

When you actually dig into the content of the chunks, you also realize that there’s a lot of duplication. For example, we have a lot of common React components but aren’t common enough to be in their own chunk.

I think I may have convinced you that chunking up the javascript can be bad, it can also be good, if the chunks are large enough. It turns out that WebPack comes with a few builtin plugins for this sort of thing. The DeDupe and MinChunkSize plugin. We don’t even have to change a single line of code!

As soon as they were appropriately configured, we went from 4 chunks to 2 chunks. Our main chunk dropped in size, and our other chunks were large enough to not hold up download threads.

So, what is the magic number that things make sense to split into different chunks? Your requirements may say something different, but it’s probably in the ballpark of 40-60kb.