WebP and Drupal: Performance, the Last Frontier

WebP is an image format introduced by Google with the aim of improving the size and performance of images on the web.

In Google's own words :

WebP is a modern image format that provides superior lossless and lossy compression for images on the web. Using WebP, webmasters and web developers can create smaller, richer images that make the web faster.

The promise is to save around 20 to 30 percent of space on images using WebP and, as you'll see in this article, this claim is consistent with the results I've found myself using WebP in Drupal.

I won't go into more details about WebP, but if you are interested in more information about the subject please visit this link: https://developers.google.com/speed/webp/.

There is also a comparative study between jpeg and WebP, and the advantages of using WebP. You can read it here: https://developers.google.com/speed/webp/docs/webp_study

The next important thing to keep in mind: which browsers support WebP, and this together with our own project requirements will define how we will attack this implementation. We’ll see that later, for now the list is here: https://caniuse.com/#feat=webp.

webp supported browsers


As we can see most of the browsers support WebP, with the exception of Safari, the old venerable IE, iOS Safari, and a few other less used browsers. It seems that Safari support could be coming though, for it is marked as “Safari is experimenting with supporting WebP images.”

LET'S START

I'm going to show you two different methods of getting WebP working in Drupal 8.

The first one is very easy to setup and start getting results. However if support for all browsers is important to you, you'll have to work a bit more on your theme layer, as we'll see later.

On the other hand, the second approach just implies installing one module, WebP. Once installed you won't need to work a lot more. At the moment of writing the module does not have a stable version, but that's something I'm planning to fix soon.

INSTALLING REQUIREMENTS AND SETTING UP THE SITE

For the purpose of this article, I have installed a new Drupal 8, and I’ll be using the content type "Article" that comes by default with a new Drupal 8 site.

webp steps configuration

The field image that comes by default and that you can see in the screenshot will be the base for what we’ll be converting into WebP images.

Drupal is ready; now you'll have to make sure that your local version has Imagemagick and WebP binaries support in the toolkit itself. GD also supports WebP, and with the second method you can actually choose to use IM or GD.

In Linux, you'll have to do something like this, below. We also tested this in ddev and ADS (Acquia Developer Studio). While in ADS support should be coming soon, right now you can adding WebP support editting your .lando.yml (in the root of your project) and adding build_as_root. Your file will end up looking something like this:

Configuring ADS with webp
name: webpsite
recipe: drupal8
config:
  webroot: docroot
services:
  appserver:
    overrides: {image: 'acquia/ads-local:lando-php'}
    build_as_root:
      - apt-get update -y
      - apt-get install -y libwebp-dev libwebp6 webp libmagickwand-dev
      - docker-php-ext-configure gd --with-freetype-dir=/usr --with-png-dir=/usr --with-jpeg-dir=/usr --with-webp-dir
      - docker-php-ext-install gd

If you are into ddev instead, you'll have to edit .ddev/config.yaml and add these files:

hooks:
 post-start:
   - exec: "sudo apt-get update"
   - exec: "sudo apt-get install -y webp"

Now, this is your local. You need to make sure that wherever you are uploading your site, WebP support is also enabled. If it's self-hosting repeat the steps in your local if necessary.

The good news is that if you are in Acquia Cloud this has already been taken care of for you, so you don't need to do anything else there, apart of deploying your Drupal site, of course.

All right, let’s do this.

Method 1. ImageMagick.

ImageMagick (IM) is a toolkit that allows you to do a lot of… ehrm, magic, to your images when you are uploading them to Drupal: from resizing to rotating, to adding backgrounds, to more boring but highly important activities in a Google dominated world, like resizing and optimizing images for the big audiences. Chances are that if you've been using Drupal, you have used IM at some point.

Installing ImageMagic is like installing any other Drupal module:

composer require drupal/imagemagick
drush en -y imagemagick

We’ll have next to make some changes in IM configuration, so it accepts WEBP format. Let’s head to the configuration area:

admin/config/media/image-toolkit

WebP as a format should be already present, but probably appears as:
 

enabled:false

We’ll need to remove or change to:

WEBP:
  mime_type: image/webp
  enabled: true

From this point, if we visit any of our image styles, for example the default:
 

admin/config/media/image-styles/manage/large

We should be able to add a new convert effect, and see our shiny brand new WebP format, such as in the next image:

web convert effect in Image Magick

Let’s create a new image style, select convert effect, and then WebP. That’s it. We can now create a new article, add a new image and fill the rest of the fields. I have used a big image in order to highlight as much as possible the benefits.

webp advantage vs jpg

 

In the image you can find two things. The first one is that, yes, I love motorbikes. Secondly, and most important for what we are doing, the images have gone down from the original 19MB to a few kb. Using JPEG we have squeezed the image to a whopping 53kb, which is already an amazing saving, but if we look at the WebP format (in the left image), we can see how the same image, using the same quality (75%) has compressed the image into an amazing 41kb.

This is pretty much the benefits that we are promised when using WebP (around 20% reduction versus jpg). It does not seem much, but if we are talking about network performance, every single kb that we can squeeze from the images is a massive improvement, especially if we talk about several dozens or hundreds of images across the site (or sites).

Now, at the beginning of the article I mentioned the browsers that support WebP. If all browsers were supported we would not need to do anything else. However that is not yet the case, so depending on our needs, we'll have to decide if this is good enough, or if we cannot afford having Safari (and the other non supported browsers) with a broken image like this:

safari showing a webp broken image

The way Google and WebP project recommends you to implement WebP and solve this is to have a fallback scenario in case the browser in which the user is viewing the content does not support the format. For example:

<picture> 
<source srcset="img/awesomeWebPImage.webp" type="image/webp"> 
<source srcset="img/creakyOldJPEG.jpg" type="image/jpeg"> 
<img src="img/creakyOldJPEG.jpg" alt="Alt Text!"> 
</picture>

For backgrounds or any other CSS-loaded elements you can apply something like this:

.no-webp .elementWithBackgroundImage {
  background-image: url("image.jpg");
}
 
.webp .elementWithBackgroundImage{
  background-image: url("image.webp");
}

In case you want to know more about this and WebP in general, there are some good sources out there, for CSS tricks, or the WebP project itself

Translating all this into the Drupal land, this could be achieved with a hook preprocess, or in your own theme displaying something like the html that I was showing before for the field image.

WebP module follows a similar approach, see for example: 
 

function THEME_preprocess_responsive_image(&$variables) {
  $placeholder = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; //1x1 Px placeholder
 
  foreach ($variables['sources'] as $source) {
    /** @var \Drupal\Core\Template\Attribute $source */
    $original_url = $source->offsetGet('srcset')->value();
 
    $source['data-srcset'] = $original_url;
    $source['srcset'] = $placeholder;
  }
}

We are simply modifying the source which will be generated to include one version with the WebP format, which will be the default one, and the fallback option with the original non-WebP image when the browser does not support the optimized version.
 

Method 2a and 2b. WebP module

A simpler method to do this is using the WebP Drupal module: https://www.drupal.org/project/webp which, to add confusion, can be used in two different ways (although the first one is not recommended, and as project maintainer I plan to deprecate at some point).

First and quicker, just applying some changes in our .htaccess as explained in the module readme. The advantage of the first one is that we just need to install the module, add those few new lines to our .htaccess and that’s it. No configuration needed, no change in our theme layer, etc.

The disadvantage is that in my experience the .htaccess method does not work very reliably, and it’s not the best approach to do WebP according to Google or the WebP maintainers themselves.

Let’s start installing the module, if you use composer and drush it would look like this:

composer require drupal/webp
drush en -y webp.   # Todo : Use dev versión and explain 

As I mentioned, if you do the .htaccess, that will not require a lot more from you, but let’s see the second option, or method 2b. This issue added a new capability to the module, modifying the html to show the source as we were explaining in the method 1, using picture tag and having a fallback: https://www.drupal.org/project/webp/issues/2912442#comment-13186717

Note that at the moment this issue has been already merged and released as a new beta, so no need of patches.

For that, you’ll need to make sure that (1) the responsive module (which is part of core now) is enabled, and

(2) that you have added at least one responsive style in admin/config/media/responsive-image-style with the desired styles to work with:

webp responsive styles

and that your fields are using those responsive styles, enabled once you follow step (2). You’d do that for example in admin/structure/types/manage/article/display.

Using field responsive to enable webp

Now, if we open our site in Chrome or any other supported browser we’ll see that our images source code have changed to something like this:

<picture>
                <!--[if IE 9]><video style="display: none;"><![endif]-->
              <source srcset="/sites/default/files/styles/max_325x325/public/2019-07/IMG_1949-orig_19.webp?itok=yZGyfm_Z 244w, /sites/default/files/styles/large/public/2019-07/IMG_1949-orig_19.JPG?itok=Q4k4z1-p 360w, /sites/default/files/styles/max_650x650/public/2019-07/IMG_1949-orig_19.JPG?itok=hUF_TXH1 488w, /sites/default/files/styles/max_1300x1300/public/2019-07/IMG_1949-orig_19.JPG?itok=_WBWx1bc 975w, /sites/default/files/styles/max_2600x2600/public/2019-07/IMG_1949-orig_19.JPG?itok=RhJu7FQA 1950w" type="image/webp" sizes="(min-width: 1290px) 1290px, 100vw">
              <source srcset="/sites/default/files/styles/max_325x325/public/2019-07/IMG_1949-orig_19.JPG?itok=yZGyfm_Z 244w, /sites/default/files/styles/large/public/2019-07/IMG_1949-orig_19.JPG?itok=Q4k4z1-p 360w, /sites/default/files/styles/max_650x650/public/2019-07/IMG_1949-orig_19.JPG?itok=hUF_TXH1 488w, /sites/default/files/styles/max_1300x1300/public/2019-07/IMG_1949-orig_19.JPG?itok=_WBWx1bc 975w, /sites/default/files/styles/max_2600x2600/public/2019-07/IMG_1949-orig_19.JPG?itok=RhJu7FQA 1950w" type="image/jpeg" sizes="(min-width: 1290px) 1290px, 100vw">
            <!--[if IE 9]></video><![endif]-->
            <img property="schema:image" srcset="/sites/default/files/styles/max_325x325/public/2019-07/IMG_1949-orig_19.JPG?itok=yZGyfm_Z 244w, /sites/default/files/styles/large/public/2019-07/IMG_1949-orig_19.JPG?itok=Q4k4z1-p 360w, /sites/default/files/styles/max_650x650/public/2019-07/IMG_1949-orig_19.JPG?itok=hUF_TXH1 488w, /sites/default/files/styles/max_1300x1300/public/2019-07/IMG_1949-orig_19.JPG?itok=_WBWx1bc 975w, /sites/default/files/styles/max_2600x2600/public/2019-07/IMG_1949-orig_19.JPG?itok=RhJu7FQA 1950w" sizes="(min-width: 1290px) 1290px, 100vw" src="/sites/default/files/styles/max_325x325/public/2019-07/IMG_1949-orig_19.JPG?itok=yZGyfm_Z" alt="png fix" typeof="foaf:Image">
 
  </picture>

The important bit, <source srcset> is pointing to the WebP image that the module has created for you, but it is also offering to load the jpg version in case your browser does not support WebP format.

And all it took is just enabling the module and setting up the styles. In my opinion this is the easiest option, however as already mentioned, it really depends on the project, requirements, legacy code, etc.

Conclusion

WebP is a format that is going to give us some good improvements in image performance and, while until now setting it up and having it running un Drupal was not completely straightforward, hopefully now with some of the improvements that I've been doing in the WEBP module, and this article, you should all set to test it in your own sites.

Please give me some feedback and share the love about this in Twitter or LinkedIn.