loading...

Lazy loading components in Vue 3

jsbroks profile image Justin Brooks ・3 min read

Fast loading speed is essential when creating any web application. A few extra seconds could have a huge impact on the number of users visiting your site. This means that having a fast site is important, not just for ranking well in Google Search Engine, but for having users interact with your webpage.

Vue 3 has introduced several new features to help you achieve this easily through the improvements to the async component API and the new Suspense component. In this article, we will be taking a look at using lazying loading components in Vue 3 to speed up your pages load times.


Check out the youtube video that this article was created for:

Alt Text


In this example app, we have a SecretImage component that displays an interactive graphic of the Vue logo only when the user is authenticated. To prevent intruders from seeing our most valuable asset, we added a button that toggles the visibility of this component.

<template>
  <!-- ... -->
  <!-- Large component that uses many libraries -->
  <SecretImage v-if="isLoggedIn" />
  <!-- ... -->
</template>

<script>
import SecretImage from './components/SecretImage.vue'

export default {
  components: { SecretImage }
  // ...
}
</script>

While building the SecretImage we used many complex libraries causing the amount of javascript code to increase. Building our app we can see it creates a large vendors file which we are loaded on our initial request to our site.

Alt Text

Async Components

We can use the new defineAsynComponent function which comes with Vue 3. All we need to do is pass a function that loads our components. Since Vue comes preconfigured with webpack we can use the dynamic import feature.

<template>
  <!-- ... -->
  <SecretImage v-if="isLoggedIn" />
  <!-- ... -->
</template>

<script>
import { defineAsyncComponent } from 'vue'
const SecretImage = defineAsyncComponent(() =>
  import('./components/SecretImage.vue')
)

export default {
  components: { SecretImage }
  // ...
}
</script>

Now when we build our app we can see a new file has been created and the vendor file has significantly reduced.

Alt Text

Logging back in we can also see a new request being created to loading our SecertImage component.

Since we are loading this component later there may be a short delay while the lazy-loaded part of your UI is being requested and rendered. We can additionally pass in a loading component property which will be displayed while the component is being loaded.

import { defineAsyncComponent } from 'vue'
import Loading from './components/Loading.vue'

const SecretImage = defineAsyncComponent({
  loader: () => import('./components/SecretImage.vue'),
  loadingComponent: Loading
})

However, using this approach can be restrictive as it is hard to pass props or slots to the loading component.

Suspense

To add more flexibility we can use the new Suspense component which allows us to have async loading content as a component in the template. All we have to do is call the Suspense component and pass in a component for the default and fallback slots.

<template>
  <!-- ... -->
  <Suspense v-if="isLoggedIn">
    <template #default>
       <SecretImage />
    </template>
    <template #fallback>
       <Loading />
    </template> 
  </Suspense>
  <SecretImage v-if="isLoggedIn" />
  <!-- ... -->
</template>

<script>
import { defineAsyncComponent } from 'vue'
import Loading from './components/Loading.vue'

const SecretImage = defineAsyncComponent(() =>
  import('./components/SecretImage.vue')
)

export default {
  components: { SecretImage, Loading  }
  // ...
}
</script>

The default slot is displayed when the async content has loaded and the fallback slot is displayed while the state is loading.


Thanks for reading! If you like my post don't forget to follow me and subscribe to my youtube channel!

Posted on by:

jsbroks profile

Justin Brooks

@jsbroks

Fullstack developer creating youtube and opensource projects.

Discussion

pic
Editor guide