Minify, generate WebP and lazyload images in your Vue & Nuxt application
Tags: vue, nuxt, lazysizes, webp
Published: 2019-05-28 14:34:14

I wouldn't have written this post if standard image optimization flow hadn't been so tough to me. At first, all I wanted is to apply my favourite [`lazysizes`](https://github.com/aFarkas/lazysizes) to the app I'm developing now. I was stuck in this concept of modules and plugins and couldn't figure out what it actually is. Next step was image optimization and transforming current PNGs and JPEGs into WebPs — and that became a pain in the ass.

We all read posts like this to see a working example, so here it is!

## Inject lazysizes
`npm i lazysizes` — no need to explain.

Then create a `vue-lazysizes.client.js` file and put it into `@/plugins/` folder.  `.client` in the name signalizes server that this plugin shouldn't be run on server — it's important! This file shoud contain just two lines:
``` javascript
import lazySizes from 'lazysizes'
export default lazySizes
```

Configure `nuxt.config.js`:
```javascript
module.exports = {
  build: {
    extend (config, { isDev, isClient, loaders: { vue } }) {
      if (isClient) {
        vue.transformAssetUrls.img = ['data-src', 'src']
        vue.transformAssetUrls.source = ['data-srcset', 'srcset']
      }
    }
  },
  plugins: [
    '~/plugins/vue-lazysizes.client.js'
  ]
}
```
You can see that our "plugin" is inserted and in `build` key we extend Webpack config, so vue-loader can transform aliases in `data-srcset`, `data-src` and `srcset` attributes in `<img>` and `<source>` tags — we'll need it in future.

That's all! Now you can make images "lazy" as you usually do:
```html
<figure class="picture">
  <img data-src="~assets/images/image.png" class="lazyload" alt="Alternate text for the image">
</figure>
```

## Image optimization & convertation to WebP
But what about making images smaller and loading WebP images + fallback? After hours of struggling and many attempts with whole bunch of npm-packages I found brilliant module [`nuxt-optimized-images`](https://github.com/bazzite/nuxt-optimized-images). I prefer to use `mozjpeg` and `pngquant` for JPEG and PNG optimization respectively.

And this is how it should be cooked:

`npm i @bazzite/nuxt-optimized-images imagemin-mozjpeg imagemin-pngquant webp-loader --save-dev` — installation of dependencies.

Configure `nuxt.config.js`:
```javascript
module.exports = {
  modules: [
    '@bazzite/nuxt-optimized-images',
  ],

  optimizedImages: {
    inlineImageLimit: -1,
    handleImages: ['jpeg', 'png', 'svg', 'webp', 'gif'],
    optimizeImages: true,
    optimizeImagesInDev: false,
    defaultImageLoader: 'img-loader',
    mozjpeg: {
      quality: 85
    },
    optipng: false,
    pngquant: {
      speed: 7,
      quality: [0.65, 0.8]
    },
    webp: {
      quality: 85
    }
  }
}
```
Settings in `optimizedImages` key are arguable, but this is my choice.

After all these manipulations you can use this snippet finally:

```html
<figure class="picture">
  <picture>
    <source data-srcset="~assets/images/image.png?webp" type="image/webp">
    <source data-srcset="~assets/images/image.png" type="image/png">
    <img data-src="~assets/images/image.png" class="lazyload" alt="Alternate text for the image">
  </picture>
</figure>
```

Note that WebP image source is added with `?webp`.

With this great module you can go further and create, for instance, small SVG-fallback and use it while big image is loading. You can create responsive images, generate fallback color and (probably) much more. But let it be your homework for today.

Thanks for reading and I hope you'll find this post with Google before you spend couple of days on experiments like me.