Skip to main content

electron-api

Guide for adding new Electron APIs to Wave Terminal. Use when implementing new frontend-to-electron communications via preload/IPC.

소스 정보

저장소
wavetermdev/waveterm
최근 소스 활동
2026년 3월 7일 00:50
감지된 SKILL.md 언어
영어
스타
22,591
포크
1,173

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
electron-api
description
Guide for adding new Electron APIs to Wave Terminal. Use when implementing new frontend-to-electron communications via preload/IPC.
# Adding Electron APIs Electron APIs allow the frontend to call Electron main process functionality directly via IPC. ## Four Files to Edit 1. [`frontend/types/custom.d.ts`](frontend/types/custom.d.ts) - TypeScript [`ElectronApi`](frontend/types/custom.d.ts:82) type 2. [`emain/preload.ts`](emain/preload.ts) - Expose method via `contextBridge` 3. [`emain/emain-ipc.ts`](emain/emain-ipc.ts) - Implement IPC handler 4. [`frontend/preview/preview-electron-api.ts`](frontend/preview/preview-electron-api.ts) - Add a no-op stub to keep the `previewElectronApi` object in sync with the `ElectronApi` type ## Three Communication Patterns 1. **Sync** - `ipcRenderer.sendSync()` + `ipcMain.on()` + `event.returnValue = ...` 2. **Async** - `ipcRenderer.invoke()` + `ipcMain.handle()` 3. **Fire-and-forget** - `ipcRenderer.send()` + `ipcMain.on()` ## Example: Async Method ### 1. Define TypeScript Interface In [`frontend/types/custom.d.ts`](frontend/types/custom.d.ts): ```typescript type ElectronApi = { captureScreenshot: (rect: Electron.Rectangle) => Promise<string>; // capture-screenshot }; ``` ### 2. Expose in Preload In [`emain/preload.ts`](emain/preload.ts): ```typescript contextBridge.exposeInMainWorld("api", { captureScreenshot: (rect: Rectangle) => ipcRenderer.invoke("capture-screenshot", rect), }); ``` ### 3. Implement Handler In [`emain/emain-ipc.ts`](emain/emain-ipc.ts): ```typescript electron.ipcMain.handle("capture-screenshot", async (event, rect) => { const tabView = getWaveTabViewByWebContentsId(event.sender.id); if (!tabView) throw new Error("No tab view found"); const image = await tabView.webContents.capturePage(rect); return `data:image/png;base64,${image.toPNG().toString("base64")}`; }); ``` ### 4. Add Preview Stub In [`frontend/preview/preview-electron-api.ts`](frontend/preview/preview-electron-api.ts): ```typescript captureScreenshot: (_rect: Electron.Rectangle) => Promise.resolve(""), ``` ### 5. Call from Frontend ```typescript import { getApi } from "@/store/global"; const dataUrl = await getApi().captureScreenshot({ x: 0, y: 0, width: 800, height: 600 }); ``` ## Example: Sync Method ### 1. Define ```typescript type ElectronApi = { getUserName: () => string; // get-user-name }; ``` ### 2. Preload ```typescript getUserName: () => ipcRenderer.sendSync("get-user-name"), ``` ### 3. Handler (⚠️ MUST set event.returnValue or browser hangs) ```typescript electron.ipcMain.on("get-user-name", (event) => { event.returnValue = process.env.USER || "unknown"; }); ``` ### 4. Call ```typescript import { getApi } from "@/store/global"; const userName = getApi().getUserName(); // blocks until returns ``` ## Example: Fire-and-Forget ### 1. Define ```typescript type ElectronApi = { openExternal: (url: string) => void; // open-external }; ``` ### 2. Preload ```typescript openExternal: (url) => ipcRenderer.send("open-external", url), ``` ### 3. Handler ```typescript electron.ipcMain.on("open-external", (event, url) => { electron.shell.openExternal(url); }); ``` ## Example: Event Listener ### 1. Define ```typescript type ElectronApi = { onZoomFactorChange: (callback: (zoomFactor: number) => void) => void; // zoom-factor-change }; ``` ### 2. Preload ```typescript onZoomFactorChange: (callback) => ipcRenderer.on("zoom-factor-change", (_event, zoomFactor) => callback(zoomFactor)), ``` ### 3. Send from Main ```typescript webContents.send("zoom-factor-change", newZoomFactor); ``` ## Quick Reference **Use Sync when:** - Getting config/env vars - Quick lookups, no I/O - ⚠️ **CRITICAL**: Always set `event.returnValue` or browser hangs **Use Async when:** - File operations - Network requests - Can fail or take time **Use Fire-and-forget when:** - No return value needed - Triggering actions **Electron API vs RPC:** - Electron API: Native OS features, window management, Electron APIs - RPC: Database, backend logic, remote servers ## Checklist - [ ] Add to [`ElectronApi`](frontend/types/custom.d.ts:82) in [`custom.d.ts`](frontend/types/custom.d.ts) - [ ] Include IPC channel name in comment - [ ] Expose in [`preload.ts`](emain/preload.ts) - [ ] Implement in [`emain-ipc.ts`](emain/emain-ipc.ts) - [ ] Add no-op stub to [`preview-electron-api.ts`](frontend/preview/preview-electron-api.ts) - [ ] IPC channel names match exactly - [ ] **For sync**: Set `event.returnValue` (or browser hangs!) - [ ] Test end-to-end
GitHub에서 보기