# How TREK Implements PWA Offline Support Using Service Workers

> Discover how TREK leverages PWA offline support with Service Workers to cache API responses and map tiles, ensuring seamless functionality even without network access.

- Repository: [Maurice/TREK](https://github.com/mauriceboe/TREK)
- Tags: how-to-guide
- Published: 2026-07-09

---

**TREK enables offline functionality by registering a Service Worker at startup that intercepts network requests to cache API responses and map tiles, while providing mechanisms to clear sensitive data on logout and handle stale authentication states.**

The TREK repository demonstrates a robust **Progressive Web App (PWA)** architecture that delivers an offline-first experience for outdoor mapping applications. By leveraging the **Cache API** and **Service Worker** lifecycle, the application ensures critical map data and user content remain accessible without network connectivity. This implementation combines automated tile prefetching with strategic cache management to balance performance against data privacy.

## Service Worker Registration and Architecture

### Automatic Registration via Vite-PWA

The application registers its Service Worker immediately at startup using the **Vite-PWA plugin**. This configuration automatically generates the [`sw.js`](https://github.com/mauriceboe/TREK/blob/main/sw.js) file and invokes `navigator.serviceWorker.register()`, establishing the interception layer required for all subsequent network requests. Once active, the Service Worker implements a **Cache-First** strategy that serves static assets and API responses from local storage when the device is offline.

### Offline-First Request Handling

When the user loses connectivity, the Service Worker prevents "page not found" errors by returning cached content. Components throughout the application check `navigator.onLine` to adjust behavior dynamically, ensuring the single-page application shell remains functional even without network access.

## Prefetching Map Tiles for Offline Navigation

### Geographic Bounding Box Traversal

The `prefetchTiles` function in [`client/src/sync/tilePrefetcher.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/sync/tilePrefetcher.ts) proactively caches map data before the user enters areas with poor connectivity. This routine accepts a geographic bounding box (`bbox`) and zoom range parameters (`minZoom` and `maxZoom`), then calculates the precise tile coordinates needed to cover the region.

```ts
// client/src/sync/tilePrefetcher.ts – prefetches map tiles into the SW cache
export async function prefetchTiles(
  bbox: TileBbox,
  tileUrlTemplate: string,
  minZoom = 10,
  maxZoom = 16,
): Promise<number> {
  if (!navigator.onLine) return 0                     // abort when offline
  if (!('serviceWorker' in navigator) || !navigator.serviceWorker.controller) return 0

  let fetched = 0
  for (let z = minZoom; z <= maxZoom; z++) {
    // compute tile coordinates …
    for (let x = minX; x <= maxX; x++) {
      for (let y = minY; y <= maxY; y++) {
        const url = buildTileUrl(tileUrlTemplate, z, x, y)
        fetch(url, { mode: 'no-cors' }).catch(() => {})   // SW caches the response
        fetched++
      }
    }
  }
  return fetched
}

```

### No-CORS Fetching for Cross-Origin Tiles

By specifying `{ mode: 'no-cors' }` in fetch requests, the tile prefetcher ensures that cross-origin map tiles can be stored in the cache even when the server lacks explicit CORS headers. The Service Worker intercepts these responses automatically, populating the cache with geographic data that remains available when the device is offline.

## Managing Sensitive Data and Cache Privacy

### Cache Purging on User Logout

When users log out, the authentication store explicitly removes caches containing private information. The `authStore.logout()` method in [`client/src/store/authStore.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/store/authStore.ts) deletes the `api-data` and `user-uploads` caches to ensure that no sensitive user information persists on the device after session termination.

```ts
// client/src/store/authStore.ts – clears SW caches on logout
if ('caches' in window) {
  await Promise.all([
    caches.delete('api-data').catch(() => {}),
    caches.delete('user-uploads').catch(() => {}),
  ])
}

```

This approach ensures that offline support does not compromise data privacy by leaving authenticated content accessible on shared or stolen devices.

## Handling Authentication and Service Worker Updates

### Stale Service Worker Detection

In scenarios where the Service Worker serves a stale application shell that causes authentication failures, TREK implements a recovery mechanism. The `unregisterSWAndReload()` function in [`client/src/api/client.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/api/client.ts) removes the active Service Worker registration and forces a full page reload, allowing the edge proxy to re-establish proper authentication with a fresh application state.

```ts
// client/src/api/client.ts – removes the SW before a forced reload
async function unregisterSWAndReload(): Promise<void> {
  try {
    const reg = await navigator.serviceWorker?.getRegistration()
    if (reg) await reg.unregister()
  } catch { /* ignore */ }
  window.location.reload()
}

```

This mechanism resolves conflicts where the cached SPA shell becomes incompatible with current authentication requirements, ensuring users can regain access without manually clearing browser data.

## Summary

- TREK registers its Service Worker at startup via the **Vite-PWA plugin**, enabling request interception from the first page load.
- The `prefetchTiles` routine in [`client/src/sync/tilePrefetcher.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/sync/tilePrefetcher.ts) pre-caches map tiles using `no-cors` fetch requests, ensuring geographic data is available offline.
- Sensitive caches including `api-data` and `user-uploads` are explicitly deleted in [`client/src/store/authStore.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/store/authStore.ts) during logout to protect user privacy.
- The `unregisterSWAndReload` helper in [`client/src/api/client.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/api/client.ts) resolves authentication conflicts by removing stale Service Workers and forcing a fresh reload.
- A **Cache-First** strategy ensures the application remains functional without network connectivity, serving previously cached assets and API responses.

## Frequently Asked Questions

### How does TREK cache map tiles for offline use?

TREK implements a tile prefetching system that traverses geographic bounding boxes and calculates tile coordinates for zoom levels 10 through 16. The `prefetchTiles` function issues fetch requests with `{ mode: 'no-cors' }` to the map tile server, which the Service Worker intercepts and stores in the browser's Cache API, making the tiles available when the device is offline.

### What happens to cached data when a user logs out of TREK?

The authentication store explicitly deletes sensitive caches during logout. Specifically, `authStore.logout()` removes the `api-data` and `user-uploads` cache stores using `caches.delete()`, ensuring that no private user information or session data remains stored locally on the device after the user signs out.

### How does TREK handle authentication failures caused by stale Service Workers?

When authentication fails due to the Service Worker serving a stale application shell, TREK calls `unregisterSWAndReload()` from [`client/src/api/client.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/api/client.ts). This function retrieves the active Service Worker registration using `navigator.serviceWorker.getRegistration()`, unregisters it, and forces a hard page reload, allowing the server to re-authenticate the user with a fresh application state.

### Does TREK check network connectivity before attempting to fetch resources?

Yes, the application checks `navigator.onLine` before initiating prefetch operations. In [`client/src/sync/tilePrefetcher.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/sync/tilePrefetcher.ts), the function returns immediately if the browser reports offline status, preventing unnecessary fetch attempts and conserving battery life on mobile devices.