One possible downside to bundling your single page app with Webpack is that you can end up with a really big bundle file, sometimes several megabytes in size!
The problem with this is that a user must download the whole file and run it before they can see anything on the screen. If the user is on a mobile device with a poor connection this process could take quite some time.
Code splitting is the idea that a bundle can be fragmented into smaller files allowing the user to only download what code they need, when they need it.
For example, looking at this simple web page, we can identify portions of the app that we don’t need on the initial load:
What if we delayed loading these parts of the code until after the initial render? It would allow a user to see and interact with the page much quicker.
In this article, I’ll show you how Vue.js and Webpack can be used to split a single page app into more optimally sized files that can be dynamically loaded.
You may also like:
What’s New in Vue?
The key to code splitting a Vue.js app is async components. These are components where the component definition (including its template, data, methods, etc) is loaded asynchronously.
Let’s say you’re declaring a component using the
component API, i.e.
Vue.component(name, definition). Rather than having a definition object as the second argument, async components have a function. This function has two notable features:
- It’s an executor for a Promise, i.e. it has a
- It’s a factory function, i.e. it returns an object (in this case, the component definition).
Async components are the first step for code splitting because we now have a mechanism for abstracting sections of our app’s code.
Dynamic Module Loading
We’ll also need Webpack’s help. Say we abstract our component definition into an ES6 module file:
How could we get our Vue.js app to load this? You may be tempted to try something like this:
However, this is static and is resolved at compile-time. What we need is a way to dynamically load this in a running app if we want to get the benefits of code splitting.
Webpack already has an implementation for
import() and treats it as a code split point, putting the requested module into a separate file when the bundle is created (a separate chunk, actually, but think of it as a separate file for now).
import() takes the file name as an argument and returns a Promise. Here’s how we’d load our above module:
Note: if you’re using Babel, you’ll need to add the
syntax-dynamic-importplugin so that Babel can properly parse this syntax.
Now when you build your project you’ll notice the module appears in its own file:
Another note: you can give a dynamically imported module chunk a name so its more easily identifiable; simply add a comment before the file name in the same way I’ve done in the above example.
Dynamic Component Loading
Bring the pieces together now: since
import() returns a Promise, we can use it in conjunction with Vue’s async component functionality. Webpack will bundle AsyncComponent separately and will dynamically load it into the app via AJAX when the app calls it.
On the initial load the page will be rendered as:
When main.js runs it will initiate a request for the async component module (this happens automatically because Webpack’s
import() implementation includes code that will load the module with AJAX!).
If the AJAX call is successful and the module is returned, the Promise resolves and the component can be rendered, so Vue will now re-render the page:
Here’s a diagram to help you visualize it:
Single File Components
The idiosyncratic way to achieve code splitting in Vue, however, is to use the beloved single file component. Here’s a refactor of the above code using an SFC.
This syntax for importing is even neater:
Code Splitting Architecture
That’s the technical part out of the way. The question, now, is how can you architect an app for code splitting?
The most obvious way is by page. For example, say you have two pages in your app, a home page and an about page. These pages can be wrapped inside components, Home.vue and About.vue, and these can be the split points of the app.
But there are other ways, for example, you could split any components that are conditionally shown (tabs, modals, drop-down menus, etc.) or that are below the page fold.
For my next article, I’ll explore some different code splitting architectures for a Vue.js SPA, so stay tuned!