Check out a free preview of the full A Tour of JavaScript & React Patterns course

The "Bundling & Compiling" Lesson is part of the full, A Tour of JavaScript & React Patterns course featured in this preview video. Here's what you'd learn in this lesson:

Lydia provides some background information about performance tools like bundlers, compilers, minifiers, and tree-shaking techniques. These tools can reduce the size of the code base, split the code base into pieces, and remove sections of code that are not being used.

Preview
Close

Transcript from the "Bundling & Compiling" Lesson

[00:00:00]
>> Well, I guess that concludes the section on React patterns. So we still have two sections, but they're kind of different. They're not patterns like we discussed with the design patterns or the React patterns. They're more ways of thinking about, how do we want to render our website, which is here, the rendering patterns?

[00:00:19]
And then also just how do we use the imports, the modules that we saw before with the module pattern? And what are all the steps that our code takes or has to take before a user can actually see it, and how can we optimize for that? So that is going to be the next sections.

[00:00:35]
Yeah, I don't know if there should be a break in between or not, but [LAUGH] otherwise I can just keep on.
>> [INAUDIBLE]
>> Okay, cool. In the case, before we start with performance patterns, let's just talk about everything that we need to do before we can actually ship it to the user.

[00:00:54]
So any clients or JavaScript in our application has to get shipped to the client in one way or another. And in order to do that, we need to make sure that it can do a couple of things. Well, the first thing, of course, is that it has to be executable in a browser environment.

[00:01:06]
Because the fact that it works in our VS Code, doesn't necessarily mean that old browsers support the syntax that we're using. And we also want to make sure that the JavaScript that we're fetching is not too large. We don't wanna have a huge bundle that takes a long time to download, use user bandwidth that eventually cost users a lot of money and stuff like that.

[00:01:26]
So in order to do this, we use bundlers. Now, there are many bundlers out there, but what a bundler does is it bundles our application into one or multiple files, depending on your configuration. And this makes it possible to execute or make our code executable in other environments as well based on your configuration.

[00:01:46]
So essentially, what under bundler does is it has a config file. In this case, I'm using Webpack, but there are many others out there, I will also list them later on. But it has an entry file, and it starts to bundle your code from that entry file. In this example, the entry point is index.js, which imports module three, which imports module two, which imports module one.

[00:02:09]
So it starts to look at index.js, and it's like, okay, I see that you want to use module three from the module three file, cool. I'll make sure to bundle that in the index.js cuz it's going to need it. And then module three in turn imports module two, so it also makes sure that it's in there as well.

[00:02:25]
So we don't have a bundle of JavaScript code that references things that aren't available. So that is the main goal of a bundler, is to make sure that the bundle that we're creating has all the code that is necessary to run certain script, certain page, and stuff like that.

[00:02:44]
Now, like I said, there are a few popular bundlers. In these examples, I will just use Webpack, just because it's right now the most commonly used one. But maybe you've also heard of Parcel, Rollup, which are also great bundlers. Yeah, I'll be using Webpack in the following examples.

[00:02:59]
Then we also have compilers. So a compiler converts JavaScripts or TypeScripts into a version of JavaScript that browsers could run. Now, of course, maybe it depends on your configuration, but in some cases, you know that your users are still on Internet Explorer or something. Now, that browser basically supports almost nothing.

[00:03:21]
So even though we want to use the latest features in JavaScript, we have to make sure that we can use a compiler that turns our code into executable code that can run in Internet Explorer. Cuz obviously, we don't want to write our code and always think about, okay, what am I writing?

[00:03:36]
Can I use that? Is that executable in the browsers that my users use? So we just want to use the latest technologies, we want to use the latest JavaScript features. So, yeah, a compiler is great for that. An example here is using private classes. So for example, I don't know if I should zoom in here or not, but we have a SecretManager.

[00:03:54]
And this is pretty new syntax here. We can actually use private values within classes. Now, obviously, a lot of browsers do not support this yet. So if we were to fetch this file in a browser, and the browser would be like, I don't know what to do with this, I cannot interpret this, I don't know what to do.

[00:04:10]
So a common or a well known transpiler here is, for example, Babel, which then turns this code and based on your configuration, it's like, okay, I can make this code executable still, so you can write it in the latest way. But I will transform it into a way that your browser will also understand, but still resulting in the same end result.

[00:04:31]
Oop, yeah, so a compiler doesn't bundle code, that's what the bundler does. It just transforms it into another version based on a certain configuration. Yeah, I don't know, if you've used TypeScript, that's also a compiler cuz there's TypeScript into a certain version of JavaScripts. But in the following examples, I'll probably be using Babel or TypeScript, I'm not sure, both are great.

[00:04:56]
And then there's also the minifier, because as you can see here, even though the code that we wrote was pretty small and concise, the result of the compiler was pretty big. Cuz we have so much code, it needs to add all these other functionality in order to make it executable in a browser.

[00:05:14]
Now, one minifier is, for example, Terser. And when you're using Webpack, you can also add Terser plugins and stuff like that. So the bundler automatically takes care of also minimizing that code, or minifying, sorry, that code, for example, in production. So we can make sure that the code that we write is super readable.

[00:05:32]
We don't really have to think too much about, do I really want to add that function? This might increase the bundle size for our users. Because the minifier will take care of that, and will make sure that it's super, super small. For example, here function t, I have no idea what that is, but this also refers to these functions that we saw here.

[00:05:50]
It just changes names, stuff like that. So yeah, this makes sure that our bundle size is very small. Now, popular minifiers are Terser or Uglify. So, now in 2022, there are also many developers working on tools that combine all the things that we just talked about. So, for example, SWC, which is a Rust-based compiler, and bundler, and minifier.

[00:06:12]
And there's also ESBuild, which is a Ro-based compiler, bundler, and minifier. So the only issue is that right now, as I'm giving this workshop, they don't support as many features as Webpack does. So sometimes it's still better to use Webpack if you're using certain features that are needed.

[00:06:28]
But it's definitely nice that there are so many developers developing better tools out there, because adding the bundler and the compiler and minifier always takes quite a lot of work. And it's just a pain to set up when you just wanna develop a code and ship your project, and you have to think about all these things.

[00:06:43]
Now, there are also certain practices that we need to think of when we think about performance. Now, one of them is bundle splitting. So what we just saw is that Webpack creates this one big bundle from our entry point. It contains all the code that is necessary in order to run that.

[00:06:59]
But of course, a larger bundle can lead to an increased amount of loading time, processing time, execution time. And yeah, users on low-end devices, especially with slower networks, will get a bad performance, your website will load pretty slowly. Now, in order to avoid larger bundles, we can also create multiple smaller bundles.

[00:07:21]
So instead of fetching everything, this one big bundle at once, we can just kinda split them up into multiple smaller bundles. Then there's also tree shaking. So tree shaking is basically eliminating dead code, cuz in many cases, maybe we're importing something, or we're creating a function. But it's not actually used anywhere, it's just kind of there, but it's not referenced at all.

[00:07:46]
For example, here we have an input, and we have the validateInput, and then we also have the format. But here, you see that we're only importing the validateInput. So this one is never used, never referenced in our application whatsoever. Now, normally, we could just bundle this in that bundle, but this would just add to the bundle size, which is bad.

[00:08:05]
So instead, a bundler usually takes care of automatically also eliminating that code that we're not using, which is called tree shaking. This is a bit tricky to do, so it's not always perfect. But it definitely tries to eliminate as much code that we don't need from the end bundle, I guess, which is shown here.

[00:08:24]
So yeah, it just removes that. There is no reference here to formatInput at all, it's only to validateInput. So these are just some things to keep in mind when we're talking about performance patterns. Any questions so far? Yeah.
>> [LAUGH] Okay, a couple. One about tree shaking? Does it make a difference, I don't know if maybe this isn't really a tree shaking question, but to do destructured imports for React, for example, instead of doing import react in every file you just import the things you need?

[00:08:57]
>> Yeah.
>> Does that help to minimize the tree shaking, or is it like, those things reference other things behind the scenes?
>> So, well, it kind of depends on how the library authors structure the module. It used to be the case that, yeah, whenever you import it, like import react from React would include more code, and for example, import use state from React.

[00:09:17]
But the way it works now is that they've restructured it, so that when you're only using React that use state, it will make sure to not include everything else. But this is also part of your configuration for your bundler. Sometimes you can also just turn it off and be like, just include everything.

[00:09:34]
And in some cases, you have files that, for example, have side effects. For example, when you just import a large file, the bundler cannot always know like, I don't know if you're going to use this. So just make sure that it's not eliminating code that you might actually end up using, it will still include that.

[00:09:51]
So there are just many things that are kind of not insecure, but it's kinda like, it doesn't always know what to do. Your bundler doesn't want to make too many assumptions and maybe break your code. So that's kinda why I said, tree shaking, it is very good right now, it's in a much better state, but it's still not as perfect as it can be, or as many people expect, but we're only getting better.

[00:10:14]
Yeah, so this also really depends on how you structure your own code. So, it's definitely not just developer's fault. It's just sometimes kinda tricky to make sure that you're also optimizing your code to make it as tree shakable as possible. But in a lot of cases, this really only is kind of important for library authors

[00:10:30]
>> And then I did have one question about bundle splitting as well. So, when you're bundling, you're following this chain of all of your imports. When you're bundle splitting, is it undoing that in any sense, or is it something very, very different?
>> No, it's something different, and we're kind of going to talk about this later on as well.

[00:10:49]
>> Okay.
>> But with bundle splitting, we can essentially say these parts of the application are just kind of standalone parts. They don't necessarily rely on each other, although they can, a bundle can require another bundle if they have to. But it doesn't create a bundle and then split it, it just outputs multiple bundles from multiple entries, if that makes sense.

[00:11:10]
So you're not just bundling your entire application into one big bundle. It's just kind of splitting it based on components, for example, on components or maybe on pages, just parts of your application.
>> Is there any difference between bundle splitting and code splitting, or are those interchangeable?
>> I believe they're interchangeable.

[00:11:28]
>> Okay.
>> But I may be wrong, but I believe they're interchangeable, yeah.
>> I have a question.
>> Sure.
>> So when you work in a large organizations, you have a boilerplate code that comes with Webpack, Babel, and everything.
>> Yeah,
>> As a normal day-to-day developer, are these things different than what comes with the boilerplate code, or we need to enable those features?

[00:11:54]
>> I mean, you can, if you see that you're working with a codebase, and it doesn't have all the performance features enabled that maybe Webpack now provides. I don't know if you're using maybe Webpack 4, you can maybe upgrade to Webpack 5 and have more features. It's definitely worth it to see the plugins that are out there, cuz Webpack has plugins and presets or stuff like that, so you can kind of customize your bundling based on that.

[00:12:18]
But working with Webpack is difficult, it is so tricky, especially, like you said, in larger code bases. So I think if you're working on a larger code base, I would say it's definitely worth it to see like, okay, what does the Webpack config currently look like? Can it add more optimizations, like maybe minimizing, preloading?

[00:12:40]
And we'll see that later. But I think it's more important, maybe if you start a new project or something, that you might consider using the latest Webpack, or maybe using one of those combination tools to make it even faster, like SWC or ESBuild. I feel like that didn't really answer your question, but I hope it makes sense.

[00:12:57]
I know that if you're working in a larger organization, it's a pain to change your Webpack config. So yeah, don't break anything, [LAUGH] yeah.
>> One follow-up question.
>> Sure. So in your mind, what defines a larger bundle? Is it in the performance uploading, or is it the size of the bundle?

[00:13:17]
>> So it's the size of the bundle, but that also, in almost all cases, affects loading time as well. When you're actually outputting with Webpack, they usually have those little colors, and they actually tell you, hey, this bundle is when it's red, cuz it's too big, which might affect your performance.

[00:13:35]
I cannot really show that right now. I won't go too deep into Webpack, by the way, cuz it's so precise that I feel like there's another Frontend Masters workshop on that. But, yeah, a larger bundle size is over a certain amount of bytes. It's different for everyone, I'm not entirely sure how much that is.

[00:13:51]
But I know that also Webpack tells you, maybe consider code splitting this bundle, cuz it's really large. And we will talk about the static imports and dynamic imports with which you can actually create those smaller bundles. Yeah, so a larger bundle is just a large bundle that also then in turn affects the loading time, download time, parsing time, execution time, stuff like that.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now