Electron Core Concepts
Electron is essentially a multi-process desktop application framework that combines **Chromium (rendering layer)** and **Node.js (system layer)**, using an independent process model to achieve interface display, logic control, and secure communication.
!(#)
Below is the Electron core architecture, showing the relationship between the main process, renderer process, IPC communication, and Preload.
**Main Process (A):**
* Runs Node.js, controls windows and system interaction.
* Uses BrowserWindow to create renderer processes.
**Renderer Process (B):**
* Each window independently runs HTML/CSS/JS for displaying the interface.
**Preload Script (B2):**
* Executes before the renderer process loads, connecting the main process and web layer.
* Securely exposes APIs through contextBridge.
**IPC Communication (dashed arrows):**
* The main process and renderer process communicate bidirectionally through ipcMain and ipcRenderer.
**Operating System (C):**
* The main process can access system functions, such as files, tray, notifications, etc.
!(#)
* * *
## Main Process
The main process is the "command center" of an Electron application, running in a Node.js environment.
It is responsible for creating windows, managing the application lifecycle, calling system APIs, and communicating with renderer processes.
After the entire application starts, the system will first run the main process script (usually `main.js`).
#### Main Process Responsibilities
* Starting and exiting the application
* Creating and destroying BrowserWindow (windows)
* Registering menus, tray, global shortcuts
* Calling operating system functions (file system, notifications, dialogs)
* Listening for events sent by renderer processes
#### Main Process Lifecycle
The main process lifecycle is consistent with the application lifecycle, starting from the `app` module:
## Example
const{ app, BrowserWindow }= require('electron');
app.whenReady().then(()=>{
const win =new BrowserWindow({ width:800, height:600});
win.loadFile('index.html');
});
app.on('window-all-closed',()=>{
if(process.platform!=='darwin') app.quit();
});
* `app.whenReady()`: Triggered after Electron initialization is complete.
* `window-all-closed`: Triggered when all windows are closed.
* `app.quit()`: Exits the entire application.
* Common special case on macOS: When users close all windows, the program remains running in the background.
#### app Module Details
The `app` module is used to control the entire application lifecycle:
* `app.on('ready')`: Triggered when Electron initialization is complete.
* `app.quit()`: Exits the application.
* `app.getPath('userData')`: Gets the system path.
* `app.setAppUserModelId(id)`: Sets the Windows taskbar ID.
* `app.isPackaged`: Determines whether the current state is packaged.
#### BrowserWindow Window Management
The main process creates visual windows through `BrowserWindow`:
## Example
const win =new BrowserWindow({
width:1024,
height:768,
resizable:true,
webPreferences:{
preload:'./preload.js',
nodeIntegration:false
}
});
* `width`, `height`: Window dimensions
* `resizable`: Whether resizing is allowed
* `webPreferences`: Used to configure renderer process behavior
* `preload`: Preload script
* `nodeIntegration`: Whether to allow the renderer process to use Node.js
#### Native Functions such as Menu, Tray, Dialog
Electron provides multiple modules to access system functions:
* **Menu / MenuItem**: Custom menu bar
* **Tray**: Create system tray icon
* **Dialog**: Call system file selection, warning dialogs
* **Notification**: Native notifications
* **shell**: Open external links or files, for example:
const { dialog } = require('electron'); dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] });
* * *
## Renderer Process
The renderer process is responsible for displaying the interface, running in a Chromium environment.
Each `BrowserWindow` has an independent renderer process.
#### Renderer Process Characteristics
* Based on Chromium, runs HTML/CSS/JS
* By default **cannot directly access Node.js API** (for security reasons)
* Can use Web technology stack: Vue, React, Svelte, etc.
* Each window corresponds to an independent thread, not affecting each other
#### Multiple Windows and Multiple Renderer Processes
Each window (`BrowserWindow`) in Electron will start an independent renderer process:
Closing one window will not affect other windows, similar to the browser's multi-tab model.
This makes the application safer and more reliable during crash recovery.
#### Web Page Loading and Display
The content of the renderer process is loaded by the main process:
win.loadFile('index.html'); // Load local page// Or win.loadURL('https://example.com'); // Load remote page
#### Renderer Process Limitations
* For security reasons, cannot directly use Node.js modules (such as `fs`, `path`).
* Not recommended to execute high-load calculations in the renderer process (will block UI).
* System interaction requires IPC communication or preload exposed APIs.
* * *
## Inter-Process Communication (IPC)
One of Electron's core mechanisms is **communication between the main process and renderer process**, called **IPC (Inter-Process Communication)**.
#### ipcMain and ipcRenderer
* `ipcMain`: Used in the main process, receives messages.
* `ipcRenderer`: Used in the renderer process, sends messages.
One-way communication example:
## Example
// main.js
const{ ipcMain }= require('electron');
ipcMain.on('ping',(event, arg)=>{
console.log(arg);// Outputs "hello from renderer"
});
// renderer.js
const{ ipcRenderer }= require('electron');
ipcRenderer.send('ping','hello from renderer');
Two-way communication example (main process returns data):
ipcMain.on('getVersion', (event) => { event.reply('getVersionResponse', app.getVersion());});
Renderer side receives:
ipcRenderer.on('getVersionResponse', (event, version) => { console.log(version);});
#### invoke/handle Pattern (Recommended Approach)
Electron provides a more concise asynchronous request method:
Main process:
ipcMain.handle('get-app-path', () => app.getPath('userData'));
Renderer process:
const result = await ipcRenderer.invoke('get-app-path'); console.log(result);
This approach is similar to `fetch` requests, avoiding multi-layer callbacks.
#### Message Passing Best Practices
* Use **explicit channel names** (such as `"user:getData"`).
* Avoid passing complex objects (JSON recommended).
* Verify source and type of data from renderer processes.
* Prefer using `invoke/handle` for structured communication.
* * *
## Preload Scripts
Preload scripts run before the renderer process is created, between the main process and web page.
Their purpose is to safely "bridge" Node.js functionality to the renderer page.
#### preload Purpose and Significance
* Can access Node.js API (because it's in an isolated context)
* Can safely expose a small amount of API to the renderer page
* Commonly used for file reading/writing, system path retrieval, application information transfer, etc.
// preload.jsconst { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('electronAPI', { getAppVersion: () => ipcRenderer.invoke('getVersion')});
Renderer process usage:
// index.html window.electronAPI.getAppVersion().then(v => { console.log('App version:', v); });
#### contextBridge Secure Communication
`contextBridge` is a secure API provided by Electron, used for:
* Only exposing required functions (whitelist mechanism)
* Preventing malicious web pages from accessing Node.js environment
* Still enabling secure communication in `contextIsolation: true` mode
#### Usage in Sandbox Mode
If sandbox is enabled (`sandbox: true`), the renderer process completely cannot use Node.js.
At this point, preload is the only bridge, responsible for:
* Receiving renderer side calls
* Forwarding through IPC to the main process
* Returning results to the web page side
* * *
## Summary
| Module | Function | Runtime Environment |
| --- | --- | --- |
| **Main Process (Main)** | Controls application lifecycle, windows, system interfaces | Node.js |
| **Renderer Process (Renderer)** | Displays UI, executes frontend logic | Chromium |
| **IPC** | Enables communication between main and renderer processes | Bidirectional channel |
| **Preload** | Securely bridges Node and Web | Middle layer |
> One sentence understanding:
>
> The main process is like a "control room", the renderer process is like "staff in each window",
>
> IPC is a "walkie-talkie", and Preload is a "filtered secure channel".
YouTip