How much does your websitecost?
We measure cost in seconds:
Source: Time To Interactive from Lighthouse. I ran the test twice and took the faster time.
Mobile Data Can Be Expensive
Would you pay $10
to load this website?
Also: loading huge sites on mobile just sucks
...and what if the connection is flaky?
We Can Fix It!
(And it doesn’t mean starting from scratch.)
The Solution:
Progressive Web Apps
With Progressive Web Apps (PWAs), we can:
- Significantly decrease the amount of data transferred on each page load
- Improve the experience for users on unreliable connections
Booooooooooooooring!
“That’s not my target market.”
Can’t we just ignore PWAs?
Here’s why:
- PWAs decrease load times on all connections
- Perceived load times improve
- Stability improves for mobile users everywhere
- User experience is better all around
Real-World Examples
lengstorf.com
- Cold: ~3s (477 KB)
- Warm: ~1s (0.5 KB)
csswizardry.com
- Cold: ~1.5s (339 KB)
- Warm: ~1s (1.1 KB)
That sounds significantly more awesome than eating vegetables.
What makes a PWA?
- Web-based application
- Provides a Web Manifest
- Registers a Service Worker
Web Manifest
{
"short_name": "AirHorner",
"name": "Kinlan's AirHorner of Infamy",
"icons": [{
"src": "launcher-icon-1x.png",
"type": "image/png",
"sizes": "48x48"
}],
"start_url": "index.html?launcher=true"
}
bit.ly/pwa-manifest
Service Worker
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('mysite-v1').then(function(cache) {
cache.addAll(
// add non-critical assets
);
return cache.addAll(
// add critical assets
);
})
);
});
bit.ly/offline-cookbook
What Service Workers do:
- Cache critical assets when first installed
- Precache non-critical assets in the background
- Act as a proxy for all outgoing requests
- Skip server & provide cached assets if possible
This allows Progressive Web Apps to
load offline on subsequent visits
Service Workers alone aren’t enough to make our apps blazing fast
(They don’t help at all on the first visit.)
To make JS-powered apps really fast, we should:
- Implement route-based code splitting
- Use HTTP/2 to serve assets
- Set up background prefetching
- Lazy load any non-critical assets
Push
Render
Pre-cache
Lazy-load
To make JS-powered apps really fast, we should:
- Implement route-based code splitting
- Use HTTP/2 to serve assets
- Set up background prefetching
- Lazy load any non-critical assets
- Eliminate all unused code
- Use server-side rendering to generate static files
That’s a lot of things.
Route-based code splitting:
- Creates smaller bundles for specific routes
- Creates shared bundles for common code
- Allows loading only what’s really needed
Code splitting with Webpack:
- Use
import()
to identify chunks
- in Webpack 4, use
optimization.splitChunks
- In Webpack 3 or earlier, use
CommonsChunkPlugin
Totally True Internet Fact
If you say “Webpack” 3 times, Sean Larkin will appear.
Serving assets with HTTP/2:
- Allows multiplexed downloads
- Provides push capabilities to minimize requests
Asset prefetching:
- Assumes which routes the user will load next
- Loads the assets for those routes in the background
- Makes loading the next route almost instantaneous
Lazy loading assets:
- Prevents images from blocking the initial load
- Only requests them once they’re in the viewport
“Won’t lazy loading make the page jump?”
Lazy loading with the blur-up technique
Source: medium.com
Lazy loading with traced SVG
Source: Gatsby.js
Lazy loading with simplified polygons
Source: Gatsby.js
Eliminating unused code:
- Reduces the overall size of the codebase
- Helps avoid module bloat
Source: Reddit?
How to remove unused code:
- Use Uglify.js to remove dead code
- Enable tree-shaking with ES modules
- Analyze your bundle output
Serving only static assets:
- Removes the need for runtime server rendering
- Eliminates an extra HTTP round-trip
- Improves cacheability
😱 Server-side rendering?! 😱
☹️
Loading 1MB of blocking JavaScript before anything can be displayed
😐
Showing a loading spinner while the framework initializes
😊
Server-side rendering so no JavaScript is required to initially display the page
“But static files won’t work for my app!”
Yes they will. Probably.
If all of this seems a little overwhelming I totally understand
We can get most of these performance improvements for free
Open source is awesome. 🎉💕
How to improve web performance for free:
- sw-precache and/or sw-toolbox
- Next.js + Now
- Gatsby.js + Netlify
sw-precache / sw-toolbox
- Helper libs from the Google team
- Sets up sane defaults for Service Workers
- Requires manual configuration
Next.js
- Framework for server-side rendering React
- Automatic code-splitting
- Requires a server
Now
- Hosting for Node, static, and Docker applications
- Purpose-built for Next.js apps
- Amazingly simple CLI tooling
Gatsby.js
- Framework for building React apps
- Compiles to static files
- Add Service Worker + Web Manifest with plugins
- Generated apps are unbelievably fast
Netlify
- Deployment and hosting for static sites
- Powerful Git workflow integrations
- Automatic, free SSL generation
🔥🔥🔥
Blazing fast apps need fine tuning️
PWA Performance Checklist:
✅ Add a Service Worker
✅ Create a Web Manifest
✅ Follow the PRPL Pattern
✅ Remove unused code
✅ Generate static files
Use frameworks to automate perf best practices
- sw-precache and sw-toolbox
- Next.js + Now
- Gatsby.js + Netlify
Spending time on performance is good for everyone.
- Lower cost to pay-per-MB users
- Better experience on mobile and low-powered devices
- Improved reliability on spotty connections
- Apps feel more “solid” on all devices
- Repeat visitors see damn-near instant page loads
When we focus on performance everybody wins
Thanks!
Jason Lengstorf
Follow me on Twitter: @jlengstorf