Bovenkant pagina

Blog

Faster Nuxt sites on Netlify

Tuning Nuxt and Netlify to work together

Nuxt and Netlify both aim to make user experiences as fast and smooth as possible. From Nuxt’s homepage:

With Nuxt.js, your application will be optimized out of the box. […] To squeeze every unnecessary bit out of your app Nuxt includes a bundle analyzer and lots of opportunities to fine-tune your app.

- Why Nuxt?

Netlify, as a platform, has a world-wide Content Delivery Network (CDN) and a smart resource caching strategy setting max-age=0, must-revalidate, public, effectively telling the browser to cache all resources but to check-in with the server to verify it’s still fresh.

So with Nuxt and Netlify we get a lot performance out-of-the-box. But we can make things even faster by tuning Nuxt and Netlify to work together. This is how:
  • Cache assets forever
  • Split assets from app bundle
  • Remove unused Nuxt features
  • Serve modern bundles

Nuxt is powered by Vue.js. Do you want to become a Vue master? During our two day hands-on workshop we’ll teach you everything you need to know to build large performant web apps with Vue.

Join our Vue masterclass

Cache assets forever

Nuxt does a great job by hashing all of its JavaScript bundles, making sure each bundle has a unique filename. When the bundle content changes, the filename changes as well. This enables us to cache them forever! Nuxt serves bundles from the /_nuxt/ folder. Let’s configure Netlify to cache files in this folder forever:

# static/_headers

# docs: https://www.netlify.com/docs/headers-and-basic-auth/#multi-key-header-rules
/_nuxt/*
  Cache-Control: max-age=365000000
  Cache-Control: immutable

This strategy can be applied for other assets as well. Basically, all fonts and images can be cached. Nuxts assets folder comes into the picture here. Let’s try to move as many assets as possible from the static folder to the assets folder. Assets in this folder are hashed and end up in the /_nuxt/ folder after a build, just like our bundles. Now all these assets will be cached forever too!

Split assets from app bundle

Now that we’re talking about assets, there is one kind of asset that impacts your performance more than you would think: SVG icons. There’s a good chance you’ve set up vue-svg-loader to load your icons. And there’s good reason to: having SVGs inlined in the html output enables us to do cool things like overwriting styling properties from our CSS and animating them.

However, this loading strategy comes with a price: our icons are included in our app.js bundle. Therefore our icons impact the critical path for our site to load and become interactive.

Fortunately, we can solve this by using Nuxt SVG sprite: a module that sprites all your SVG assets together and serves them as one SVG file. This single SVG file gets hashed and ends up in the /_nuxt/  folder, so Netlify will leverage caching on our icons as well!

The Nuxt SVG sprite module provides great developer experience, by injecting a global component to use your icons in your templates:

<svg-icon name="sample" />

This will output the following HTML:

<svg xmlns="http://www.w3.org/2000/svg">
    <use href="/_nuxt/722f7bfaeddba2b3577b8f83c9ce5ed0.svg#i-sample" xlink:href="/_nuxt/722f7bfaeddba2b3577b8f83c9ce5ed0.svg#i-sample"></use>
</svg>

The effect of the <use> tag is like the original SVG nodes are cloned, enabling us to still treat it like an inline SVG for styling purposes, without affecting our critical path.

If you need IE11 support, be aware IE11 doesn’t support the <use> tag with external URI’s. This can be solved by using svg4everybody: a package to fall back to loading sprites over XHR and injecting them into the HTML.

Remove unused features

By default your Nuxt websites ships an app.js bundle containing all core features. But what if we don’t use some of these features? It’s a waste to let users download and parse these excessive kilobytes of JavaScript.

Nuxt app.js size (48kb default vs 42kb with fetch and validate disabled)

Since Nuxt 2.10.0 an undocumented, powerful and yet dangerous feature has been released. It’s now possible to disable unused features in Nuxt. To research how much we can shave off our app.js, I created an empty Nuxt project and disabled fetch and validate. By doing so, our app.js bundle size reduced from 48kb to 42kb (13%).

Nuxt app.js size (48kb default vs 28kb with all core features disabled)

By disabling all Nuxt features, we were able to bring it down to 28kb (42%). Of course there’s no point in disabling all Nuxt features, but it’s nice to see we’re able to shave off that much.

Nuxt’s core contributor mentioned feature detection might be used in Nuxt 3 to automagically enable features once you’re using them. So this optimisation might be automated in the future. Awesome!

Serve modern bundles

You can run nuxt generate --modern to tell Nuxt to output two versions of each JavaScript bundle: a legacy one and a modern one. The generated HTML will now contain two script tags per bundle:

<script nomodule="" src="/_nuxt/a230eea68ca24259c016.js" defer=""></script>
<script type="module" src="/_nuxt/0ce5ca1f220b7ebc1f9a.js" defer=""></script>

Legacy browser’s don't support JavaScript modules. Therefore they won’t load the modern bundles. Modern browsers supporting esmodules, won’t load the legacy scripts since Nuxt attaches a nomodule attribute. This enables us to serve code optimised for the users browser!

Total bundle sizes (114kb without modern flag vs 104kb with modern flag)

For voorhoede.nl, we’ve been able to reduce our total JavaScript footprint from 114 kilobytes to 104 kilobytes (9% reduction).

Please notice Nuxt now builds a doubled number of JavaScript bundles, increasing your build minutes usage on Netlify. If this is problematic, check out our blog post 10x faster Nuxt builds on Netlify.

More performance optimisations

Want to make your Nuxt apps even faster? Here’s a few more suggestions of what you could do:
Have fun making the web faster!
← Alle blogposts

Ook verliefd op het web?

Technologie en gebruikservaring. Snel, toegankelijk en een plezier om te gebruiken. Maar ook een plezier om te ontwikkelen. Geldt dit ook voor jou?
Kom ons versterken