Nuxt and Universal Web Applications
Nuxt comes with support for Vue.js for components and Vuex for state handling. Webpack provides the build automation. If you are more inclined to use React, have a look at Next.js for a similar functionality.
Making Nuxt faster
This post helps you to optimise this further by adding preview images and reducing the CSS included in the page. An upcoming post will cover how to optimise Nuxt for search engines and social media. I will show example code from this website (my homepage). I’ll introduce helpful plugins and their real-world use and configuration. Your requirements might be different, your mileage may vary depending on what you’re trying to achieve.
Extend Nuxt with webpack plugins
Showing pre-rendered HTML in the browser includes no images yet. The smaller the images are, the faster they will load. You can include preview images of a smaller resolution in the initial HTML while the user is waiting for the full image.
Optimise SVG images with imagemin
Even if you use small vector SVG images, they contain unnecessary comments and tags you can remove. When you automate this in your build with the image-webpack-loader, the SVGs you serve are always optimal. The original files in your repository will remain unchanged.
First you add the new plugin and save it to your package.json file. As a development dependency it runs only at build time, and will not increase the size of your app in the browser.
Then add the plugin to the build process. The following snippet shows the lines you add to your configuration. Leave all other lines unchanged.
The additional plugin configuration keeps the viewbox but removes the dimensions so Internet Explorer show the images in the correct size.
Optimise raster images with the responsive loader
Images in the correct size with optimal compression save bandwidth and speed up rendering your page, but this is tedious to ensure. The solution is the responsive loader plugin instead of the original image loader. Again, the original files remain untouched. Compared to minimising SVGs this takes more computing time during your build. It re-scales the images you use and also calculates previews. You can show the preview in the pre-rendered page while the browser loads the real image from the server.
Now you add the new loader to handle JPEG, GIF and PNG images, and tune the existing image loader to exclude them. For development you can skip generating previews and scaled images to speed up the build, but you cannot test the previews in development this way.
It compresses the images using the quality stated in the configuration (here: 85%). This reduces the size of the images if your original files have a higher quality.
The new loader adds resizing functionality. When you reference images in your style sheets, you can add query parameters. The plugin creates a scaled image at build time and replaces this with the filename of the resized image.
You can use this plugin to provide a scaled set of images as a source set. This allows the browser to select a pre-scaled image matching the screen resolution and displayed size of the image. While adding a source set is straightforward, you must also provide the sizes attribute with the expected size of the image depending on the screen’s width. If you don’t provide this attribute, the browser takes the full width of the window as the default and loads a bigger image than necessary. The following example sets the image widths via query parameters for this specific image. You can also provide defaults in the plugin’s configuration.
The following box shows the two images side by side instead of layering them on top of each other. The preview is 1.1k (gzip’ed) and will be inlined in the pre-rendered page, the full picture is 30k and will be loaded afterwards.
Things to watch out for:
Google Chrome will prefer a cached image with a higher resolution even if the sizes attribute indicates a smaller resolution. When you test and verify in the Network tab of the developer tools that the correct images are loading, you’ll need to issue a hard-reload or clear-cache-reload command. To do this, right-click on the reload button while your developer tools are open and choose the appropriate option.
Google Chrome will also load the images even when the element is hidden. To not load the image, clear the background image when element is hidden, and use the picture element to direct images to a placeholder.
Optimise CSS with purgecss
In the default configuration each pre-rendered page of Nuxt contains all the CSS your application needs. You can change this and externalise it to a file that every pre-rendered page links to, but this would cause a re-layout of the page if the browser doesn’t have a cached version of the CSS.
Once the user navigates within your Nuxt application, this is no longer an issue as Vue.js will not reload the page but only exchange the information rendered in the DOM.
When you use a CSS framework, the first page sent to the browser can become quite big. The plugin purgecss helps you to include only the parts of the CSS framework you used on the site. This will substantially reduce the size.
Purgecss can run as a webpack plugin or a postcss plugin. For Nuxt you must use it as a postcss plugin to keep the CSS inside the page. There is now also a Nuxt plugin to do this, but as the lines of code necessary are very similar, I used the webpack plugin directly.
As a developer you can choose if you want to have purgecss running in development mode:
When you make major CSS changes, you might need re-start the Nuxt development mode for purgecss to pick up the new CSS.
If you disable purgecss in development mode, you might miss a situation where it removed some CSS in the production build you wanted to keep.
I’ve settled for the first option here. If you want to try the second option, you can install nuxt-purgecss that has an automatic development.
First install the plugin:
This is my extended purgecss configuration. I’ve added additional content folders for purgecss to scan for CSS classes.
Purgecss needs some hints for CSS classes it can’t discover from the sources. It accepts these as a white list of CSS classes or as regular expressions. My white list includes the html and body tag that are present only in the generated index.html that’s not visible to purgecss. has-navbar-fixed-top is a CSS class I’ve set to the html tag using my Nuxt configuration using htmlAttrs (see below).
nuxt-progress is the progress bar when Nuxt is loading from the background, and nuxt-link-exact-active is the class added to Nuxt links when they are active. The layout and error pages use the __layout and __nuxt classes.
As I’m using font awesome, I add the svg-inline--fa classes it adds at run time.
Thanks reading this post. You have seen how to
boost your user experience with preview images,
speed up your website by minimising images and CSS, and
extend Nuxt with webpack and postcss plugins.
You’ve looked at real-life configuration examples that will give you an idea for your own projects. If you have questions, contact me via a direct message on twitter or via email, I’m happy to help.If you found this article helpful and you want to share it, please do so via the Twitter button below. If you found this article helpful and you want to share it, do so on Twitter.