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:
- Why Nuxt?
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.
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.
Cache assets 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!
<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.
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’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
--
<script nomodule="" src="/_nuxt/a230eea68ca24259c016.js" defer=""></script>
<script type="module" src="/_nuxt/0ce5ca1f220b7ebc1f9a.js" defer=""></script>
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.