Skip to main content
The Rowboat desktop application is built with Electron, featuring a React UI, TypeScript throughout, and a sophisticated build system to handle the pnpm workspace.

Architecture Overview

Electron apps have three main components:
  1. Main process - Node.js backend, manages windows and system access
  2. Renderer process - Chromium frontend, runs the React UI
  3. Preload scripts - Secure bridge between main and renderer

Main Process

The main process is the entry point for the Electron app.

Location and Configuration

  • Source: apps/x/apps/main/src/main.ts
  • Output: .package/dist/main.cjs (bundled)
  • Package: apps/x/apps/main/package.json

Build Process

The main process uses a two-step build:
1

TypeScript compilation

TypeScript compiles src/ to JavaScript:
2

esbuild bundling

esbuild bundles everything into a single CommonJS file:
This includes all dependencies and workspace packages.
Why bundle? pnpm uses symlinks for workspace packages. Electron Forge’s dependency walker can’t follow symlinks. Bundling with esbuild creates a single file with all code, eliminating the need for node_modules in the packaged app.

Dependencies

Renderer Process

The renderer process is a React application built with Vite.

Location and Configuration

  • Source: apps/x/apps/renderer/src/main.tsx
  • Output: apps/renderer/dist/
  • Dev server: http://localhost:5173

Development Mode

In development, Vite provides:
  • Fast hot module replacement (HMR)
  • Instant updates without full reload
  • React Fast Refresh
The main process waits for the Vite dev server to be ready before starting Electron. This is handled by the wait-on package.

Technology Stack

  • React 19 - UI framework
  • Vite 7 - Build tool and dev server
  • TailwindCSS - Utility-first CSS
  • Radix UI - Accessible component primitives
  • TypeScript - Type safety

Preload Scripts

Preload scripts run in a context that has access to both Node.js APIs and the DOM.

Location and Purpose

  • Source: apps/x/apps/preload/src/preload.ts
  • Output: apps/preload/dist/preload.js
  • Purpose: Expose safe APIs to the renderer via contextBridge

Security Model

Never expose the entire ipcRenderer or Node.js APIs directly to the renderer. Always wrap them in specific, validated functions.

Build Order and Dependencies

The workspace packages must be built in a specific order:

Building Dependencies

The npm run deps command chains these together:

Development Workflow

Starting the App

1

Build dependencies

2

Start development mode

This runs two processes concurrently:
  • Vite dev server (renderer)
  • Electron main process
The dev script uses concurrently to run both:

Making Changes

Renderer (Hot Reload)

Changes to React components hot-reload automatically:

Main Process (Restart Required)

Changes to the main process require a restart:
Main process changes don’t hot-reload. Always restart the dev server after editing main process code.

Shared/Core Packages (Rebuild Required)

Changes to workspace packages require rebuilding:

Common Development Tasks

Add a New Dependency

Add a Shared Type

1

Edit the shared package

2

Rebuild dependencies

3

Import in your code

Verify Compilation

This builds all packages and runs ESLint across the workspace.

Electron Entry Points

Key Configuration Files

  • forge.config.cjs - Electron Forge packaging configuration
  • bundle.mjs - esbuild bundler for main process
  • vite.config.ts - Vite configuration for renderer
  • tsconfig.json - TypeScript compiler options (per package)