
A few years ago, I came across Nolan Lawson's article from 2015 describing how he created pokedex.org - a demo on how one by employing the best practices (of 2015) could create an experience on the web that could rival that of native mobile applications:
- 60 fps animations
- near-instant loading
- background sync
- offline capability
- virtual dom
- web workers doing vdom-diffing and sending patches to the UI thread
It still is a great POC and an impressive piece of machinery, and in some sense, it is jarring how this describes a utopia that most 2025 pages are nowhere near achieving. But this begged some questions ... why are we not doing this and how does our current best practices stack up against this?
Achieving great frontend experiences (2015)
As Nolan writes, it's not rocket science. All native developers try to do these two things:
- Eliminate network calls.
- Use background threads.
He does it. It's not magic. Back then, in 2015, these technologies (Service Workers, Web Workers, GPU enabled animations, IndexedDB) were pretty new, but not super-new, either: my first task as a frontend developer at Making Waves in 2013 was to build an abstraction layer on top of LocalStorage, WebSQL and IndexedDB for browser-side persistence. But the use was not wide-spread, and it still is not.
I re-read it today, and I was reminded of a few nice tricks:
- the FLIP animation technique is still a great trick to GPU accelerate rendering of animations
- PouchDB still works great for syncing in the background and LocalForage actually just adds < 10 KB for a nice API on top of IDB. Might use this for a thing I have in mind.
All the rest still works too: the performance is no less than ten years ago.
𤯠So why does no-one bother implementing PWA features?
Because for many apps, those advanced features are not and were not critical and UX speed is about perception. Developers (and users) of modern frameworks get:
- Fast loads via SSR/static rendering.
- Smooth transitions via client routing.
- Reduced bandwidth via CDN edge caching.
- Responsive UI via hydration + React/Vue ergonomics.
PWA tech (service workers, local DBs, etc.) and modern frameworks solve different problems. But the perceived UX improvements that PWAs promised ā speed, resilience, instant loading ā got absorbed by SSR/CDN-first frameworks through other means.
"Why struggle with service workers and IndexedDB when this new stack gives us the same perceived speed with less risk?"
Pokedex envisioned as a Remix app
Next.js might have wiped the SSR floor with Remix (now React Router), but I still much prefer the standards based approach of Remix any day. Here is how I envision a Pokedex app of 2015 would look like:
| Concern | Old PWA-style Approach | Remix Way (Modern Approach) |
|---|---|---|
| Data caching | IndexedDB + Cache API | Route loaders + automatic data prefetching on navigation |
| App shell model | Service worker loads minimal shell, then fetches data | Nested layouts + static HTML + route data = app-like UX by default |
| Instant transitions | Manual cache logic + JS routing | <Link preload="intent"> + automatic data loading and transition |
| Image optimization | Cache API or base64 preloading | Lazy <img> or external CDN proxy (Cloudflare, Vercel, etc.) |
| Offline mode | Full service worker with offline fallback | Optional: use Workbox or vite-plugin-pwa |
| State persistence | IndexedDB or localStorage manually synced |
Use localStorage, sessionStorage, or React state as needed |
| Background sync | Service worker + sync event | Not built-in; possible with Workbox + background sync plugin |
| Push notifications | Service worker + Push API | Not supported directly by Remix; requires manual SW + push setup |