GeoLibre PWA vs. Tauri Desktop: How Offline Behavior Differs in OpenGeos/GeoLibre

The GeoLibre PWA requires an initial online visit to install its service worker and cache assets progressively, while the Tauri desktop build ships all core UI assets inside the native binary for immediate offline operation.

GeoLibre, the open-source geospatial analysis platform from OpenGeos, ships two "offline-ready" builds of the same application. Understanding how offline behavior differs between the PWA and Tauri desktop builds is critical for choosing the right deployment for your environment—whether you need browser-based portability or guaranteed offline operation in disconnected field conditions.

What Makes Each Build "Offline"?

The foundational difference lies in how assets become available without network access.

PWA: Service Worker Progressive Caching

The Progressive Web App relies on a Workbox service worker generated by vite-plugin-pwa. This is conditionally enabled only for web builds through the IS_TAURI_BUILD guard in apps/geolibre-desktop/vite.config.ts (lines 30-38 and 58-66).

The service worker implements a two-tier caching strategy:

  1. App shell caching — HTML, core JavaScript, and CSS are cached on first visit
  2. Runtime caching — Heavy, lazily-loaded assets like DuckDB-WASM and map plugins are cached on first use
// vite.config.ts — the IS_TAURI_BUILD guard disables PWA plugin for desktop
const IS_TAURI_BUILD = process.env.TAURI_ENV_PLATFORM !== undefined;

const pwaPlugin = IS_TAURI_BUILD
  ? null // No service worker for Tauri builds
  : VitePWA({
      // Workbox configuration with runtimeCaching rules...
      runtimeCaching: [
        {
          urlPattern: /geolibre-basemaps/,
          handler: 'CacheFirst',
          options: { cacheName: 'geolibre-basemaps' }
        }
      ]
    });

Tauri Desktop: Bundled Native Assets

The Tauri desktop build takes a fundamentally different approach. All static assets—JS, CSS, images, and map tiles—are bundled inside the native binary at build time. The service worker registration in src/main.tsx (lines 36-90) becomes a no-op for desktop builds.

// src/main.tsx — service worker registration skipped for Tauri
if (!isTauri()) {
  registerSW({
    onNeedReload() {
      // Defer reload until stale chunk 404s to preserve UI state
    }
  });
}

First-Run Experience Comparison

Scenario PWA Behavior Tauri Desktop Behavior
Core UI launch Requires online first visit Offline immediately
Heavy engines (DuckDB, PGlite, Pyodide) Downloaded from jsDelivr on first use, then cached Downloaded from CDN on first use unless bundled
Map tiles Cached after "Download Offline Area" action Written to local filesystem via same UI

The PWA's first-run dependency is validated by the end-to-end test in e2e/pwa.spec.ts (lines 4-26 and 58-88), which confirms the service worker installation flow and subsequent offline boot capability.

Basemap and Offline Area Handling

Both builds share the same "Download Offline Area" user interface, but the underlying storage mechanism differs:

  • PWA: Tiles are cached via the Cache API into the geolibre-basemaps cache defined in vite.config.ts runtimeCaching rules (lines 21-33)
  • Tauri: Tiles are written to the local filesystem through src/lib/offline-tiles.ts, then served from bundled assets without network requests
// src/lib/offline-tiles.ts — used by both builds
import { downloadOfflineArea } from '../lib/offline-tiles';

// Cache current view with 3km radius
downloadOfflineArea({
  radiusMeters: 3000,
  styleUrl: 'geolibre://offline-basemap/example'
});

The implementation in src/lib/offline-tiles.ts abstracts this difference—PWA writes to the Cache API, while Tauri writes to the local filesystem.

Engine Availability: CDN vs. Bundled

Heavy computational engines present the most significant offline behavior difference between builds:

Engine PWA Source Tauri Desktop Source
Pyodide jsDelivr CDN, cached by service worker jsDelivr CDN or bundled asset
PGlite/PostGIS jsDelivr CDN, cached by service worker jsDelivr CDN or bundled asset
Cereus-DB jsDelivr CDN, cached by service worker jsDelivr CDN or bundled asset

The cache definition in vite.config.ts (lines 71-84) specifies the geolibre-cdn-engines cache for PWA runtime caching. For fully offline Tauri builds, use environment flags to bundle engines directly:


# Force bundling of heavy engines — no CDN dependency

GEOLIBRE_PGLITE_CDN=0 GEOLIBRE_CEREUS_CDN=0 npm run build

When these flags are set to 0, the build system includes the WASM assets under /assets/, making them available without any network request.

Update and Reload Behavior

PWA: State-Preserving Lazy Reload

The PWA overrides Workbox's default autoUpdate behavior through the onNeedReload callback in src/main.tsx (lines 92-104). Rather than immediately reloading when a new service worker activates, GeoLibre:

  • Keeps the current UI state intact
  • Defers reload until a stale lazy chunk triggers a 404
  • Coordinates this through installStaleChunkReload

Tauri Desktop: Atomic Binary Replacement

With no service worker, the desktop build eliminates automatic reload entirely. Updates are delivered via:

  • The Tauri installer for standard builds
  • The native Microsoft Store updater for Store builds

UI state persists across upgrades because assets are replaced atomically by the installer process.

Environment Detection Patterns

Code that needs to branch based on build type can use these patterns:

// Detect active service worker (PWA only)
if (navigator.serviceWorker?.controller) {
  console.log('SW active – offline caching enabled');
}

// Detect Tauri environment (desktop only)
import { isTauri } from './lib/is-tauri';

if (isTauri()) {
  console.log('Running inside Tauri – assets are bundled locally');
}

Summary

  • PWA offline behavior depends on a Workbox service worker that progressively caches the app shell and engines after an initial online visit—ideal for browser users who can tolerate first-use downloads
  • Tauri desktop offline behavior bundles core UI assets in the native binary for immediate offline operation, with optional engine bundling via GEOLIBRE_PGLITE_CDN=0 and GEOLIBRE_CEREUS_CDN=0
  • Both builds use src/lib/offline-tiles.ts for basemap caching, but store data differently (Cache API vs. filesystem)
  • The IS_TAURI_BUILD guard in vite.config.ts and the conditional registration in src/main.tsx are the primary code locations where build-specific offline behavior is determined

Frequently Asked Questions

Can the PWA work completely offline after the first visit?

Yes, but only after the service worker installs during the first online visit and all required lazy-loaded engines have been fetched and cached on their first use. The core UI becomes offline-capable immediately after SW installation; heavy engines like DuckDB-WASM require their own first-use download.

How do I create a Tauri build with no external dependencies?

Set GEOLIBRE_PGLITE_CDN=0 and GEOLIBRE_CEREUS_CDN=0 before building. This forces the Vite configuration to bundle the PGlite, PostGIS, and Cereus-DB WASM assets under /assets/ rather than relying on jsDelivr fetches. The resulting binary requires no network access for any functionality.

Does the "Download Offline Area" feature work identically in both builds?

The user interface is identical, but the storage backend differs. The PWA uses the Cache API with the geolibre-basemaps cache; the Tauri build writes tiles to the local filesystem. Both are accessed through src/lib/offline-tiles.ts, which abstracts this implementation difference.

Why does the PWA need update handling code that Tauri doesn't?

The PWA's service worker requires explicit coordination to preserve UI state during updates—GeoLibre overrides onNeedReload to defer reload until necessary. Tauri updates happen at the binary level through the native installer, which replaces assets atomically without requiring in-application reload logic.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →