Skip to content

4.1 Main Process and Window Lifecycle

coding man edited this page Nov 4, 2026 · 1 revision

Main Process and Window Lifecycle

Relevant source files

The following files were used as context for generating this wiki page:

This page details the Electron main process implementation within VariantScope, focusing on electron/main.js and electron/menu.js. It covers application initialization, user-data path configuration, custom protocol handling for the renderer bundle, security sandboxing, permission controls, and native menu accelerators communicating via custom DOM events.


Application Bootstrap and Initialization

The main process entry point (electron/main.js) manages the lifecycle of the desktop application. Upon launch, it configures runtime paths, optional background operational flags, and privileged custom schemes before the Electron framework finishes initialization.

Key bootstrapping mechanisms include:

  • User Data Paths: Tests or custom environments can override the default user data directory via the VARIANTSCOPE_USER_DATA environment variable using app.setPath('userData', ...) electron/main.js:24-25.
  • Background Mode: Automated headless test runs can enable VARIANTSCOPE_BACKGROUND=1. On macOS, this sets the activation policy to an accessory role, hiding the Dock icon and preventing the application from taking focus during tests electron/main.js:27-31.
  • Custom Secure Scheme: The app registers app:// as a standard, secure protocol with fetch API support using protocol.registerSchemesAsPrivileged electron/main.js:43-47. This provides a stable origin and real Content Security Policy (CSP) headers for the bundled renderer UI.
graph TD
    Start["Electron App Launch"] --> CheckEnv["Check process.env"]
    CheckEnv --> SetUserData["app.setPath('userData') electron/main.js"]
    CheckEnv --> CheckBg["Check VARIANTSCOPE_BACKGROUND"]
    CheckBg -->|True & macOS| SetAcc["app.setActivationPolicy('accessory') electron/main.js"]
    CheckBg -->|False / Other| RegScheme["protocol.registerSchemesAsPrivileged electron/main.js"]
    SetUserData --> RegScheme
    RegScheme --> Ready["app.whenReady()"]
Loading

Sources: electron/main.js:24-47

Sources: electron/main.js:24-47


Window Creation and Protocol Routing

Once the application is ready, BrowserWindow instances are instantiated. Depending on whether the environment is running in development mode (VARIANTSCOPE_DEV_URL) or production packaging, the renderer target changes.

  • Production / Bundled Mode: Requests are intercepted by handleAppProtocol, which reads files from dist/electron-renderer over the app:// scheme, mapping paths safely and rejecting directory traversal attempts outside RENDERER_DIR electron/main.js:53-68.
  • Development Mode: If VARIANTSCOPE_DEV_URL is provided, the window loads the Vite development server directly electron/main.js:15, and installDevCsp injects development CSP headers into incoming response headers via session.defaultSession.webRequest.onHeadersReceived electron/main.js:70-78.
graph TD
    Sub["Window Creation & URL Resolution"] --> DevCheck{{"DEV_URL defined?"}}
    DevCheck -->|Yes| LoadDev["win.loadURL(DEV_URL)"]
    DevCheck -->|No| RegisterProto["protocol.handle('app', handleAppProtocol) electron/main.js"]
    RegisterProto --> LoadApp["win.loadURL('app://local/index.html')"]
    
    subgraph "handleAppProtocol electron/main.js"
        LoadApp --> ParsePath["Parse pathname and decode URI"]
        ParsePath --> ValidatePath["Verify path stays within RENDERER_DIR"]
        ValidatePath -->|Escape| Fail["Return 403 Forbidden"]
        ValidatePath -->|Safe| ReadFile["fs/promises.readFile()"]
        ReadFile --> ReturnResp["Return Response with Content-Type & CSP"]
    end
Loading

Sources: electron/main.js:15-22, electron/main.js:53-68

Sources: electron/main.js:15-22, electron/main.js:53-68


Security Policies and Permissions

electron/main.js enforces strict security boundaries to prevent unauthorized navigation, remote code execution, and permission escalation:

  • Permission Management: denyPermissions blocks all browser permission requests (geolocation, camera, notifications) except fullscreen requests originating from the trusted application origin, which are required by the 3D viewer component (viewer3d.js) electron/main.js:80-87.
  • WebContents Locking: lockDownWebContents intercepts navigation and window opening attempts (will-navigate, will-redirect, setWindowOpenHandler). External links must satisfy isAllowedExternalLink before opening in the host system browser via shell.openExternal electron/main.js:89-107. Webview attachments are unconditionally blocked electron/main.js:106.
  • IPC Sender Verification: IPC handlers check message origins against TRUSTED_ORIGIN using isTrustedSender to ensure messages originate from valid renderer frames electron/main.js:109-116.

Sources: electron/main.js:80-116


Menu System and Keyboard Accelerators

The native application menu is defined and installed in electron/menu.js via installMenu. It configures standard roles, platform-specific menus, and keyboard accelerators such as CmdOrCtrl+E (Export CSV), CmdOrCtrl+K (Focus Search), and CmdOrCtrl+D (Toggle Dark Mode) electron/menu.js:13-91.

When a user interacts with application menus, actions are dispatched to the renderer window through webContents.executeJavaScript by firing a custom DOM event (vs:menu) containing a fixed action string electron/menu.js:17-23.

graph TD
    UserAction["User clicks menu item / Accelerator"] --> MenuClick["Menu item click handler electron/menu.js"]
    MenuClick --> SendCheck{{"Has active BrowserWindow?"}}
    SendCheck -->|No| Exit["Return"]
    SendCheck -->|Yes| ExecJS["win.webContents.executeJavaScript electron/menu.js"]
    
    ExecJS --> DispatchEvent["window.dispatchEvent(new CustomEvent('vs:menu', ...))"]
    DispatchEvent --> RendererProcess["Renderer processes action (e.g. export-csv, focus-search, toggle-theme)"]
Loading

Sources: electron/menu.js:13-91

Sources: electron/menu.js:13-91


Clone this wiki locally