cd /news/developer-tools/one-react-vite-product-across-pwa-an… · home › topics › developer-tools › article
[ARTICLE · art-140664] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=· neutral

One React/Vite product across PWA and Tauri—without pretending they are identical

A developer's WorldScript Studio case study shows how a single React/Vite codebase can target GitHub Pages, an installed PWA, edge hosts, and a Tauri desktop app while keeping platform authority boundaries explicit rather than pretending the surfaces are interchangeable. The project shares domain semantics but routes persistence and networking through platform-specific adapters: browser/PWA projects use origin-scoped IndexedDB with passphrase-based encryption, while the Tauri desktop store uses filesystem-backed application data that is not currently encrypted at rest. Because GitHub Pages cannot inject response headers, the deployment relies on a meta Content Security Policy as the sole enforcement point there, whereas Vercel and Cloudflare Pages set real headers and run a shared same-origin Claude proxy.

by read5 min views2 publishedSep 27, 2026

One React/Vite codebase can power a GitHub Pages site, an installed PWA, an edge-hosted deployment, and a Tauri desktop app.

That does not make those surfaces interchangeable.

This distinction matters whenever an application handles user projects, offline behavior, AI providers, filesystem access, or security policy. Shared components are valuable. Shared assumptions can be dangerous.

WorldScript Studio is a useful case study because its React/Vite application is intentionally available across browser/PWA and Tauri desktop environments. The product shares domain semantics, but it does not pretend that a browser tab and a native shell have the same authority boundaries. Code references are from the repository at commit 2d9157c0 (2026-09-28), release v1.28.8; simplified excerpts are labeled.

A cross-platform product needs a stable answer to questions such as:

Those answers should be shared.

The mechanisms underneath them should not be forced to look identical.

For a PWA, the browser provides IndexedDB, Cache Storage, service workers, Web APIs, WebGPU, and origin-scoped storage. A desktop shell can provide application-data filesystem access, native networking, OS integration, and platform packaging.

Trying to hide every difference behind a single universal abstraction often creates a worse outcome: browser APIs leak into desktop code, native assumptions leak into web code, and the product accumulates several accidental definitions of persistence or network policy.

A better rule is:

Share domain semantics and interoperability contracts. Expose platform capabilities through explicit adapters.

The same static build can be deployed to different hosts, but hosting changes what the application can guarantee.

Surface Important capability Important limitation
GitHub Pages Static public deployment Cannot inject arbitrary HTTP security headers
Vercel / Cloudflare Pages Response headers and edge-function capabilities Still browser-origin storage for web project data
Installed PWA Cached shell and browser-native installation Storage remains origin- and browser-specific
Tauri desktop Filesystem persistence and native HTTP Desktop project files are not currently app-encrypted at rest

GitHub Pages is a good example of why "deployed from the same source" is not enough.

WorldScript uses a meta Content Security Policy there because GitHub Pages cannot add the corresponding response headers — the project's deployment documentation calls that meta tag the sole enforcement point on that host. Vercel and Cloudflare Pages can set real response headers that mirror the meta CSP, and both can run a same-origin edge relay for supported functionality (a Claude proxy lives at api/claude-proxy.ts for Vercel and functions/api/claude-proxy.ts for Cloudflare, sharing one core module). Those are materially different deployment guarantees, even when users see the same React interface.

The right documentation does not flatten that distinction. It names it.

The PWA's live project path uses browser storage. The desktop path uses filesystem-backed stores under application data.

Both are local. They are not the same.

Browser persistence is governed by the browser's origin, quota, eviction behavior, and storage APIs. Desktop persistence is governed by filesystem access, native process boundaries, and the application's own read/write rules.

That difference becomes especially important for security language. Browser/PWA protected IndexedDB data can use the application's passphrase-based encryption lifecycle when configured. The filesystem-backed desktop project store currently does not receive that same at-rest encryption.

A UI toggle with the same name is not enough to make the protection equivalent. The actual persistence path decides what is protected.

A browser connecting to localhost is still subject to browser rules such as CORS and Private Network Access. A Tauri desktop application can use an admitted native HTTP capability for local or cloud endpoints.

That does not mean desktop networking is automatically safer. It means its policy must be defined and enforced differently — and "narrowly admitted" is meant literally here. The desktop shell's HTTP capability is an explicit allowlist, not an open pipe:

// src-tauri/capabilities/default.json (excerpt)
{
  "identifier": "http:default",
  "allow": [
    "http://localhost:*/*",
    "http://127.0.0.1:*/*",
    "https://generativelanguage.googleapis.com/*",
    "https://api.openai.com/*"
    // …remaining provider hosts, nothing else
  ]
}

At runtime, the fetch adapter picks its implementation by environment: in the Tauri runtime it dynamically loads the native HTTP plugin; everywhere else it uses the browser's fetch. For WorldScript, that desktop-native path supports local inference-server workflows such as Ollama-compatible endpoints without requiring the WebView to bypass browser-origin rules. The browser/PWA path should not silently probe local ports or pretend that the same route will work without user-managed server configuration.

The general lesson is simple:

A service worker is a powerful browser feature, but it is not a universal application runtime.

WorldScript's service worker caches its web shell and handles offline fallbacks on web surfaces. In Tauri, the registration code takes the opposite path — it actively tears the browser mechanism down:

// register-sw.ts (excerpt — called only from the Tauri branch)
async function teardownServiceWorkerInTauri(): Promise<void> {
  if (!('serviceWorker' in navigator)) return;
  const registrations = await navigator.serviceWorker.getRegistrations();
  await Promise.all(registrations.map((reg) => reg.unregister()));
  const keys = await caches.keys();
  await Promise.all(
    keys.filter(isWorldScriptOwnedCacheName).map((k) => caches.delete(k)),
  );
}

It unregisters any existing service worker and purges the app's own caches. That prevents a stale browser cache from serving an offline fallback over the real bundled desktop application.

This is a subtle example of platform adaptation done well: the feature is not merely disabled because it is inconvenient. It is disabled because its browser lifecycle would be the wrong authority for a native bundle.

Before claiming that a web and desktop product are "the same app," ask:

A shared codebase is an implementation advantage. It is not a reason to erase the differences users and maintainers need to understand.

The goal is parity where the product contract is shared—and honesty where the platform changes the contract.

Source note: WorldScript Studio is open source (github.com/qnbs/WorldScript-Studio). Code references correspond to main at 2d9157c0 (2026-09-28); release anchor v1.28.8. Key files: register-sw.ts, index.html, vercel.json, docs/DEPLOYMENT.md, src-tauri/capabilities/default.json, services/ai/fetchAdapter.ts, api/claude-proxy.ts, functions/api/claude-proxy.ts. Part of the "Engineering WorldScript Studio" series.

AI disclosure: AI tools helped with repository research, structure, and editing of this article. I reviewed the technical claims against the referenced source files before publication.

── more in #developer-tools 4 stories · sorted by recency
── more on @worldscript studio 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/one-react-vite-produ…] indexed:0 read:5min 2026-09-27 · —