A Tour of JavaScript & React Patterns

Static & Dynamic Imports

Lydia Hallie

Lydia Hallie

Lydia Hallie
A Tour of JavaScript & React Patterns

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

The "Static & Dynamic Imports" 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 explains the difference between static and dynamic imports. Static imports are immediately available in the application bundle and are easy to optimize and tree shake. Dynamic imports provide a faster initial load but can lead to layout shifts or a decreased user experience if they are not loaded by the time they are needed. The React useInView hook and route-based splitting are also demonstrated in this segment.


Transcript from the "Static & Dynamic Imports" Lesson

>> So, first we have the static import, which I'm sure most of us have used many times or use most of the time. So with a static import, we can just use the built in import keyword, so import module from this file. So in that case, what happens is when the JavaScript engine sees this code I'd like import module 1 for module 1, it will execute module 1, then execute module 2, then execute module 3.

Is pretty similar to what we saw before when we talked about the bundler. So in this case, if we were to statically import module 3 from module 3, it will add this to the bundle and then statically import module 2 in module 3, it will all add this to the bundle.

Yeah, I won't really talk about the implementation here just because it's pretty straightforward. This is kind of the normal import that we use nowadays in at least in ES6. So the static import is pretty useful because the dependencies are instantly available to the user. Because when we statically import something, it's available in the bundle, it gets bundled in the main bundle that the user initially requests.

It's also better for optimizations because a bundler can statically analyze it and maybe tree shake it. But yeah, like I said before, it's pretty easy to end up with pretty large bundle size when we statically import components that may not necessary or may not be necessary on that initial render.

So just make sure that you're not statically importing a lot of components that aren't instantly available to the user. So in decades we can maybe use something like a dynamic import. So just to show you an example, for example we can have this search bar and only when a user clicks on that we wanna show that list.

So that list isn't really necessary for the initial load, because it will only ever render it when a user clicks on it. Now, if we were just statically important, this search input or this flyout would have been included in the bundle for essentially no reason. Maybe the user never clicks on it, right.

Of course, this is very small example but just as an example, so instead, what we could have done, is dynamically loading this component. And when we're doing that, we're just telling the vendor, hey, this component is on its own. So it can be in its own little bundle, so it can be split out of that larger bundle, and put into its own bundle.

Many bundle wars here. But so here we have a static import and then a dynamic import. So here we see that we're splitting that search papa bundle, which is here this component from the big bundles. So we can reduce the bundle size by lazy loading the search bar pop up, and we can do this with a built in component in react called react suspense.

So we don't have to touch a lot back here at all. Which is super nice, it automatically will create this separate bundle for us. And as it's loading this, so only when a user actually needs it or when we're actually rendering the component so when it's open, will it fetch that bundle and render it.

In the meantime, while it's fetching it, we of course don't want to just show something random, it will show this fallback component. Let me show you an example. For example here I'm just going to open this in StackBlitz. I'm going to leave this one, so what I have here is I have multiple cards.

I don't know what the messages are there. So in here I am statically importing card1 and Card2 but I'm dynamically importing card3 and card4 with a lazy method is available on react. Now I'm adding this webpack chunk name. I'll show you in a second why it's just like a nice thing.

But now what we can do is click here to dynamically import a card 3 component. So what I have here is I have a suspense which we imported from react. And whenever this card is open, so whenever we click on it, which is here like on click toggle, then it's open and then this component will render, and only then will it fetch that bundle for that component.

So I can hear it dynamically rendered at 3:45:03 PM while whereas these were rendered at 3:44 PM, same work for card4. Now you can see that if we go into the bigger one, I'm just going to go to the network request. I'm going to make this a little bit bigger.

When we're dynamically importing it, you can see that it's now fetching that card3 bundle. And here card4 bundle. So, it's only fetching that bundle when we actually request it when the user actually needs to see it. So, that initial bundle can be a lot smaller. Now this is called a magic common the webpack junk name.

It just makes it possible to see the card3 bundle and card4 a bundle because when we remove that you will just see, I can just show you what it shows instead. So this is just kind of like developer experience. I'll just reload this. I'll just show the 0.bundle and like 0.1, that's not always like super obvious what is actually loading there.

So I like to use these magic commons to change the name of our bundles. Yeah, so this is already a really good way. So dynamically importing components is a really nice way to reduce that initial bundle size and only fetch the bundle when a user actually needs it.

So the trade offs here of course is the pester initial load. This ensures that we can have that smaller initial bundle however it can also lead to layout shift. Now layout shift is like, for example here if this component didn't match this component which is kind of doesn't it can lead to like a weird layout shift that's not great.

It's just about like user experience. And then also, if you're lazy loading a component and that component actually ends up being pretty large. Maybe this card4 bundle is another large bundle because somehow we didn't code split that one. User clicked on something and it takes a while maybe they're homeless so internet or something, takes a while to fetch it, to render i,t there you're like I don't see anything.

I don't know what's going on. So just something to think about. But, normally you kinda wanna lazy load those smaller components that just aren't instantly visible on the initial render. Now another, type of dynamic import, is what we just saw what like clicking on the cards is kinda go like import on user interaction, import on interaction, but we also have input on visibility.

This is really nice for example if we wanted to show all those listings on a smaller viewpoint. And of course this is again a small example but we are rendering those listings that aren't directly in the viewport. So instead, we might lazy load those listings. And in the meantime, we'd to show a fallback.

I know this is a really bad animation. But anyway, only when the user actually sees it in the viewport will we render that bundle. So instead of having an onclick, we kind of have if it's in the viewport. Now really nice and really easy way to do that is by using the intersection observer API.

But then even easier way is to use the the hook that they also provide with that react intersection observer. So we can just use a simple hook called use interview, which returns a reference and then in view. So we can say, okay, if this components with that ref is in the view, then show that listing.

Now I just again have this example just with the cards but see if I can open this, I feel like if I open it and StackBlitz it'll be in the viewport. So I'm just gonna keep this a bit small, well okay, yeah, okay, so here we can see that we statically import it, actually I'm just going to show you the code real quick though that.

Ignore this for now. Sorry about that, maybe I don't know, right. So we have this card1 card2 which we statically import it and then we also have the card3 and part4, which we dynamically import it. And we are using this dynamic current and we're using the ref and view.

So here we see scroll down because it just had to be in the viewport not immediately [LAUGH], so here we see dynamically imported at 3:48:56 and here it is at 4:49:01. So it's basically the same as what we saw with the dynamic import unclick but this time it'll fetch the bundle automatically what's in the viewport.

Now of course from a react perspective, we implemented this the exact same way. But instead of being open, we just had an interview that was returned from this using view hook. But this is often also used when you have maybe a large list or just many components that are normally outside of the view.

Or it's the initial viewport, it's a nice way to import them visibility not necessarily on user interaction. It's like the same trade off that we saw with the with the dynamic input, but this time a user may not be expecting to see something. So you don't really have that, what's it?

I'm clicked on something, why can't I see your component? Because it's on visibility it doesn't require user interaction. But it's still not great, it can still lead to layout shifts and stuff like that, but definitely worth it for the faster initial load in most cases. Then we also have the route based splitting.

Now for example, I'm not entirely sure what this animation is going to show you? Yeah, so we can have a separate bundle per page for example if we normally with an SBA we have one large bundle that contains the code for everything. And although this does give you really fast navigation what we can do instead is have a bundle per page.

So when a user here requests the about page or navigates to the about page it fetches this bundle and then it'll render the about page. This is also a great way to have that smaller initial bundle so we only render what is necessary for the current navigation. Maybe if you're, I don't know if you're using React Router but they provide a pretty easy way to implement it.

I feel like this is the updated syntax. I'm just going to open this real quick. So here you can see that we are importing those pages, those routes, as in the Router, the React Router we're saying that the elements is just a wreck suspense, like we saw before.

And then we're rendering this component. So again, from a React perspective, it's basically the exact same thing. But when we are, I'm just going to show you the network request again. This time the code for the about and contact page it's not included in the initial bundle based on their route, so I can do about in contact.

Now in this case it didn't use the magic comments so they just got one bundle two bundle. Yeah, so these are the bundles that are just necessary for this page like here's the pages contact and here's the other pages about. So this is also a very nice way to make sure that we're only fetching the minimal necessary code.

Any questions so far on bundle splitting based on certain events? No, perfect.

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