2018-02-19 23:16:51 +00:00
|
|
|
|
# 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.
|
|
|
|
|
|
|
|
|
|
## 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.
|
|
|
|
|
|
|
|
|
|
### 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
|
2020-08-04 19:08:35 +00:00
|
|
|
|
> In Electron, communicating between the main process and renderer processes,
|
|
|
|
|
> is done through the [`ipcRenderer`](../api/ipc-renderer.md) and
|
|
|
|
|
> [`ipcMain`](../api/ipc-main.md) modules. There is also an FAQ entry on [how
|
|
|
|
|
> to share data between web pages][share-data].
|
|
|
|
|
|
2018-02-19 23:16:51 +00:00
|
|
|
|
|
|
|
|
|
## 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:
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
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,
|
2018-05-07 15:46:14 +00:00
|
|
|
|
some from both. The documentation for each individual API will
|
|
|
|
|
state which process it can be used from.
|
2018-02-19 23:16:51 +00:00
|
|
|
|
|
|
|
|
|
A window in Electron is for instance created using the `BrowserWindow`
|
|
|
|
|
class. It is only available in the main process.
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
// This will work in the main process, but be `undefined` in a
|
|
|
|
|
// renderer process:
|
|
|
|
|
const { BrowserWindow } = require('electron')
|
|
|
|
|
|
2018-02-19 23:28:24 +00:00
|
|
|
|
const win = new BrowserWindow()
|
2018-02-19 23:16:51 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Since communication between the processes is possible, a renderer process
|
2020-08-04 19:08:35 +00:00
|
|
|
|
can call upon the main process to perform tasks through IPC.
|
2018-02-19 23:16:51 +00:00
|
|
|
|
|
|
|
|
|
```javascript
|
2020-08-04 19:08:35 +00:00
|
|
|
|
// In the main process:
|
|
|
|
|
const { ipcMain } = require('electron')
|
2018-02-19 23:16:51 +00:00
|
|
|
|
|
2020-08-04 19:08:35 +00:00
|
|
|
|
ipcMain.handle('perform-action', (event, ...args) => {
|
|
|
|
|
// ... do something on behalf of the renderer ...
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// In the renderer process:
|
|
|
|
|
const { ipcRenderer } = require('electron')
|
|
|
|
|
|
|
|
|
|
ipcRenderer.invoke('perform-action', ...args)
|
2018-02-19 23:16:51 +00:00
|
|
|
|
```
|
|
|
|
|
|
2020-08-04 19:08:35 +00:00
|
|
|
|
Note that code in the renderer may not be trustworthy, so it's important
|
|
|
|
|
to carefully validate in the main process requests that come from renderers,
|
|
|
|
|
especially if they host third-party content.
|
|
|
|
|
|
2018-02-19 23:16:51 +00:00
|
|
|
|
## 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:
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
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][security].
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
npm install --save aws-sdk
|
|
|
|
|
```
|
|
|
|
|
|
2018-05-08 05:16:09 +00:00
|
|
|
|
Then, in your Electron app, require and use the module as if you were
|
2018-02-19 23:16:51 +00:00
|
|
|
|
building a Node.js application:
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
// 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.
|
|
|
|
|
|
2018-02-20 15:47:18 +00:00
|
|
|
|
The vast majority of Node.js modules are _not_ native. Only 400 out of the
|
2019-09-30 17:41:58 +00:00
|
|
|
|
~650,000 modules are native. However, if you do need native modules, please
|
2018-05-07 15:46:14 +00:00
|
|
|
|
consult [this guide on how to recompile them for Electron][native-node].
|
2018-02-19 23:16:51 +00:00
|
|
|
|
|
|
|
|
|
[node-docs]: https://nodejs.org/en/docs/
|
|
|
|
|
[security]: ./security.md
|
|
|
|
|
[native-node]: ./using-native-node-modules.md
|
2018-02-20 15:47:18 +00:00
|
|
|
|
[share-data]: ../faq.md#how-to-share-data-between-web-pages
|