1 of 62

Building a Fast Website for every single visitor

2 of 62

What makes the web user so special?

2G

3G

4G

5G

@med7atdawoud

3 of 62

Developers are privileged

4 of 62

Building a Fast Website for every single visitor

More Accessible

5 of 62

Medhat Dawoud

Senior Software Engineer at Miro

Google Developer Expert in #WebPerf

๐• @med7atdawoud

medhat.dev

6 of 62

Performance depends on the user perception

๐ŸŽ๏ธ

๐Ÿš—

๐Ÿšดโ€โ™‚๏ธ

๐Ÿ›น

Wow, this is so fast ๐Ÿคฉ

Oh no, this is so slow ๐Ÿ™„

7 of 62

Would a motorcycle be considered fast or slow?!

๐ŸŽ๏ธ

๐Ÿš—

๐Ÿšดโ€โ™‚๏ธ

๐Ÿ›น

๐Ÿ๏ธ

It is slow

It is fast

8 of 62

#2 Field Testing

#1 Lab Testing

How to measure performance?

9 of 62

Core Web Vitals

10 of 62

Device Distribution

11 of 62

Connection Distribution

12 of 62

No one-size fits all

13 of 62

Pick a Target

๐Ÿ˜ More A11y but poor UX

๐Ÿ˜ poor A11y but great UX

@med7atdawoud

To build a web app for the user with guaranteed conditions

To build a web app with cutting edge tech for best user conditions

๐Ÿ˜ข

๐Ÿ˜Š

low-end

high-end

๐Ÿ˜Š

๐Ÿ˜ข

low-end

high-end

14 of 62

15 of 62

Or, build for everyone

๐ŸŽ‰ Best A11y and best UX for everyone

@med7atdawoud

a web application that can adapt to user conditions

๐Ÿฅณ

๐Ÿฅณ

low-end

high-end

๐Ÿฅณ

๐Ÿฅณ

low-end

high-end

๐Ÿฅณ

๐Ÿฅณ

low-end

high-end

16 of 62

Core features

Glory UX ๐Ÿ†

And Best DX

Graceful Degradation

Progressive Enhancement

17 of 62

What user-related factors are beyond our control?

@med7atdawoud

18 of 62

Screen Sizes

Browsers

Device (CPU + RAM)

Internet connection

What user-related factors are beyond our control?

@med7atdawoud

Seating position

โŒ

โŒ

Seating position

19 of 62

Screen Sizes

@med7atdawoud

20 of 62

Components should be responsive like water

21 of 62

Components should be responsive like water

Cats

22 of 62

Images are 60-70% of a webpageโ€™s total size

23 of 62

<img

src="spaceX-mechazilla.jpg"

alt="SpaceX Mechazilla" />

Regular HTML image tag

@med7atdawoud

~500KB

~500KB

~500KB

> 1024px

< 800px

< 480px

24 of 62

<img

srcset="spaceX-mechazilla-480w.jpg 480w, spaceX-mechazilla-800w.jpg 800w"

sizes="(max-width: 600px) 480px, 800px"

src="spaceX-mechazilla-800w.jpg"

alt="SpaceX Mechazilla" />

Responsive Images

@med7atdawoud

~500KB

~100KB

~36KB

> 1024px

< 800px

< 480px

25 of 62

Responsive Images (OOTB)

@med7atdawoud

https://developer.chrome.com/docs/aurora

<Image src="/me.jpg" />

๐Ÿค

<img

srcset="

/_next/image?url=%2Fme.jpg&w=640&q=75 1x,

/_next/image?url=%2Fme.jpg&w=828&q=75 2x

"

src="/_next/image?url=%2Fme.jpg&w=828&q=75"

/>

Input:

Output:

pixel density descriptor

26 of 62

const sharp = require('sharp');

const fs = require('fs');

const directory = './images';

fs.readdirSync(directory).forEach(file => {

sharp(`${directory}/${file}`)

.resize(200, 100) // width, height

.toFile(`${directory}/${file}-small.jpg`);

});

Server Different Images with different sizes using Sharp or ImageMagick

Or use an image service like Cloudinary or Vercel

@med7atdawoud

27 of 62

Browsers Support

@med7atdawoud

28 of 62

29 of 62

What causes a feature to be unsupported by a specific browser?

30 of 62

Gecko

Blink

Webkit

Blink

Rendering Engines

Blink

31 of 62

SpiderMonkey

V8

Nitro

V8

JavaScript Engines

V8

32 of 62

How can we determine if a feature is now supported?

33 of 62

34 of 62

Use Web APIs from the future

if("share" in window.navigator) {

} else {

// use regular 3rd party lib

}

await window.navigator.share(info);

35 of 62

Images (Again?)

<picture>

<source srcset="photo.jxl" type="image/jxl" />

<source srcset="photo.avif" type="image/avif" />

<source srcset="photo.webp" type="image/webp" />

<img src="photo.jpg" alt="photo" />

</picture>

@med7atdawoud

<img src="photo.jpg" alt="photo" />

โŒ

โœ…

36 of 62

Lossless 50:1 compression

37 of 62

38 of 62

Browserlist

@med7atdawoud

{

"browserslist": [

"> 0.25%",

"not dead",

"last 2 versions",

"Firefox ESR"

]

}

39 of 62

Device (CPU + RAM)

@med7atdawoud

40 of 62

@med7atdawoud

41 of 62

42 of 62

navigator.deviceMemory ๐Ÿงช

8

> window.navigator.deviceMemory

It returns the approximate device memory in GB

@med7atdawoud

43 of 62

import { createContext, useContext } from 'react';

// Device context to determine strength (simplified example)

const DeviceContext = createContext();

const DeviceProvider = ({ children }) => {

const deviceStrength = navigator.deviceMemory > 2 ? 'strong' : 'weak';

return (

<DeviceContext.Provider value={deviceStrength}>

{children}

</DeviceContext.Provider>

);

};

// Use in a component

const MyComponent = () => {

const deviceStrength = useContext(DeviceContext);

return deviceStrength === 'strong' ? <HeavyFeature /> : <LightFeature />;

};

44 of 62

@med7atdawoud

45 of 62

navigator.hardwareConcurrency

10

> window.navigator.hardwareConcurrency

Returns number of logical processors available to run threads on the user's computer.

@med7atdawoud

46 of 62

47 of 62

if (navigator.hardwareConcurrency) {

const cores = navigator.hardwareConcurrency;

console.log(`This device has ${cores} logical processor cores.`);

if (cores > 4) {

console.log("This device has a high number of cores, enabling advanced features.");

enableHighPerformanceMode();

} else {

console.log("Device has fewer cores, applying optimizations for lower CPU power.");

enableLowPerformanceMode();

}

} else {

console.log("Unable to detect hardware concurrency. Applying default optimizations.");

enableDefaultPerformanceMode();

}

48 of 62

@med7atdawoud

49 of 62

2G

3G

4G

5G

1G

Internet Connection

@med7atdawoud

50 of 62

@med7atdawoud

51 of 62

@med7atdawoud

52 of 62

SSR ?

Use <Form />

Works great without javascript, falls back to HTML form

53 of 62

Network Information APIs ๐Ÿงช

{

downlink: 3.85

effectiveType: "4g"

onchange: null

rtt: 50

saveData: false

}

> window.navigator.connection

@med7atdawoud

54 of 62

const networkType = navigator.connection.effectiveType;

if (networkType === '4g') {

// Load heavy assets (like high-quality images or videos)

} else {

// Load lighter assets (like lower-quality images)

}

55 of 62

56 of 62

@med7atdawoud

57 of 62

interface NetworkInformation : EventTarget {

readonly attribute boolean metered;

readonly attribute unrestricted double sustainedSpeed;

attribute EventHandler onchange;

};

UNOFFICIAL (PROPOSAL)

58 of 62

React Adaptive Hooks โš›๏ธ

import { useNetworkStatus } from 'react-adaptive-hooks/network';

import { useSaveData } from 'react-adaptive-hooks/save-data';

import { useHardwareConcurrency } from 'react-adaptive-hooks/hardware-concurrency';

export const Func = () => {

const { effectiveConnectionType } = useNetworkStatus();

// effectiveConnectionType can be slow-2G, 3G, 4G

. . .

}

59 of 62

โœ… Screen Sizes

โœ… Browsers support

โœ… Device (CPU + RAM)

โœ… Internet connection

Recap

@med7atdawoud

60 of 62

61 of 62

Resources

62 of 62

Thanks