How to use the Storyblok Image Service with Vue.js

Contents

Assets uploaded to Storyblok are automatically available through a CDN, besides that you’re also able to transform, resize and modify those uploaded assets directly by changing parameters in the URL itself. You can checkout our documentation for the basic usage of it, best thing: it is already included into our free plan.

The basic Storyblok Asset URL structure

To enable the image service in Vue.js all you have to do is to replace some parts of the asset URL in Storyblok. Before we start, lets have a look at the structure of a freshly uploaded image (Thanks to Nathan Anderson Tejedor for this picture):

//a.storyblok.com/f/51376/6016x4016/328eff2b8c/nathan-anderson-fhijwobodrs-unsplash.jpg
    |                |       |        |                        |
    |_ Asset Domain  |       |        |__ unique ID            |__ file name on upload
                     |       |
                     |       |__ original size
                     |
                     |_ storyblok space ID

The above structure is the starting point for your implementation. You can calculate the aspect ratio for lazy-loading images right from the URL itself, without doing another API call.

Using a component Method in Vue.js

Lets move to the real image service: We’re able to use a method in Vue.js to add options to our Image URL, for this we only need the asset URL image and the transformation option as a string to combine it. The Storyblok image service also runs on a different subdomain so we need to replace that as well.

...
  methods: {
    transformImage(image, option) {
      if (!image) return "";
      if (!option) return "";

      let imageService = "//img2.storyblok.com/";
      let path = image.replace("//a.storyblok.com", "");
      return imageService + option + path;
    }
  }

First we check if we even got an image and if there are any options. After that all we have to do is to replace the domain and to add the options in front of the original path of the Storyblok Asset URL. Once we have added the method above, we can use it in our Vue.js template.

Resized to 200x200

Adding fixed values for width & height will result in a cropped image of the original:

<img
  :src="transformImage(imageSrc, '200x200')"
  alt="two man laughing at each other by Nathan Anderson"
>

The resulting src URL will be:

//img2.storyblok.com/200x200/f/51376/6016x4016/328eff2b8c/nathan-anderson-fhijwobodrs-unsplash.jpg
        |                     |       |
        |                     |       |_ Original Asset Path
        |                     |
        |                     |__ Option
        |             
        |__ Image Service Domain

Resized Proportional to Width

By replacing the first value with 0 instead of a fixed pixel amount, our image service will automatically calculate the right width based on the aspect ratio of the original image.

<img
  :src="transformImage(imageSrc, '0x400')"
  alt="two man laughing at each other by Nathan Anderson"
>

Resized Proportional to Height

By replacing the second value with 0 instead of a fixed pixel amount, our image service will automatically calculate the right height based on the aspect ratio of the original image.

<img
  :src="transformImage(imageSrc, '400x0')"
  alt="two man laughing at each other by Nathan Anderson"
>

Appling filters (Grayscale)

You’re able to combine resizing and filters to generate thumbnails of all kinds. In this case we will receive an image of the size 200x200 and completely grayscaled!

<img
  :src="transformImage(imageSrc, '200x200/filters:grayscale()')"
  alt="two man laughing at each other by Nathan Anderson"
>

Using a picture tag and format filter for webp

Utilizing a picture tag we can use the type property and the format filter to generate different versions including webp and png from our original jpg.

<picture>
  <source type="image/webp" :srcset="transformImage(imageSrc, '200x200/filters:format(webp)')">
  <source type="image/png" :srcset="transformImage(imageSrc, '200x200/filters:format(png)')">
  <img :src="transformImage(imageSrc, '200x200')" alt="two man laughing at each other by Nathan Anderson">
</picture>

Using a Vue.js filter method

Instead of adding the transformImage method to your Vue.js components you are able to use a Vue.js filter. To register a new Vue.js filter you can use the following source in your main.js:

Vue.filter("transformImage", function(image, option) {
  if (!image) return "";
  if (!option) return "";

  let imageService = "//img2.storyblok.com/";
  let path = image.replace("//a.storyblok.com", "");
  return imageService + option + path;
});

Usage of Vue.js filter in templates

The transformImage filter can now be used to output the image URL and transform the structure in your templates.

<div>
  {{ image | transformImage('100x0') }}
</div>

or as a property by calling the filter programatically:

<img
  :src="$options.filters.transformImage(imageSrc, '400x0')"
  alt="two man laughing at each other by Nathan Anderson"
>

Codesandbox example

You can checkout our codesandbox example for more options and filter combinations.


More to read...

About the author

Dominik Angerer

Dominik Angerer

A web performance specialist and perfectionist. After working for big agencies as a full stack developer he founded Storyblok. He is also an active contributor to the open source community and one of the organizers of Stahlstadt.js.