All skills
jwynia avatar

/electron-best-practices

@075cb8f
by J Wyniajwynia/agent-skills160 stars
20

Guide AI agents through Electron app development with React including security patterns, type-safe IPC, React integration, packaging with code signing, and testing. Keywords: electron, electron-vite, electron-forge, contextBridge, IPC, security, react, packaging, code signing, notarization, playwright, desktop app.

Use this Skill: https://skilld.dev/gh/jwynia/agent-skills/electron-best-practices

This session only. Nothing lands on disk.

assetstemplatespreload-script.ts.md

≈993 tokens on demand. Your agent reads this file only when SKILL.md points to it.

Preload Script Template

This template provides a type-safe preload script that bridges the main and renderer processes using Electron's contextBridge. It exposes a structured API object on window.electronAPI with invoke wrappers for request/response calls and event listeners that return cleanup functions to prevent memory leaks.

/**
 * Preload Script
 *
 * Secure bridge between main and renderer processes.
 * Uses contextBridge to expose typed API functions.
 *
 * TODO: Add your IPC channel wrappers
 * TODO: Update type declarations in preload.d.ts
 */

import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron';

// Type-safe invoke wrapper
function invoke<T>(channel: string, ...args: unknown[]): Promise<T> {
  return ipcRenderer.invoke(channel, ...args);
}

// Type-safe event listener with cleanup
function on<T>(channel: string, callback: (value: T) => void): () => void {
  const handler = (_event: IpcRendererEvent, value: T) => callback(value);
  ipcRenderer.on(channel, handler);
  return () => ipcRenderer.removeListener(channel, handler);
}

// Expose API to renderer
contextBridge.exposeInMainWorld('electronAPI', {
  // === File Operations ===
  // TODO: Add your file operation wrappers
  saveFile: (content: string) => invoke<{ success: boolean; path: string }>('save-file', content),
  openFile: () => invoke<{ success: boolean; content: string; path: string }>('open-file'),

  // === App Info ===
  getVersion: () => invoke<string>('get-app-version'),

  // === Events ===
  // TODO: Add your event listeners (always return cleanup function!)
  onFileChanged: (callback: (path: string) => void) => on('file-changed', callback),
  onUpdateAvailable: (callback: (version: string) => void) => on('update-available', callback),
});

The following type declaration file should be placed alongside your preload script so the renderer process gets full type safety when accessing window.electronAPI.

// preload.d.ts
interface ElectronAPI {
  // File Operations
  saveFile: (content: string) => Promise<{ success: boolean; path: string }>;
  openFile: () => Promise<{ success: boolean; content: string; path: string }>;

  // App Info
  getVersion: () => Promise<string>;

  // Events (return cleanup function)
  onFileChanged: (callback: (path: string) => void) => () => void;
  onUpdateAvailable: (callback: (version: string) => void) => () => void;
}

declare global {
  interface Window {
    electronAPI: ElectronAPI;
  }
}

export {};

Customization Notes

  • Adding new IPC channels: For each new channel, add a wrapper function in the contextBridge.exposeInMainWorld call and a matching entry in the ElectronAPI interface in preload.d.ts. Keep both files in sync.
  • Invoke vs. event patterns: Use invoke for request/response operations where the renderer needs a result back from main. Use on for push-style events where the main process notifies the renderer asynchronously.
  • Cleanup functions: Every event listener returns an unsubscribe function. In React components, call this in useEffect cleanup to prevent memory leaks. Never register listeners without a corresponding cleanup path.
  • Channel naming: Use descriptive, kebab-case channel names (e.g., save-file, file-changed). Group related channels with a common prefix for clarity.
  • Type safety: The generic type parameters on invoke<T> and on<T> flow through to the API surface. Keep the generics accurate so renderer code gets correct type checking.
  • Security boundary: The preload script is the only place where ipcRenderer should be used. Never expose ipcRenderer directly to the renderer. The contextBridge ensures only the explicitly listed functions are accessible.
  • Allowed channels pattern: For additional security, you can maintain an allowlist of channel names and validate against it in the invoke and on wrappers before forwarding to ipcRenderer.

Source: SKILL.md on GitHub

2 warnings16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill provides comprehensive guidance, templates, reference scripts, and architectural configurations for developing secure Electron applications with React. All components adhere strictly to security standards, and all external tools, scripts, and configurations are handled using safe practices without any malicious or suspicious patterns.

  • Socket16d

    1 alert: gptSecurity

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    35/35 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 075cb8f. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Dormantupdated 8 months ago
Other metadata
compatibility
Requires Deno for analysis scripts. Applicable to any Electron project using TypeScript and React.
metadata
{
  "author": "agent-skills",
  "version": "1.0",
  "domain": "development",
  "type": "utility",
  "mode": "assistive"
}

README badge

README badge for jwynia/agent-skills/electron-best-practices