DEV Community

Shahzaib
Shahzaib

Posted on

How I Made PdfWord Work Fully Offline as a PWA

Series: Building PdfWord — a free, no-backend PDF tools site (Part 10)

Most "free PDF tools" die the moment your Wi-Fi does. That's weird when you think about it — the actual work (merging, compressing, converting) happens on your CPU, not on their server. So when I built PdfWord with zero backend — every tool is static HTML + JavaScript running entirely in your browser — making it work fully offline wasn't a feature request. It was the obvious consequence of the architecture.

Here's how I did it, including the two mistakes that cost me the most time.

Try it: PdfWord — install it, then turn on airplane mode. It still works.


The architecture made it easy (the details made it hard)

A PWA is really two things: a manifest.json (name, icons, colors, how it launches) and a service worker (a script that intercepts network requests and serves cached files). Because there's no server to reach, the service worker just needs to make the files available offline.

The manifest was the fun part. Beyond the basics (name, 192/512 icons, display: standalone, theme color #4f46e5), I added two things users actually feel:

  • App shortcuts — long-press the icon and jump straight to Merge PDF or Compress PDF. Skips the homepage entirely.
  • Share target — share a PDF from WhatsApp, and PdfWord appears in the share sheet. The service worker catches the shared file via a POST to /share.html, stashes it in a cache, and opens the app with the file ready. This one felt like magic the first time it worked.

The precache mistake

My first service worker precached everything: pdf-lib, pdf.js, SheetJS, Tesseract — over 2MB of libraries on install. The installed app opened noticeably slowly, especially on low-end Android phones (which is most of my audience).

The fix was a rule I now apply everywhere: precache only the true app shell (~120KB) — the homepage, the shared JS/CSS, the icons, the manifest. The heavy libraries cache on demand: the first time you open the PDF-to-Excel tool, its SheetJS library downloads and gets cached; after that it works offline too. Nobody should wait for libraries they haven't used yet.

The caching strategy: two rules, no exceptions

// HTML pages: network-first (always fresh), offline falls back to cache
if (isPage) {
  e.respondWith(fetch(e.request).then(res => {
    // stash a fresh copy, then serve it
    const copy = res.clone();
    caches.open(CACHE).then(c => c.put(e.request, copy));
    return res;
  }).catch(() => caches.match(e.request)));
}
// Static assets (JS/CSS): cache-first — they change rarely
Enter fullscreen mode Exit fullscreen mode

Pages are network-first because a stale tool page is worse than a slow one. Assets are cache-first because they're fingerprinted by the cache version anyway. Simple, predictable, debuggable.

The version-bump discipline (learned the hard way)

Here's the thing nobody tells you about service workers: the worker only updates when sw.js bytes change. I once shipped a deploy where I bumped the cache version (pdfword-v7 → v9) only in the staging folder and forgot the source file. The source drifted, and installed apps kept serving stale files essentially forever — the update mechanism never triggered because the served sw.js was byte-identical.

Now it's a ritual: bump the version in the source sw.js, copy every file to its exact staged path, grep-verify the staged copy, then deploy. And on the UX side, there's a one-tap "New version available!" banner — users click Refresh once instead of ever needing a hard reload.

Related war story: Ctrl+Shift+R does NOT bypass the service worker. I once "verified" a bug fix for a full hour while unknowingly testing the old cached code. My QA rule now: if the banner appears, refresh until it's gone, then trust the test.

The honest limitations

  • The first visit needs internet (obviously — the files have to come from somewhere).
  • A tool's heavy library downloads on first use, so "offline" for a tool you never opened means a one-time download first.
  • On iOS it's "Add to Home Screen," not a store install — Apple being Apple.

None of these are dealbreakers for a tools site. The win is real: open the app in airplane mode, merge two PDFs, get your file. No server was ever involved, so no server is missed.

Try it: PdfWord — install it to your home screen, go offline, and merge a PDF. That's the whole demo.

What's the smallest useful thing you've ever made work offline? I'm collecting ideas for what deserves the offline treatment next.

Top comments (0)