In the last video, we saw how we can limit the size of the bundle by using tree-shakeable dependencies. In this lesson, let's see how we can break that bundle up into different chunks so that the user only gets the code relevant to the page or the part of the page that they're currently viewing. This process is known as code splitting. The most obvious split points in our apps are the pages.
Why? Well, because no user will ever be viewing different pages of the application at the same time in a single browser tab. We already have an example of how to set this up within the router file of our view app. Creating a page that is included in the final bundle looks like this.
We import the page at the top of the file and then assign it as the component for a particular route. Notice that the tree shaking end and tree shaking begin pages are done this way. That's why those were included in our main bundle in the last lesson. However, if we want to code split that route, instead of passing in the component that's already imported, we pass in a callback function that does a dynamic import of the page component.
In the browser, let me open up the DevTools, choose the Network tab, and then I'll search for code splitting end. This is a different page in our application, than the one we're currently looking at. Right now we're on code splitting begin. Now let me refresh the page.
And you'll notice in our network tab results, this page has not loaded yet. If I open up the main navigation of my app and then go to code splitting end, the JavaScript for that page pops in when we begin to visit it. So code splitting pages means the JavaScript for that page component is not going to load until you actually visit that route. And as you saw in the code, it's super easy to set up.
Besides splitting pages though, we can also split certain components within our pages. These are typically components that are only displayed upon a certain condition with the if. Let's take a look at the three code splitting begin page. Here we've got a setup that does exactly that.
We have a show reactive ref set to false. We have a button that when clicked will toggle show to its opposite. When it's false, it'll become true. When it's true, it will become false.
And then we have a code split example component that has a vf on it to only display when show is truthy. At the top of the page, we are importing that component immediately. Over in the browser now, let's go back to the code splitting begin page, open up the browser dev tools, choose the network tab, and then I'll search for the example component, which is the component being shown conditionally. If I were to refresh the page now, notice that we do have the component's JavaScript still split into its own file, but it is loaded as soon as the page loads.
Even though we don't actually need the component, until the button is clicked. It would be nicer if we could take this chunk and only load it when it's needed. Well, that's totally possible with Vue. Instead of importing it like this, we'll use a function called defineAsyncComponent.
Make sure you import that from Vue, and then much like the lazy loaded route, we'll provide a callback function that does a dynamic import. The result of defineAsyncComponent will be the code split example component instance. Awesome. Let's test things out in the browser again.
In the network tab, I'll clear things out for good measure, reload the page, and sure enough, this time the example component does not load immediately. However, when I click the button, then it loads in exactly when we need it. So you can code split not only your pages to be lazy loaded, but you can also code split your components to be lazy loaded as well. If you want even more control over how your async component is loaded, over in the code splitting end file, you can see a more thorough example of the different options that you can pass to define async component.
So instead of passing just a callback function, you could also pass an object where the loader is that callback function that we just used a minute ago. But the other options are to provide a loading component. that displays while the JavaScript chunk is downloading to the browser. Here we're just using a render function.
Same thing for an error component if your server fails or the user's internet connection breaks for some reason or another. Then we can show this component if the chunk is not loaded successfully. We could also provide a delay, meaning don't show the loading component for at least one second to make things feel a little bit snappier. And then we could also provide a timeout.
to say that if the chunk doesn't load in three seconds, then just throw the error and don't continue to try. That's how you can code split and lazy load different component chunks in a vanilla view app. But what about a Nuxt application? Let's close these three files and take a look at the code splitting begin page within the Nuxt application.
All right, so here you'll notice that pages are actually code split and lazy loaded by default. in Nuxt 3. So there's literally nothing you have to do in order to make code splitting work for your pages. But what about your components?
Well, Nuxt provides a super handy lazy prefix that you can slap onto any component within the template section, and it does exactly what define async component did in the view app. Let's open up the code splitting begin page on the Nuxt app just to confirm that this is working. Refresh the page. No example component loaded yet.
But when I click the button, it loads right in. In closing, note that it's not useful to lazy load every single component in your app. Components that are displayed immediately, and especially those displayed immediately above the fold, should never be lazy loaded. Also, imagine that if you lazy loaded a bunch of nested components, it would cause a waterfall effect causing huge performance issues.
as a lazy-loaded component inside of another lazy-loaded component would only start loading after its parent had loaded and on and on down the tree. Finally, while code split and lazy-loaded components are a great boost for performance, there is of course trade-offs. Split chunks may fail to load if there's an internet connectivity issue or problems on your server. Also, instead of components displaying immediately upon a truthy condition, Users will have to wait the extra couple hundred milliseconds for the chunk to download from your server.
In the next lesson, we'll see how we can mitigate that last caveat by pre-fetching lazy loaded chunks.