Journey to a

performant website

Prashant Palikhe

Nepal 🛫 🛬 Netherlands

@prashantpalikhe

What is fast enough?

90+ on Google PSI

< 1000ms SpeedIndex on WebPagetest

90+ on PWA Lighthouse

Profiling & analysing

Content efficiency

whatdoesmysitecost.com

Compress and cache

Easily achievable by configuring web server

h5bp/server-configs

Gzip text-based assets

Brotli for higher compression

Include image optimisation in build process

Use progressive jpegs

WebP for ~30% savings

<picture>
    <source srcset="2x.webp 2x, 1x.webp 1x" type="image/webp">

    <source srcset="2x.jpg 2x, 1x.jpg 1x" type="image/jpeg">

    <img src="fallback.jpg" alt="">
</picture>

Lazy load images

Intersection observer to detect elements in viewport

// create observer
const observer = new IntersectionObserver(onChange);

function onChange(changes) {
	changes.forEach(change => {
	    // take image url from `data-src` attribute
	    change.target.src = change.target.dataset.src;

	    // stop observing the current target
	    observer.unobserve(change.target);
  	});
}

// convert node list to array
const imgs = [ ...document.querySelectorAll('.lazy') ];

// observe each image
imgs.forEach(img => observer.observe(img));

requestIdleCallback() to prevent scroll jank

Optimize web fonts

Use lightweight woff2

Font-loader to get around lazy font-loading

Render text asap with system font

Render actual font when available

<style>
    body {
        font-family: Arial, sans-serif;
    }

    body.has-fonts-loaded {
        font-family: "My fancy font";
    }
</style>


<script>

someFontLoader
    .load('My fancy font')
    .then(() => {
        document.body.classList.add('has-fonts-loaded');
    });

</script>

Using system UI fonts

body {
    font-family:
        /* 1 */ -apple-system, BlinkMacSystemFont,
        /* 2 */ "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
        /* 3 */ "Helvetica Neue", sans-serif;
}

<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin=""> />

Cache your static content

 cache-control:immutable

to prevent revalidations

Trash junk CSS/JS

DevTools coverage

Inline critical CSS & load the rest async

Critical CSS within

first 14kb

TCP starts slow

addyosmani/critical

github.com/

Eliminate network

Service Worker

// index.html

if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/sw.js');
}

[1/4] Download

// sw.js

self.addEventListener('install', (event) => {
    // Prime your cache 
});

[2/4] Install

// sw.js

self.addEventListener('activate', (event) => {
    // This SW is taking control, clean up old caches and do migration work if needed
});

[3/4] Activate

// sw.js

self.addEventListener('fetch', (event) => {
    // Intercept network requests, resolve from cache if hit.
});

[4/4] Intercept

🏅100 on Google PSI

🏅~1000ms SpeedIndex

🏆 100 on Lighthouse

Thanks!

Journey to a performant website

By Prashant Palikhe

Journey to a performant website

  • 798