Draw.io Desktop electron.js Main Process File Structure and IPC Handlers Explained
The src/main/electron.js file serves as the entry point for the Draw.io Desktop Electron application, organizing imports, security policies, window management, and inter-process communication through a structured series of IPC handlers that bridge the renderer process and native OS capabilities.
The jgraph/drawio-desktop repository bundles the popular draw.io diagram editor as a cross-platform desktop application. Understanding the electron.js main process file structure is essential for developers extending the application or debugging its native behavior, as this file orchestrates everything from window creation to export pipelines and auto-updates according to the source code in the dev branch.
Overview of the Main Process Architecture
The main process file follows a layered architecture that prioritizes security and modularity. At approximately 1,500+ lines, src/main/electron.js (viewable on GitHub at [src/main/electron.js](https://github.com/jgraph/drawio-desktop/blob/dev/src/main/electron.js)) divides functionality into distinct regions: global constants and imports, security helpers, window factory functions, IPC handler registrations, the export pipeline, and application lifecycle management.
File Structure and Organization
Imports and Global Configuration
The first 21 lines establish the runtime environment by loading Node.js modules, Electron APIs (app, BrowserWindow, ipcMain, session), and third-party dependencies including electron-log, commander, electron-updater, @cantoo/pdf-lib, and electron-store (lines 1-21). This section defines critical path constants such as __dirname, codeDir, and appBaseDir that anchor the application relative to the bundled draw.io submodule.
Following imports, the code initializes an electron-store instance and evaluates update flags including disableUpdate and silentUpdate, which determine whether the auto-updater runs silently or prompts the user (lines 22-41).
Security Helpers and Window Factory
Three essential functions located in the helper section (lines 36-66) enforce security and window integrity:
validateSender(frame)– Guarantees that IPC messages originate exclusively from the bundled draw.io code by verifying the sender URL againstcodeUrl.isWithinDisplayBounds(pos)– Validates that a saved window position actually exists on a connected display before restoration.createWindow(opt)– Builds aBrowserWindowwith hardened security flags, restores previous size/position from the store, injects the preload script atsrc/main/electron-preload.js, and registers per-window IPC listeners.
Key IPC Handlers in electron.js
The file registers two categories of IPC channels: per-window handlers created inside createWindow, and global handlers attached directly to ipcMain outside any window context.
Per-Window IPC Channels
Inside createWindow() (around lines 44-53), the main process attaches listeners specific to each browser instance:
openDevTools– Opens Chrome DevTools on demand when the renderer sends a debug request.isModified-result– Receives the answer to a "has the document changed?" query from the renderer. The handler shows a save modal if needed, deletes draft files, or forces window closure based on theisModifiedboolean anddraftPathprovided.
Global Application IPC Channels
Outside the window factory, the file registers global channels (approximately lines 106-120) that respond to application-wide shortcuts and menu actions:
newfile– Creates a brand-new window with optional dimension parameters.toggleSpellCheck,toggleStoreBkp,toggleGoogleFonts,toggleFullscreen– Toggle boolean user settings persisted inelectron-store.checkForUpdates– Manually triggersautoUpdater.checkForUpdates().zoomIn,zoomOut,resetZoom– UI-level zoom controls wired to the application menu.
The Export Pipeline (exportDiagram)
The most complex IPC handler is the export pipeline (starting at line 378 and spanning to line 754). When the renderer sends an export event, exportDiagram executes the following workflow:
- Creates an off-screen
BrowserWindowinvisible to the user. - Loads
export3.htmlfrom the bundled drawio submodule (drawio/src/main/webapp/export3.html). - Listens for
render-finishedfrom the off-screen renderer, indicating the diagram has rasterized. - Sends
renderto the off-screen window with export arguments (format, width, height, XML data). - Handles callbacks
export-success,export-error,svg-data,xml-data, andexport-finalizeto coordinate PDF merging (viamergePdfsusing@cantoo/pdf-lib), PNG metadata injection (viawritePngWithText), DPI settings, and base64 encoding.
Security Implementation
Security hardening begins before any window loads. The app.whenReady() block (lines 671-752) installs a strict Content Security Policy via session.defaultSession.webRequest.onHeadersReceived and registers a file:// request filter.
The navigation guard (lines 724-796) blocks all will-navigate events and disallows external webview creation. The setWindowOpenHandler only permits about:blank or external URLs opened via shell.openExternal, preventing unwanted redirects from the draw.io web codebase.
Code Examples for Renderer Communication
Below are minimal snippets that a renderer process uses to interact with the main-process IPC channels defined in electron.js.
Open DevTools
// In a renderer script (via the contextBridge API)
window.electronAPI.request('openDevTools');
Handled in createWindow() → ipcMain.on('openDevTools', …) (lines 44-53).
Check Modified Document Status
const uid = crypto.randomUUID();
ipcRenderer.send('isModified-result', {
uniqueId: uid,
isModified: true,
draftPath: '/tmp/foo.dtmp'
});
The main process validates the sender via validateSender(frame) before processing the modification state.
Export Diagram to PNG (Base64)
ipcRenderer.send('export', {
format: 'png',
w: 800,
h: 600,
base64: '1',
embedXml: '1',
xml: '<mxGraphModel>…</mxGraphModel>'
});
ipcRenderer.once('export-success', (e, data) => {
// data is a base64 PNG string
const img = document.createElement('img');
img.src = `data:image/png;base64,${data}`;
document.body.append(img);
});
The exportDiagram function (line 378) coordinates this operation through the off-screen window pipeline.
Toggle Spell Check Setting
ipcRenderer.send('toggleSpellCheck');
This triggers the handler at approximately line 885, which persists the new boolean value to electron-store.
Manual Update Check
ipcRenderer.send('checkForUpdates');
The handler at line 1002 invokes autoUpdater.checkForUpdates(), displaying a progress bar via electron-progressbar unless running in silentUpdate mode (lines 818-874).
Summary
src/main/electron.jsis the single entry point that bootstraps the Draw.io Desktop application, initializes security policies, and manages the window lifecycle.- Security-first design mandates that all IPC messages pass through
validateSender()and that navigation is blocked viawebRequestfilters andsetWindowOpenHandler. - Two-tier IPC architecture separates per-window channels (like
openDevTools) from global channels (likenewfileandtoggleSpellCheck). - Export pipeline uses an off-screen
BrowserWindowloadingexport3.htmlto rasterize diagrams, handling PNG metadata injection and PDF merging through dedicated helper functions (writePngWithText,mergePdfs) at lines 1445-1527. - Auto-update logic respects the
disableUpdateandsilentUpdateflags established early in the file (lines 22-41) before wiring thecheckForUpdatesIPC handler.
Frequently Asked Questions
How does electron.js verify that IPC messages come from legitimate renderer processes?
The file implements a validateSender(frame) helper function that checks the senderFrame URL against the codeUrl constant (pointing to the bundled draw.io source). If the message originates from any other origin, the handler returns early, preventing malicious scripts from invoking main-process capabilities. This validation runs before processing sensitive channels like isModified-result or export.
What is the purpose of the exportDiagram function and how does it handle different file formats?
exportDiagram (starting at line 378) creates a hidden BrowserWindow, loads export3.html, and establishes a coordination protocol with the off-screen renderer. It sends a render event with export parameters, then waits for render-finished. Depending on the requested format, it processes svg-data, xml-data, or binary buffers, injects DPI metadata into PNGs via writePngWithText, and merges multi-page PDFs via mergePdfs using @cantoo/pdf-lib.
Where are user preferences like spell check and backup settings stored?
Toggle handlers such as toggleSpellCheck, toggleStoreBkp, and toggleGoogleFonts modify an electron-store instance initialized near line 22. These settings persist across application restarts and are accessed by both the main process (to configure window behavior) and indirectly by the renderer through IPC queries.
How does the application prevent navigation to external URLs or unauthorized content?
The security block (lines 724-796) registers session.defaultSession.webRequest.onHeadersReceived to inject a strict CSP, blocks all will-navigate events on web-contents-created, and sets a setWindowOpenHandler that only allows about:blank or explicitly allowed URLs opened via shell.openExternal. This ensures the draw.io web app cannot be redirected to malicious sites or open unapproved windows.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →