# Offline Map Tile Capabilities in WorldMonitor’s PWA Service Worker

> Explore offline map tile capabilities in WorldMonitor's PWA service worker. Discover how its NetworkFirst caching strategy enables full map rendering without an internet connection.

- Repository: [Elie Habib/worldmonitor](https://github.com/koala73/worldmonitor)
- Tags: internals
- Published: 2026-03-09

---

**WorldMonitor’s Progressive Web App uses a NetworkFirst caching strategy in its service worker to store PMTiles vector tile ranges locally, enabling full map rendering without an internet connection after the initial load.**

The `koala73/worldmonitor` repository implements a robust offline-first architecture for its mapping interface through a carefully configured service worker. By leveraging `vite-plugin-pwa` to intercept PMTiles requests and apply intelligent caching policies, the application ensures that users can browse geographic data even when connectivity is unavailable or intermittent.

## Network-First Caching for PMTiles Ranges

The service worker configuration in [`vite.config.ts`](https://github.com/koala73/worldmonitor/blob/main/vite.config.ts) specifically targets vector tile archives using a **NetworkFirst** handler. This strategy intercepts requests where the URL ends with `.pmtiles` or originates from PMTiles CDNs (`*.r2.dev` or `build.protomaps.com`).

```typescript
// vite.config.ts - runtimeCaching configuration
{
  urlPattern: ({ url }) => url.pathname.endsWith('.pmtiles') || 
                         url.hostname.includes('r2.dev') ||
                         url.hostname === 'build.protomaps.com',
  handler: 'NetworkFirst',
  options: {
    cacheName: 'pmtiles-ranges',
    expiration: {
      maxEntries: 500,
      maxAgeSeconds: 30 * 24 * 60 * 60 // 30 days
    }
  }
}

```

This approach prioritizes fresh data by attempting the network first, but stores the response bytes in the `pmtiles-ranges` cache. Subsequent requests for identical tile ranges are served directly from the cache, allowing the map to continue drawing even when `navigator.onLine` returns false.

### Cache Size and Lifetime Management

The configuration imposes strict storage constraints to prevent unbounded growth. The `pmtiles-ranges` cache retains a maximum of **500 entries** and automatically purges tiles older than **30 days** (2,592,000 seconds). This balance ensures sufficient offline coverage while maintaining reasonable storage footprints on user devices.

## Static Asset Precaching for UI Reliability

Beyond dynamic tile data, the service worker precaches all essential application assets at install time. The `workbox.globPatterns` in [`vite.config.ts`](https://github.com/koala73/worldmonitor/blob/main/vite.config.ts) captures JavaScript bundles, CSS stylesheets, icons, images, and font files:

```typescript
// vite.config.ts - workbox configuration
workbox: {
  globPatterns: ['**/*.{js,css,ico,png,svg,woff2}'],
  // Additional runtimeCaching entries...
}

```

This guarantees that the map interface itself—including the MapLibre GL rendering engine and UI components—loads instantly from the cache during subsequent visits, regardless of network status.

## Stale-While-Revalidate for Visual Assets

Map-related imagery and typography receive a **StaleWhileRevalidate** treatment. The worker caches image assets matching patterns like `\.(?:png|jpg|jpeg|svg|gif)` and Google Fonts (`fonts.googleapis.com`) with this strategy, serving cached versions immediately while fetching updates in the background. This ensures map icons, glyphs, and symbols remain available offline while silently refreshing when connectivity returns.

## Service Worker Lifecycle and Protocol Registration

The registration logic in [`src/main.ts`](https://github.com/koala73/worldmonitor/blob/main/src/main.ts) handles version consistency critical for offline reliability. On initialization, the application clears stale workers and caches, then registers the new worker. It also triggers page reloads when updated workers take control, preventing version skew that could otherwise break offline rendering after deployments.

For the service worker to intercept PMTiles requests, the application must register the custom protocol handler. The `registerPMTilesProtocol` function in [`src/config/basemap.ts`](https://github.com/koala73/worldmonitor/blob/main/src/config/basemap.ts) configures MapLibre GL to route `pmtiles://` URLs through the standard fetch pipeline, making them visible to the service worker's caching rules.

```typescript
// src/config/basemap.ts
import { registerPMTilesProtocol } from '@/config/basemap';

// Called before map instantiation
registerPMTilesProtocol();

```

When the map requests vector tiles through this protocol, the URLs match the service worker's `urlPattern` and the tile ranges are stored in `pmtiles-ranges`.

## Verifying Offline Behavior

To test the offline capabilities manually, enable the "Offline" toggle in your browser's Developer Tools under Application → Service Workers. Refresh the page—the UI including the map should still render, and network requests for `*.pmtiles` will show `(from ServiceWorker)` in the response column.

## Summary

- **NetworkFirst caching** for `.pmtiles` files and CDN endpoints stores vector tile ranges in the `pmtiles-ranges` cache, enabling offline map rendering after the initial network fetch.
- **Storage limits** cap the tile cache at 500 entries with a 30-day expiration, managed automatically by Workbox to prevent excessive disk usage.
- **Precached static assets** including JavaScript, CSS, and fonts ensure the map UI framework loads without network connectivity.
- **Stale-while-revalidate strategies** keep map icons and typography available offline while updating in the background when connections resume.
- **Protocol registration** is required in [`src/config/basemap.ts`](https://github.com/koala73/worldmonitor/blob/main/src/config/basemap.ts) for the service worker to intercept and cache PMTiles requests properly.

## Frequently Asked Questions

### How does WorldMonitor handle map tiles when the user goes offline?

The service worker serves previously cached PMTiles ranges from the `pmtiles-ranges` cache using a NetworkFirst strategy. After the first successful fetch, tile data persists locally for 30 days, allowing the map to render geographic features without an active connection.

### What is the storage limit for offline map tiles?

The configuration restricts the `pmtiles-ranges` cache to **500 entries** and a **30-day maximum age**. Older or excess entries are automatically purged by the Workbox expiration plugin to prevent excessive disk usage on user devices.

### Does the offline functionality work for all map providers or only PMTiles?

According to the [`vite.config.ts`](https://github.com/koala73/worldmonitor/blob/main/vite.config.ts) source code, the offline caching specifically targets PMTiles archives (`.pmtiles` files) and their CDN endpoints (`*.r2.dev`, `build.protomaps.com`). The service worker configuration explicitly filters for these URL patterns, meaning offline capabilities are optimized for the PMTiles provider implementation.

### How do I verify that the service worker is caching tiles correctly?

Open your browser's Developer Tools, navigate to the Application panel, and enable the "Offline" toggle in the Service Workers section. Refresh the page and inspect the Network tab—requests for `.pmtiles` resources should show `(from ServiceWorker)` in the size column, confirming cached responses are being served instead of network requests.