HoRain云--Electron 架构
可以把 Electron 看成是一个多进程的应用容器内置了一个浏览器引擎 (Chromium) 和一个 Node.js 运行时通过进程间通信IPC协同运行实现网页 系统能力的桌面应用。它的核心组成是角色说明类比Main Process主进程Electron 的大脑控制应用生命周期、创建窗口、调用系统 API操作系统管理者Renderer Process渲染进程每个窗口运行的网页环境HTML、CSS、JS浏览器标签页Preload Script预加载脚本在渲染前运行可桥接主进程 API 给网页用安全中间层IPC进程通信主进程与渲染进程间的通信通道电话线BrowserWindow 对象主进程创建的窗口容器里面加载网页浏览器窗口App 模块控制应用生命周期启动、退出总控主进程 (Main Process)主进程是 Electron 应用的大脑每个 Electron 应用有且只有一个主进程。它负责创建和管理应用窗口渲染进程处理应用程序生命周期启动、退出、前后台切换与操作系统原生 API 交互管理菜单、对话框等系统级组件实例// main.js - 主进程示例const { app, BrowserWindow } require(electron);function createWindow() {// 创建浏览器窗口const mainWindow new BrowserWindow({width: 800,height: 600,webPreferences: {nodeIntegration: true,contextIsolation: false}});// 加载应用的 index.htmlmainWindow.loadFile(index.html);}// 当 Electron 完成初始化时调用app.whenReady().then(createWindow);渲染进程 (Renderer Process)渲染进程负责显示用户界面每个 Electron 窗口都是一个独立的渲染进程运行在 Chromium 浏览器环境中使用 HTML、CSS、JavaScript 构建界面每个窗口都是独立的进程互不影响通过 IPC 与主进程通信实例!-- index.html - 渲染进程示例 --!DOCTYPE htmlhtmlheadtitle我的 Electron 应用/title/headbodyh1Hello Electron!/h1button idbtn点击我/buttonscript// 渲染进程中的 JavaScriptdocument.getElementById(btn).addEventListener(click, () {alert(按钮被点击了);});/script/body/html预加载脚本 (Preload Scripts)预加载脚本是连接主进程和渲染进程的桥梁在渲染进程加载网页之前运行有权访问 Node.js API 和 DOM通过 contextBridge 安全地暴露 API 给渲染进程实例// preload.js - 预加载脚本示例const { contextBridge, ipcRenderer } require(electron);// 向渲染进程暴露安全的 APIcontextBridge.exposeInMainWorld(electronAPI, {showDialog: (message) ipcRenderer.invoke(show-dialog, message)});进程间通信 (IPC)IPC 通信模式IPCInter-Process Communication是 Electron 的通信核心。由于主进程与渲染进程是独立的所以必须通过 IPC 传递数据。通信方向类型主进程监听渲染进程发送渲染 → 主ipcMain.on(channel, handler)ipcRenderer.send(channel, data)主 → 渲染event.sender.send(channel, data)ipcRenderer.on(channel, callback)基本通信示例主进程代码实例const { ipcMain, dialog } require(electron);// 监听来自渲染进程的消息ipcMain.handle(show-dialog, async (event, message) {const result await dialog.showMessageBox({type: info,message: message,buttons: [确定, 取消]});return result;});渲染进程代码实例// 通过预加载脚本暴露的 API 进行通信document.getElementById(btn).addEventListener(click, async () {const result await window.electronAPI.showDialog(你好Electron);console.log(用户点击了:, result.response);});架构优势与特点优势对比特性Electron传统桌面开发开发技术Web 技术 (HTML/CSS/JS)原生语言 (C/C#/Java)跨平台支持一次开发多平台运行需要为每个平台单独开发开发效率高利用现有 Web 生态较低需要学习平台特定技术性能相对较低占用资源较多高原生性能安装包大小较大包含 Chromium较小核心特点跨平台一致性应用在所有操作系统上外观和行为一致Web 生态利用可以直接使用 npm 包和 Web 框架快速原型开发基于熟悉的 Web 技术开发周期短丰富的 API提供访问系统原生功能的完整 API 集实际应用示例让我们创建一个简单的文件管理器应用来演示 Electron 架构主进程 (main.js)实例const { app, BrowserWindow, ipcMain, dialog } require(electron);const fs require(fs).promises;const path require(path);let mainWindow;function createWindow() {mainWindow new BrowserWindow({width: 1000,height: 700,webPreferences: {preload: path.join(__dirname, preload.js),contextIsolation: true}});mainWindow.loadFile(index.html);}// 处理文件读取ipcMain.handle(read-file, async (event, filePath) {try {const content await fs.readFile(filePath, utf-8);return { success: true, content };} catch (error) {return { success: false, error: error.message };}});// 处理文件选择ipcMain.handle(select-file, async () {const result await dialog.showOpenDialog(mainWindow, {properties: [openFile],filters: [{ name: 文本文件, extensions: [txt, md, js, html, css] }]});return result;});app.whenReady().then(createWindow);预加载脚本 (preload.js)实例const { contextBridge, ipcRenderer } require(electron);contextBridge.exposeInMainWorld(fileAPI, {readFile: (filePath) ipcRenderer.invoke(read-file, filePath),selectFile: () ipcRenderer.invoke(select-file)});渲染进程 (index.html)实例!DOCTYPE htmlhtmlheadtitle简单文件管理器/titlestylebody { font-family: Arial, sans-serif; margin: 20px; }.container { max-width: 800px; margin: 0 auto; }button { padding: 10px 15px; margin: 5px; cursor: pointer; }#content { border: 1px solid #ccc; padding: 15px; margin-top: 10px;min-height: 300px; white-space: pre-wrap; }/style/headbodydiv classcontainerh1简单文件管理器/h1button idselectBtn选择文件/buttonbutton idclearBtn清空内容/buttondivh3文件内容/h3div idcontent请选择一个文件.../div/div/divscriptconst selectBtn document.getElementById(selectBtn);const clearBtn document.getElementById(clearBtn);const contentDiv document.getElementById(content);selectBtn.addEventListener(click, async () {const result await window.fileAPI.selectFile();if (!result.canceled result.filePaths.length 0) {const filePath result.filePaths[0];const fileResult await window.fileAPI.readFile(filePath);if (fileResult.success) {contentDiv.textContent 文件路径: ${filePath}\n\n${fileResult.content};} else {contentDiv.textContent 读取文件失败: ${fileResult.error};}}});clearBtn.addEventListener(click, () {contentDiv.textContent 请选择一个文件...;});/script/body/html其他重要模块主进程可用模块名作用app控制应用生命周期启动/退出Menu/MenuItem创建应用菜单栏Tray系统托盘图标Notification系统通知dialog打开文件/保存对话框shell调用系统默认程序打开文件或网址nativeImage操作图片图标clipboard操作剪贴板内容powerMonitor监听系统电源事件screen获取屏幕信息多显示器支持安全架构与沙箱隔离由于渲染进程能运行网页为防止恶意代码攻击系统Electron 推行以下安全设计策略描述关闭 NodeIntegration默认false避免网页直接调用系统 API。启用 ContextIsolation让页面脚本与 Preload API 在独立上下文中运行。Preload contextBridge明确控制暴露给前端的安全 API。Content Security Policy (CSP)限制脚本来源防止 XSS。sandbox 模式可开启沙箱使渲染进程完全隔离。验证远程 URL不信任的远程内容必须进行白名单校验。运行流程从启动到渲染1、启动应用 (electron .) ↓ 2、执行 main.js主进程启动 ↓ 3、app.whenReady() 触发创建 BrowserWindow ↓ 4、BrowserWindow 启动新的渲染进程Chromium 实例 ↓ 5、preload.js 先执行在隔离上下文中 ↓ 6、index.html 加载并显示运行前端框架 ↓ 7、渲染进程通过 IPC 调用主进程逻辑 ↓ 8、主进程处理请求、返回结果 ↓ 9、用户关闭窗口 → 主进程监听 → app.quit()主从多窗口模型多进程并行一个 Electron 应用始终只有一个主进程但可以有多个渲染进程每个窗口独立它们之间通信要通过主进程中转或使用ipcMain.handle进行异步桥接。示意主进程 (Main) ├── 窗口1 → 渲染进程A (index.html) ├── 窗口2 → 渲染进程B (settings.html) └── 窗口3 → 渲染进程C (dashboard.html)Electron 内部核心组件底层依赖层级技术界面渲染层ChromiumBlink V8系统接口层Node.jslibuv C bindings进程管理层Electron 内核C JavaScript应用逻辑层你的 JS / TS 代码Main Renderer你写的 JS 代码跑在 Electron 封装的 Node 环境里而渲染界面跑在 Chromium WebView 里。