Rails 8 will be a PWA (Progressive Web App) by default!
1. Progressive Web Apps = Freedom #
The Web is the only free way to access the internet without a major gatekeeper like “Apple App Store” or “Google Play Store”.
Accessing the Web on mobile sucks. People prefer apps over browser tabs on mobile.
A B2B app can get away with having only a web version (that people use at work from their computer, not phone).
A B2C app is dead on arrival if it can not be installed on a phone.
Progressive Web Apps are a minimal compromise to make a web app “installable” on a mobile device. A PWA will have it’s own icon and launch without the browser controls. To make an app installable, you will need a manifest.json
file.
The killer feature of having a PWA VS a browser tab is having Push Notifications. They can be managed via the service-worker.js
file.
2. PWA in Rails 8 #
Recently DHH merged a PR into Rails Add default pwa manifest and service worker file #50528.
The PR adds basic manifest.json
& service-worker.js
files to a new Rails app.
Rails 8 will Release Action Notifier framework for push notifications
3. Activate Manifest.json #
Add a Manifest and make your app installable!
Chrome prompt to install PWA:
Edge prompt to install PWA:
If you added app to Dock in Safari, you get a prompt to open it in app:
Current SupeRails manifest:
// app/views/pwa/manifest.json.erb
{
"name": "<%= Rails.application.config_for(:settings).dig(:site, :name) %>",
"short_name": "<%= Rails.application.config_for(:settings).dig(:site, :short_name) %>",
"icons": [
{
"src": "/logo.png",
"type": "image/png",
"sizes": "512x512"
},
{
"src": "/logo.png",
"type": "image/png",
"sizes": "512x512",
"purpose": "maskable"
}
],
"start_url": "/",
"id": "/",
"display": "standalone",
"scope": "/",
"description": "<%= Rails.application.config_for(:settings).dig(:site, :description) %>",
"categories": "<%= Rails.application.config_for(:settings).dig(:site, :keywords) %>",
"theme_color": "#f43f5e",
"background_color": "#f43f5e",
"shortcuts": [
{
"name": "<%= t('posts.index.title') %>",
"description": "<%= t('posts.index.subtitle') %>",
"url": "<%= posts_path %>",
"icons": [{ "src": "<%= image_url("pwa/shortcuts/play-circle.svg") %>", "sizes": "96x96" }]
},
{
"name": "<%= t('playlists.index.title') %>",
"description": "<%= t('playlists.index.subtitle') %>",
"url": "<%= playlists_path %>",
"icons": [{ "src": "<%= image_url("pwa/shortcuts/playlist.svg") %>", "sizes": "96x96" }]
}
],
"screenshots": [
{
"src": "<%= image_url("pwa/screenshots/narrow.png") %>",
"sizes": "850x1628",
"form_factor": "narrow",
"label": "<%= Rails.application.config_for(:settings).dig(:site, :description) %>"
},
{
"src": "<%= image_url("pwa/screenshots/wide.png") %>",
"sizes": "3420x1964",
"form_factor": "wide",
"label": "<%= Rails.application.config_for(:settings).dig(:site, :description) %>"
}
]
}
Inspect manifest in Chrome Dev Tools:
Be sure that you also have these links in your app/views/layouts/application.html.erb
:
<link rel="manifest" href="/manifest.json">
<link rel="icon" href="/logo.png" type="image/png">
<link rel="icon" href="/logo.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/logo.png">
You can even have multiple isolated instances of a PWA running on one devise:
4. Activate Service Worker #
Service worker can:
- manage push notifications đź’Şđź’Şđź’Ş
- cache pages so that your app works offline đź’Şđź’Şđź’Ş
To start, activate an empty service worker with this script:
// app/javascript/application.js
if ('serviceWorker' in navigator) {
// Register the service worker
navigator.serviceWorker.register('/service-worker.js')
.then(function(registration) {
console.log('Service Worker registered with scope:', registration.scope);
})
.catch(function(error) {
console.log('Service Worker registration failed:', error);
});
}
// app/views/pwa/service-worker.js
// The install event is fired when the service worker is first installed
self.addEventListener('install', function(event) {
console.log('Service Worker installed');
});
// The activate event is fired after the install event when the service worker is actually controlling the page
self.addEventListener('activate', function(event) {
console.log('Service Worker activated');
});
Now you have a useless service worker running:
Service workers can get really sophisticated. I will not dig into this rabbithole now.
Campfire already has all the PWA goodies.
Let’s wait for smart people to extract it into Action Notifier framework for push notifications.
Useful resources #
- MDN PWA docs
- Follow Danny Moerkerke - he has great content about PWAs.
- 🤠Learn What PWA Can Do Today
- Alicia Rojas - Building an offline experience with a Rails-powered PWA - Rails World 2023
Did you like this article? Did it save you some time?