Offline
A service worker the build writes for you: the site keeps working with no network, writes wait for the connection, and a new version is offered, not forced.
4.1. Name offline in the config and the build writes a service worker that keeps the site usable with no network: stored pages load, writes made offline are sent when the connection returns, and a new deploy is offered to the reader rather than swapped in under them. There is no worker to write and no cache to name by hand.
Turning it on
Name offline in webfluent.app.json and the build writes a service worker, sw.js, that stores the site for when the network is gone:
json
{ "offline": {
"precache": ["/", "/docs/*"],
"fallback": "/offline",
"cache": { "/api/*": "network-first" },
"sync": true
} }
| Key | What it does |
|---|---|
|
|
The routes a first visit stores, as globs — |
|
|
A page's |
|
|
How a path the build did not write is fetched: |
|
|
A write made with no network is kept and sent later (below). |
A stored route loads with no network at all. When there is one, a navigation still goes to it first, so a page that changed is never served stale while the server is there to ask.
A write made offline
With sync, a write — any method but GET and HEAD, through fetch or an api — that fails because the network is gone is kept instead of thrown, and the call resolves with nothing, so what the page showed stays shown. The writes are sent in order when the connection returns: by Background Sync where the browser has it, so a closed tab still sends them, and by the page otherwise. A server that answers has the write, even if it refuses it; one that is down or asks to wait keeps it for later. A File body is not kept, and its call fails as before.
network.queued is how many wait.
A new version
The worker is versioned by a hash of everything the build wrote, so any deploy that changes a byte is a new version. It installs beside the old one and waits for the page to take it:
wf
page Home(path: "/", title: "Home", description: "The front page.") {
if update.available {
Button("A new version is ready — reload") { on click { update.apply() } }
}
if network.queued > 0 {
Text("{network.queued} change(s) will be sent when you are back online").muted
}
Heading("Home").h1
}
update.apply() takes it and reloads the page once: never on the first install, which only takes over a page that already works, and never twice for one update. The old version's store is deleted when the new one takes over.
Under wf serve the worker takes itself away: a page answered from its own store would hide every edit you make.
What it needs
- HTTPS, or
localhost. Browsers only run service workers from a secure origin. - A host that serves
sw.jsfresh. The page registers it withupdateViaCache: "none", so the browser asks for it on every visit — but a CDN in front can still hold a copy. Givesw.jsCache-Control: no-cache(Deploying). - Everything in
build/deployed together. The worker's version is a hash of every file the build wrote; deploying half a build confuses it.
Trying it
wf build, then servebuild/with anything static —python3 -m http.server -d buildwill do. (wf serveremoves the worker on purpose.)- Open the site, then in the browser's developer tools, Application → Service workers, check it is activated.
- Tick Offline in the Network panel and reload: stored routes load, the rest show the
fallback. - Make a write, untick Offline, and watch it go out.
wf verify runs against the built output too, and the repository's own browser tests hold the whole flow to a real Chrome.
Limits
- A
Filebody is never kept: an upload made offline fails as before. - A kept write is sent once it can be, possibly minutes later — make the server's endpoints safe to receive late, and idempotent where a retry could repeat one.
- What
cachedoes not name passes straight through, so an API the site depends on while offline needs anetwork-firstorstale-while-revalidateentry. - The browser decides how much it keeps; a store can be evicted under storage pressure, and the next visit fetches it again.
Checked by the test suite
Every code block in the guide is parsed, checked and type-checked on each release.