Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Building PWAs using Workbox
Search
Arnelle Balane
August 01, 2020
Programming
250
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Building PWAs using Workbox
Arnelle Balane
August 01, 2020
More Decks by Arnelle Balane
See All by Arnelle Balane
Introduction to building Chrome Extensions
arnellebalane
0
150
Color Palettes Of The Most Colorful Birds
arnellebalane
0
150
Let's build a video streaming app using Web technologies
arnellebalane
0
170
Let's build a video calling app with Web technologies and Firebase!
arnellebalane
0
200
Ridiculous Scientific Names
arnellebalane
0
320
Fishes With Terrestrial-Animal Names
arnellebalane
0
170
Making the Web more capable with Project Fugu
arnellebalane
0
150
Frontend Web Development in 2021+
arnellebalane
0
200
Extending CSS using Houdini
arnellebalane
0
150
Other Decks in Programming
See All in Programming
メールのエイリアス機能を履き違えない
isshinfunada
0
250
AI時代に設計が 最大の生産性レバーになる 意図駆動開発とデータを消さない設計|Don't Delete Your Data or Your Intent — Design as the Deepest Lever in the AI Era
tomohisa
1
1.1k
複数の Claude Code が"放置"されてしまう問題をCLI ダッシュボードを自作して解決した話
sumihiro3
1
710
AIを紡ぐPMのお話
swdtkuy
0
120
How I Won Prize Money at a Hackathon Using Codex and Symphony Alpha
yasei_no_otoko
0
110
20260722_microCMSで考える、AI時代のコンテンツ運用設計
yosh1
0
440
Japan Community Day at Kubecon + CloudNativeCon Japan 2026: Learning Container Privilege Control by Building My Own Low-Level Container Runtime
ternbusty
1
160
進化を続けるGo toolsの現在地 / The Current State of Ever-Evolving Go Tools
hond0413
0
240
komatsuna「分散システムにおけるバグ分析手法」
komatsunaqa
0
270
書籍「プロフェッショナルAI駆動開発」紹介スライド
juntaromatsumoto
0
120
属人化した知識を、 AIが辿れる地図にする
pkshadeck
PRO
1
200
仕様駆動開発の消費期限
watany
20
8.8k
Featured
See All Featured
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
What's in a price? How to price your products and services
michaelherold
247
13k
Optimising Largest Contentful Paint
csswizardry
37
3.9k
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
390
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
490
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.1k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
210
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
370
Fashionably flexible responsive web design (full day workshop)
malarkey
408
67k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
The SEO Collaboration Effect
kristinabergwall1
1
520
Transcript
Software Developer, Newlogic Arnelle Balane @arnellebalane Building PWAs using Workbox
Arnelle Balane Software Developer at Newlogic Google Developers Expert for
Web Technologies I write about Web stuff on my blog, arnellebalane.com @arnellebalane
None
Progressive Web Apps Websites built using Web technologies, and act
and feel like native apps
❖ Can be installed to the home screen ❖ Works
well even in intermittent or unreliable network conditions ❖ Works on any device ❖ Send notifications even when app is closed Progressive Web Apps
❖ Usually built using the application shell model, minimizing page
refresh ❖ Generally easier to deploy and maintain than native apps ❖ SEO, URLs, etc. Progressive Web Apps
Service Workers <script> if (navigator.serviceWorker) { window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js'); }); } </script>
Service Workers // sw.js addEventListener('install', event => { /**/ });
addEventListener('activate', event => { /**/ }); addEventListener('fetch', event => { /**/ });
❖ Service Workers ❖ Cache API ❖ Push Notifications ❖
Background Sync ❖ Background Fetch ❖ Web Application Manifest Moar APIs for our PWAs!
None
Workbox JavaScript libraries for adding offline support to Web applications
❖ from CDN ❖ Node module ❖ Webpack plugin Using
Workbox
Credits to Afrian Hanafi dribbble.com/shots/13125619-Makers-Workshop-Concept-II
Credits to Afrian Hanafi dribbble.com/shots/13125619-Makers-Workshop-Concept-II 2 pages 2 images 1
stylesheet 1 script
Import the library // sw.js importScripts('https://storage.googleapis.com/workbox-cdn/ releases/5.1.2/workbox-sw.js');
Precache site assets (deprecated) workbox.precaching.precache([ '/', '/classes', '/index.css', '/index.js', '/images/image-01.jpg',
'/images/image-02.jpg' ]);
Precache site assets, with versioning workbox.precaching.precache([ {url: '/', revision: 'v1'},
{url: '/classes', revision: 'v1'}, {url: '/index.css', revision: 'v1'}, {url: '/index.js', revision: 'v1'}, {url: '/images/image-01.jpg', revision: 'v1'}, {url: '/images/image-02.jpg', revision: 'v1'} ]);
Verify cache in Chrome Devtools
Y u no work?
Route precached assets workbox.precaching.precache([ /* ... */ ]); workbox.precaching.addRoute();
Precache and route site assets workbox.precaching.precacheAndRoute([ {url: '/', revision: 'v1'},
{url: '/classes', revision: 'v1'}, {url: '/index.css', revision: 'v1'}, {url: '/index.js', revision: 'v1'}, {url: '/images/image-01.jpg', revision: 'v1'}, {url: '/images/image-02.jpg', revision: 'v1'} ]);
Now it works offline!
Precaching Adding items to the cache in advance, even before
they are used
Gradually adding items to the cache as they are requested
Runtime caching
Cache a specific URL at runtime workbox.routing.registerRoute( '/images/image-01.jpg', new workbox.strategies.NetworkFirst()
);
Verify cache in Chrome Devtools
Cache a URL pattern at runtime workbox.routing.registerRoute( /\.jpg$/, new workbox.strategies.NetworkFirst()
);
Runtime caching using a “match callback” workbox.routing.registerRoute( (context) => context.url.origin
=== 'https://arnelle.me', new workbox.strategies.NetworkFirst() ); workbox.routing.registerRoute( (context) => context.request.destination === 'image', new workbox.strategies.NetworkFirst() );
Runtime caching https://developers.google.com/web/tools/workbox/reference-docs /latest/module-workbox-routing Precaching https://developers.google.com/web/tools/workbox/reference-docs /latest/module-workbox-precaching More Info
Workbox provides simple implementations for common service worker caching strategies
Caching strategies
Network-First Image from web.dev
Network-First workbox.routing.registerRoute( /\.jpg$/, new workbox.strategies.NetworkFirst() );
Network-First workbox.routing.registerRoute( /\.jpg$/, new workbox.strategies.NetworkFirst({ networkTimeoutSeconds: 3 }) );
Cache-First Image from web.dev
Cache-First workbox.routing.registerRoute( /\.css$/, new workbox.strategies.CacheFirst() );
Stale-While-Revalidate Image from web.dev
Stale-While-Revalidate workbox.routing.registerRoute( (context) => context.url.pathname.startsWith('/blog'), new workbox.strategies.StaleWhileRevalidate() );
❖ Nothing special other than they can use Workbox Plugins
Cache-Only Network-Only
The Offline Cookbook https://developers.google.com/web/fundamentals/instant-and -offline/offline-cookbook Workbox Strategies https://developers.google.com/web/tools/workbox/reference-docs /latest/module-workbox-strategies More
Info
Additional service worker behaviours without writing more boilerplate code Workbox
plugins
❖ ExpirationPlugin ❖ BroadcastUpdatePlugin ❖ BackgroundSyncPlugin ❖ CacheableResponsePlugin ❖ RangeRequestsPlugin
Workbox plugins
Using plugins workbox.routing.registerRoute( /\.jpg$/, new workbox.strategies.CacheFirst({ plugins: [ /* plugins
here */ ] }) );
ExpirationPlugin, expire after some time workbox.routing.registerRoute( /\.jpg$/, new workbox.strategies.CacheFirst({ cacheName:
'image-cache', plugins: [ new workbox.expiration.ExpirationPlugin({ maxAgeSeconds: 10 }) ] }) );
ExpirationPlugin, custom cache name workbox.routing.registerRoute( /\.jpg$/, new workbox.strategies.CacheFirst({ cacheName: 'image-cache',
plugins: [ new workbox.expiration.ExpirationPlugin({ maxAgeSeconds: 10 }) ] }) );
ExpirationPlugin, limit number of entries workbox.routing.registerRoute( /\.jpg$/, new workbox.strategies.CacheFirst({ cacheName:
'image-cache', plugins: [ new workbox.expiration.ExpirationPlugin({ maxEntries: 1 }) ] }) );
ExpirationPlugin
ExpirationPlugin
BroadcastUpdatePlugin workbox.routing.registerRoute( /\/blog\/.+$/, new workbox.strategies.StaleWhileRevalidate({ plugins: [ new workbox.broadcastUpdate.BroadcastUpdatePlugin() ]
}) );
BroadcastUpdatePlugin, handle in main page // index.js navigator.serviceWorker.onmessage = event
=> { if (event.data.meta === 'workbox-broadcast-update') { displayUpdateAvailableUI(); } };
BroadcastUpdatePlugin, handle in main page // index.js navigator.serviceWorker.onmessage = event
=> { if (event.data.meta === 'workbox-broadcast-update') { displayUpdateAvailableUI(); } };
BroadcastUpdatePlugin
Custom Plugins https://developers.google.com/web/tools/workbox/guides /using-plugins#custom_plugins Using Plugins https://developers.google.com/web/tools/workbox/guides /using-plugins More Info
Use Workbox with popular JavaScript frameworks. Webpack plugin
Install dependencies npm install -D workbox-webpack-plugin
GenerateSW plugin const {GenerateSW} = require('workbox-webpack-plugin'); module.exports = { /*
... */ plugins: [ new GenerateSW({ swDest: 'sw.js' }) ] };
InjectManifest plugin const {InjectManifest} = require('workbox-webpack-plugin'); module.exports = { /*
... */ plugins: [ new InjectManifest({ swSrc: './www/sw.js' }) ] };
InjectManifest plugin // sw.js importScripts('https://storage.googleapis.com/...'); workbox.precaching.precacheAndRoute([ {url: '/', revision: 'v1'},
{url: '/classes', revision: 'v1'}, {url: '/index.css', revision: 'v1'}, {url: '/index.js', revision: 'v1'} ]);
InjectManifest plugin, add injection point // sw.js importScripts('https://storage.googleapis.com/...'); workbox.precaching.precacheAndRoute( self.__WB_MANIFEST
);
InjectManifest plugin, build result // dist/sw.js importScripts('https://storage.googleapis.com/...'); workbox.precaching.precacheAndRoute([ {'revision':'b91028...','url':'index.329fc4.js'}, {'revision':'20420e...','url':'index.html'}
]);
Update service worker imports // sw.js import {precacheAndRoute} from 'workbox-precaching';
precacheAndRoute(self.__WB_MANIFEST);
Update service worker imports import {registerRoute} from 'workbox-routing'; import {StaleWhileRevalidate}
from 'workbox-strategies'; import {BroadcastUpdatePlugin} from 'workbox-broadcast-update'; registerRoute( /\/blog\/.+$/, new StaleWhileRevalidate({ plugins: [new BroadcastUpdatePlugin()] }) );
Webpack plugin reference https://developers.google.com/web/tools/workbox/reference-doc s/latest/module-workbox-webpack-plugin Using bundlers with Workbox https://developers.google.com/web/tools/workbox/guides
/using-bundlers More Info
a.k.a I didn’t know where to put these content so
I’ll just put them at the end... Common recipes
Cache Google Fonts workbox.routing.registerRoute( (context) => context.url.origin === 'https://fonts.googleapis.com', new
workbox.strategies.StaleWhileRevalidate({ cacheName: 'google-fonts-stylesheets' }) );
Cache Google Fonts workbox.routing.registerRoute( (context) => context.url.origin === 'https://fonts.gstatic.com', new
workbox.strategies.CacheFirst({ cacheName: 'google-fonts-webfonts', plugins: [ new workbox.expiration.ExpirationPlugin({ maxAgeSeconds: 60 * 60 * 24 * 365, // one year maxEntries: 30 }) ] }) );
Generic fallbacks
Generic fallbacks
Generic fallbacks, precache fallback image workbox.precaching.precache([ {url: '/images/fallback-image.png', revision: 'v1'},
]);
Generic fallbacks, route all images workbox.precaching.precache([ {url: '/images/fallback-image.png', revision: 'v1'},
]); workbox.routing.registerRoute( (context) => context.request.destination === 'image', new workbox.strategies.NetworkOnly() );
Generic fallbacks workbox.routing.setCatchHandler(async context => { if (context.request.destination === 'image')
{ return workbox.precaching.matchPrecache( '/images/fallback-image.png' ); } });
Generic fallbacks, respond with fallback image workbox.routing.setCatchHandler(async context => {
if (context.request.destination === 'image') { return workbox.precaching.matchPrecache( '/images/fallback-image.png' ); } });
Generic fallbacks
Generic fallbacks, for other pages
Workbox https://developers.google.com/web/tools/workbox Common Recipes https://developers.google.com/web/tools/workbox/guides /common-recipes More Info
❖ Workbox caching strategies ❖ Workbox plugins ❖ Using Workbox
with Webpack ❖ Common Workbox recipes Recap!
❖ Web Application Manifest ❖ Push Notifications ❖ Background Sync
❖ Web Capabilities What’s next?
Building PWAs using Workbox Arnelle Balane That’s all for today!
Thank you!