zudo-text

検索したい単語を入力

いつでも検索バーを開ける

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-app/.env.example). 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 /auth/desktop-handoff, 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:build

This runs bash scripts/build-root-thin.sh, 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:

  1. Frontend build — Vite compiles the React app to tauri-app/dist-renderer/ with optimized chunks:

    • codemirror — CodeMirror editor, vim mode, and lezer parsers

    • markdown — react-markdown, rehype, remark, and related plugins

    • mermaid — Diagram rendering

  2. Core dylib build — Compiles the Rust core as a cdylib in release mode with --features tauri/custom-protocol

  3. Stub bundle — Cargo-tauri builds the KB-scale stub executable (the thin launcher)

  4. Assembly — The cdylib is staged and injected into Contents/Frameworks/libzudotext_core.dylib; the stub is ad-hoc signed

For the LEAF assembly pipeline (no Rust toolchain needed) see the App Generation architecture page.

Bundle Configuration

Bundle settings are in tauri-app/tauri.conf.json:

{
  "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:

  1. Code signed with a Developer ID certificate

  2. 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 name

  • APPLE_CERTIFICATE — Base64-encoded .p12 certificate

  • APPLE_CERTIFICATE_PASSWORD — Certificate password

Vite Build Configuration

The Vite config (tauri-app/vite.config.ts) 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.