Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

The preload script and contextBridge

A preload script is a file Electron runs in a window before the page loads. It has access to part of the Electron API, and with the contextBridge module it can put the functions the page needs onto the page's window object. This way the page gets exactly what it was allowed and nothing more.

Creating the script

Create preload.js in the project root:

// preload.js
const { contextBridge } = require('electron');
 
contextBridge.exposeInMainWorld('appInfo', {
  electron: process.versions.electron,
  chrome: process.versions.chrome,
  node: process.versions.node,
});

exposeInMainWorld takes a name and an object. On the page that object appears as window.appInfo.

Attaching it to the window

The script is set in the window's webPreferences in main.js:

// main.js
const { app, BrowserWindow } = require('electron');
const path = require('node:path');
 
function createWindow() {
  const win = new BrowserWindow({
    width: 900,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    },
  });
  win.loadFile('index.html');
}
 
app.whenReady().then(createWindow);

Now the script runs before every page load in this window.

Using it on the page

Add a paragraph <p id="versions"></p> before the ul in index.html, and these lines to renderer.js:

// renderer.js
const versions = document.querySelector('#versions');
versions.textContent =
  `Electron ${window.appInfo.electron}, Chromium ${window.appInfo.chrome}, Node.js ${window.appInfo.node}`;

After npm start a line with versions appears under the heading. The page read data it does not have itself: process exists only in preload.

Functions, not modules

You can pass strings, numbers, objects and functions. The object is copied, so the page cannot change it inside preload. Usually the bridge carries wrapper functions around IPC — this is how the window.notes object will work in the next lessons:

// preload.js
const { contextBridge, ipcRenderer } = require('electron');
 
contextBridge.exposeInMainWorld('notes', {
  load: () => ipcRenderer.invoke('notes:load'),
});

The page calls window.notes.load() without knowing how it works inside.

What preload can use

By default preload runs in a sandbox and can load only:

ModuleWhat it contains
electroncontextBridge, ipcRenderer, webFrame, webUtils, nativeImage and a few more
events, timers, urlPart of the standard Node.js modules

A limited process object is also available: versions and platform.

Common mistake

require('fs') in preload fails to load the module: the sandbox has no Node.js modules for files. Do not turn the sandbox off for this. The main process reads the file, and preload gives the page a function that asks it to do so over IPC.

Thanks for reading!

Donate to the site — we work hard for you.