Vue dynamic, async components (lazy load)

Vue is very nice framework that allows us to simply and quickly create apps. After many many hours and after hundreds of lines, our app can be big, really big. It’s bad for user experiences, because of long loading and delays. If we use a lot of components and many of them are rendering conditionally, we can load them asynchronously, as other chunks. How do this? It’s very simple, we must just import required files not always, but only on demand – something like lazy loading. Everything is build-in, so we only have to make only few small changes.

Lazy load components

Let’s see this small example, we have here some additional components, one of them is big and complicated, import many additional data etc. Everything is always in the same bundle:

<template>
	<div>
		// Some code here

		<my-other-component v-if="myCondition"
			            v-bind:foo="bar"
		></my-other-component>
	</div>
</template>



<script>
import MyOtherComponent from './components/my-other-component.vue'

export default {
    name: 'ParentComponent',
    components: {
        MyOtherComponent,
  		// or other components
    }

But.. this complicated component is rendered only then condition is met – not always, so, it isn’t good option to attach all the code every time. We can make it async, and Vue will load required code only if we really need it. There is small example using short code (arrow function):

export default {
    name: 'ParentComponent',
    components: {
    	MyOtherComponent: () => import('./components/my-other-component.vue')
    }


What’s that? We don’t set component as always read-to-use, but use Promise (because import returns promise). It will not called, before code requires it – so import will work only if condition in met. You can check this using browser console: when you change value and condition is met, browser will load additional js chunk file and all dependencies related to attached component.

There is one, very important thing. It’s lazy load for component and all its data – so, if inside this component we load lot of assets / resources required only by this one component, all will be available only it this separate chunk. Our app main fill will be much smaller, so faster to download, analyze and run our app. Of course inside such async component, you can use other async component and divide app into many, smaller chunks.

Lazy load in routing

Good option is to do this on routing level, so moving into another router, will dynamically load other chunks. With such structure, production bundle consists of many separate modules loaded asynchronously. It’s much faster then one, very big main file. There is classic example of routing:

import MyComponent from '@/components/my-component.vue'

export default [
    {
        path: '/foobar/test',
        name: 'foobar-test',
        component: MyComponent,
    },

And there is route example using lazy load:

export default [
    {
        path: '/foobar/test',
        name: 'foobar-test',
        component: () => import('@/components/my-component.vue'),
    },

With such approach, bundle with components data (and all dependencies) will be loaded only if user go to this route. In other case, browser will not download unnecessary data.

Bundle goruping

You can also group many components into one bundle using special webpack comment for this. There is an example:

export default [
    {
        path: '/foobar/test',
        name: 'foobar-test',
        component: () => import(/* webpackChunkName: "mybundle" */ '@/components/my-component.vue'),
    },
    {
        path: '/foobar/test2',
        name: 'foobar-test2',
        component: () => import(/* webpackChunkName: "mybundle" */ '@/components/my-component.vue'),
    },

Using this, all code from both test and test2 routes will be in one bundle called “mybundle”. User must visit only test OR test2 page, to load all required data. After that, moving to other page from the same group will not call downloading any additional bundles.

Drawbacks and conclusions

Does using chunks and lazy loading have any drawbacks? Yes. There are some potential issues with loading data after rebuild our application: app in browser has old main file, download new chunks and code may “doesn’t match”. But there is solution for that and I will write about that in next post.

Generaly, lazy loading is very good practise, because you can avoid massive main app js file. Our apps are bigger in bigger, have a lot of dependencies and can load very slow, especially on mobile devices. It’s real problem, so if we can speed up, we should do this. Lazy loading is great solution – very simple to implement, but has a lot of advantages.