Translate

Thursday, 18 April 2019

Optimize the Performance of a Vue App with Async Components

Optimize the Performance of a Vue App with Async Components

Single-page applications sometimes cop a little flack for their slow initial load. This is because traditionally, the server will send a large bundle of JavaScript to the client, which must be downloaded and parsed before anything is displayed on the screen. As you can imagine, as your app grows in size, this can become more and more problematic.

Luckily, when building a Vue application using Vue CLI (which uses webpack under the hood), there are a number of measures one can take to counteract this. In this article, I’ll demonstrate how make use of both asynchronous components and webpack’s code-splitting functionality to load in parts of the page after the app’s initial render. This will keep the initial load time to a minimum and give your app a snappier feel.

To follow this tutorial, you need a basic understanding of Vue.js and optionally Node.js.

Async Components

Before we dive into creating asynchronous components, let’s take a look at how we normally load a component. To do so, we’ll use a very simple message component:

<!-- Message.vue -->
<template>
  <h1>New message!</h1>
</template>

Now that we’ve created our component, let’s load it into our App.vue file and display it. We can just import the component and add it to the components option so we can use it in our template:

<!-- App.vue -->
<template>
  <div>
    <message></message>
  </div>
</template>

<script>
import Message from "./Message";
export default {
  components: {
    Message
  }
};
</script>

But what happens now? The Message component will be loaded whenever the application is loaded, so it’s included in the initial load.

This might not sound like a huge problem for a simple app, but consider something more complex like a web store. Imagine that a user adds items to a basket, then wants to check out, so clicks the checkout button which renders a box with all details of the selected items. Using the above method, this checkout box will be included in the initial bundle, although we only need the component when the user clicks the checkout button. It’s even possible that the user navigates through the website without ever clicking the checkout button, meaning that it doesn’t make sense to waste resources on loading this potentially unused component.

To improve the efficiency of the application, we can combine both lazy loading and code splitting techniques.

Lazy loading is all about delaying the initial load of a component. You can see lazy loading in action on sites like medium.com, where the images are loaded in just before they’re required. This is useful, as we don’t have to waste resources loading all the images for a particular post up front, as the reader might skip the article halfway down.

The code splitting feature webpack provides allows you to split your code into various bundles that can then be loaded on demand or in parallel at a later point in time. It can be used to load specific pieces of code only when they’re required or used.

Dynamic Imports

Luckily, Vue caters for this scenario using something called dynamic imports. This feature introduces a new function-like form of import that will return a Promise containing the requested (Vue) component. As the import is a function receiving a string, we can do powerful things like loading modules using expressions. Dynamic imports have been available in Chrome since version 61. More information about them can be found on the Google Developers website.

The code splitting is taken care of by bundlers like webpack, Rollup or Parcel, which understand the dynamic import syntax and create a separate file for each dynamically imported module. We’ll see this later on in our console’s network tab. But first, let’s take a look at the difference between a static and dynamic import:

// static import
import Message from "./Message";

// dynamic import
import("./Message").then(Message => {
  // Message module is available here...
});

Now, let’s apply this knowledge to our Message component, and we’ll get an App.vue component that looks like this:

<!-- App.vue -->
<template>
  <div>
    <message></message>
  </div>
</template>

<script>
import Message from "./Message";
export default {
  components: {
    Message: () => import("./Message")
  }
};
</script>

As you can see, the import() function will resolve a Promise that returns the component, meaning that we’ve successfully loaded our component asynchronously. If you take a look in your devtools’ network tab, you’ll notice a file called 0.js that contains your asynchronous component.

Code splitting webpack

Conditionally Loading Async Components

Now that we have a handle on asynchronous components, let’s truly harvest their power by only loading them when they’re really needed. In the previous section of this article, I explained the use case of a checkout box that’s only loaded when the user hits the checkout button. Let’s build that out.

Project Setup

If you don’t have Vue CLI installed, you should grab that now:

npm i -g @vue/cli

Next, use the CLI to create a new project, selecting the default preset when prompted:

vue create my-store

Change into the project directory, then install the ant-design-vue library, which we’ll be using for styling:

cd my-store
npm i ant-design-vue

Next, import the Ant Design library in src/main.js:

import 'ant-design-vue/dist/antd.css'

Finally, create two new components in src/comonents, Checkout.vue and Items.vue:

touch src/components/{Checkout.vue,Items.vue}

The post Optimize the Performance of a Vue App with Async Components appeared first on SitePoint.



No comments:

Post a Comment