Making GitLab a PWA
Or, how I learned to stop worrying and embrace the boring solution.
Sam Beckham
@samdbeckham
3G
WiFi
1s
3s
3G
WiFi
0.3s
0.3s
Offline
3G
WiFi
0.3s
0.3s
0.3s
It's a
website
that acts like a
native app
Install to
your device
Load offline
Just a
website
It's a
progressive enhancement
The
boring
solution
Lighthouse
✅ Non-Javascript content
✅ https
✅ https redirect
✅ Fast enough on 3g
✅ <meta viewport> tag
✅ Sized for the viewport
❌ Custom splash screen
❌ Themed Address Bar
❌ Service Worker
❌ 200 When offline
❌ Prompted to install the web app
Lighthouse
// TODO: Insert hilarious slide that makes a pun about there being a break right now.
❌
Custom Splash Screen
❌
Themed Address bar
{
"name": "GitLab",
"short_name": "GitLab",
"display": "standalone",
"scope": "/",
"start_url": "/",
"theme_color": "#474D57",
"background_color": "#380D75",
"icons": [
{
"src": "/pwa_icon_512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
./manifest.json
<head>
<!-- other head stuff -->
<link rel="manifest" href="/manifest.json">
</head>
./yourpage.html
Lighthouse
✅ Custom splash screen
✅ Themed Address Bar
❌ Service Worker
❌ 200 When offline
❌ Prompted to install the web app
❌
Service worker
💻
🌐
Browser
Server
request
response
💻
🌐
Browser
Server
🐲
Service
Worker
💻
🌐
Browser
Server
🐲
Service
Worker
cat.png
cat.png
💵
Cache
💻
🌐
Browser
Server
🐲
Service
Worker
cat.png
cat.png
💵
Cache
💤
❌
200 when offline
The
boring
solution
❌
200 when offline
💻
🌐
Browser
Server
🐲
Service
Worker
offline.html
💵
Cache
💻
🌐
Browser
Server
🐲
Service
Worker
issue
offline
💵
Cache
issue
❌
💧
// Register a service worker if our
// browser allows it
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(
'/service_worker.js',
{ scope: '/'}
);
}
Register
const CURRENT_CACHE = '<%= Gitlab.version %>_<%= Gitlab.revision %>';
const OFFLINE_PAGE = '/-/offline';
self.addEventListener('install', event => {
event.waitUntil(caches.open(CURRENT_CACHE)
.then(cache => cache.add(OFFLINE_PAGE)));
});
self.addEventListener('activate', event => {
event.waitUntil(
caches
.keys()
.then(cacheNames =>
Promise.all(
cacheNames.map(cache =>
cache !== CURRENT_CACHE ? caches.delete(cache) : Promise.resolve(),
),
),
),
);
});
self.addEventListener('fetch', event => {
const { request } = event;
const { method, mode } = request;
if (method === 'GET' && mode === 'navigate') {
event.respondWith(fetch(request).catch(() => caches.match(OFFLINE_PAGE)));
}
});
./service_worker.js
const CURRENT_CACHE = '<%= Gitlab.version %>_<%= Gitlab.revision %>';
const OFFLINE_PAGE = '/offline';
self.addEventListener('install', event => {
event.waitUntil(
caches
.open(CURRENT_CACHE)
.then(cache =>
cache.add(OFFLINE_PAGE))
)
});
Install
./service_worker.js
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames =>
Promise.all(
cacheNames.map(cache =>
cache !== CURRENT_CACHE ?
caches.delete(cache) :
Promise.resolve(),
))));
});
Activate
./service_worker.js
self.addEventListener('fetch', event => {
const { request } = event;
const { method, mode } = request;
if (
method === 'GET' &&
mode === 'navigate') {
event.respondWith(
fetch(request).catch(() => (
caches.match(OFFLINE_PAGE)));
)
}
});
Fetch
./service_worker.js
const CURRENT_CACHE = '<%= Gitlab.version %>_<%= Gitlab.revision %>';
const OFFLINE_PAGE = '/-/offline';
self.addEventListener('install', event => {
event.waitUntil(caches.open(CURRENT_CACHE)
.then(cache => cache.add(OFFLINE_PAGE)));
});
self.addEventListener('activate', event => {
event.waitUntil(
caches
.keys()
.then(cacheNames =>
Promise.all(
cacheNames.map(cache =>
cache !== CURRENT_CACHE ? caches.delete(cache) : Promise.resolve(),
),
),
),
);
});
self.addEventListener('fetch', event => {
const { request } = event;
const { method, mode } = request;
if (method === 'GET' && mode === 'navigate') {
event.respondWith(fetch(request).catch(() => caches.match(OFFLINE_PAGE)));
}
});
./service_worker.js
/offline
/-/offline
Lighthouse
❌ Prompted to install the web app
✅ Service worker
✅ 200 when offline
✅ https
✅ http => https
✅ Custom Splash Screen
✅ Themed Address bar
✅ non-javascript content
✅ Fast enough on 3g
✅ <meta viewport> tag
✅ Sized correctly for the viewport
❌
Prompted to install the web app
Do literally nothing else
✅ Service worker
Lighthouse
✅ 200 when offline
✅ https
✅ http => https
✅ Prompted to install the web app
✅ Custom Splash Screen
✅ Themed Address bar
✅ non-javascript content
✅ Fast enough on 3g
✅ <meta viewport> tag
✅ Sized correctly for the viewport
Basic PWA Support
Vulnerability Caching
July 22nd 2019
v12.1.0
Thanks!
Sam Beckham
@samdbeckham
Making GitLab a PWA (FENE May 2019)
By Sam Beckham
Making GitLab a PWA (FENE May 2019)
- 1,383