Did you know that Vue.js performance optimization is critical for user retention? Users hate waiting. In fact, a sluggish application not only frustrates users but also directly impacts your SEO and conversion rates. Therefore, if you are working with Vue 3, it is time to audit your code.
Here are 4 core optimization techniques to make your app lighter, faster, and smoother immediately.
1. Code Splitting & Lazy Loading (Divide and Conquer)
Instead of forcing users to download the entire application (a massive bundle.js) on their first visit, you should break it down. The goal is to load only what the user actually needs at that moment.
How to implement Lazy Loading
First, let’s look at the Router. You should not import components directly into your router file. Instead, use dynamic import().
Read more about Vue Router Lazy Loading
// ❌ Old way: Load everything at once
import Home from './views/Home.vue'
import Admin from './views/Admin.vue'
// ✅ New way: Load only when the user visits the route
const Home = () => import('./views/Home.vue')
const Admin = () => import('./views/Admin.vue')
Secondly, consider your Components. For heavy components (like Modals, Charts, Maps) that aren’t visible immediately, use defineAsyncComponent.
import { defineAsyncComponent } from 'vue'
// This component is only downloaded when rendered (e.g., v-if="true")
const HeavyChart = defineAsyncComponent(() =>
import('./components/HeavyChart.vue')
)
💡 Benefit: This strategy significantly reduces the First Contentful Paint (FCP) time.
2. Optimize Reactivity: Use shallowRef over ref
Vue 3’s reactivity system is powerful. However, it comes at a cost. When you use ref(), Vue deeply watches every single nested property inside the object. Consequently, this wastes resources if your data is massive and doesn’t require deep modification tracking.
When to use shallowRef?
- Instance 1: When you have a large list (e.g., 10,000 rows) returned from an API.
- Instance 2: When you only need to replace the entire data set (data.value = newData) rather than modifying individual properties (data.value[0].id = 1).
Code Comparison:
import { ref, shallowRef } from 'vue'
// ❌ Expensive: Vue tracks every property of 10,000 items
const products = ref([...list_10000_items])
// ✅ Efficient: Vue tracks only the .value, ignoring nested details
const products = shallowRef([...list_10000_items])
// How to update data with shallowRef
products.value = new_list_items // OK (Triggers render)
products.value[0].name = 'New Name' // DOES NOT trigger render
3. Optimize Rendering: v-memo and Virtual Scrolling
Re-rendering is the most expensive task for the browser. Thus, minimizing it is a key step in Vue.js performance optimization.
Using v-memo (Vue 3.2+)
This feature helps Vue “memoize” part of the template tree. If the input conditions haven’t changed, it skips the Virtual DOM comparison entirely. It is extremely useful for long lists (v-for).
<div v-for="item in heavyList" :key="item.id" v-memo="[item.status, item.isSelected]">
<ComplexComponent :data="item" />
</div>
Implementing Virtual Scrolling
On the other hand, if you have a list of 1,000 items, don’t render 1,000 div elements at once. You should use libraries like vue-virtual-scroller to render only the items currently visible in the viewport.
4. Library Management: Tree Shaking
Don’t import the entire forest when you only need a single leaf. Many libraries (like Lodash) are heavy; importing them incorrectly will bloat your application size.
Golden Rule: Always use Named Imports.
// ❌ BAD: Imports the entire library (heavy ~70kb)
import _ from 'lodash'
_.isEmpty(data)
// ✅ GOOD: Imports only the specific function needed (light < 1kb)
import { isEmpty } from 'lodash'
isEmpty(data)
Conclusion
To sum up, Vue.js performance optimization isn’t a one-time task; it’s a mindset. Start simple by applying Lazy Loading to your Routes and switching to shallowRef for large datasets in your next project!
What techniques do you use to speed up your Vue App? Let me know in the comments below!