Pages

Tuesday 21 April 2020

Easy tool for Pagespeed optimization

Last october, I talked at Duugfest about Google Pagespeed and how to optimize your page for scoring high ...  having a fast, mobile-friendly website.

I even blogged about it in februari, after winning the Google Hackathon and in more technical detail  here.

One of the things I mentioned at Duugfest was that I had made a "tool" (an MVC ActionFilterAttribute) that would post-process all rendered HTML and "do something" with all the images.
Hang tight, I'll get less vague in a minute.

More than one of you asked if I could share the code for the filter, and it took me until now to get around to that. So, I created a nuget package with my ActionFilter and called it Our.Umbraco.PageSpeed. The intention is to add more tricks as I devise them along the way.

The reason for this one-filter-catches-all approach is 2-fold.

1. Lazy-loading

Google Pagespeed Insights recommends lazy loading your images. It's very easy to use LaySizes for it. So easy, in fact, that I won't repeat anything you can easily read in their README.

Now, what you'll have to do, is go through all your code (views, partial views, ...) and tweak your images a bit.
Basically, your images look like this:

<img data-src="image.jpg" class="lazyload" />

There are reasons NOT to do this however:

  • it's boring, repetitive work, prone to errors.
  • you may miss an image here and there. Nobody will notice, until you run Pagespeed insights.
  • you don't control ALL places where images are rendered. E.g. a content editor can put an image inside a richtext-field.

A filter will just parse the HTML and replace all images. None are missed, no typo's are made.

2. Serve images in better formats

Google suggest serving images in WEBP, as it is a better format than jpg, png, ...
Not all browsers support it, however, so you may want to resort to using <picture> instead of <img> and provide multiple images, out of which your browser can choose, depending on it's capabilities.

This would mean something along the lines of:

<picture>
  <source type="image/webp" src="webp-version of image.jpg" />
  <source data-src="image.jpg" class="lazyload" />
</picture>
If only there was a way of converting images to webp without requiring our content editors to manage multiple versions of each image.

But wait, there IS : ImageProcessor is baked in in Umbraco and has a plugin for Webp.


Combining it all 

Now, if we combine the possibility of

  • replacing all our img-tags on-the-fly by source-tags,
  • providing a way to convert to Webp,
  • lazy loading the result.
we get the following:

<picture>
  <source type="image/webp" data-src="image.jpg?format=webp&quality=70" class="lazyload" />
  <source data-src="image.jpg" class="lazyload" />
</picture>

How to achieve this?

  1. Install LazySizes in your project as per their instructions.
  2. Install nuget ImageProcessor.Plugins.WebP
  3. Install nuget Our.Umbraco.PageSpeed
  4. Decorate your controller with the LazyLoadFilter-attribute
[LazyLoadFilter]
public class MyRenderMvcController : RenderMvcController
{
    public override ActionResult Index(RenderModel model)
    {
        //Do stuff here. Or not, see if I care.
        return base.Index(model);
    }
}

And for all those DocTypes that you didn't write a Controller for. How do you make sure they get their fair share of the fun?

For these, you can set the default Controller to your MyRenderMvcController, and it will also benefit from the LazyLoadFilter-attribute.

DefaultRenderMvcControllerResolver.Current.SetDefaultControllerType(typeof(MyRenderMvcController));

If you want to give this a go and it doesn't work for you for any reason, give me a shout and we'll figure something out.

No comments:

Post a Comment