Build & Deploy
Building the App
Prerequisites
The desktop build requires VITE_BETTER_AUTH_URL, VITE_SYNC_SERVER_URL, and VITE_PUBLISH_SERVER_URL in tauri-app/.env (gitignored — copy tauri-). vite.config.ts fails before producing a bundle when any value is empty, and a production bundle requires HTTPS origins. Better Auth normally shares the sync-server origin; publish-server is a separate Worker.
There is no provider dashboard callback to configure. The desktop opens sync-server's /, which validates the runtime ROOT/LEAF scheme and returns a single-use OTT to that app's own custom-scheme callback. These origins are build-time bootstrap identity because the app must sign in before it can open the workspace-synced settings document.
pnpm tauri:buildThis runs bash scripts/, which builds ROOT (zudotext.app) as a thin launcher: a KB-scale stub executable plus the shared Tauri core dylib (libzudotext_core.dylib). A plain cargo tauri build is insufficient — the core must be compiled as a cdylib in a separate step before the stub bundle is assembled. The build process:
Frontend build — Vite compiles the React app to
tauri-app/dist-renderer/with optimized chunks:codemirror— CodeMirror editor, vim mode, and lezer parsersmarkdown— react-markdown, rehype, remark, and related pluginsmermaid— Diagram rendering
Core dylib build — Compiles the Rust core as a cdylib in release mode with
--features tauri/custom-protocolStub bundle — Cargo-tauri builds the KB-scale stub executable (the thin launcher)
Assembly — The cdylib is staged and injected into
Contents/; the stub is ad-hoc signedFrameworks/ libzudotext_ core. dylib
For the LEAF assembly pipeline (no Rust toolchain needed) see the App Generation architecture page.
Bundle Configuration
Bundle settings are in tauri-:
{
"bundle": {
"active": true,
"targets": "all",
"category": "DeveloperTool",
"macOS": {
"minimumSystemVersion": "10.15"
}
}
}Bundle Size
The resulting .app is approximately 5 MB — compared to ~260 MB for an equivalent Electron + Node.js app. This is possible because:
The backend is a compiled Rust binary (no Node.js runtime)
The frontend is a standard web build (HTML/CSS/JS)
Tauri uses the system WebView (WebKit on macOS) instead of bundling Chromium
Code Signing (macOS)
For distribution outside the Mac App Store, the .app needs to be:
Code signed with a Developer ID certificate
Notarized with Apple's notary service
Without signing, macOS Gatekeeper will block the app from running. During development, this isn't needed — cargo tauri dev runs unsigned.
Tauri supports signing configuration via environment variables:
APPLE_SIGNING_IDENTITY— The signing identity nameAPPLE_CERTIFICATE— Base64-encoded .p12 certificateAPPLE_CERTIFICATE_PASSWORD— Certificate password
Vite Build Configuration
The Vite config (tauri-) imports manualChunks from the shared vite-shared.ts module, which handles chunk splitting for all build targets (desktop, mock, REST, web):
import { manualChunks, buildDefines } from "./vite-shared";
export default defineConfig({
define: buildDefines,
build: {
outDir: "dist-renderer",
emptyOutDir: true,
chunkSizeWarningLimit: 2000,
rollupOptions: {
output: { manualChunks },
},
},
});The manualChunks function in vite-shared.ts splits by package group: codemirror (CodeMirror, vim mode, lezer parsers), markdown (react-markdown, rehype, remark family), mermaid (diagram rendering). Mermaid is checked first so its module IDs are claimed before broader patterns match.