Build a lazy loading image component for Nuxt.js

In the most lazy way possible.

Google Lighthouse tests show lazy loading images is an easy win for performance. So here’s how.

Credit goes to Alex for his post on this topic

Import `lazysizes`

lazysizes is a fast (jank-free), SEO-friendly and self-initializing lazyloader for images (including responsive images picture/srcset), iframes, scripts/widgets and much more. It also prioritizes resources by differentiating between crucial in view and near view elements to make perceived performance even faster.

First, follow the steps that Alex has detailed.

The first part of Alex’s article, installing and importing lazysizes into Nuxt, is what we need for this project.

The second part of the article, image optimisation, isn’t necessary for this component but is well worth a look.

Change the build extend method

Adding LazyImage: ['src'] to transformAssetUrls lets webpack know that the src should be transformed if needed.

extend(config, { isClient, isDev, loaders: { vue } }) {
vue.transformAssetUrls.LazyImage = ["src"];
}

As I run SSR using yarn generate, I need the asset url transform to happen on the server too; the isClient check is removed.

You can leave the other lines in from the article if you want, but they are not necessary for this component.

For more info on the transformAssetUrls property, checkout this bootstrap article.

Create a LazyImage component

<template>
<img class="lazyload" :data-src="src" src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkqAcAAIUAgUW0RjgAAAAASUVORK5CYII="
/>
</template>
<script>
export default {
props: {
src: { type: String, required: true }
}
};
</script>

The src attribute is initially set with a transparent pixel. This prevents showing the broken image icon on the page on load.

The data-src attribute (used by lazysizes) is set by relocating the src property from the parent.

Register the component for global use

import Vue from "vue";import LazyImage from "@/components/LazyImage";Vue.component("LazyImage", LazyImage)

Register the plugin in the nuxt.config.js

Using the LazyImage component

<LazyImage class="my-class" src="/some/asset.png" alt="something" />
<!-- becomes -->
<img class="my-class lazyload" data-src="/some/asset.png" alt="something" />

Any attribute not matched by the props object is added to the img tag automatically.

<!-- Can use property and event binding too -->
<LazyImage
class="my-class"
custom-attribute="custom value"
:src="transform(myObj.imageSrc)"
:alt="myObj.alt"
@click="doSomething"
/>