Skip to content

Desktop App: Frontend Architecture

Part 2 of 5 in the Architecture & Foundation series.

This page covers the frontend layer shared by both the website and the desktop app: why JavaScript and React, how Vite builds the code, and how Tauri bridges that same web code into a native desktop binary.

JavaScript & React 19: Foundation of the UI

Why JavaScript?

JavaScript is the only programming language that runs natively in web browsers. Every website you visit uses JavaScript for interactivity. When you click a button, scroll a page, or submit a form, JavaScript is responding to your actions.

Could Ediky's UI be written in Python or Go instead? Not directly — browsers only understand JavaScript. Any other language would need to compile to JavaScript or run on a server, which is slower and defeats the purpose of a responsive UI.

JavaScript has evolved from "make things blink on a webpage" to a full programming language capable of running complex applications. Ediky's entire UI logic — dashboard updates, code editor interactions, notes synchronization — is written in JavaScript.

What Is React?

React is a component library: a toolkit for building interactive user interfaces by breaking them into reusable pieces called components.

Without React, building a UI means writing raw HTML, CSS, and JavaScript, manually updating the DOM (document object model) every time data changes. Update data → find the right HTML element → change its text → update its styles. This gets messy fast in complex apps.

React simplifies this: you describe what the UI should look like, and React handles updating it when data changes.

Components: reusable UI pieces. A Dashboard component, a Button component, a CodeEditor component. Each encapsulates its own logic and styling.

JSX: HTML-like syntax inside JavaScript. It looks like HTML but is actually JavaScript that creates UI elements:

javascript
function Welcome({ userName }) {
  return <h1>Welcome, {userName}</h1>;  // This is JSX
}

Props: data passed into a component from its parent, like function arguments. The Dashboard component receives userName as a prop and displays it.

State: data that a component remembers and can change. Unlike props, which come from outside, state is internal:

javascript
const [problemsSolved, setProblemsSolved] = useState(0);
// setProblemsSolved increments when the user solves a problem

When state changes, React re-renders the component — it updates the UI automatically.

Why React 19

React 19 improves on React 18 with better hooks for simpler state management (useTransition, useOptimistic), async components that can wait for data before rendering, foundations for server components, and improved error boundaries. For Ediky, this means cleaner code and better performance on both web and desktop — including keeping a filterable list of a few thousand problems responsive while a student is still typing.

Vite: Turning Code into Optimized Files

What Vite Does

Vite is a build tool. Its job: take React code — JavaScript, CSS, images, libraries — scattered across many files, and combine it into optimized files a browser can efficiently load.

You write code like this:

src/
├── components/
│   ├── Dashboard.jsx
│   ├── CodeEditor.jsx
│   ├── Button.jsx
├── styles/
│   ├── main.css
├── App.jsx

Vite transforms this into:

dist/
├── index.html (2 KB)
├── js/app-abc123.js (450 KB, minified React)
├── css/styles-def456.css (50 KB)
├── assets/ (optimized images)

Why Vite Over Webpack?

The older standard, Webpack, was powerful but complex — configuration files ran hundreds of lines, and dev reload could take seconds. Vite is faster because it serves source files over native browser ES modules during development instead of rebundling everything on each change, pre-bundles dependencies once and app code separately, and injects changes into the running app directly via Hot Module Replacement.

Dev workflow (npm run dev):

  1. Vite starts a dev server and watches your files for changes.
  2. You edit Dashboard.jsx.
  3. Vite re-bundles only that module, not the full 450 KB build.
  4. The browser reloads that module in about a second, not ten.
  5. You see changes instantly.

Vite on Desktop: Building for Tauri

When building for desktop, Vite's job is identical: bundle React code into optimized files. Instead of uploading to a web server, those files get embedded in the Tauri desktop app.

npm run build produces a /dist folder with the bundled app. cargo tauri build takes that folder, embeds it in the app binary, and produces an .exe or .app file. The React code doesn't know the difference — it runs on the web or inside a desktop app identically.

Tauri: Web Code to Desktop App

What Is Tauri?

Tauri is a framework that bridges web code — React, HTML, CSS, JavaScript — and native desktop capabilities in Rust.

Normally, a desktop app means writing in a desktop-specific language: C# on Windows, Swift on macOS, Java for cross-platform. Each requires learning a new language and framework. Tauri's approach instead: write the UI in React, write the backend in Rust, ship as a single binary.

Why Tauri Over Electron?

Electron — used by VS Code, Discord, Figma — bundles Chromium and Node.js inside the app. That gives it a single web+desktop codebase and the full Node.js ecosystem, but it's large (150+ MB per app), memory-heavy (three runtimes running at once), slow to start, and can feel like a web page in a window rather than a native app.

Tauri bundles the OS's own WebKit/WebView2 engine plus a Rust backend instead of shipping Chromium. That makes it smaller (30–50 MB), lighter (no Node.js overhead), fast to start, and gives it native OS integration for the file system, processes, and notifications — at the cost of a steeper Rust learning curve and a smaller pre-built library ecosystem than Node's.

For Ediky, offline capability (local SQLite) and exam proctoring (system monitoring) both need OS-level access that only Rust provides, and the smaller binary matters for distributing installers to students.

Architecture: Webview + Rust Backend

diagram100%
rendering diagram…

drag to pan · ctrl / ⌘ + scroll to zoom

A webview is an embedded browser window that runs the React app — it looks and feels like a browser tab, but it's part of the desktop app's own window.

IPC (inter-process communication) is how React talks to Rust. Instead of HTTP over a network, IPC is a local function call: React invokes a Rust function → Rust does the work → sends the result back.

How React Calls Rust

Example: a student clicks "Run" in the code editor.

javascript
// React component (frontend)
async function runCode(codeText, language) {
  try {
    const result = await invoke("run_code", {
      code: codeText,
      language: language,
      testCases: [/* ... */]
    });

    // Rust returns: { output: "...", status: "Accepted" }
    displayResult(result);
  } catch (error) {
    showError(error);
  }
}

Behind the scenes, Rust's run_code handler receives the code, language, and test cases, calls the Judge0 API (or queues the request if offline), captures output and status, and returns it to React. React doesn't know about Judge0 — it just knows it asked for code to run and got results back. Rust handles the complexity.

IPC beats HTTP here on every axis that matters locally: no network latency, faster because it's the same machine, more secure since nothing crosses the internet, and typed, since Rust enforces the shape of the data.

Same Codebase, Two Platforms

The React UI is identical on web and desktop — same components, same logic, same styling. The difference is entirely in the backend: Cloudflare Pages Functions and Workers plus Firebase on web, versus Rust with IPC plus SQLite on desktop.

Developers write React once. Vite builds it for both platforms. Each platform gets a backend optimized for its own constraints.


← Previous: Introduction & Product Vision→ Next: Backend & Services↩ Overview: Architecture & Foundation

Ediky Workflow — internal engineering documentation.