---
title: "Rails 8 will be a PWA (Progressive Web App) by default!"
author: "Yaroslav Shmarov"
date: "2024-05-09"
canonical_url: "https://blog.superails.com/rails-8-pwa"
markdown_url: "https://blog.superails.com/rails-8-pwa.md"
description: "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."
tags: ["pwa","rails"]
license: "GNU AGPL v3. Credit Yaroslav Shmarov and link the canonical URL."
video_url: "https://www.youtube.com/watch?v=dU3Znt5E8Bg"
---

# 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**](https://developer.mozilla.org/en-US/docs/Web/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](https://github.com/rails/rails/pull/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](https://github.com/rails/rails/issues/50454)

### 3. Activate Manifest.json

Add a [Manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest) and make your app installable!

Chrome prompt to install PWA:

![Install a PWA in Chrome](https://blog.superails.com/assets/images/pwa-install-chrome.png)

Edge prompt to install PWA:

![Edge prompt to install app](https://blog.superails.com/assets/images/pwa-install-edge.png)

If you added app to Dock in Safari, you get a prompt to open it in app:

![If you added app to Dock in Safari, you get a prompt to open it in app](https://blog.superails.com/assets/images/pwa-open-safari.png)

Current [SupeRails](https://superails.com/) manifest:

```json
// 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:

![Inspect manifest in Chrome Dev Tools](https://blog.superails.com/assets/images/pwa-manifest-debug.png)

Be sure that you also have these links in your `app/views/layouts/application.html.erb`:

```html
  <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:

![Multiple instances of a PWA](https://blog.superails.com/assets/images/pwa-multiple-instances.jpeg)

### 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](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration#examples):

```js
// 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);
    });
}
```

```js
// 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 Worker activated on a PWA](https://blog.superails.com/assets/images/pwa-service-worker-activated.png)

Service workers can get really sophisticated. I will not dig into this rabbithole now.

[Campfire](https://once.com/campfire) already has all the PWA goodies.

Let's wait for smart people to extract it into [Action Notifier framework for push notifications](https://github.com/rails/rails/issues/50454).

### Useful resources

- [MDN PWA docs](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps)
- Follow [Danny Moerkerke](https://twitter.com/dannymoerkerke) - he has great content about PWAs.
- 🤠 Learn [What PWA Can Do Today](https://whatpwacando.today/)
- [Alicia Rojas - Building an offline experience with a Rails-powered PWA - Rails World 2023](https://www.youtube.com/watch?v=Gj8ov0cOuA0&ab_channel=RubyonRails)
