
Offline-First PWAs: Field Notes from the Middle of Nowhere
The Day the Bars Disappeared
Nothing humbles a web dev like opening Chrome DevTools in the middle of a soybean field and watching the No Internet dino pop up. Our farm-management PWA looked slick on office Wi-Fi, but growers needed it thirty kilometres past the last cell tower. Here's how we moved from "works on my laptop" to reliably offline-first.
Why "Offline-First" Beats "Offline-Capable"
- Trust – Users treat cached apps like native; you get one chance to prove their data is safe.
- Speed – Local reads are always faster than network hops, signal or not.
- Battery – Fewer retries mean less radio time and longer device life in the field.
1 | Register the Service Worker (the Right Way)
// public/sw.js — bare minimum
self.addEventListener("install", (evt) =>
evt.waitUntil(
caches.open("static-v1").then((c) => c.addAll(["/", "/index.html", "/styles.css"]))
)
);
self.addEventListener("fetch", (evt) => {
evt.respondWith(
caches.match(evt.request).then(
(hit) => hit || fetch(evt.request)
)
);
});
Pro tip: register the worker after window.load so first-paint isn't blocked.
2 | Choose a Caching Recipe
| Scenario | Strategy | My pick for the farm app |
|---|---|---|
| Static assets | Cache-first | Yes |
| API GETs | Stale-while-revalidate | Yes (inventory lists) |
| Mutations | Network-first + queue fallback | Yes (field-visit logs) |
The golden rule: never risk staleness for anything that affects money or safety.
3 | Syncing Mutations After You’re Back Online
- Write actions to IndexedDB with a UUID and timestamp.
- Show them in the UI immediately (optimistic).
- When
navigator.onLineflips or a Background Sync event fires, replay the queue. - Make endpoints idempotent so duplicate retries can’t corrupt state.
4 | Debugging the Invisible
- DevTools → Application → Service Workers → "Offline" checkbox.
navigator.onLinelies; pull Wi-Fi to test real radio drop.- Use Chrome
––disable-cacheflag to confirm fresh installs.
5 | Field-Test Checklist
- App loads in airplane mode after first visit
- Cached version warns if backend schema changed ("x-app-version" header)
- Mutation queue survives page reload & device reboot
- Light-house PWA score ≥ 90 on 3G throttle
- Clear “sync pending” badge when queue drains successfully
What Changed for Our Growers?
| Metric | Before | After |
|---|---|---|
| Failed form submissions | 42 % | 2 % |
| Avg. time to sync field visits | N/A (manual) | 15 s |
| Support tickets about “data lost” | Weekly | Zero in 3 months |
Parting Seeds
Service Workers aren’t magic—but with a disciplined caching plan, background sync, and a good debug story, they turn flaky networks into a non-issue. If your users venture off the grid (literally or figuratively), building offline-first isn’t a luxury; it’s table stakes.
Next stop: integrating push notifications so the app can whisper, “Sync complete!” while farmers are already on the next tractor row.