Updated: Jul 4
When members of his analytics team began noticing long load times in the Wix Dashboard, originally, Eyal Eizenberg wasn’t quite sure why.
When taking a closer look at the code he realized what was wrong: a progress bar, a minor, largely superficial feature that happened to be weighing down the entire app. Turns out Eyal’s problem is common to all web developers (even those who don’t realize it).
In our new podcast episode, we talked with Eyal and Addy Osmani, Engineering Manager at Google, to learn how developers optimize their code and avoid major headaches.
Hi and welcome to the Wix Engineering podcast, I’m Ran Levi.
Interviewer: I think most people outside the industry to the extent that we think about it at all tend to assume that developers produce all their code from scratch. But how much of every website we visit, every software tool that we use is actually composed of prepackaged software?
Addy: That’s a great question.
You’re listening to Addy Osmani, an engineering manager at Google.
Addy: A lot of the time these days, developers - I’m a developer too, so I’m in this boat - we try to build
something as quickly as we can to meet whatever deadlines our teams, our bosses, our projects are setting us. And sometimes it could be more convenient for us to just grab whatever it is that’s popular or generally functions well off of NPM.
So yeah, you can probably tell why developers like using NPM packages. If only the rest of us could do the same thing! If only you could visit a website to get a free slide deck for that big presentation you have coming up, or a prefabricated and fully-furnished living room for the house you’re building.
Addy: And something that we don’t do quite as much as we probably should is being cautious with just checking, you know, what is the cost of the dependencies that we’re adding to our page?
The cost. Today’s episode of our show is about optimizing web performance, and the real cost of free.
A “bundle” is exactly what it sounds like--all the various components that make up an application, combined together.
Addy: So all of the different views and routes and things that you would need to get content on the screen - that’s a bundle.
A bundle can be a pretty simple thing if, for example, a developer writes their entire application from scratch. Such a developer will know their program inside and out, and will have developed each part of it to fit well with the others.
But as we said, that’s not how most applications are built.
Addy: Your application has got a lot of code you’re writing yourself and then a lot of code that you’re pulling off of the internet, and NPM, and places like that.
Lots of the code on npm was written by talented people and well-reviewed by thousands of other developers who’ve incorporated it into their own software. So it only makes sense to use it, instead of writing something similar entirely from scratch.
The problem is that lots of developers stop here.
It’s only natural--you download a highly-rated npm package, plop it into your application and move on. But even quality npm packages don’t always work how you want them to.
Addy: Picking up a lot of off the shelf components and libraries off of places like NPM, what can end up in our bundles today is not always going to be transparent when it comes to the cost.
Eyal: My name is Eyal Eizenberg. I’m the Head of R&D at Wix Dashboard group.
Recently, Eyal was working on an odd little issue in the Wix Dashboard.
Eyal: We measure and monitor everything at Wix. Every little thing that is done, every performance metric that we can get, we measure. And this specifically was raising a flag, as they would say, that it was longer than expected for something that’s relatively small and simple.
It was a simple progress bar.
Eyal: It’s a progress bar that listens to events that came from the server with the web socket and modals and happy moment pop-ups and so on.
Addy: They wanted to be able to show various steps to help you kind of succeed with your business like SEO and shipping regions and so on.
You know the kind of thing we’re talking about--you complete a task and the progress bar at the top of your screen fills in a little bit further. A simple feature common to all kinds of apps.
Addy: And they discovered that they were getting some complaints after adding this feature from their analytics team that said that the load times for the page have kind of increased in a pretty significant way.
The issue wasn’t as simple as fixing a little progress bar. The issue was with the bundle.
Addy: They took a look at the Chrome DevTools and they discovered that their bundle was surprisingly large. It was 190 kilobytes in size.
Eyal: So I took this specific application and I started analyzing it.
Analyzing bundles to optimize web performance is its own kind of science: a surgical process of deconstructing how different parts of your software are working with each other.
Addy: Bundle analysis allows you to discover large dependencies and ask the questions like “Why are they so large?”. So you can consider whether there are smaller alternatives or more optimal ways that you could be stripping down some of those dependencies from those libraries so that they’re not using quite as much of your bundle when you’re transferring those – that code down to your users.
It also allows you to do things like detect duplicate dependencies. Sometimes we might have multiple views or multiple components and we could be importing a library in multiple times.
[. . .]
And then there are things like just helping us discover if there are similar dependencies that happen to do roughly the same job. And this can happen especially if you’re on a big team or you work at a big company where there are lots of different components, maybe even being maintained by different teams. And one team might have chosen a particular dependency for their use case, you may have picked something different for yours - and unless you have sort of a good dialogue happening between teams, you can easily end up in a place where there are multiple libraries that have similar responsibilities in your bundles.
The actual work of bundle optimization is much more difficult than simply spotting redundancies or duplicate components. In fact, doing it all on your own would be incredibly difficult--modern applications are simply too large and too intertwined. That’s why there are software tools designed specifically to help make sense of big, complicated bundles.
Eyal: So the first thing that I always do when I’m looking at big bundle sizes is run it through the Webpack Analyzer.
Webpack Analyzer might be the simplest, most popular tool out there for doing this kind of work. What it does is it takes all the various dependencies in a program and creates a visualization of how all of them fit together--like a big map of your code.
Eyal: There is a built-in tool for the Webpack Analyzer which shows you in a graphical interface of what’s comprising your bundle, what takes a big part of it and what makes small parts of it.
Picture a word cloud: a bunch of words clumped together, the more common ones larger by proportion. Webpack Analyzer shows you something just like a word cloud - instead the “words” are software components and their size is determined by just how big and taxing they are on performance.
THE LOTTIE PROBLEM
Addy: So they popped open Webpack Bundle Analyzer and they discovered that they were using this one dependency that helped them with animations, it was called lottie-web and added about 60-plus kilobytes to their bundle.
Lottie-web is a simple animation tool developed by AirBnB engineers.
Addy: Lottie is a really awesome library that allows you to render After Effect animations natively.
Eyal: It lets the animators – it lets them export their animation that they make in various design tools and lets us as web developers easily implement this animation basically by just taking this JSON that they exported and throwing it into this Lottie component.
If that description was confusing, don’t worry--for purposes of this story, Lottie could’ve been anything. The reason we’re focusing on it is not because of what it does, but what it represents within the wider Wix Dashboard.
Eyal: I noticed that Lottie, though it was really great – for me as a developer it was a very great experience - I noticed it was taking a lot of kilobytes in the bundle.
Addy: The overall cost of both the library and then this JSON and any other dependencies they needed to get this effect in place were costing them anywhere up to 94 kilobytes, which is quite a large portion of their bundle for what it was doing.
Eyal: And what I did next was try to figure out OK, I know we need this because this is required. But how do I take the impact off of our users so it’s only impacting them when they need it?
IMPROVING VS. EMPHASIS
Let’s pause for a moment here, because what Eyal just said gets to something very important.
Note how he phrased that last thought: he didn’t say he wanted to fix the animation feature, only to “take the impact off our users.” This is a subtle but key distinction.
Sometimes bundle analysis allows you to identify how you can materially improve your software code. You might use Webpack Analyzer to spot a library that needs replacing, or a component that you downloaded from npm but, now, you realize would be better just writing from scratch. Other times, though, bundle analysis is just about figuring out how to reorganize an application to work better for the people who use it.
Interviewer: How much of bundle optimization is about improving code and how much is just about emphasis?
[. . .]
Is bundle optimization more about actually improving the code or is it like an emphasis thing hiding some parts and prioritizing others?
Addy: That’s a fantastic question. One of the optimal ways to deliver experiences to users, I think it’s good to think about doing this in a progressive manner. So serving the code that users need when they need it. If there’s a way for us to serve the minimal code needed to deliver most of the user experience or the main parts of the experience that you’re going to need right away when you land on a web page, that’s great.
And then for anything that is not necessarily critical, so things that require you to interact with other parts of the UI or things that require you to scroll or go to other routes and things like that. Those are typically good candidates for better splitting up your bundle and lazy-loading those resources or those components’ functionality at a more opportune time.
“Lazy-loading” is just like how it sounds: you load less urgent components of your application more slowly than the more critical components. A great example of how bundle analysis can help developers improve user experience without actually having to change the code itself.
Addy: Do we need all of this stuff right away? And what are the things in here that we can consider punting to later on in the user’s journey, or replacing with something more optimal?
In order to determine the ordering of what should be loaded fastest, a developer needs a keen understanding of how people are actually using their software. So before he could address that nagging progress bar, Eyal had to understand exactly how users interacted with it--how it worked with the other features of the Dashboard, and when it would trigger that “happy moment,” filling up upon completion of a task.
Eyal: I mean if I don’t understand that this happy moment is only shown in this specific case when everything is done and you have completed everything, you have permission to see it and so on and so forth, that takes some product understanding that you need to work with your product managers to understand this and then you know, OK, I can cut this out only when I need it.
[. . .]
Eyal: So I approached our product manager and I told him, “This weighs a lot. Do we always need it? Is this something we need the second the person or user sees this progress bar?” and the answer was no.
It appeared that the Lottie component was not necessary for almost the entire time users were interacting with the Dashboard.
Eyal: They only need this once they complete the progress bar. When the progress bar is completed, there is like, I don’t know, 15 steps depending on your application and only when it’s done completely then we show this pop-up that has this Lottie animation in it, that’s like a firework or a metal or something, and only then do we need it.
My response was, “Great!” So this is what we’re going to do. We’re going to do web packs clipping, which means that we’re going to split our main bundle. Let’s say it was 100 kilobytes and let’s say the Lottie part with JSON was 40 kilobytes. Basically when we split our bundle into two parts, one part being the 60 kilobytes of the main application, the second one being the 40 kilobytes of Lottie with JSON
Addy: So what Wix ended up doing was better than Lazy-loading this library, and this idea of the happy moment, that it wasn’t a cost that all of their users have to pay right up front.
Eyal didn’t have to fix the problematic dependency. He merely shifted it, to only activate once it was needed.
Eyal: Only once the user completes the entire progress bar, right before we need to show them this
animation, then we’re going to use Webpack to bring this part of the bundle in and then we’re going to basically execute this code and show this happy moment.
Addy: And this helped them to drop their bundle size down by about 50% down to 96 kilobytes
HOW EARLY 2 OPTIMIZE
Interviewer: How early on in the process should a developer be thinking about optimization?
Eyal: Oh. So that’s a tough question because it’s very complex. Because developers usually don’t work in a vacuum. There are product managers. There are deadlines. There’s an endless amount of variables that determine how much time you have to work on a specific task and when it should be released.
Working on performance is something that takes time. It takes time to save time. And this is something that’s also a little hard to do in the beginning because you are building an application. Usually you are building it kind of like Lego pieces, block by block. It is hard to know exactly what it’s going to look like and what are going to be the pain points when you finish this big Lego puzzle.
[. . .]
I think that developers should be aware and think about performance right from the beginning. But should they optimize right from the beginning? That’s a little hard to say.
You can’t optimize an app before it’s built, but developers would be well-advised to start thinking about web performance early on in the process. That means being more cautious of installing npm packages that might disagree with the rest of your app, and trying to avoid those situations before they get out of hand.
Addy Osmani, who’s preparing a book about the subject, has witnessed some horror stories.
Addy: I would say that the wildest bundle that I’ve seen was probably one I saw in the last year. And this was a case where a very large retailer had a pretty big e-commerce application that many different teams were contributing to - writing components, writing routes and so on. And one of the things they didn’t realize was that different teams were relying on different versions of React. And it got so bad that it got to a point where you would enter the site and then as you navigated through to it and ultimately got to a check out, they would load between five and nine unique versions of React itself.
IMPORTANCE OF BA
Most developers won’t experience a scenario quite as bad as running multiple different versions of React on a single project. But bundle analysis is important even if your software is pretty good. Because the difference between pretty good and great, when it comes to web performance, can mean everything.
Eyal: There are endless amounts of studies and information around the web showing that when web pages load slowly, the users - they simply don’t want to work with this webpage. And if we’re talking about, for example, e-commerce websites, if you go into it and it loads terribly slow, the experience is terrible, you’re going to leave that site and go to the competitor which loads fast and everything goes quickly.
[. . .]