Nuxt 3 Performance Pt 1

Performance is crucial for the long-term success of a modern web app because it affects SEO, user experience, engagement, and conversion rates. Nuxt 3 comes with built-in tools and features that optimize performance, such as code splitting, auto-imports, configured build tools, server-side rendering, and more. These features guarantee a smooth user experience and boost conversions and revenue while enhancing search engine rankings.

In this article, we’ll be looking at Performance in Nuxt 3 applications and how we can leverage its abilities to boost the performance of our apps. Before delving into the specific methods for optimizing the performance of our Nuxt apps, it’s important to have a clear understanding of what web performance involves and what we should keep in mind as developers of highly performant applications.

Performance on the Web

As developers, it is crucial to prioritize user experience when designing and optimizing our apps. This emphasis on quality is essential for the long-term success of both the site and the product.

Web performance measures how quickly web pages load and how responsive they are to user interactions, which contribute to the user’s experience on your website. A website that loads quickly and is easy to use is more likely to keep users engaged and interested, which can lead to better business outcomes such as increased conversions and retention rates. Therefore, good web performance is a key ingredient for delivering a satisfying user experience and achieving business success.

According to a report by Google, 53% of users will leave a website if it takes longer than 3 seconds to load. This means that performance is crucial for user retention and improving conversion rates. Additionally, search engines like Google use site speed as a factor in determining search results, which can have a negative impact on website ranking and discovery, ultimately affecting sales.

Google introduced Core Web Vitals to improve user experience. These metrics measure loading performance, interactivity, and visual stability of the page, and they are very important for us to be mindful of optimizing.

These metrics include:

  1. Largest Contentful Paint (LCP).
  2. First Input Delay (FID).
  3. Cumulative Layout Shift (CLS).

Largest Contentful Paint

This is a performance metric that measures the time it takes a webpage to completely render the largest piece of content and be ready for interaction relative to when the page first started loading. This content can either be an image (<img> or <image>), a video (using <video>), block-level elements, and elements with a background image loaded via the url() function.

This metric signifies a meaningful event from the user’s perspective that helps in evaluating and optimizing web page loading speed and the overall user experience. To provide a good user experience, the expected LCP for a site is expected to be 2.5 seconds or less.

First Input Delay

First Input Delay (FID) is a web performance and user experience metric that tracks the time from when a user first interacts with a site (performs an action that is not scrolling or zooming) to the time in which the browser responds to this interaction and starts to process the necessary event handlers to respond.

It is sometimes called Input Delay and is measured in milliseconds. This delay often varies based on the size, complexity, and number of JavaScript files needed to be downloaded, parsed, and executed. Sites with a delay of 100 milliseconds or less can be said to offer users a good experience.

However, It is important to note that FID does not measure the event processing time or the time it takes the browser to update the UI after running event handlers. It only measures the delay in processing such event.

Cumulative Layout Shift

Cumulative Layout Shift (CLS) is a metric that measures user experience by evaluating how much a webpage shifts unexpectedly during its loading process. This shift usually occurs when images, banners, third-party libraries, and other site elements are not fully loaded or when they change position from one rendered frame to the next (size).

This shift can cause users to perform the wrong action or get lost on the part of the page they were on before the shift. However, it is important to note that new elements added to the DOM or a change in the size of an existing element do not count as layout shifts if these changes do not cause a change in the start position of other visible elements.

To provide a good user experience, web pages are expected to have a CLS score in the range of 0.1 or less.

Importance of Good Performance

Providing a good user experience and ensuring that web pages load quickly and perform well on Lighthouse is great. However, delivering good performance on the web involves more than just achieving a good Lighthouse score.

We should also be mindful of:

  1. SEO: Good site speed is important for high search rankings on Google. Slow sites result in visitors spending less time on the site, which negatively impacts search ranking.
  2. Engagement and Retention: A good user experience results in visitors staying on the site for longer and exploring more content. This increases the chances of them returning to the site in the future.
  3. Conversion Rate: A good user experience is crucial to converting visitors into customers. If the site does not provide a good experience, visitors are more likely to change their minds about using the services offered.
  4. Mobile Experience: Since a lot of internet traffic comes from mobile devices, it’s important to consider building sites that perform well on mobile devices as well as desktops. Mobile phones have less powerful hardware and take longer to load sites, so optimizing for mobile devices is crucial.

Built-in Nuxt 3 Performance Features

Nuxt 3 comes with a variety of built-in tools and features that optimize performance out-of-the-box. Nuxt developers can focus on building great apps without having to worry so much about performance optimization from the ground up.

These techniques include:

Code Splitting

As your project evolves, the size of your codebase and its dependencies expands to include multiple JavaScript and CSS files, some of which can grow to thousands of lines.

Tools like Webpack and Vite are used to bundle these files into a single file, giving the application a consolidated codebase. However, as the application grows larger and includes third-party libraries, the bundle size can become a performance bottleneck. This is where code splitting becomes crucial.

Code splitting is a technique that lets you break up your code into smaller pieces, which helps your app load faster. Instead of loading everything at once, it only loads what it needs to get started. Then, as your users navigate around the app, it loads the additional code as needed. This makes the app run more smoothly and saves resources on your device and network.

Configured Build tools

Nuxt prioritizes performance by providing a build tool like Vite. Vite is a build tool that aims to provide a faster and leaner development experience for modern web projects. It offers out-of-the-box support for common web patterns and features like glob imports and SSR primitives.

Vite was created to tackle the problem of slow JavaScript-based tooling. It reduces the wait time to spin up a development server and for changes to reflect in the browser. Vite also includes a pre-configured build command with many performance optimizations out of the box.

For example, Vite automatically extracts the CSS used by modules in your apps into an async chunk and generates a separate file for it. The file is then loaded via a <link> tag when the associated async chunk is loaded.

Server-side Rendering(SSR)

Nuxt has built-in server-side rendering (SSR) capabilities by default, which enhances performance.

With SSR, a webpage is fully rendered on the server before it reaches the browser, resulting in a faster perceived page load time and better user experience, especially on slower networks or devices. SSR eliminates additional round-trips for data fetching and templating on the client side, which improves performance.

As we know, site speed is a factor in search ranking. Server-side rendered (SSR) pages are rendered on the server and do not rely on users’ browsers and devices to process the JavaScript needed to run the page. This means that SSR pages are immediately available to be crawled. They do not require JavaScript to render content on the client side, which allows search engines to more easily index them.

Optimizing Performance in Nuxt 3

Despite all the baked-in features that help Nuxt performance by default, these techniques may not be enough to maintain good performance as your app scales. This is especially true if you have many media files and JavaScript files in your application.

So how can we make more customized enhancements to improve the performance of our Nuxt 3 apps over time?

Image Optimization

When working with images, it’s important to ensure they are of high quality and display correctly for the user (without being stretched or compressed). Often, images are large, which can significantly impact page load time, especially when you have multiple large images.

To address this problem, you can use newer image formats like AVIF and WebP instead of older ones like JPEG and PNG. These newer formats are better at compressing images while maintaining high quality, which makes them faster to load and use less data.

Another way to optimize images is to use the NuxtImage module to render your images. This module helps resize and transform images using the built-in optimizer or your preferred image CDN, it also offers support for webp and avif image formats.

Another way to optimize images is to serve images from an image Content Delivery Network. An Image CDN focuses on the delivery and optimization of images across the internet. It is a specialized subset of CDN services that is designed to efficiently store, cache, and deliver image files to end users. Cloudinary is an example of an image CDN.

Lazy Loading Components

As applications get larger, developers start to think of ways to reduce code duplication and repetition. This is how the concept of “components” was created.

But there are times when certain components are being used in several files, which involves importing such components over and over again.

With dynamic imports, we do not need to import such components into each file before we can use them. Also, by prefixing these components’ names with Lazy, they get to be lazy-loaded which means they are not loaded until they are absolutely needed, which can be helpful for optimizing JavaScript bundle size.

Delayed Hydration

Delaying hydration is a technique to hint to Google that our scripts are not required for our app to function. By doing this on your site, it improves performance by reducing the ‘Blocking Time” for your apps.

Nuxt has a nuxt-delay-hydration module which helps achieve delayed hydration. This module injects a promise into your app using a location that is specified based on the mode, which is resolved as soon as any of the following events is fired:

  • an interaction event (mouse move, scroll, click, etc)
  • an idle callback with a fixed timeout

Putting it into Practice

In order to see all of these performance impacts on a real project, you’ll want to check out part 2 of this series as we take a Nuxt 3 project and boost its performance with the tools available to us.

Download the cheatsheets

Save time and energy with our cheat sheets.