src-tauri/ — the app window
Mathew as a desktop app (Tauri 2, Linux / Windows / macOS): the wiki in a
window of its own, no browser around it. The shell is deliberately thin — the
app is the same Nuxt bundle the website serves, written out as plain files
and embedded in the binary. Nothing in frontend/app/ is desktop code; the
bundle asks at run time whether it happens to be sitting in a window
(app/utils/desktop.ts) and only then takes the window's habits: a link leads
out to the system's browser instead of replacing the wiki in the only view
there is, and the session token and interface language are mirrored into
localStorage because a webview is not everywhere obliged to keep cookies for
its own tauri://localhost address.
The wiki needs a wiki to talk to: the window holds no server and no database. It calls the public Mathew over HTTPS by default — the API base is baked in at build, see the table below.
Build & run
From frontend/ — these need Rust (stable) and the
Tauri prerequisites for your OS;
on Linux that is the WebKitGTK stack:
libwebkit2gtk-4.1-dev libgtk-3-dev libssl-dev libxdo-dev librsvg2-dev build-essential.
| Script | What it does |
|---|---|
npm run desktop:dev |
tauri dev — opens the Nuxt dev server (localhost:3000, started for you) in the window, hot-reload included; isDesktop() is already true inside it |
npm run desktop:build |
tauri build — runs desktop:generate (below), compiles the shell, embeds the files, and leaves installers under src-tauri/target/release/bundle/ (deb/rpm/AppImage on Linux, NSIS/MSI on Windows, .app/.dmg on macOS) |
npm run desktop:generate |
the bundle the window loads: MATHEW_DESKTOP=1 nuxt generate → dist-desktop/public, the frontendDist this config names (a desktop build never overwrites the web .output/) |
npm run desktop:icons |
re-cuts src-tauri/icons/ from desktop/icon-source.png (redraw that one with python3 desktop/make-icon.py) |
The desktop shape lives in nuxt.config.ts under one flag
(MATHEW_DESKTOP=1, also implied by the TAURI_ENV_* the Tauri CLI passes to
its build hooks): ssr: false, no /api proxy route, and the pre-paint theme
script served from public/preboot.js instead of inline. The web build takes
none of it. Deep routes (/wiki/en/bayes-theorem, …) are not files in the
bundle — Tauri's own asset serving answers unknown paths with index.html, so
the client router takes over exactly as it does on a static host.
Dev-server port: devUrl is fixed to 3000, and Nuxt falls back to 3001
when 3000 is taken (see the main gotchas) — free the port before
desktop:dev, or the window loads whatever else answers there.
Where the app reaches
| Build variable | Default (desktop) | Meaning |
|---|---|---|
NUXT_PUBLIC_API_BASE |
https://mathew.aranroig.com |
the wiki the app reads and writes; point it at http://localhost:5000 to test against this machine |
NUXT_PUBLIC_LEAN_URL |
empty | the Lean server /lean talks to; empty leaves that page saying there is no server here, which is the honest answer on a random laptop. The API's default CORS (*) carries the window's tauri://localhost origin fine — it sends a bearer header, not cookies |
Set them in the environment before npm run desktop:build.
What the shell owns
- one window per launch —
tauri-plugin-single-instance: pressing the icon again brings the open window forward instead of stacking a second wiki behind it (src/lib.rs). - the way out —
tauri-plugin-openeris the doorapp/utils/desktop.tshands outward links to the system's browser;capabilities/default.jsonis what grants it. That andcore:defaultare the whole permission list: reading and writing the wiki is the webview's own business. - no CSP (
csp: nullintauri.conf.json): the window loads no foreign script and talks to one API over HTTPS, and/lean's Monaco wantseval-like tricks a strictscript-srcwould have to excuse. The one script the page writes itself (the pre-paint theme,public/preboot.js) already lives in a file, so turning a policy on later is a config line — keep it that way if one is ever set.
Nothing here is signed: bundles come out unsigned, and updating is reinstalling. An updater, signing, and a per-machine "which wiki?" setting are the obvious next steps if this ever ships for real.
Versioning
The app's version lives in tauri.conf.json (version); it names the
installers and the platform bundle metadata. Commit Cargo.lock once a build
has produced one — for an application binary, a locked dependency set is what
makes a rebuild reproducible.