rastrillo / pwa Public

Clone
git clone https://amadan.net/rastrillo/pwa

Plain git — no account needed to clone.

Download

Download this file

1# Rastrillo PWA
2
3Add an installable app manifest, a public offline page and controlled worker
4updates to a web app. This optional module has no runtime dependencies.
5Web Push composes through [aviso](https://amadan.net/rastrillo/aviso).
6
7The kit does not store pages, API responses, messages, keys or pending writes.
8Offline navigation shows a public fallback. Offline reading and editing need
9an application data model and synchronisation contract; see
10[docs/offline.md](docs/offline.md).
11
12## Try it
13
14From this checkout:
15
16```sh
17cd examples/basic
18go run .
19```
20
21Open `http://127.0.0.1:8080`, reload once after the worker has installed,
22then disconnect and reload. The worker returns an offline page with a retry
23link. Connect again and retry to return to the app. The sample serves valid
24PNG icons as placeholders; replace them with your app's icons.
25
26The sample imports aviso's worker helper and wires notification handlers.
27It does not enrol subscriptions or send push messages. Follow aviso's own
28skill to provision its server and browser enrolment.
29
30## Add it to an app
31
32Read [SKILL.md](SKILL.md). Install a reviewed version of
33`amadan.net/rastrillo/pwa`. Create `pwa.Manifest` with a permanent ID,
34name, start URL, scope ending in `/`, and your icons. Call `.Handler()` at
35boot and handle its error. Serve the manifest and worker assets without
36authentication redirects. Mount the returned handler at
37`/manifest.webmanifest`. Mount assets with:
38
39```go
40mux.Handle("/pwa/", http.StripPrefix("/pwa", pwa.Assets()))
41```
42
43Add the manifest link, theme colour and Apple touch icon to the page head:
44
45```html
46<link rel="manifest" href="/manifest.webmanifest">
47<meta name="theme-color" content="#234d45">
48<link rel="apple-touch-icon" href="/static/icon-180.png">
49```
50
51Serve your own `/sw.js` with `Content-Type: text/javascript` and
52`Cache-Control: no-cache`:
53
54```js
55importScripts("/pwa/worker.js");
56RastrilloPWA.install();
57```
58
59Then register it from your page's JavaScript:
60
61```js
62import { register } from "/pwa/client.mjs";
63await register({onUpdate: () => { updateNotice.hidden = false; }});
64```
65
66Define `updateNotice` in the app. Suggested text: “An update is ready. Save
67your work in all tabs, then close and reopen the app.” The helper neither
68reloads pages nor automatically activates a waiting worker. Browser support
69is detected; registration resolves to `null` without service workers.
70
71`activateUpdate(registration)` explicitly asks a waiting worker to activate
72and returns whether there was one. Activation affects all tabs in its scope.
73Use it only when the app has resolved unsaved work across those tabs; handle
74`controllerchange` in the app if a reload is appropriate. Closing all tabs
75allows normal browser activation without this helper.
76
77## Worker contract
78
79`RastrilloPWA.install({offlineHTML})` attaches navigation and update-message
80handlers once. `offlineHTML` is optional, trusted build-time public HTML.
81The default is a self-contained English page. Provide an app-owned public
82translation if needed; neither account details nor keys belong in it.
83
84Only same-origin, in-scope GET navigations are intercepted. A network
85failure returns the fallback with status 503 and `Cache-Control: no-store`.
86HTTP errors remain unchanged. API calls and mutations are untouched. The
87fallback permits inline styles but no scripts, forms or external resources.
88
89The worker and imported scripts are persisted by the browser's worker
90installation; the kit never writes Cache Storage or IndexedDB. With no
91`clients.claim`, the first page stays uncontrolled until its next navigation.
92Removing the worker registration removes the fallback capability.
93
94Use one worker registration per app scope. To add push, import aviso's
95helper into this same `sw.js`, attach its push/click/subscription-change
96handlers, and pass the same registration to its browser module. Read the
97version-pinned aviso skill for its authentication and key-rotation contracts.
98Keep notification payloads and encryption in the app.
99
100Production needs HTTPS. Installation UI differs by browser; on iOS guide
101the person to add the app to the Home Screen and sign in inside that copy
102before enabling push. Registration alone does not prompt installation or
103grant notification permission.
104
105## Validation
106
107`make ci` runs Go and JavaScript tests and a real Chromium/WebKit browser
108drive. Install the matching Playwright browsers first with
109`npx playwright install chromium webkit` after `npm ci`. Missing browsers
110fail the gate. The nested example is built and tested by the gate too.
111
112The browser drive covers navigation failures, preservation of HTTP errors,
113API failure behaviour, empty caches and updates across two edited tabs.
114Chromium uses its offline switch; WebKit uses a dropped network connection
115because its automation switch can abort before calling the worker. Device
116installation and real iOS push delivery remain manual checks; this gate
117does not claim them.
118
119MPL-2.0; see [LICENSE](LICENSE).
120