Electron Desktop App
TradeFlow uses Electron to provide a standalone desktop application experience while sharing the same codebase as the web version.
Architecture
electron/
├── main.js # Main process — creates BrowserWindow
└── preload.js # Preload script — security isolation
Main Process (electron/main.js)
The main process:
- Creates a
BrowserWindow(1400x900, titled “TradeFlow”) - In development — loads
http://localhost:5173(Vite dev server) - In production — loads
dist/index.htmlvia thefile://protocol - Handles macOS app lifecycle (keeps running when windows close)
Security Configuration
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js'),
}
- nodeIntegration disabled — renderer process cannot access Node.js APIs
- contextIsolation enabled — preload scripts run in a separate context from web content
Build Configuration
The build is configured in package.json:
{
"build": {
"appId": "com.tradeflow.app",
"productName": "TradeFlow",
"files": ["dist/**/*", "electron/**/*"],
"directories": { "output": "release" },
"mac": { "target": "dmg" },
"win": { "target": "nsis" },
"linux": { "target": "AppImage" }
}
}
Build Commands
| Command | Description |
|---|---|
npm run electron:dev | Start Vite + Electron concurrently for development |
npm run electron:build | Build production web assets, then package with electron-builder |
How electron:dev Works
concurrently -k "vite" "wait-on http://localhost:5173 && NODE_ENV=development electron ."
- Starts Vite dev server
- Waits for
localhost:5173to be available - Launches Electron pointing at the dev server
- Both processes are killed together when you stop
How electron:build Works
vite build && electron-builder
- Vite builds the production bundle to
dist/ - electron-builder packages
dist/+electron/into a platform installer - Output goes to
release/
Platform Outputs
| Platform | Format | File |
|---|---|---|
| macOS | DMG | release/TradeFlow-1.0.0-arm64.dmg |
| Windows | NSIS Installer | release/TradeFlow Setup 1.0.0.exe |
| Linux | AppImage | release/TradeFlow-1.0.0.AppImage |
HashRouter Requirement
The web app uses HashRouter instead of BrowserRouter for client-side routing. This is critical for Electron because:
- Production Electron loads files via the
file://protocol - The
file://protocol doesn’t support the HTML5 History API BrowserRouterwould cause 404 errors when navigating to any route other than/HashRouterencodes the route in the URL hash (index.html#/TradeLog), which works with any protocol
Data Storage in Electron
The Electron app uses the same IndexedDB storage mechanism, but under a different origin than the browser version:
- Web version: origin is
http://localhost:5173 - Electron version: origin is
file://(managed by Chromium)
This means the two versions maintain separate databases. Data created in the browser won’t appear in the Electron app and vice versa. Use the Export & Backup feature to transfer data between them.
Adding a Custom App Icon
- Create icon files:
- macOS:
.icnsformat (1024x1024 recommended) - Windows:
.icoformat (256x256 recommended) - Linux:
.pngformat (512x512 recommended)
- macOS:
-
Place them in a
build/directory at the project root - Update
package.json:
{
"build": {
"mac": { "target": "dmg", "icon": "build/icon.icns" },
"win": { "target": "nsis", "icon": "build/icon.ico" },
"linux": { "target": "AppImage", "icon": "build/icon.png" }
}
}
Code Signing
macOS
For distribution outside the Mac App Store:
- Obtain an Apple Developer ID certificate
- Set environment variables:
export CSC_LINK="path/to/certificate.p12" export CSC_KEY_PASSWORD="certificate-password" - For notarization, configure
afterSignin electron-builder
Without signing, macOS displays a Gatekeeper warning on first launch.
Windows
For EV code signing, configure the win.certificateFile and win.certificatePassword fields in the build configuration.