DEV Community

Justin Brooks
Justin Brooks

Posted on • Edited on

Lazy loading components in Vue 3

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>


Enter fullscreen mode Exit fullscreen mode

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>


Enter fullscreen mode Exit fullscreen mode

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
})


Enter fullscreen mode Exit fullscreen mode

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>


Enter fullscreen mode Exit fullscreen mode

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!

Top comments (6)

Collapse
 
pezhvak profile image
Pezhvak

This is sooooo useful! Thanks for sharing.

Collapse
 
itsmnthn profile image
Manthankumar Satani

This is useful! thanks

Collapse
 
mostafaamine profile image
mostafa amine briere

Than you so much

Collapse
 
yaroslavhorokhovets profile image
Abdul Hameed

great!

Collapse
 
onlyplanb profile image
CodeCase

Do we have any options here for offset the point when lazyloading should load?
If I have short pages to scroll, the component loads still even if its not in viewport.

Collapse
 
vishaal_meduri_985d10a657 profile image
Vishaal Meduri

@onlyplanb

Read Intersection Observer, dev.to/onlyplanb/comment/236h2