SlideShare une entreprise Scribd logo
1  sur  163
@joshholmes
Performant
PWAs
Josh Holmes
josh.holmes@microsoft.com
@joshholmes
@joshholmes
Microsoft Edge and Chromium Open
Source: Our Intent
1. We will adopt Chromium as the web platform for Microsoft Edge
desktop.
2. We will evolve the Microsoft Edge app architecture, enabling
distribution to all supported versions of Windows including
Windows 7 and Windows 8, as well as Windows 10. We will also
bring Microsoft Edge to other desktop platforms, such as macOS.
3. We will offer our Windows platform expertise to improve the
experience of all Chromium-based browsers on Windows.
https://github.com/MicrosoftEdge/MSEdge
@joshholmes
A.K.A. “PWA”
@joshholmes
PROGRESSIVE WEB APP
@joshholmes
Game
Gallery
Book
Newspaper
Art Project
Tool
PROGRESSIVE WEB APP
@joshholmes
PROGRESSIVE WEB SITE
@joshholmes
PROGRESSIVE WEB SITE++
@joshholmes
PROGRESSIVE WEB SITE++
HTTPS
Manifest.json
ServiceWorker.js
@joshholmes
PWA IS
@joshholmes
PWA IS
@joshholmes
PWA IS
@joshholmes
PWA IS
@joshholmes
PWA IS
@joshholmes
PWA IS
@joshholmes
PWA IS
@joshholmes
PWA IS
@joshholmes
PWA IS
@joshholmes
PWA IS
@joshholmes
PWA IS
@joshholmes
https://www.pwabuilder.com/
@joshholmes
{"dir" : "ltr",
"lang" : "en",
"name" : "Twitter",
"scope" : "/",
"display" : "standalone",
"start_url" : "https://m.twitter.com/",
"short_name" : "Twitter",
"theme_color" : "#ffffff",
"description" : "",
"orientation" : "any", "background_color" : "transparent",
"related_applications" : "", "prefer_related_applications"
: "false",
"icons" : [ { "src": "https://abs.twimg.com/responsive-
web/web/icon-ios.8ea219d08eafdfa4.png", "sizes": "192x192"
} ]}
Manifest.json
@joshholmes
//Install stage sets up the offline page in the cache and opens a new cache
self.addEventListener('install', function(event) {
var offlinePage = new Request('offline.html');
event.waitUntil(
fetch(offlinePage).then(function(response) {
return caches.open('pwabuilder-offline').then(function(cache) {
console.log('[PWA Builder] Cached offline page during Install'+ response.url);
return cache.put(offlinePage, response);
});
}));
});
//If any fetch fails, it will show the offline page.
self.addEventListener('fetch', function(event) {
event.respondWith(
fetch(event.request).catch(function(error) {
console.error( '[PWA Builder] Network request Failed. Serving offline page ' + error );
return caches.open('pwabuilder-offline').then(function(cache) {
return cache.match('offline.html');
});
}
));
});
//This is a event that can be fired from your page to tell the SW to update the offline page
self.addEventListener('refreshOffline', function(response) {
return caches.open('pwabuilder-offline').then(function(cache) {
console.log('[PWA Builder] Offline page updated from refreshOffline event: '+ response.url);
return cache.put(offlinePage, response);
});
});
Service Worker
@joshholmes
//Add this below content to your HTML page, or add the js file to your page at the very top to register service
worker
if (navigator.serviceWorker.controller) {
console.log('[PWA Builder] active service worker found, no need to register')
} else {
//Register the ServiceWorker
navigator.serviceWorker.register('pwabuider-sw.js', {
scope: './'
}).then(function(reg) {
console.log('Service worker has been registered for scope:'+ reg.scope);
});
}
Register the SW
@joshholmes
/ˈfrikSH(ə)n/
@joshholmes
Poor performance
is friction
@joshholmes
Source: eMarketer
@joshholmes
Source: eMarketer
Which of
these matter
to your
context…
Always
measure
what
matters…
@joshholmes
A 1s delay in page
load can reduce
conversions by 7%
Source: Kissmetrics
@joshholmes
For an online shop earning
$100k/day, that’s about
$2.5m in lost sales
Source: Kissmetrics
@joshholmes
For Amazon, 1s is worth
about $1.6b in sales
Source: HubSpot
@joshholmes
Source: eMarketer
@joshholmes
53% abandon
websites that take
more than 3s to load
Source: Google
@joshholmes
By shaving 7s off load,
Edmunds increased
page views by 17%
& ad revenue by 3%
Source: HubSpot
@joshholmes
Mozilla reduced page load
by 2.2s and saw a 15.4%
increase in downloads
Source: HubSpot
@joshholmes
Performance
matters
@joshholmes
/dôɡˈfo͞odiNG/
@joshholmes
Let’s talk (briefly)
about page load
@joshholmes
time
Your Device The Web
DNS Lookup
Icons by Mahmure Alp
@joshholmes
time
Your Device The Web
TCP Handshake
Icons by Mahmure Alp
@joshholmes
time
Your Device The Web
Request
Icons by Mahmure Alp
@joshholmes
time
Your Device The Web
Server Processing
Icons by Mahmure Alp
@joshholmes
time
Your Device The Web
Response
Icons by Mahmure Alp
@joshholmes
Icons by Mahmure Alp
@joshholmes
WEB RUNTIME
ARCHITECTURE
@joshholmes
WEB RUNTIME ARCHITECTURE
Networking /
Cache
Parsers
1
2 7
43 8 9
5 6
DOM
Tree
Formatting Layout Painting
1
2 7
43 8 9
5 6
Display Tree
Compositing
DOM API
& Capabilities
JavaScript
DMANIP
Hit Testing
InputCSS Cascade
@joshholmes
WEB PLATFORM ARCHITECTURE
Networking /
Cache
Parsers
1
2 7
43 8 9
5 6
DOM
Tree
Formatting Layout Painting
1
2 7
43 8 9
5 6
Display Tree
Compositing
DOM API
& Capabilities
JavaScript
DMANIP
Hit Testing
InputCSS Cascade
@joshholmes
WEB PLATFORM ARCHITECTURE
Networking /
Cache
Parsers
1
2 7
43 8 9
5 6
DOM
Tree
Formatting Layout Painting
1
2 7
43 8 9
5 6
Display Tree
Compositing
DOM API
& Capabilities
JavaScript
DMANIP
Hit Testing
InputCSS Cascade
@joshholmes
WEB PLATFORM ARCHITECTURE
Networking /
Cache
Parsers
1
2 7
43 8 9
5 6
DOM
Tree
Formatting Layout Painting
1
2 7
43 8 9
5 6
Display Tree
Compositing
DOM API
& Capabilities
JavaScript
DMANIP
Hit Testing
InputCSS Cascade
@joshholmes
WEB PLATFORM ARCHITECTURE
Networking /
Cache
Parsers
1
2 7
43 8 9
5 6
DOM
Tree
Formatting Layout Painting
1
2 7
43 8 9
5 6
Display Tree
Compositing
DOM API
& Capabilities
JavaScript
DMANIP
Hit Testing
InputCSS Cascade
@joshholmes
WEB PLATFORM ARCHITECTURE
Networking /
Cache
Parsers
1
2 7
43 8 9
5 6
DOM
Tree
Formatting Layout Painting
1
2 7
43 8 9
5 6
Display Tree
Compositing
DOM API
& Capabilities
JavaScript
DMANIP
Hit Testing
InputCSS Cascade
@joshholmes
WEB PLATFORM ARCHITECTURE
Networking /
Cache
Parsers
1
2 7
43 8 9
5 6
DOM
Tree
Formatting Layout Painting
1
2 7
43 8 9
5 6
Display Tree
Compositing
DOM API
& Capabilities
JavaScript
DMANIP
Hit Testing
InputCSS Cascade
@joshholmes
WEB PLATFORM ARCHITECTURE
Networking /
Cache
Parsers
1
2 7
43 8 9
5 6
DOM
Tree
Formatting Layout Painting
1
2 7
43 8 9
5 6
Display Tree
Compositing
DOM API
& Capabilities
JavaScript
DMANIP
Hit Testing
InputCSS Cascade
@joshholmes
WEB PLATFORM ARCHITECTURE
Networking /
Cache
Parsers
1
2 7
43 8 9
5 6
DOM
Tree
Formatting Layout Painting
1
2 7
43 8 9
5 6
Display Tree
Compositing
DOM API
& Capabilities
JavaScript
DMANIP
Hit Testing
InputCSS Cascade
@joshholmes
WEB PLATFORM ARCHITECTURE
Networking /
Cache
Parsers
1
2 7
43 8 9
5 6
DOM
Tree
Formatting Layout Painting
1
2 7
43 8 9
5 6
Display Tree
Compositing
DOM API
& Capabilities
JavaScript
DMANIP
Hit Testing
InputCSS Cascade
@joshholmes
WEB PLATFORM ARCHITECTURE
Networking /
Cache
Parsers
1
2 7
43 8 9
5 6
DOM
Tree
Formatting Layout Painting
1
2 7
43 8 9
5 6
Display Tree
Compositing
DOM API
& Capabilities
JavaScript
DMANIP
Hit Testing
InputCSS Cascade
@joshholmes
WEB PLATFORM ARCHITECTURE
Networking /
Cache
Parsers
1
2 7
43 8 9
5 6
DOM
Tree
Formatting Layout Painting
1
2 7
43 8 9
5 6
Display Tree
Compositing
DOM API
& Capabilities
JavaScript
DMANIP
Hit Testing
InputCSS Cascade
@joshholmes
WEB PLATFORM ARCHITECTURE
Networking /
Cache
Parsers
1
2 7
43 8 9
5 6
DOM
Tree
Formatting Layout Painting
1
2 7
43 8 9
5 6
Display Tree
Compositing
DOM API
& Capabilities
JavaScript
DMANIP
Hit Testing
InputCSS Cascade
@joshholmes
WEB PLATFORM ARCHITECTURE
Networking /
Cache
Parsers
1
2 7
43 8 9
5 6
DOM
Tree
Formatting Layout Painting
1
2 7
43 8 9
5 6
Display Tree
Compositing
DOM API
& Capabilities
JavaScript
DMANIP
Hit Testing
InputCSS Cascade
@joshholmes
DOM Parsing
<html>
<head>
<title>Silly example</title>
<script src="head.js"></script>
<link rel="stylesheet" href="main.css">
<style>h2 { font-weight: bold; }</style>
<script>console.log('hi');</script>
</head>
<body>
<img src="my.png" alt="">
<script src="body.js"></script>
</body>
</html>
@joshholmes
DOM Parsing
<html>
<head>
<title>Silly example</title>
<script src="head.js"></script>
<link rel="stylesheet" href="main.css">
<style>h2 { font-weight: bold; }</style>
<script>console.log('hi');</script>
</head>
<body>
<img src="my.png" alt="">
<script src="body.js"></script>
</body>
</html>
@joshholmes
DOM Parsing
<html>
<head>
<title>Silly example</title>
<script src="head.js"></script>
<link rel="stylesheet" href="main.css">
<style>h2 { font-weight: bold; }</style>
<script>console.log('hi');</script>
</head>
<body>
<img src="my.png" alt="">
<script src="body.js"></script>
</body>
</html>
@joshholmes
DOM Parsing
<html>
<head>
<title>Silly example</title>
<script src="head.js"></script>
<link rel="stylesheet" href="main.css">
<style>h2 { font-weight: bold; }</style>
<script>console.log('hi');</script>
</head>
<body>
<img src="my.png" alt="">
<script src="body.js"></script>
</body>
</html>
@joshholmes
DOM Parsing
<html>
<head>
<title>Silly example</title>
<script src="head.js"></script>
<link rel="stylesheet" href="main.css">
<style>h2 { font-weight: bold; }</style>
<script>console.log('hi');</script>
</head>
<body>
<img src="my.png" alt="">
<script src="body.js"></script>
</body>
</html>
@joshholmes
DOM Parsing
<html>
<head>
<title>Silly example</title>
<script src="head.js"></script>
<link rel="stylesheet" href="main.css">
<style>h2 { font-weight: bold; }</style>
<script>console.log('hi');</script>
</head>
<body>
<img src="my.png" alt="">
<script src="body.js"></script>
</body>
</html>
@joshholmes
DOM Parsing
<html>
<head>
<title>Silly example</title>
<script src="head.js"></script>
<link rel="stylesheet" href="main.css">
<style>h2 { font-weight: bold; }</style>
<script>console.log('hi');</script>
</head>
<body>
<img src="my.png" alt="">
<script src="body.js"></script>
</body>
</html>
@joshholmes
DOM Parsing
<html>
<head>
<title>Silly example</title>
<script src="head.js"></script>
<link rel="stylesheet" href="main.css">
<style>h2 { font-weight: bold; }</style>
<script>console.log('hi');</script>
</head>
<body>
<img src="my.png" alt="">
<script src="body.js"></script>
</body>
</html>
@joshholmes
DOM Parsing
<html>
<head>
<title>Silly example</title>
<script src="head.js"></script>
<link rel="stylesheet" href="main.css">
<style>h2 { font-weight: bold; }</style>
<script>console.log('hi');</script>
</head>
<body>
<img src="my.png" alt="">
<script src="body.js"></script>
</body>
</html>
@joshholmes
DOM Parsing
<html>
<head>
<title>Silly example</title>
<script src="head.js"></script>
<link rel="stylesheet" href="main.css">
<style>h2 { font-weight: bold; }</style>
<script>console.log('hi');</script>
</head>
<body>
<img src="my.png" alt="">
<script src="body.js"></script>
</body>
</html>
@joshholmes
DOM Parsing
<html>
<head>
<title>Silly example</title>
<script src="head.js"></script>
<link rel="stylesheet" href="main.css">
<style>h2 { font-weight: bold; }</style>
<script>console.log('hi');</script>
</head>
<body>
<img src="my.png" alt="">
<script src="body.js"></script>
</body>
</html>
@joshholmes
DOM Parsing
<html>
<head>
<title>Silly example</title>
<script src="head.js"></script>
<link rel="stylesheet" href="main.css">
<style>h2 { font-weight: bold; }</style>
<script>console.log('hi');</script>
</head>
<body>
<img src="my.png" alt="">
<script src="body.js"></script>
</body>
</html>
@joshholmes
DOM Parsing
<html>
<head>
<title>Silly example</title>
<script src="head.js"></script>
<link rel="stylesheet" href="main.css">
<style>h2 { font-weight: bold; }</style>
<script>console.log('hi');</script>
</head>
<body>
<img src="my.png" alt="">
<script src="body.js"></script>
</body>
</html>
@joshholmes
DOM Parsing
<html>
<head>
<title>Silly example</title>
<script src="head.js"></script>
<link rel="stylesheet" href="main.css">
<style>h2 { font-weight: bold; }</style>
<script>console.log('hi');</script>
</head>
<body>
<img src="my.png" alt="">
<script src="body.js"></script>
</body>
</html>
@joshholmes
Steps for better performance
1. Use native features whenever possible
2. Only include assets you actually need
3. Optimize everything
4. Think about when you load assets
5. Consider how you load assets
6. Only load assets when they add value
75
@joshholmes
Step 1:
Use native features
whenever possible
@joshholmes
(they’re effectively free)
@joshholmes
Por exemplo
<header>
Header content…
</header>
@joshholmes
Por exemplo
<input id="n" name="n"
required aria-required="true"
autocorrect="off"
autocapitalize="words"
placeholder="Sir Tim Berners Lee"
autocomplete="name"
>
@joshholmes
Por exemplo
<input type="email"
id="e" name="e"
required aria-required="true"
autocorrect="off"
autocapitalize="off"
autocomplete="email"
placeholder="you@yourdomain.tld"
>
@joshholmes
Por exemplo
@media (min-width:600px) {
.gridded {
display: grid;
grid-template-columns: 1fr 300px;
grid-gap: 20px;
}
}
@joshholmes
Step 2:
Only include assets
you actually need
@joshholmes
Great tools,
possibly overkill
@joshholmes
Every tool has a cost
Framework Size (Compressed)
Bootstrap 2 149 kB
Bootstrap 3 103 kB
Angular 1.4 51 kB
Ember 2.2.0 111 kB
Foundation 4 266 kB
jQuery 32 kB
UI Kit 86 kB
React 16 + React DOM 35 kB
Vue 2.4.2 20 kB
@joshholmes
Chances are, your
library of choice
is on a CDN
@joshholmes
time
Your Device The Web
Icons by Mahmure Alp
@joshholmes
time
Your Device The Web
Icons by Mahmure Alp
You can optimize this
@joshholmes
Find the server early
<link rel="prefetch"
href="https://cdn.foo.com">
@joshholmes
time
Your Device The Web
Icons by Mahmure Alp
You can optimize this
@joshholmes
Go for the handshake
<link rel="preconnect"
href="https://cdn.foo.com">
@joshholmes
time
Your Device The Web
Icons by Mahmure Alp
You can even optimize this
@joshholmes
Grab that resource
<link rel="preload"
href="https://cdn.foo.com/jquery.min.js"
as="script">
@joshholmes
Download isn’t everything
Source: The Filament Group
@joshholmes
Download isn’t everything
Framework Method/function operations/s
Vanilla JS document.getElementById() 12,137,211
Dojo dojo.byId(); 5,443,343
Prototype $() 2,940,734
Ext JS Ext.get() 997,562
jQuery $() 350,557
YUI YAHOO.util.Dom.get() 326,534
MooTools document.id() 78,802
Source: VanillaJS
@joshholmes
@joshholmes
We used some hints though
<link rel="preconnect"
href="//10kapart.blob.core.windows.net">
<link rel="preconnect"
href="//cdnjs.cloudflare.com">
<link rel="preconnect"
href="//www.google-analytics.com">
@joshholmes
Step 3:
Optimize
everything
@joshholmes
Our approach to CSS (Gulp)
1. Write modular CSS in Sass (+ Breakup for MQ management)
2. Compile CSS with a precision of 4 decimal places (gulp-sass)
3. Fallbacks for the last 2 browser versions (gulp-autoprefixer)
4. CSS shorthand declarations if possible (gulp-shorthand)
5. Remove any unused declarations/rule sets (gulp-uncss)
6. Optimize the files (gulp-csso)
7. Minify (gulp-clean-css)
8. Gzip (gulp-zopfli)
9. Brotli (gulp-brotli)
103
@joshholmes
Before
@joshholmes
After
@joshholmes
Our approach to JS (Gulp)
1. Write modular JavaScript, grouped as appropriate
2. Combine files based on folder structure (gulp-folders, gulp-concat)
3. Create an wrapping closure to isolate from other JS (gulp-insert)
4. Minify (gulp-uglify)
5. Gzip (gulp-zopfli)
6. Brotli (gulp-brotli)
106
@joshholmes
Results
about 8 kB all-up
@joshholmes
Interesting side note
@joshholmes
We also minified
& pre-compressed
our HTML
@joshholmes
Step 4:
Think about when
you load assets
@joshholmes
We had 10 JS files
๏ Global
‣ main.js - the site’s library
‣ serviceworker.js - The site’s service worker
๏ Browser-specific
‣ html5shiv.js - local copy of the HTML5 Shiv for < IE9
111
@joshholmes
We had 10 JS files
๏ Page-specific
‣ enter.js - Entry form-related code
‣ form-saver.js - Used to save form entries locally until submitted
‣ hero.js - Runs the SVG animation on the homepage
‣ home.js - Handles homepage-specific tasks
‣ project.js - Used on project pages during voting
‣ update.js - Handles the winner update form
112
@joshholmes
Per the common wisdom
<script src="/j/main.min.js"></script>
</body>
</html>
@joshholmes
No need to run immediately
<script src="/j/main.min.js"></script>
<script src="/j/home.min.js"
defer
></script>
</body>
</html>
@joshholmes
Run whenever you can
<script src="/j/main.min.js"></script>
<script src="/j/home.min.js"
async
></script>
</body>
</html>
@joshholmes
Consider dependencies
<script src="/j/main.min.js"></script>
<script src="/j/home.min.js" async></script>
@joshholmes
Consider dependencies
<script src="/j/main.min.js" async></script>
<script src="/j/home.min.js" async></script>
@joshholmes
“race condition”
@joshholmes
Avoid race conditions
<script src="/j/main.min.js"></script>
<script src="/j/home.min.js" async></script>
@joshholmes
Why so many
separate files?
@joshholmes
Connections in HTTP/1.1
Browser Per host Overall
IE 9 6 35
IE 10 8 17
IE 11 13 17
Firefox 4+ 6 17
Opera 11+ 6 user defined
Chrome 4+ 6 10
Safari 7+ 6 17
@joshholmes
time
Your Device The Web
HTTP/1.1
Icons by Mahmure Alp
@joshholmes
HTTP/2 creates
a single connection and
contents stream in
@joshholmes
time
Your Device The Web
HTTP/2
Icons by Mahmure Alp
@joshholmes
Source: A List Apart
@joshholmes
Demo: Akamai
@joshholmes
Source: A List Apart
@joshholmes
Step 5:
Consider how
you load assets
@joshholmes
Start simple
<link rel="stylesheet" href="/c/d.min.css">
<link rel="stylesheet" href="/c/a.min.css"
media="only screen">
@joshholmes
Fault tolerance FTW!
<link rel="stylesheet" href="/c/d.min.css">
<link rel="stylesheet" href="/c/a.min.css"
media="only screen">
@joshholmes
Conditional scripting
<!--[if lt IE 9]>
<script src="/j/html5shiv.min.js"></script>
<![endif]-->
@joshholmes
Conditional scripting
<!--[if gt IE 8]><!-->
<script src="/j/main.min.js"></script>
<script src="/j/home.min.js" async
></script>
<!--<![endif]-->
</body>
</html>
@joshholmes
Conditional imagery
@joshholmes
Conditional images
@media (min-width: 36.375em) {
.presented-by [href*=microsoft]::before {
background-image: url(/i/c/edge.png);
background-image: url(/i/c/edge.svg),
none;
…
}
}
@joshholmes
Conditional images
@media (min-width: 36.375em) {
.presented-by [href*=microsoft]::before {
background-image: url(/i/c/edge.png);
background-image: url(/i/c/edge.svg),
none;
…
}
}
@joshholmes
Conditional images
@media (min-width: 36.375em) {
.presented-by [href*=microsoft]::before {
background-image: url(/i/c/edge.png);
background-image: url(/i/c/edge.svg),
none;
…
}
}
@joshholmes
Conditional images
@media (min-width: 36.375em) {
.presented-by [href*=microsoft]::before {
background-image: url(/i/c/edge.png);
background-image: url(/i/c/edge.svg),
none;
…
}
}
@joshholmes
Conditional animation
@joshholmes
How do we get there?
JS?
No
No imageLoad
Yes
<>
SVG support?
Yes
SVG
Ajax request SVG
Yank out script & add to document
No
picture
Save the markup for
next page load
NoYes
Verify browser
width condition
@joshholmes
Step 6:
Only load assets
when they add value
@joshholmes
@joshholmes
@joshholmes
Evaluate images case-by-case
๏ Does the image reiterate information found in the surrounding text?
๏ Is the image necessary to understand the surrounding content?
๏ Does the image contain text?
๏ Is the image a graph, chart, or table?
๏ Could the content of the image be presented in a different format
that would not require an image?
๏ Is the image purely presentational?
143
@joshholmes
53% of the average web page
Source: Internet Archive
@joshholmes
And they don’t always fit
@joshholmes
Source: The Outline
@joshholmes
If you can avoid
using an image, do it
@joshholmes
If you need an image,
choose the best format
@joshholmes
Quick format recap
๏ GIF
‣ for images with large swaths of solid colors
‣ Binary transparency
๏ JPG
‣ For photographs and images with gradations of color
‣ Can be compressed (introduces artifacts)
149
@joshholmes
Quick format recap
๏ PNG (8-Bit)
‣ Alternative to GIF
‣ Can support alpha transparency (with the right creation software)
๏ PNG (24-bit)
‣ Alternative to JPG
‣ Usually larger than JPGs
‣ Supports alpha tranparency
150
@joshholmes
Quick format recap
๏ WebP
‣ Newer format, not universally supported
‣ Smaller than JPGs and 24-bit PNGs
‣ Support alpha transparency
‣ and so much more…
151
@joshholmes
Sometimes images
are “nice to have”
@joshholmes
@joshholmes
@joshholmes
Oh wait…
optimize everything
@joshholmes
@joshholmes
@joshholmes
Source: 38 kB JPG
@joshholmes
B&W: 35 kB JPG (-7%)
@joshholmes
Crop & Resize: 12 kB JPG (-68%)
@joshholmes
Blur & optimize: 9 kB JPG (-76%)
@joshholmes
@joshholmes
WebP: 4 kB (-89%)JPG: 9 kB (-76%)
@joshholmes
Steps for better performance
1. Use native features whenever possible
2. Only include assets you actually need
3. Optimize everything
4. Think about when you load assets
5. Consider how you load assets
6. Only load assets when they add value
179
@joshholmes
https://webhint.io
@joshholmes
Every choice we
make affects our
users’ experiences
@joshholmes
Let’s spend our time to
save it for our users
@joshholmes
Speedy performance is
a great user experience
@joshholmes
Performant
PWAs
Josh Holmes
josh.holmes@microsoft.com

Contenu connexe

Dernier

Dernier (20)

Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 

En vedette

Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
Kurio // The Social Media Age(ncy)
 
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them well
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them wellGood Stuff Happens in 1:1 Meetings: Why you need them and how to do them well
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them well
Saba Software
 
Introduction to C Programming Language
Introduction to C Programming LanguageIntroduction to C Programming Language
Introduction to C Programming Language
Simplilearn
 

En vedette (20)

How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work
 
ChatGPT webinar slides
ChatGPT webinar slidesChatGPT webinar slides
ChatGPT webinar slides
 
More than Just Lines on a Map: Best Practices for U.S Bike Routes
More than Just Lines on a Map: Best Practices for U.S Bike RoutesMore than Just Lines on a Map: Best Practices for U.S Bike Routes
More than Just Lines on a Map: Best Practices for U.S Bike Routes
 
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
 
Barbie - Brand Strategy Presentation
Barbie - Brand Strategy PresentationBarbie - Brand Strategy Presentation
Barbie - Brand Strategy Presentation
 
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them well
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them wellGood Stuff Happens in 1:1 Meetings: Why you need them and how to do them well
Good Stuff Happens in 1:1 Meetings: Why you need them and how to do them well
 
Introduction to C Programming Language
Introduction to C Programming LanguageIntroduction to C Programming Language
Introduction to C Programming Language
 

High Performance PWAs

Notes de l'éditeur

  1. Hi there, my name is Aaron Gustafson WaSP Microsoft - Web Standards, PWAs & a11y
  2. You’ll hear me use the terms Progressive Web App and PWA interchangeably throughout this talk
  3. Let’s ignore the first part of this term for a moment, but I promise I will circle back to it shortly. The term “web app” may sound like something you can put your finger on, right? It’s software, on the Web, you use to complete a task. Like the expense manager, but it can be any web site or property, really.
  4. And so it is with progressive web apps too. “Web apps” in this context can be any website… newspapers, games, books, shopping sites… it really doesn’t matter what the content or purpose of the website is, the “web app” moniker is applicable to all of them.
  5. The term could just have easily been progressive web site and it may be helpful to think of it as such It doesn’t need to be a single page app You don’t need to be running everything client side There are no particular requirements for the type of PWA you are developing
  6. Essentially a PWA is a website that is capable of being promoted to being native-ish. It gets many of the benefits of being a native app (some of which I will cover in this talk), but is also has all of the benefits of being a website too
  7. Google defined 10 characteristics they believe define this new breed of web application
  8. Progressive: Works for every user, regardless of browser choice because it's built with progressive enhancement as a core tenet We’ll circle back to discuss progressive enhancement a bit more in a moment
  9. Responsive: Fits any form factor
  10. Network independent: Works offline & on low-quality networks (Service Worker)
  11. App-like: Feels like an app in terms of responsiveness and UX
  12. Fresh: Always up to date (Service Worker)
  13. Safe: Served via HTTPS to prevent snooping and to ensure content hasn't been tampered with
  14. Discoverable: Search spiders can identify these websites as apps through their use of the Web Application Manifest and Service Worker
  15. Re-engageable: Makes re-engagement easy through features like push notifications
  16. Installable: Allows users to install apps they find useful, independent of (but not exclusive of) an app store.
  17. Linkable: Easily shared via a URL. Can also respond to URLs (deep linking).
  18. In terms of designing user experiences, the problem we are often charged with solving is how to help users accomplish a task. In most cases, we want to do as much as we can to remove any obstacles that can get in their way. You know, friction. This is probably the 48th time you’ve heard that word at this conference and there’s a reason for that: Our job is to reduce friction in order to help people do what they need to do with as little pain or annoyance as possible.
  19. We need to be concerned about the performance of our web pages because poor performance is friction.
  20. I’m sure you’ve seen countless studies that have shown time & time again that people want speedy access to websites. It matters. The Harris Poll found that speed was the second most important attribute of a website, ranked right behind easy navigation, and just ahead of reliability. In other words, they’d rather it be fast than work all the time :-)
  21. I’m sure you’ve seen countless studies that have shown time & time again that people want speedy access to websites. It matters. The Harris Poll found that speed was the second most important attribute of a website, ranked right behind easy navigation, and just ahead of reliability. In other words, they’d rather it be fast than work all the time :-)
  22. Going on Akamai and Gomez data, Kissmetrics determined that…
  23. Translated… Of course this is somewhat hypothetical. Let’s look at practical.
  24. Amazon knows how much poor performance costs.
  25. Mobiquity found that slow mobile load times was the greatest source of frustration for mobile shoppers.
  26. Google has found that…
  27. Switching gears from negative to positive…
  28. It should be obvious by now that performance really matters.
  29. In building the site, I decided to challenge the team to make the contest site abide by the same rules. After all, if we were going to ask it of others, we didn’t want to be hypocrites. In a way, we decided to eat our own dogfood.
  30. Before I get into the ins and outs of some of the performance optimizations we made to the site, I want to give you a quick overview of how pages load. Just so we are all on the same page. This isn’t going to be exhaustive, but it will give you a sense of what we are dealing with when we deliver things on the web.
  31. First step when you enter an address in the URL bar This may be cached locally or somewhere in your local or provider’s network
  32. Then the browser & server greet each other
  33. Then the browser requests a file
  34. Server processing can be as simple as finding a static file or retrieving a ton of data from a database and crunching a bunch of numbers. This piece is widely variable, but can be tuned as well. That discussion falls outside of the boundaries of this talk though.
  35. Once we have the response, the browser can get to work doing something with it.
  36. This is a really high-level overview of how parsing occurs. Generally this is how it goes, but there are some optimizations individual browsers make that are unique to them. This is a really contrived example, but I wanted to use it to inform you of how all of this comes together so you have a better sense of how markup and source order affects page load performance.
  37. As the DOM parser moves through the HTML document…
  38. Additionally, each request may also require building up a full DNS & TCP handshake request
  39. With all of this in mind, here are my recommended first steps for performance tuning your projects…
  40. For more on the autocomplete property, Jason Grigsby wrote a very exhaustive walkthrough of what it is and how to use it on the Cloud Four blog.
  41. Here’s another example with an email field
  42. Modern approaches to layout are far more code-efficient.
  43. Modern JavaScript can also allow you to work without libraries.
  44. Make use of system fonts. You can even create elaborate font stacks offering a bunch of options that should produce a desirable match. This was our setup in the contest site.
  45. And the fallbacks were relatively close or at least close enough to not present weird layout issues when our top picks weren’t available.
  46. Subsetting means removing unused characters from the font file. There are numerous tools for this: command line, Font Squirrel and it’s supported by services like Typekit, Google Fonts
  47. But be cautious in how you do this as you might discover you’ve removed a character you actually needed.
  48. There are a lot of great tools out there… many may be more than you need.
  49. If you use Foundation all-up, that’s about 266 kB or a relatively large image worth of code and you’re only likely to be using a portion of it. Some of these libraries and frameworks do enable you to customize a “build” to your needs, only including what you are actually using. A colleague of mine was hired to consult on the performance of a high profile retail website. When he tucked into the code, he saw they were using jQuery, Prototype, Scriptaculous, MooTools, and a handful of other libraries. In total, they were loading 3.5 MB of JavaScript. All because their developers didn’t standardize on a single library and just added them willy nilly, as if they were free.
  50. Some folks rely on a Content Delivery Network (or CDN) to deliver the libraries they use. That can be great (as long as there’s not a network issue). But it’s important to remember, as I mentioned before, that these can incur some additional overhead in the network connection realm. And that can cost precious time, especially on high-latency mobile networks.
  51. For each CDN domain, we might have to go through the whole connection process to request a file. The more CDN shards, the more connection overhead you have.
  52. Thankfully we can optimize some of these steps a little bit
  53. Resource hints
  54. Browsers use the “as” attribute to help them slot the request into the right part of the loading process.
  55. Of course download isn’t all we need to worry about… A few years ago Filament Group ran a test, building the same “app” using several frameworks commonly employed at the time and tested how long it took them to become usable. Ember 1.9 was the worst offender, taking nearly 5 seconds to become usable on a mobile device on a 3G network. The reason is a combination of poor network performance with a slower mobile chipset.
  56. And even once you have the library downloaded, they usually pale in comparison to JavaScript code when it comes to execution speed. Just as a quick example, an ID lookup in jQuery runs about 98% slower than the native DOM method. Every layer of abstraction reduce performance.
  57. And so, we opted to skip the libraries and frameworks and write pretty much everything from scratch.
  58. We did use some hints though. And we did borrow the SVG support test from Modernizr. (Credited in the source, of course)
  59. We used Gulp to help out with a lot of the optimization work. Gulp is great, but it’s not the only game in town for this sort of thing. There are other task runners like Grunt or even Make, and bundling systems like Webpack or Parcel. I’m not here to tell you what to use, you should figure out what’s right for you & your team. It’s important to point out that we pre-compressed our static assets because that meant there was one less thing for the server to have to do.
  60. You can create a map to load files in a particular way, but you can also use filenames in many systems (because they will bundle them alphabetically). When you need certain bits of code to be placed early or late in a file. _ & omega can enable that.
  61. Even though we were using a Node backend, we pre-compressed our HTML files so we had one less task for the server to do dynamically (further reducing it’s processing time). It’s worth noting we also used Varnish to cache dynamic pages generated out of the Node backend.
  62. 2 global 1 browser specific (which I’ll get to)
  63. 7 page or feature-specific
  64. As you’d expect…
  65. And since JS was not necessary, but rather enhanced the page functionality, we were able to defer loading page-specific scripts.
  66. Defer is one option, another is async, which means…
  67. It’s tempting to defer or asynchronously load every bit of JS, but that can be problematic.
  68. What if one file loads before the other. With async we don’t control when things load.
  69. We only set async and defer on files other than our main.js file.
  70. Parallel connections per host and overall are limited
  71. Under HTTP/1.1, we also had to deal with head of line blocking where resource requests need to be resolved before a new one can be made.
  72. HTTP/2 is quite an advancement and, among its features, offers…
  73. Request as much as you want - 1 connection
  74. To throw that into the waterfall chart you might be used to seeing in devtools…
  75. Demo Akamai put together that shows HTTP1 vs HTTP2 379 individual tiles loading in
  76. Recommended reading…
  77. the default CSS file is tiny
  78. In most cases, the older browsers we’re talking about are mobile anyway. Or IE8 and below. And I’m ok giving them a mobile layout to be honest.
  79. Conditional comments, while no longer supported in modern versions of IE and Edge can still be useful. This one delivers the HTML5 shim to IE8 and below so our HTML5 elements render properly.
  80. You can also use them to hide specific content from older browsers. We used them to hide scripts from IE8 and below And since the site works without JS, we didn’t have to worry about it.
  81. You can also load images conditionally. We did that in the footer with the Microsoft Edge and AEA logos.
  82. Uses the hero.js I want to use an Interface Experience Map to show how we enhance for different experiences
  83. Images can be useful to draw users’ eyes when dealing with a page where competition is high.
  84. They become less useful when competition is low
  85. Some images are nice to have, but not necessary.
  86. We need to justify each and every one we use.
  87. The truth is… I highly recommend reading this article on the Outline. It’s interesting, especially as it comes from a non-tech perspective. Distillation: If you’re writing an article about cyber security, I really don’t need to see some stock photo of a phony hacker. Unless it adds real value, leave it out.
  88. We need to justify each and every image we use.
  89. I’m just going to run through some high-level bits about image formats. Una (You-nah) Kravets has a great talk on image formats she gave at AEA in Denver last year that goes into way more depth…
  90. I’m ok just showing their names as the default experience.
  91. We had it both ways. No image as the default and an image if certain conditions were met To do it, I used a data attribute and wrote up a little shorthand for defining what to do with the images.
  92. Don’t worry about totally following this JS code, but here’s how I got CSS & JS in sync. Created a div to enable me to watch for specific breakpoints and injected it dynamically via JavaScript (invisibly of course).
  93. In CSS I used font-family to store the breakpoint name for each of the major breakpoints in the design Adam Bradley came up with this approach.
  94. Then I gave myself a method to access that information from JavaScript. This is a simplification of the actual code.
  95. Then I could use it.
  96. Let’s look at how we got those file sizes so low!
  97. Here’s the process we used for each image.
  98. First we removed the color information, which saved us about 7% off of the original file size.
  99. Then we cropped and resized the images, reducing the file size by 68%
  100. Save For Web in Photoshop + ImageOptim
  101. Instead of lazy loading an img element, we lazy load a picture element.
  102. You can add as many sources as you want, just put the smallest one first as the first match wins.
  103. So instead of lazy loading this…
  104. We lazy load this
  105. To summarize what I just covered.
  106. It’s important to recognize that… We must… Think about what we load & how we load it Be realistic about what we ”need” Make every resource have to fight for its place in our sites Realize that there are trade-offs between design and performance
  107. We should always aim to make decisions in our users’ favor over our own desires
  108. After all…
  109. Hi there, my name is Aaron Gustafson WaSP Microsoft - Web Standards, PWAs & a11y