Electron
-
一款应用广泛的跨平台的桌面应用开发框架
-
Electron的本质是结合了Chromium、Node.js、Native API -
使用
HTML、CSS、JS等Web技术构建桌面应用程序。
Electron 流程模型
单一进程
网页浏览器是一个极其复杂的应用程序。除了显示网页内容的主要能力之外,他们还有许多次要的职责,如:管理众多窗口(或标签页)和加载第三方扩展
在早期,浏览器通常使用单个进程来处理所有功能,虽然这样做打开每个标签页的开销较少,但也同时意味着一个网站的崩溃或无影响会影响到整个浏览器
多进程模型
为了解决这个问题,Chrome 团队决定让每个标签页在自己的进程中渲染, 从而限制了一个网页上的有误或恶意代码可能导致的对整个应用程序造成的伤害。 然后用单个浏览器进程控制这些标签页进程,以及整个应用程序的生命周期。
Electron 应用程序的结构非常相似。将控制两种类型的进程:主进程 和 渲染器进程。
主进程
每个 Electron 应用都有一个单一的主进程,作为应用程序的入口点。 主进程在 Node.js 环境中运行,这意味着它具有 require 模块和使用所有 Node.js API 的能力。
窗口管理
主进程的主要目的是使用 BrowserWindow 模块创建和管理应用程序窗口。
BrowserWindow 类的每个实例创建一个应用程序窗口,且在单独的渲染器进程中加载一个网页。 您可从主进程用 window 的 webContent 对象与网页内容进行交互。
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 1500 })
win.loadURL('https://github.com')
const contents = win.webContents
console.log(contents)
注意:渲染器进程也是为
web embeds而被创建的,例如BrowserView模块。 嵌入式网页内容也可访问webContents对象。
由于 BrowserWindow 模块是一个 EventEmitter, 所以您也可以为各种用户事件 ( 例如,最小化 或 最大化您的窗口 ) 添加处理程序。
当一个 BrowserWindow 实例被销毁时,与其相应的渲染器进程也会被终止。
应用程序生命周期
主进程还能通过 Electron 的 app 模块来控制您应用程序的生命周期。 此模块提供了大量事件和方法,可用于添加自定义应用程序行为(例如,以编程方式退出应用程序、修改应用程序停靠栏或显示“关于”面板)。
这是一个实际的例子,这个 app 来源于快速入门指南,用 app API 创建了一个更原生的应用程序窗口体验。
// quitting the app when no windows are open on non-macOS platforms
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
原生 API
为了使 Electron 的功能不仅仅限于对网页内容的封装,主进程也添加了自定义的 API 来与用户的作业系统进行交互。 Electron 有着多种控制原生桌面功能的模块,例如菜单、对话框以及托盘图标。
渲染器进程
每个 Electron 应用都会为每个打开的 BrowserWindow ( 与每个网页嵌入 ) 生成一个单独的渲染器进程。 洽如其名,渲染器负责 渲染 网页内容。 所以实际上,运行于渲染器进程中的代码是须遵照网页标准的 (至少就目前使用的 Chromium 而言是如此) 。
因此,一个浏览器窗口中的所有的用户界面和应用功能,都应与网页开发上使用相同的工具和规范来进行攥写。
警告:为了方便开发,可以用完整的
Node.js环境生成渲染器进程。 在历史上,这是默认的,但由于安全原因,这一功能已被禁用。
Preload 脚本
预加载(preload)脚本包含了那些执行于渲染器进程中,且先于网页内容开始加载的代码 。 这些脚本虽运行于渲染器的环境中,却因能访问 Node.js API 而拥有了更多的权限。
预加载脚本可以在 BrowserWindow 构造方法中的 webPreferences 选项里被附加到主进程。
const { BrowserWindow } = require('electron')
// ...
const win = new BrowserWindow({
webPreferences: {
preload: 'path/to/preload.js'
}
})
// ...
因为预加载脚本与浏览器共享同一个全局 Window 接口,并且可以访问 Node.js API,所以它通过在全局 window 中暴露任意 API 来增强渲染器,以便你的网页内容使用。
虽然预加载脚本与其所附着的渲染器在共享着一个全局 window 对象,但您并不能从中直接附加任何变动到 window 之上,因为 contextIsolation 是默认的。
window.myAPI = {
desktop: true
}
console.log(window.myAPI)
// => undefined
语境隔离(Context Isolation)意味着预加载脚本与渲染器的主要运行环境是隔离开来的,以避免泄漏任何具特权的 API 到您的网页内容代码中。
取而代之,我们將使用 contextBridge 模块来安全地实现交互:
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
desktop: true
})
console.log(window.myAPI)
// => { desktop: true }
此功能对两个主要目的来说非常有用:
-
通过暴露
ipcRenderer帮手模块于渲染器中,您可以使用 进程间通讯 (inter-process communication,IPC) 来从渲染器触发主进程任务 ( 反之亦然 ) 。 -
如果您正在为远程
URL上托管的现有 web 应用开发Electron封裝,则您可在渲染器的window全局变量上添加自定义的属性,好在web客户端用上仅适用于桌面应用的设计逻辑 。
创建项目
前提:确保安装了
Node,npm。
初始化
npm init
生成package.json文件
- 入口点 应当是
main.js(您很快就会创建它) author、license和_description_可为任意值,但对于应用打包是必填项。
{
"name": "electron_test",
"version": "1.0.0",
"description": "Electron测试项目",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "happlay71",
"license": "ISC"
}
安装Electron
npm i electron -D
修改package.json文件
"scripts": {
"start": "electron ."
}
创建json中main键对应的值里的js文件,然后运行
npm start
初始化窗口,在主JS文件里:
// app: 应用,BrowserWindow:窗口对象
const { app, BrowserWindow } = require("electron");
app.on("ready", () => {
const win = new BrowserWindow({
width: 800,
height: 600,
autoHideMenuBar: true,
});
win.loadURL("http://happlay.online"); // 将网页显示在窗口内
});