To run in development mode:
pnpm electron:devThis will:
- Start the Vite dev server on an available port (typically 3002)
- Wait for the dev server to be ready
- Launch Electron which will:
- Start the AD4M executor on a free port (12000-13000)
- Generate a unique credential token
- Load the Vite dev server in the Electron window
- Open DevTools automatically
To build for production:
pnpm electron:buildThis will:
- Build the renderer with Vite
- Package the app with Electron Builder
- Include the executor binary and any embedded apps (like Flux)
- Output to
dist-electron/
The production build creates:
- AppImage for Linux
- Can be configured for Windows (NSIS) and Mac (DMG)
The Electron launcher can embed external apps via iframe. Here's how to set up Flux as an example:
/path/to/projects/
├── we/ (this repo)
├── ad4m/ (AD4M monorepo - required)
└── flux/ (Flux monorepo - optional)
cd ../../../flux/app
pnpm install
pnpm buildThis creates flux/app/dist/ which the Electron app will serve.
The Electron app automatically serves Flux in production builds from the bundled resources. In development, you can:
Option A: Use Flux dev server
# Terminal 1: Start Flux dev server
cd ../../../flux/app
pnpm dev # Runs on port 3030
# Terminal 2: Start Electron
cd we/apps/we-electron
pnpm electron:devOption B: Use Flux production build
Just build Flux once and the Electron app will serve it from dist/.
Development:
- Launcher: Uses Vite dev server on available port (set via
VITE_DEV_SERVER_URL) - Flux iframe:
http://localhost:3030(Flux dev server, if running)
Production:
- Launcher:
http://localhost:9080(Express server) - Flux iframe:
http://localhost:8080(Express server)
Both are served via HTTP (not file://) to avoid cross-origin issues.
The app automatically detects whether it's running in development or production:
- Development: Uses
import.meta.env.DEVfrom Vite (true in dev server, false in build) - Platform adapter exposes
isDevelopmentflag to the app - Flux URL switches automatically based on this flag:
- Dev:
http://localhost:3030(expects Flux dev server) - Prod:
http://localhost:8080(serves bundled Flux)
- Dev:
This is configured in LauncherTemplate.schema.ts using conditional rendering based on adamStore.isDevelopment.
Electron requires special handling for getDisplayMedia() in iframes:
- A polyfill is automatically injected into embedded apps
- The polyfill uses Electron's
desktopCapturerAPI - Works by accessing parent window's
window.electronAPI - Requires
webSecurity: falsein BrowserWindow config
If Electron fails to download its binary after pnpm install, this is due to pnpm workspace behavior with lifecycle scripts.
The postinstall script in package.json handles this automatically:
"postinstall": "cd ../../node_modules/.pnpm/electron@*/node_modules/electron 2>/dev/null && node install.js || true"This workaround ensures Electron's install script runs even in pnpm workspaces. The .npmrc file in the workspace root also enables lifecycle scripts with enable-pre-post-scripts=true.
If login hangs with a timeout after Hot Module Reload updates in dev mode:
Cause: HMR can break the WebSocket connection to the AD4M executor while keeping stale connection references.
Solution: Refresh the browser (Ctrl+R / Cmd+R) instead of relying on HMR after code changes that affect the Apollo client or WebSocket connections.
See electron/main.js for implementation details.
Embedded apps receive AD4M credentials via postMessage. See ../EMBEDDING.md for the complete protocol.
Make sure you've built the AD4M executor:
cd ../../ad4m/cli
cargo build --releaseCheck the console for errors. Common issues:
- Flux not built (run
pnpm buildin flux/app) - Wrong port configuration
- Missing postMessage request (see EMBEDDING.md)
If login hangs with a timeout after Hot Module Reload updates in dev mode:
Cause: HMR can break the WebSocket connection to the AD4M executor while keeping stale connection references.
Solution: Refresh the browser (Ctrl+R / Cmd+R) instead of relying on HMR after code changes that affect the Apollo client or WebSocket connections.
If Electron fails to download its binary after pnpm install, this is due to pnpm workspace behavior with lifecycle scripts.
The postinstall script in package.json handles this automatically:
"postinstall": "cd ../../node_modules/.pnpm/electron@*/node_modules/electron 2>/dev/null && node install.js || true"This workaround ensures Electron's install script runs even in pnpm workspaces. The .npmrc file in the workspace root also enables lifecycle scripts with enable-pre-post-scripts=true.
- Check that the polyfill is being injected (look for logs in console)
- Verify
webSecurity: falsein main.js - Check that
window.electron.getDesktopSourcesexists
If the build fails, check:
package.jsonextraResources paths are correct- AD4M executor binary exists
- Flux dist folder exists (if bundling Flux)