Zum Inhalt springen

Electron Cheat Sheet

Overview

Electron is an open-source framework maintained by GitHub/Microsoft that enables developers to build cross-platform desktop applications using web technologies. It combines the Chromium rendering engine with the Node.js runtime, allowing full access to both web APIs and native system capabilities from a single JavaScript codebase. Applications built with Electron run on Windows, macOS, and Linux, and notable production apps include Visual Studio Code, Slack, Discord, Figma, and Notion.

Electron uses a multi-process architecture with a main process (Node.js) that manages application lifecycle, native OS interactions, and window creation, and renderer processes (Chromium) that display the web UI. Inter-process communication (IPC) bridges these two worlds. While Electron apps are larger than native apps due to bundling Chromium, the framework offers unmatched developer productivity for teams with web expertise, extensive ecosystem support, and a mature plugin system through native Node.js modules.

Installation

# Initialize a new project
mkdir my-electron-app && cd my-electron-app
npm init -y

# Install Electron
npm install --save-dev electron

# Or use a boilerplate
npx create-electron-app@latest my-app
cd my-app

# Using Electron Forge (recommended)
npm init electron-app@latest my-app -- --template=webpack-typescript
cd my-app

# Using Electron Vite (modern alternative)
npm create @quick-start/electron my-app
cd my-app

# Verify installation
npx electron --version

Project Structure

my-electron-app/
├── package.json
├── main.js              # Main process entry
├── preload.js           # Preload script (bridge)
├── renderer/
│   ├── index.html       # UI entry point
│   ├── renderer.js      # Renderer process code
│   └── styles.css
├── src/                 # Application source
│   ├── main/
│   │   ├── index.ts     # Main process
│   │   └── ipc.ts       # IPC handlers
│   └── renderer/
│       ├── App.tsx       # React/Vue/Svelte app
│       └── index.html
├── resources/           # App icons and assets
├── forge.config.js      # Electron Forge config
└── electron-builder.yml # electron-builder config

Main Process

// main.js
const { app, BrowserWindow, ipcMain, Menu, dialog } = require('electron');
const path = require('path');

let mainWindow;

function createWindow() {
    mainWindow = new BrowserWindow({
        width: 1200,
        height: 800,
        minWidth: 600,
        minHeight: 400,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js'),
            contextIsolation: true,    // Security: always true
            nodeIntegration: false,     // Security: always false
            sandbox: true
        },
        titleBarStyle: 'hiddenInset', // macOS frameless
        icon: path.join(__dirname, 'resources/icon.png')
    });

    // Load app
    if (process.env.NODE_ENV === 'development') {
        mainWindow.loadURL('http://localhost:5173');
        mainWindow.webContents.openDevTools();
    } else {
        mainWindow.loadFile('dist/index.html');
    }

    mainWindow.on('closed', () => {
        mainWindow = null;
    });
}

app.whenReady().then(createWindow);

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') app.quit();
});

app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
});

Preload Script

// preload.js - Bridge between main and renderer
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
    // File operations
    openFile: () => ipcRenderer.invoke('dialog:openFile'),
    saveFile: (content) => ipcRenderer.invoke('dialog:saveFile', content),
    readFile: (path) => ipcRenderer.invoke('fs:readFile', path),
    
    // App info
    getVersion: () => ipcRenderer.invoke('app:getVersion'),
    getPlatform: () => process.platform,
    
    // Events from main process
    onUpdateAvailable: (callback) => 
        ipcRenderer.on('update-available', (_event, info) => callback(info)),
    onProgress: (callback) =>
        ipcRenderer.on('progress', (_event, value) => callback(value)),
    
    // Send to main
    sendMessage: (channel, data) => {
        const validChannels = ['toMain', 'minimize', 'maximize', 'close'];
        if (validChannels.includes(channel)) {
            ipcRenderer.send(channel, data);
        }
    }
});

IPC Communication

// Main process - handle IPC
const { ipcMain, dialog } = require('electron');
const fs = require('fs/promises');

// Handle invoke (async request/response)
ipcMain.handle('dialog:openFile', async () => {
    const result = await dialog.showOpenDialog({
        properties: ['openFile'],
        filters: [
            { name: 'Text Files', extensions: ['txt', 'md'] },
            { name: 'All Files', extensions: ['*'] }
        ]
    });
    if (result.canceled) return null;
    const content = await fs.readFile(result.filePaths[0], 'utf-8');
    return { path: result.filePaths[0], content };
});

ipcMain.handle('dialog:saveFile', async (event, content) => {
    const result = await dialog.showSaveDialog({
        filters: [{ name: 'Text', extensions: ['txt'] }]
    });
    if (!result.canceled) {
        await fs.writeFile(result.filePath, content, 'utf-8');
        return result.filePath;
    }
    return null;
});

ipcMain.handle('app:getVersion', () => app.getVersion());

// Handle one-way messages
ipcMain.on('minimize', () => mainWindow.minimize());
ipcMain.on('maximize', () => {
    mainWindow.isMaximized() ? mainWindow.unmaximize() : mainWindow.maximize();
});
ipcMain.on('close', () => mainWindow.close());
// Renderer process - use exposed APIs
document.getElementById('openBtn').addEventListener('click', async () => {
    const file = await window.electronAPI.openFile();
    if (file) {
        document.getElementById('editor').value = file.content;
    }
});

window.electronAPI.onProgress((value) => {
    document.getElementById('progress').style.width = `${value}%`;
});
const { Menu, MenuItem } = require('electron');

const template = [
    {
        label: 'File',
        submenu: [
            { label: 'New', accelerator: 'CmdOrCtrl+N', click: () => createNewFile() },
            { label: 'Open', accelerator: 'CmdOrCtrl+O', click: () => openFile() },
            { label: 'Save', accelerator: 'CmdOrCtrl+S', click: () => saveFile() },
            { type: 'separator' },
            { role: 'quit' }
        ]
    },
    {
        label: 'Edit',
        submenu: [
            { role: 'undo' },
            { role: 'redo' },
            { type: 'separator' },
            { role: 'cut' },
            { role: 'copy' },
            { role: 'paste' },
            { role: 'selectAll' }
        ]
    },
    {
        label: 'View',
        submenu: [
            { role: 'reload' },
            { role: 'forceReload' },
            { role: 'toggleDevTools' },
            { type: 'separator' },
            { role: 'zoomIn' },
            { role: 'zoomOut' },
            { role: 'resetZoom' },
            { type: 'separator' },
            { role: 'togglefullscreen' }
        ]
    }
];

const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);

Configuration

// package.json
{
  "name": "my-electron-app",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "dev": "electron . --enable-logging",
    "build": "electron-builder",
    "build:mac": "electron-builder --mac",
    "build:win": "electron-builder --win",
    "build:linux": "electron-builder --linux",
    "pack": "electron-builder --dir"
  }
}
# electron-builder.yml
appId: com.example.myapp
productName: My App
directories:
  output: release
  buildResources: resources
files:
  - "**/*"
  - "!src/**"
mac:
  target:
    - dmg
    - zip
  category: public.app-category.developer-tools
  hardenedRuntime: true
win:
  target:
    - nsis
    - portable
linux:
  target:
    - AppImage
    - deb
    - snap
  category: Utility
nsis:
  oneClick: false
  allowToChangeInstallationDirectory: true
publish:
  provider: github

Build and Distribute

# Build with electron-builder
npx electron-builder --mac --win --linux

# Build specific platform
npx electron-builder --mac dmg
npx electron-builder --win nsis
npx electron-builder --linux AppImage

# With Electron Forge
npx electron-forge make
npx electron-forge publish

# Code signing (macOS)
export CSC_LINK="path/to/certificate.p12"
export CSC_KEY_PASSWORD="password"
npx electron-builder --mac

# Auto-update setup
npm install electron-updater

Advanced Usage

// System tray
const { Tray, nativeImage } = require('electron');

let tray;
app.whenReady().then(() => {
    const icon = nativeImage.createFromPath('resources/tray-icon.png');
    tray = new Tray(icon.resize({ width: 16, height: 16 }));
    
    const contextMenu = Menu.buildFromTemplate([
        { label: 'Show App', click: () => mainWindow.show() },
        { label: 'Quit', click: () => app.quit() }
    ]);
    
    tray.setToolTip('My Electron App');
    tray.setContextMenu(contextMenu);
    tray.on('double-click', () => mainWindow.show());
});

// Notifications
const { Notification } = require('electron');
new Notification({
    title: 'Update Available',
    body: 'A new version is ready to install.',
    icon: 'resources/icon.png'
}).show();

// Global shortcuts
const { globalShortcut } = require('electron');
app.whenReady().then(() => {
    globalShortcut.register('CommandOrControl+Shift+I', () => {
        mainWindow.webContents.toggleDevTools();
    });
});

// Native file drag
mainWindow.webContents.on('will-navigate', (event) => {
    event.preventDefault(); // Prevent navigation on file drop
});

Troubleshooting

IssueSolution
White screen on loadCheck loadFile/loadURL path; check console for errors
require not defined in rendererUse preload script with contextBridge; never enable nodeIntegration
App too largeUse electron-builder asar packing; exclude unnecessary files
High memory usageProfile with DevTools; close unused windows; watch for memory leaks
macOS notarization failsUse electron-notarize package; ensure hardened runtime enabled
Auto-update not workingCheck publish config in builder; verify update server/GitHub releases
Native module build failsUse electron-rebuild: npx electron-rebuild
CSP errorsUpdate Content-Security-Policy in HTML meta tag or webPreferences
Slow startupLazy-load modules; defer non-critical initialization
IPC not workingEnsure channel names match; check preload script is loaded correctly