I’m usually quite pedantic when it comes to minimizing code and optimizing web page performance. I was a bit surprised to find that this blog’s page speed was far from ideal! Google PageSpeed Insights returned a very low score for this blog. Back when I started this blow, I must’ve neglected optimization, as I was too busy learning Grav, modifying my template, etc.

Grav Settings

I assumed that Grav’s default settings would optimize the HTML, CSS and JS generated by the templates and plugins, but in my case, I had to enable a few settings in the Grav Configuration page:

  • Under Caching > enable Gzip compression
  • User Assets > enable CSS pipeline and JavaScript pipeline - which according to Grav Documentation, merges multiple CSS and JS files together.

After any changes, remember to head back to the Grav Dashboard and Clear Cache. Then, reload the page in a New Private Window or clear your web browser cache to see the changes take effect.

Grav Configuration Assets for CSS and JavaScript pipeline

Moving JavaScript out from the Head Element

I edited my template file /user/themes/mytheme/templates/partials/base.html.twig (which overrides the default Antimatter file of the same name), moving all JavaScript out from the <head> element to the end of the page, just before the closing </body> tag:

The original file had a structure like this:

    {% block head %}
        {% block javascripts %}
            {% do assets.addJs('theme://js/antimatter.js') %}
            {% do assets.addJs('theme://js/slidebars.min.js') %}
        {% endblock %}
    {{ assets.js() }}
    {% endblock %}
    {% block bottom %}
        {{ assets.js('bottom') }}
    {% endblock %}

You can easily guess that I moved {{ assets.js() }} from the <head> to the <body> just above {{ assets.js('bottom') }}. I’m sure the developers had a good reason from scripts in the header, but I don't care - this still works for me.

In-Line JavaScript

I noticed some plug-ins like Featherlite and Highlight were inserting in-line Javascript to the HTML pages that would render the JavaScript pipeline less effective. So, knowing I’ll regret it later, I went into the plugins folder and changed the addInlineJS function calls, e.g. in /user/plugins/highlight/highlight.php, I made the following change:

$this->grav['assets']->addJs($init, 'bottom');

My theme and plugins used Grouped Assets.

Delay loading CSS

I also noticed my Font Awesome CSS was blocking. Per Start a New Project guide at FontAwesome, the typical method of including Font Awesome via a CDN is to include the following in the HTML <head> element:

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" 

Modern browsers have a rel="preload" attribute to load the link in the background but not actually apply it. So, to load Font Awesome’s CSS asynchronously, I used the simplest method described at Modern Asynchronous CSS Loading - which is to use JavaScript to actually apply the CSS after it’s loaded:

<link rel="preload" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" 
      crossorigin="anonymous" as="style" onload="this.rel='stylesheet'">

You can read more at Mozilla, Preloading content with rel="preload".

Caveat: No JavaScript, not Font Awesome!


I also got rid of wow.js - see How to stop WOW.js from killing your SEO.

Finally, I've posted about JPEG and PNG compression optimization before - do optimize and re-optimize images. I use ImageOptim.


PageSpeed Insights before making the changes above, for Mobile:

PageSpeed Insights before optimizing Grav

After making any changes, prior to running PageSpeed Insights, do load your homepage at least once in your browser for Grav to cache the output - the first run takes a longer time!

And after:

PageSpeed Insights after optimizing Grav

I got similar improvements for Desktop - 93, up from 63! I think more can be done, but this’ll do for now!

Short blurb, dated 21 May 2019: If you really want “optimization,” check out my post on My Custom Grav Theme, any my final PageSpeed Insights score of 99!