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:
- App shell caching — HTML, core JavaScript, and CSS are cached on first visit
- 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-basemapscache defined invite.config.tsruntimeCaching 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=0andGEOLIBRE_CEREUS_CDN=0 - Both builds use
src/lib/offline-tiles.tsfor basemap caching, but store data differently (Cache API vs. filesystem) - The
IS_TAURI_BUILDguard invite.config.tsand the conditional registration insrc/main.tsxare 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →