How to Get a Perfect Lighthouse Score on Your Statamic Site

lokman musliu
Lokman Musliu

February 12, 2024 · 4 min read · 404 views

Statamic Blogpost Image

Having a high-performance website is not just a nice-to-have; it's essential for keeping users engaged and building a strong online presence. If you're using Statamic for your CMS, aiming for an excellent Lighthouse score is critical. A superior score improves performance, user experience, and search engine visibility. Let's walk through the steps we took to boost a client's Statamic site performance by 80% and how you can do the same for your site.

Upgrade to Statamic v4

Upgrading your site from an older Statamic version, like v2, to the latest version, Statamic v4, can seriously improve your site's performance. Every new release brings improvements that can optimize your site's speed and efficiency. This step alone can make a noticeable difference in how your site runs.

Optimize Site Elements for Performance

Optimize Sliders

Originally, the site had custom JavaScript for several sliders, which was inconvenient and prone to accessibility issues. By switching to Swiffy Slider, we capitalized on its small bundle size and accessibility features. This switch made a clear difference in performance and user experience.

Lazy Load with Async Alpine

By bringing in Async Alpine, we're lazy-loading Alpine.js components, so JavaScript only loads when it's needed for content on a specific page. This method makes everything run smoother by cutting down on loading JavaScript we don't need.

import AsyncAlpine from 'async-alpine';
import Alpine from 'Alpine.js';

AsyncAlpine
  .init(Alpine)
  .data(
		'slider',
		() => import('./components/Slider.js')
	)
  .start();

Alpine.start();

The following code ensures the slider only loads when it's within the user's viewport.

<div
  x-ignore
  ax-load="visible"
  x-data="slider"
></div>

Upgrade and Localize JavaScript Libraries

We updated critical JavaScript libraries like Alpine.js to the latest version, v3, and shifted away from using CDN script imports. By installing Alpine.js and Axios directly on the site, we minimized external requests and improved loading times. We also served fonts locally using Font Source for an extra speed boost. Plus, we set up lazy loading for non-essential scripts like Google Analytics and Bing to give performance another lift.

Enhance Video Embeds

To optimize YouTube video embeds, we developed a custom Statamic Tag that only loads videos when someone clicks on them. This approach saves bandwidth and boosts page speed, which is a win for user experience. We wrote a blog post about how to Optimize Video Embeds with a Custom Statamic Tag and Alpine.js.

Lighthouse score for a client

Accessibility and User Experience Improvements

Accessible Mobile Menu

We made significant accessibility enhancements to the mobile menu, improving users' navigation and positively impacting Google PageSpeed scores. Make sure you are using the nav tag and the necessary aria attributes. Here is a sample menu:

<nav class="py-5 bg-transparent md:py-6 shadow-nav" aria-labelledby="nav-heading" :aria-expanded="isOpen"
    @keydown.escape="isOpen = false" x-data="{ isOpen: false }" @click.outside="isOpen = false">
    <div class="container">
        <div class="flex flex-wrap items-center justify-between">
            <div class="flex items-center shrink-0">
                <a aria-label="logo" href="/">
                    {{ svg src="logo" }}
                </a>
            </div>

            {{ partial:partials.toggle_button }}
            <div class="w-full lg:flex lg:items-center lg:w-auto {{ $menu_classes }}"
                :class="{ 'block shadow-3xl': isOpen, 'hidden': !isOpen }">
                <ul
                    class="flex flex-col w-full px-3 mt-5 divide-y-2 lg:flex-row lg:items-center lg:divide-y-0 md:mt-0 lg:px-0 lg:py-0 lg:space-x-8">
                    {{ nav:navigation include_home="true" }}
                        {{ partial:components.menu_item }}
                    {{ /nav:navigation }}
                </ul>
            </div>
        </div>
    </div>
</nav>

Responsive Image Component

We switched all images over to Statamic's Responsive Image component. This move really helped our Cumulative Layout Shift (CLS) score by making sure images fit the device they're on, which is super important for user experience. Here is a sample Picture component:

{{ if image }}
    <picture>
        {{ asset :url="image" }}
            {{ if extension == 'svg' || extension == 'gif' }}
                <img class="{{ class }}" src="{{ url }}" alt="{{ alt }}" />
            {{ else }}
                <source
                    srcset="
                        {{ glide:url preset='xs-webp' }} 320w,
                        {{ glide:url preset='sm-webp' }} 480w,
                        {{ glide:url preset='md-webp' }} 768w,
                        {{ glide:url preset='lg-webp' }} 1280w,
                        {{ glide:url preset='xl-webp' }} 1440w,
                        {{ glide:url preset='2xl-webp' }} 1680w"
                    sizes="{{ sizes }}"
                    type="image/webp"
                >
                <source
                    srcset="
                        {{ glide:url preset='xs' }} 320w,
                        {{ glide:url preset='sm' }} 480w,
                        {{ glide:url preset='md' }} 768w,
                        {{ glide:url preset='lg' }} 1280w,
                        {{ glide:url preset='xl' }} 1440w,
                        {{ glide:url preset='2xl' }} 1680w"
                    sizes="{{ sizes }}"
                    type="{{ image.mime_type }}"
                >
                <img
                    {{ if cover }}
                        class="object-cover w-full h-full {{ class }}"
                        style="object-position: {{ focus | background_position }}"
                    {{ else }}
                        class="{{ class }}"
                    {{ /if }}
                    src="{{ glide:url preset='lg' }}"
                    alt="{{ alt ensure_right='.' }}"
                    {{ if lazy }}
                        loading="lazy"
                    {{ /if }}
                >
            {{ /if }}
        {{ /asset }}
    </picture>
{{ /if }}

Leverage Cloud Services and Server Configurations

Utilizing Cloudflare

By implementing services like Cloudflare, we were able to take advantage of its huge network to speed up response times. Cloudflare also adds an extra layer of security against malicious attacks, ensuring your site remains secure and reliable.

Use Statamic Static Caching

Whenever possible, we use full Static Caching on our Statamic sites. This approach minimizes server load, as every response is served as static HTML, enhancing speed and reliability.

Optimize NGINX Configuration

Optimizing your server's NGINX configuration to cache images and fonts can lead to a drastic reduction in load times. Effective caching strategies decrease the number of HTTP requests required, facilitating faster delivery of content to your audience. Here is a sample nginx config we use in our projects along with Static Caching:

# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/example.com/before/*;

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com;
    server_tokens off;
    root /home/forge/example.com/public;
    
    # Expires
    expires $expires;

    index index.html index.htm index.php;

    charset utf-8;

    # FORGE CONFIG (DO NOT REMOVE!)
    include forge-conf/example.com/server/*;

    location / {
        try_files /static${uri}_${args}.html $uri /index.php?$args;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/example.com-error.log error;

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
    
}

map $sent_http_content_type $expires {
    default    off;
    text/css    max;
    ~image/    max;
    application/javascript    max;
    application/octet-stream    max;
    application/font-woff      max;
    application/font-woff2     max;
    application/font-ttf      max;
    font/woff2    max;
}

# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/example.com/after/*;

By carefully applying these strategies, we significantly enhanced our client's site performance. Keep in mind that chasing that perfect Lighthouse score is a continuous effort – it needs regular checks and tweaks. With these insights, you're all set to start tuning up your Statamic site for better speed, efficiency, and a top-notch user experience.


Bring Your Ideas to Life 🚀

Kickstart Your Statamic Project with the #1 Statamic Agency

Are you planning a new Statamic project or thinking about migrating your WordPress site to Statamic? Learn more about our expertise as a renowned Statamic development agency.

lokman musliu
Lokman Musliu

Founder and CEO of Lucky Media

Technologies:

Statamic
Heading Pattern

Related Posts

Stay up to date

Be updated with all news, products and tips we share!