
How dynamically lazy load vue 3 components for better performance
Let's see how we can dynamically lazy load vue 3 components by using defineAsyncComponent.
Large Components Issue
When you application grows, developers face a new challenge, loading large components.
And it's hard to address that without compromising application performance and it might lead to Massive initial bundle sizes and definitely Poor user experience.
but, in this article we want to know how we can properly handle this in
Scenario
Imagine you have number of big components that you want load them dynamically based on the input or prop,
you might say, Okay I just Import them and use
<template>
<BigComponent v-if="size === 'big'" />
<BiggerComponent v-if="size === 'bigger'" />
<BiggestComponent v-if="size === 'biggest'" />
</template>
But the problem is that you just render them conditionally and all of them will be bundled and imported at build time! so the problem is still exist.
The Magic of defineAsyncComponent
the
So we can re-write the example like this
<script setup>
const BigComponent = defineAsyncComponent(() => import('./BigComponent.vue')) const BiggerComponent = defineAsyncComponent(() => import('./BiggerComponent.vue')) const BiggestComponent = defineAsyncComponent(() => import('./BiggestComponent.vue')) </script>
<template>
<BigComponent v-if="size === 'big'" />
<BiggerComponent v-if="size === 'bigger'" />
<BiggestComponent v-if="size === 'biggest'" />
</template>
Now components will be simply rendered only if needed.
For advanced usage we can pass an object to
to handle loading, error, timeout and etc.defineAsyncComponent
Real-World Example
We need a components that decide to show an Icon (Represents any heavy component or parts of application) based on the prop value.
<script setup lang="ts">
import { defineAsyncComponent, computed } from 'vue'
const definedProps = defineProps<{ extension: string }>()
const iconComponents = {
json: () => import('./Icons/JSON.vue'),
html: () => import('./Icons/HTML.vue'),
shell: () => import('./Icons/Shell.vue'),
js: () => import('./Icons/JavaScript.vue'),
ts: () => import('./Icons/TypeScript.vue'),
}
const Icon = computed(() => defineAsyncComponent(iconComponents[definedProps.extension]))
</script>
<template>
<Suspense>
<template #default>
<component :is="Icon" />
</template>
<template #fallback>
<span>icon</span>
</template>
</Suspense>
</template>
In here we combined
anddefineAsyncComponentto handle loading state of async component.Suspense
This approach ensures that you only load and render what we want!
A couple of Question and Answer about this topic
How does
Can you explain the performance benefits of
Asynchronous component loading allows applications to:
- Reduce initial bundle size
- Improve initial page load speed
- Load components only when necessary
- Minimize memory consumption
- Provide a more responsive user experience, especially on mobile devices or slower networks
What's the difference between
How can I implement error handling with async components?
const AsyncComponent = defineAsyncComponent({
loader: () => import('./MyComponent.vue'),
errorComponent: ErrorHandler, // Component shown on load failure
delay: 200, // Delay before showing loading state
timeout: 3000 // Timeout for component loading
})
::