# How TREK's PWA Implementation Enables Offline Support with Service Workers

> Discover how TREK's PWA uses Service Workers to enable seamless offline support by caching API responses and map tiles. Learn about data clearing and auth updates.

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

---

**TREK enables offline support by registering a Service Worker that intercepts network requests, caches API responses and map tiles via the Cache API, and serves cached content when the device is offline, while providing mechanisms to clear sensitive data on logout and handle authentication updates.**

TREK is an open-source trekking application built with modern web technologies that leverages Progressive Web App (PWA) capabilities to deliver a seamless offline-first experience. According to the TREK source code, the implementation combines a Service Worker generated by the Vite-PWA plugin with custom prefetching routines and cache management strategies to ensure users can access map data and core functionality without network connectivity.

## Service Worker Registration and Initialization

The foundation of TREK's offline capability begins with Service Worker registration handled automatically by the Vite-PWA plugin. During application startup, the plugin calls `navigator.serviceWorker.register()` to install the [`sw.js`](https://github.com/mauriceboe/TREK/blob/main/sw.js) file, which immediately begins intercepting network requests.

As implemented in the project's [`vite.config.js`](https://github.com/mauriceboe/TREK/blob/main/vite.config.js), this configuration generates a Service Worker that employs a **Cache-First** strategy for static assets. Once registered, the Service Worker acts as a network proxy, allowing the application to store and retrieve responses even when the device disconnects from the internet.

## Prefetching Map Tiles for Offline Use

A critical component of TREK's offline support is the aggressive prefetching of map tiles before connectivity is lost. The `prefetchTiles` function in [`client/src/sync/tilePrefetcher.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/sync/tilePrefetcher.ts) programmatically populates the Service Worker cache by fetching tiles within a specified geographic bounding box.

The function iterates through zoom levels from 10 to 16, calculates tile coordinates, and issues `fetch` requests with `{ mode: 'no-cors' }`. Because the Service Worker intercepts these requests, the responses are automatically cached, making map data available offline:

```typescript
// 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
}

```

This approach ensures that users can browse previously viewed map regions without consuming additional bandwidth or requiring live connectivity.

## Caching API Responses and Static Assets

Beyond map tiles, the Service Worker intercepts all API requests and static asset fetches, storing responses in the Cache API. This provides **instant offline reads** for previously accessed data, preventing "page not found" errors when users navigate through cached sections of the application.

Components throughout the application check `navigator.onLine` to determine connectivity status, allowing the UI to gracefully degrade to cached content when the network is unavailable. This offline-first architecture ensures the application shell and critical data remain accessible regardless of network conditions.

## Security: Clearing Sensitive Caches on Logout

TREK implements strict cache hygiene to protect user privacy. When a user logs out, the `authStore.logout()` method explicitly deletes caches containing sensitive information, specifically the `api-data` and `user-uploads` stores:

```typescript
// 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 ensures no private trekking data, user uploads, or authentication artifacts persist on the device after logout, maintaining security while preserving the benefits of offline caching during active sessions.

## Handling Service Worker Updates and Authentication

Stale Service Workers can interfere with authentication flows by serving cached versions of the application shell. TREK addresses this through the `unregisterSWAndReload()` function in [`client/src/api/client.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/api/client.ts), which removes the Service Worker registration and forces a full page reload when authentication redirects are required:

```typescript
// 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 ensures that users always receive the latest application version when re-authenticating, preventing edge cases where the Service Worker might serve a stale shell that cannot properly handle authentication tokens.

## Summary

- **Service Worker Registration**: TREK uses the Vite-PWA plugin to register [`sw.js`](https://github.com/mauriceboe/TREK/blob/main/sw.js) at startup, establishing a Cache-First strategy for offline asset delivery.
- **Tile Prefetching**: The `prefetchTiles` function in [`client/src/sync/tilePrefetcher.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/sync/tilePrefetcher.ts) proactively caches map tiles using `no-cors` fetches, enabling offline map viewing.
- **Offline Detection**: Components check `navigator.onLine` to determine connectivity status and serve cached content when offline.
- **Cache Security**: The `authStore.logout()` method clears sensitive caches (`api-data` and `user-uploads`) to protect user privacy.
- **Update Handling**: `unregisterSWAndReload()` in [`client/src/api/client.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/api/client.ts) removes stale Service Workers during authentication failures to ensure fresh application shells.

## Frequently Asked Questions

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

TREK's `prefetchTiles` function in [`client/src/sync/tilePrefetcher.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/sync/tilePrefetcher.ts) calculates tile coordinates for a geographic bounding box and zoom range (10-16), then issues `fetch` requests with `{ mode: 'no-cors' }`. The Service Worker intercepts these requests and caches the responses, making map data available when the device goes offline.

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

When a user logs out, the `authStore.logout()` method explicitly deletes the `api-data` and `user-uploads` caches using the Cache API. This ensures sensitive trekking data and user uploads do not persist on the device after the session ends.

### Why does TREK unregister the Service Worker during authentication failures?

TREK unregisters the Service Worker via `unregisterSWAndReload()` in [`client/src/api/client.ts`](https://github.com/mauriceboe/TREK/blob/main/client/src/api/client.ts) when authentication fails because the Service Worker might be serving a stale Single Page Application (SPA) shell. Removing the registration and reloading ensures the edge proxy can re-authenticate the user and serve the latest application version.

### How does TREK detect offline status?

Components throughout the application check the `navigator.onLine` property to determine network connectivity. When the device is offline, the application continues to function using cached data from the Service Worker, avoiding "page not found" errors and maintaining usability.