Electron 应用架构
在我们深入了解Electron的API之前,我们需要探讨一下在Electron中可能遇到的两种进程类型。 它们是完全不同的,因此理解它们非常重要。
Electron Application Architecture
Before we can dive into Electron's APIs, we need to discuss the two process types available in Electron. They are fundamentally different and important to understand.
主进程和渲染器进程
Electron 运行 package.json
的 main
脚本的进程被称为主进程。 在主进程中运行的脚本通过创建web页面来展示用户界面。 一个 Electron 应用总是有且只有一个主进程。
由于 Electron 使用了 Chromium 来展示 web 页面,所以 Chromium 的多进程架构也被使用到。 每个 Electron 中的 web 页面运行在它自己的渲染进程中。
在普通的浏览器中,web页面通常在沙盒环境中运行,并且无法访问操作系统的原生资源。 然而 Electron 的用户在 Node.js 的 API 支持下可以在页面中和操作系统进行一些底层交互。
Main and Renderer Processes
In Electron, the process that runs package.json
's main
script is called the main process. The script that runs in the main process can display a GUI by creating web pages. An Electron app always has one main process, but never more.
Since Electron uses Chromium for displaying web pages, Chromium's multi-process architecture is also used. Each web page in Electron runs in its own process, which is called the renderer process.
In normal browsers, web pages usually run in a sandboxed environment and are not allowed access to native resources. Electron users, however, have the power to use Node.js APIs in web pages allowing lower level operating system interactions.
主进程和渲染进程之间的区别
主进程使用 BrowserWindow
实例创建页面。 每个 BrowserWindow
实例都在自己的渲染进程里运行页面。 当一个 BrowserWindow
实例被销毁后,相应的渲染进程也会被终止。
主进程管理所有的web页面和它们对应的渲染进程。 每个渲染进程都是独立的,它只关心它所运行的 web 页面。
在页面中调用与 GUI 相关的原生 API 是不被允许的,因为在 web 页面里操作原生的 GUI 资源是非常危险的,而且容易造成资源泄露。 如果你想在 web 页面里使用 GUI 操作,其对应的渲染进程必须与主进程进行通讯,请求主进程进行相关的 GUI 操作。
题外话:进程间通讯
Electron为主进程( main process)和渲染器进程(renderer processes)通信提供了多种实现方式,如可以使用
ipcRenderer
和ipcMain
模块发送消息,使用 remote模块进行RPC方式通信。 这里也有一个常见问题解答:web页面间如何共享数据。
Differences Between Main Process and Renderer Process
The main process creates web pages by creating BrowserWindow
instances. Each BrowserWindow
instance runs the web page in its own renderer process. When a BrowserWindow
instance is destroyed, the corresponding renderer process is also terminated.
The main process manages all web pages and their corresponding renderer processes. Each renderer process is isolated and only cares about the web page running in it.
In web pages, calling native GUI related APIs is not allowed because managing native GUI resources in web pages is very dangerous and it is easy to leak resources. If you want to perform GUI operations in a web page, the renderer process of the web page must communicate with the main process to request that the main process perform those operations.
Aside: Communication Between Processes
In Electron, we have several ways to communicate between the main process and renderer processes, such as
ipcRenderer
andipcMain
modules for sending messages, and the remote module for RPC style communication. There is also an FAQ entry on how to share data between web pages.
使用Electron的API
Electron在主进程和渲染进程中提供了大量API去帮助开发桌面应用程序, 在主进程和渲染进程中,你可以通过require的方式将其包含在模块中以此,获取Electron的API
const electron = require('electron')
所有Electron的API都被指派给一种进程类型。 许多API只能被用于主进程或渲染进程中,但其中一些API可以同时在上述两种进程中使用。 每一个API的文档都将声明你可以在哪种进程中使用该API。
Electron中的窗口是使用BrowserWindow
类型创建的一个实例, 它只能在主进程中使用。
// 这样写在主进程会有用,但是在渲染进程中会提示'未定义'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
因为进程之间的通信是被允许的, 所以渲染进程可以调用主进程来执行任务。 Electron通过remote
模块暴露一些通常只能在主进程中获取到的API。 为了在渲染进程中创建一个BrowserWindow
的实例,我们通常使用remote模块为中间件:
//这样写在渲染进程中时行得通的,但是在主进程中是'未定义'
const { remote } = require('electron')
const { BrowserWindow } = remote
const win = new BrowserWindow()
Using Electron APIs
Electron offers a number of APIs that support the development of a desktop application in both the main process and the renderer process. In both processes, you'd access Electron's APIs by requiring its included module:
const electron = require('electron')
All Electron APIs are assigned a process type. Many of them can only be used from the main process, some of them only from a renderer process, some from both. The documentation for each individual API will state which process it can be used from.
A window in Electron is for instance created using the BrowserWindow
class. It is only available in the main process.
// This will work in the main process, but be `undefined` in a
// renderer process:
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
Since communication between the processes is possible, a renderer process can call upon the main process to perform tasks. Electron comes with a module called remote
that exposes APIs usually only available on the main process. In order to create a BrowserWindow
from a renderer process, we'd use the remote as a middle-man:
// This will work in a renderer process, but be `undefined` in the
// main process:
const { remote } = require('electron')
const { BrowserWindow } = remote
const win = new BrowserWindow()
使用 Node.js 的 API
Electron同时在主进程和渲染进程中对Node.js 暴露了所有的接口。 这里有两个重要的定义:
1)所有在Node.js可以使用的API,在Electron中同样可以使用。 在Electron中调用如下代码是有用的:
const fs = require('fs')
const root = fs.readdirSync('/')
// 这会打印出磁盘根级别的所有文件
// 同时包含'/'和'C:'。
console.log(root)
正如您可能已经猜到的那样,如果您尝试加载远程内容, 这会带来重要的安全隐患。 您可以在我们的 安全文档 中找到更多有关加载远程内容的信息和指南。
2)你可以在你的应用程序中使用Node.js的模块。 选择您最喜欢的 npm 模块。 npm 提供了目前世界上最大的开源代码库,那里包含良好的维护、经过测试的代码,提供给服务器应用程序的特色功能也提供给Electron。
例如,在你的应用程序中要使用官方的AWS SDK,你需要首先安装它的依赖:
npm install --save aws-sdk
然后在你的Electron应用中,通过require引入并使用该模块,就像构建Node.js应用程序那样:
// 准备好被使用的S3 client模块
const S3 = require('aws-sdk/clients/s3')
有一个非常重要的提示: 原生Node.js模块 (即指,需要编译源码过后才能被使用的模块) 需要在编译后才能和Electron一起使用。
绝大多数的Node.js模块都不是原生的, 只有大概400~650个模块是原生的。 当然了,如果你的确需要原生模块,可以在这里查询如何重新为Electron编译原生模块(很简单)。
Using Node.js APIs
Electron exposes full access to Node.js both in the main and the renderer process. This has two important implications:
1) All APIs available in Node.js are available in Electron. Calling the following code from an Electron app works:
const fs = require('fs')
const root = fs.readdirSync('/')
// This will print all files at the root-level of the disk,
// either '/' or 'C:'.
console.log(root)
As you might already be able to guess, this has important security implications if you ever attempt to load remote content. You can find more information and guidance on loading remote content in our security documentation.
2) You can use Node.js modules in your application. Pick your favorite npm module. npm offers currently the world's biggest repository of open-source code – the ability to use well-maintained and tested code that used to be reserved for server applications is one of the key features of Electron.
As an example, to use the official AWS SDK in your application, you'd first install it as a dependency:
npm install --save aws-sdk
Then, in your Electron app, require and use the module as if you were building a Node.js application:
// A ready-to-use S3 Client
const S3 = require('aws-sdk/clients/s3')
There is one important caveat: Native Node.js modules (that is, modules that require compilation of native code before they can be used) will need to be compiled to be used with Electron.
The vast majority of Node.js modules are not native. Only 400 out of the ~650.000 modules are native. However, if you do need native modules, please consult this guide on how to recompile them for Electron.