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
0
210
Building PWAs using Workbox
Arnelle Balane
August 01, 2020
Tweet
Share
More Decks by Arnelle Balane
See All by Arnelle Balane
Introduction to building Chrome Extensions
arnellebalane
0
91
Color Palettes Of The Most Colorful Birds
arnellebalane
0
100
Let's build a video streaming app using Web technologies
arnellebalane
0
120
Let's build a video calling app with Web technologies and Firebase!
arnellebalane
0
130
Ridiculous Scientific Names
arnellebalane
0
180
Fishes With Terrestrial-Animal Names
arnellebalane
0
140
Making the Web more capable with Project Fugu
arnellebalane
0
100
Frontend Web Development in 2021+
arnellebalane
0
150
Extending CSS using Houdini
arnellebalane
0
94
Other Decks in Programming
See All in Programming
Domain-Driven Transformation
hschwentner
2
1.9k
SwiftUI Viewの責務分離
elmetal
PRO
1
220
sappoRo.R #12 初心者セッション
kosugitti
0
240
『GO』アプリ バックエンドサーバのコスト削減
mot_techtalk
0
140
2,500万ユーザーを支えるSREチームの6年間のスクラムのカイゼン
honmarkhunt
6
5.2k
Open source software: how to live long and go far
gaelvaroquaux
0
630
Grafana Cloudとソラカメ
devoc
0
140
自分ひとりから始められる生産性向上の取り組み #でぃーぷらすオオサカ
irof
8
2.7k
Kubernetes History Inspector(KHI)を触ってみた
bells17
0
220
一休.com のログイン体験を支える技術 〜Web Components x Vue.js 活用事例と最適化について〜
atsumim
0
320
TokyoR116_BeginnersSession1_環境構築
kotatyamtema
0
110
第3回関東Kaggler会_AtCoderはKaggleの役に立つ
chettub
3
950
Featured
See All Featured
Imperfection Machines: The Place of Print at Facebook
scottboms
267
13k
A Philosophy of Restraint
colly
203
16k
How STYLIGHT went responsive
nonsquared
98
5.4k
Building Better People: How to give real-time feedback that sticks.
wjessup
366
19k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
132
33k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
99
18k
Navigating Team Friction
lara
183
15k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
33
2.1k
Large-scale JavaScript Application Architecture
addyosmani
510
110k
Visualization
eitanlees
146
15k
Facilitating Awesome Meetings
lara
51
6.2k
Code Review Best Practice
trishagee
66
17k
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!