Files
J621/desktop
JakeBreath cf129714be Add an Electron desktop shell for the SPA
desktop/ serves the normal frontend build over a privileged app://j621
scheme, so localStorage, OPFS, Web Workers, WebCodecs and history routing
behave exactly like Chrome. Development points at the Vite dev server;
`npm run smoke` runs headless Electron and checks the bundled app.

External links open in the system browser, and download navigations
(?download=1 or media URLs) are rerouted through webContents.downloadURL,
since preventing them cancels the download. The setup screen names the
shell's origin when the connection test fails, and the deploy docs list
app://j621 for CORS_ALLOWED_ORIGINS.
2026-09-20 17:07:22 -05:00
..

J621 desktop (Electron)

An Electron shell around the web build. The main process serves the SPA from the privileged app://j621 scheme — a real origin, so localStorage, OPFS, Web Workers and WebCodecs all behave exactly like they do in Chrome — and the SPA keeps its normal first-run flow: on launch it asks where the backend is (or runs in local mode with no backend at all).

The renderer code is not forked: the shell loads frontend/dist as built by npm run build in frontend/.

Layout

src/main.ts      window, app:// protocol handler, menu, external links
src/preload.ts   window.j621Desktop bridge
electron-builder.yml   deb + pacman + nsis packaging

Development

# terminal 1: the SPA with its /api proxy (needs the backend for library pages)
cd frontend && npm run dev

# terminal 2
cd desktop && npm run dev

npm run dev builds the main process and points the window at http://localhost:5173 (J621_DEV_SERVER). Without the dev server, npm start builds both halves and serves the bundled SPA over app://j621.

Builds

npm run dist:linux   # release/*.deb + release/*.pkg.tar.zst
npm run dist:win     # release/J621-Setup-*.exe (cross-built with wine; untested)
npm run dist:all

The Arch package can be installed and removed with pacman:

sudo pacman -U release/j621-*.pkg.tar.zst

Smoke test

npm run smoke builds everything, runs Electron headless through xvfb-run and checks that the bundled SPA loads over app://j621: the SPA fallback, an asset fetch, localStorage, OPFS, WebCodecs and the preload bridge. It exits non-zero on failure.

Backend CORS

A desktop app is cross-origin to the backend, exactly like the frontend-only Docker deployment. Add the shell's origin to the backend:

CORS_ALLOWED_ORIGINS=app://j621

The setup screen shows this hint (with the actual origin) when the connection test fails. Without a backend, choose "Continue without a backend" — the e621-facing pages work the same as in the browser.