Skip to content
Back to blog
Freelance
2026-09-19 8 min read

Case Study: Building a PWA Coaching Platform Without a Framework

The Sri Prayag Classes coaching PWA, installable app shell, offline-first service worker, deep course taxonomy, and a Cloudflare edge in front of a custom domain.

PWA
Service Worker
Vanilla JS
Cloudflare
Case Study: Building a PWA Coaching Platform Without a Framework

In 2025 I took on the web presence for Sri Prayag Classes as a solo delivery, architecture, frontend, and the full deploy pipeline. The result, sriprayagclasses.com, is a progressive web app: installable on a phone, openable offline, and deep-linkable straight into a specific course.

Why No Framework

The target device is a mid-range Android on 3G, and the person maintaining the codebase after me is not a developer. A framework runtime, 60-90 KB of min+gzip just to bootstrap React or Vue, is a cost I did not want to push through the app shell. So the frontend is vanilla JavaScript composed as ES modules: small purpose-built modules (banner, main, modal) with no build step and no transpile. The module graph stays tiny, and the code remains legible to a different kind of maintainer.

The PWA Layer

Two artifacts carry the weight:

  • Web app manifest, display: standalone, theme_color, and the 192/512 icon set. This is what makes the app installable to the home screen with its own splash and standalone viewport.
  • Service worker, the offline brain. Its fetch handler routes by resource type:
// navigate requests (real URLs): network-first, fall back to cache
// static assets: cache-first, backfill the cache on miss
// That split keeps the shell instant on revisit while letting
// course-catalog updates propagate.

Network-first for routes, cache-first for static assets, the whole offline strategy in one line.

Deep Course Taxonomy

The catalog is not one list. It is a set of deep routes: /courses/jee-advanced, /courses/neet-ug, and so on, each with its own head, metadata, and CTA. The routes are real URLs (not hash fragments), which is exactly what lets the service worker's navigation handler intercept and serve them offline.

Conversion and Retention Surfaces

  • Student sign-in at /signin, the portal gates study material behind a client-managed session.
  • WhatsApp deep links (wa.me) on every course page, the conversion channel that actually works in this market: one tap exits to the messaging app with the enrollment message pre-filled.

The Edge

The site sits behind Cloudflare on a custom domain: TLS termination at the edge, CDN-cached static assets, and PWA assets tagged as long-lived immutable URLs, so the service worker's cache is filled with byte-stable content.

Performance Budget

The targets I set for the build:

  • LCP under 2.5 s on a mid-range phone over throttled 3G.
  • JS payload kept under ~30 KB total.
  • WebP images, hero carrying fetchpriority="high".
  • Near-zero CLS, every image gets a fixed aspect-ratio box.

What I Learned

Shipping a PWA without a framework forced me to think about where each byte runs. A service worker is not a cache, it is a routing and fallback policy. Get that right and the offline story mostly takes care of itself.