Electron-handbook
openaigptmodelllm
项目模版
对于electron无论是webpack、vite都需要分别对main
、preload
、renderer
进行打包并和chromium、node api生成对应平台应用
- electron-forge: 通过其插件系统提供了项目环境、打包分发、包发布、等完整流程,并且具有webpack、vite两种构建可以选择
- electron-vite: 以vite为构建方案的不同框架模版
核心API
Main Process
主进程主要提供作用到操作系统的api及事件,通常位于main工程目录下
- app: 包含了主应用程序事件触发及监听
ts
app.on('window-all-closed', () => { app.quit();})
- BrowserWindow: 主应用窗口相关(配置、页面渲染、调试工具、窗口事及监听)
- 一个应用可以存在多个窗口但需要指明父级窗口
ts
function createWindow() { mainWIndow = new BrowserWindow({ /* ... */ })
secondaryWindow = new BrowserWindow({ // ..., modal: false, // 是否以modal形式展示 show: false, // modal为true时生效 parent: mainWindow });}
- webContents: 作为
BrowserWindow
的属性(对应的配置也将反映到属性当中)用于响应和控制web页面的事件触发及监听- mainWindow.webContents
ts
const wc = mmainWindow.webContents;wc.on('did-finish-load', () => {})wc.on('dom-ready', () => {})wc.on('focus', () => {})// ...
- Accelerator: 用于监听组合快捷键
ts
globalShortcut.register('CommandOrControl+Shift+Alt+C', () => { app.focus(); browserWindow.show(); browserWindow.focus();});
- Menu: 菜单相关配置(Menu、MenuItem、context-menu)
ts
const mainMenu = new Menu();const menuItem = new MenuIitem({ label: 'File': subMenu: [/**/] })mainMenu.append(menuItem)Menu.setApplicationMenu(mainMenu)
const contextMenu = Menu.buildFromTemplate({ label: 'xxx', subMenu: [/**/]})mainWindow.webContents.on('context-menu', e => contextMenu.popup())
- Tray: 系统托盘图标菜单配置
ts
const someTray = new Tray('xxx/xxx/icon.png')someTray.setToolTip('hover tip text')someTray.on('click', e => { // do something})
- screen: 屏幕相关事件及方法(尺寸、显示、光标位置)
ts
const [dp1, dp2] = screen.getAllDisplays()console.log(` primary monitor: ${dp1.size.width}x${dp1.size.height}\n srcondary monitor: ${dp2.size.width}x${dp2.size.height}`)screen.on('display-metrics-changed', (e, display, metricsChanged) => { console.log(metricsChanged)})
Renderer Process
渲染进程主要包含mainwindow
中渲染的web相关页面及资源,通常位于renderer
工程目录下.新版本不能直接在渲染进程中使用必须通过preload
桥接
- clipboard: 系统粘贴板相关
- contextBridge: 通过
ipcRenderer
通信暴露桥接主线程与渲染线程的事件,通常位于preload
中 - crashRepoeter: 自动提交崩溃报告到远端服务器
- ipcRenderer: 用于主进程和渲染进程之间监听和派发约定事件
- webFrame: 用于自定义渲染当前的web页面(zooom、insertCSS、insetText、executeJavascript、...)
- desktopCapturer: 桌面音视频捕捉
IPC(inter-process communication)
IPC主要用于ipcMain
和ipcRenderer
之间的通信
- Renderer to main: 渲染进程到主进程,出了
send > on
这种通用订阅方式还有invoke > handle
的异步返回方式
ts
import { contextBridge, ipcMain, ipcRenderer } from "electron"
// main.tsipcMain.on('someContent', (e, content: string) => console.log(content))ipcMain.handle('otherContent', async (e, content: string) => dealWithContent(content))
// preload.tscontextBridge.exposeInMainWorld('app', { sendToMain: (content: string) => { ipcRenderer.send('someContent', content) }, otherToMain: async (content: stirng) => { const result = await ipcRenderer.invoke('otherContent') return result }})
// renderer/index.tsdocument.getElementById('dom1').onclick = () => { window.app.sendToMain()}document.getElementById('dom2').onclick = () => { window.app.otherToMain()}
- Main to renderer: 主进程到渲染进程除了
send > on
以外的webContents
方式
ts
import { BrowserWindow, ipcMain, ipcRenderer } from "electron"
// main.tsconst mainWindow = new BrowserWindow(/* ... */)
Menu.buildFromTemplate([ { label: 'xxx' subMenu: [ { label: 'xxx', click: () => mainWindow.webContents.send('updateSomething', 'xxx') }, // ... ] }])
// preload.ts// 这里可以不暴露到renderer中,直接定义在preload中window.addEventListener('DOMContentLoaded', () => { const contentDom = document.getElementById('dom') ipcRenderer.on('updateSomthing', (_event, content) => { contentDom.innerText = content })})
// index.html<body> <div id="dom">/* ... */</div></body>
<script type="module" src="renderer/index.ts">
Shared Modules
- process: 包含了可以在主、渲染进程中访问使用的属性、方法、事件
- shell: 包含了与桌面集成相关的功能(
openPath
、showItemInFolder
、...,不同操作系统的表现也不相同) - nativeImage: 图片相关api可以通过本机路径、nativeImage实例创建并包含很多图片实例方法(
toPNG
、toJPEG
、toDataURL
、...) - clipboard: 粘贴板相关功能
扩展功能
- Offsreen Rendering: 使用禁止硬件加速开启离屏渲染(不渲染页面的情况下进行逻辑处理)
ts
import { app, BrowserWindow } from "electron"
app.disableHardwareAcceleration()
const mainWindow = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, offscreen: true }}})
mainWindow.loadURL('https://electronjs.org')let i = 1mainWindow.webContents.on('paint', (e, dirty, image) => { fs.writeFile(app.getPath('desktop') + `/screenshot_${i}`, image.toPNG(), console.log) i++;})mainWindow.webContents.on('did-finish-load', () => { // ...})
- Network Detection: 网络状况监测
- Notification: 消息通知
- autoUpdater: 自动更新应用