We don’t want to build slow apps, but there are many reasons why it happens anyway. Maybe there was no time or budget for „invisible“ things like performance. Maybe other technical challenges needed a lot of attention, and you had pressure to ship. Or your app just grew a lot over time!
Facing performance issues often makes developers feel guilty that they didn’t „build it better“, and worried that they don’t know enough to solve the issues. If you feel this way, let me tell you that there are a lot of quick wins and methods available to start optimizing.
In this article, we’re taking a look at the basics of performance optimization for Vue apps and guide you towards resources and tools that help you go deeper.
Why is performance optimization important?
😊 It makes users happy
Performance has a big impact on user experience. People are using your app to get things done. A snappy app that delivers results and information fast will help users accomplish their goals while feeling efficient. It also boosts trust in your brand and app.
While I hope you like making people happy, contented users are also important for your business:
🔥 It makes your app more successful
Happy users that don’t have to wait for your app or website to load are *less likely to bounce (= leave), and more likely to convert (= sign up and pay).
Additionally, performance impacts your ranking on search in two ways:
Search engines rank performant pages higher
If fewer people bounce quickly from your page, search engines take that as a signal that your content is helpful - therefore ranking you higher
🦾 It makes your app more accessible
Not everyone is using your app / website on a brand-new MacBook Pro and on a flat-rate, high-speed network. Being mindful about size and CPU impact makes it possible and less costly for more people to access your app.
7 factors that impact Vue app performance, and how to optimize them
When we’re talking about performance, we’re usually talking about metrics measuring two important aspects:
Load time: How fast does the page and content load? How long does it take until it’s interactive?
Responsiveness: How fast and smooth does the app respond when I interact with it? (Menus, buttons, forms, data tables, charts, filters, animations,..)
So, what are we doing (or not doing) to make our app heavier to load and less responsive? There are many things that can impact performance, and it’s not just about the code you write as a frontend developer.
You’ll have to see the broader picture including the user and their hardware & network, your backend, server and also the design of your app (visual design and architecture-wise).
Read on for a summary of the most important factors and some tips on how to optimize!
1️⃣ Bundle size
How much bandwidth is needed to load your app? The larger, the slower.
Keep an eye on your bundle size and reduce third party code. Choose your dependencies carefully and weigh up the benefit of the functionality against the impact of bundle size.
Remove unused code. Use a build step with a code bundler like Webpack or Vite (if possible) to make use of tree-shaking. This allows you to get rid of any code you don’t actually use (e.g. some of Vue’s APIs or parts of your UI component library).
Use lazy loading and code splitting. Split your bundle into smaller parts that are loaded only when needed to avoid loading unused parts of your app.
How much bandwidth is needed specifically to load images, videos and fonts? Are you smart about delivering only what is needed?
Optimize your images. Make sure your images are properly sized and compressed, and serve responsive images. Think about using next-gen formats like WebP for better compression, and serve animated content in video formats where possible. Define the correct dimensions on image elements.
Optimize font usage. Only load the fonts you need, and make sure text is visible for users until they are finished loading (font-display: swap;).
Question design choices. It’s not exactly coding, but it’s still your responsibility to point out implications of design decisions on performance! Do you really need 6 different styles of your fonts from light to extra bold or can you reduce together with the designer? Do you need this large video background for the header? Sometimes the answer will be yes, and that’s okay – but maybe you can use an image fallback for slower connections?
Lazy-load images and videos. It makes sense to only load the resources that your users need at that moment. Postpone loading images and videos that are off-screen at first, and lazy load them later.
Preload / prefetch important assets. Prioritize the fetching of critical assets – for example by preloading images in your header or hero section so users see them faster.
Use caching so your users don't have to download the same assets multiple times.
The network conditions of your users are halfway out of your control - but you can still account for them.
Take network quality into account when deciding what to serve your users. Think about how you can make your app offline-ready, serve different resources for low bandwidth, hold off on downloading large files,.. to make your app easier to use with slower connection types.
Consider using content delivery networks (CDNs). CDNs are optimized for delivering content to your users quickly, as they serve assets from the server closest to your user, so they have shorter latency.
Avoid redirects where possible.
4️⃣ Code performance
How efficiently does your (Vue) code do what you want it to do?
Optimize event handling. Think about the cost of event handlers for 'mousemove' and similar events that are triggered multiple times per second. Replace 'click' with 'mouseup' events.
Avoid unnecessary component updates / rendering loops. Update only what is needed!
Reduce the amount of component instances. e.g. by removing unnecessary component abstractions.
5️⃣ Data requests / backend / APIs
If you need to load content from a CMS or a third party API to display in your app, your frontend performance is inevitably bound to the amount and performance of those API calls. Also, requests for analytics apps, ad networks and similar services can be costly.
Avoid unnecessary API requests and defer requests until the data is needed.
Avoid extensive user tracking (if possible).
Prefetch components & routes that your users will probably need next. (Nuxt will help with that out of the box!)
Eliminate render-blocking resources and inline CSS and JS that is critical for the first paint of your page.
Cache requests.
6️⃣ Resource usage
How costly is your app in terms of memory and CPU usage? Depending on the device your users are on, this may impact performance a lot for them.
Use server-side rendering or static site generation. Serve static HTML or HTML generated directly on your server to your users, so they don’t have to wait for your JavaScript to download and execute on the client side. Nuxt helps you with this!
Use virtualization for big data lists. When displaying a lot of data, e.g. in a large table, make sure your components support UI and data virtualization that provides only the data needed for the user at the moment.
Be careful with animations. Avoid animations that are not GPU-based, and go easy on those 3D animations.
Test on lower-end devices / slower connections to evaluate possible problems yourself. Did you know you can throttle speed in the Chrome developer console?
How snappy does the app feel to the user? Your user’s perception of how long it takes your app to load is actually even more important than the objective load time. It can be impacted by how loading resources is prioritized, handled and communicated.
Give users feedback about the status of actions that take longer, like loading a lot of data. But wait a bit before showing a loading spinner, or it might be perceived as slower!
Provide a preview of your content (e.g. with loading skeletons or image placeholders) to show users what to expect, and to avoid content jumping around too much and to promote visual completeness.
Minimize the initial load and provide a first chunk of content quickly.
Prioritize making the most important interactive elements usable and responsive as soon as possible, so users can do what they came for quickly.
Don’t over-animate. Don’t set animation durations longer than 300ms, and don’t overuse transitions.
If you want to make performance a priority, it makes sense to set yourself budgets for the most important metrics like pagespeed and bundle size, and measure your app against them regularly.
Bundle size budgeting
To keep your bundle size in check, you can use CLI tools like siddharthkp/bundlesize to set up automated checks for your build pipeline. Tools like Packtracker (#madewithvuejs!) offer an additional dashboard visualizing bundle size over time.
The Lighthouse CI CLI tool and GitHub actionlets you analyze your app continuously in your workflows and set up performance budgets for the metrics you care about.
(Fullstack) Performance monitoring
If you want to take it a step further, performance monitoring helps you keep track of your app’s performance over time and notifies you about issues as soon as they crop up.
Monitoring services provide insights about where and how to solve issues. They track your app as a whole, and help you identify the source of issues – is your frontend, backend, or API xyz at fault? Sentry is our weapon of choice. We use their Vue and Laravel SDKs, but they support almost every other stack as well!
We're starting our #intervue article series with Hassan Djirdeh, author of Fullstack Vue. He shares insights about his journey to become a Frontend Developer & Author, and what he loves about Vue.js.
In this part of our #intervue series, Jonathan Johnson shares his journey of building packtracker.io, a Webpack Bundle Analyzer built with Rails and Vue.js. Read on to find out about his process and challenges.