javascriptelectronipcrenderer

window.electron is undefined after exposing ipcRenderer with contextBridge in Electron (with context isolation enabled)


I'm having an issue where I am trying to expose ipcRenderer from the main process to the renderer process using contextBridge in Electron. However, after exposing it successfully, window.electron is undefined in my renderer process, even though the context is isolated and ipcRenderer is successfully exposed using contextBridge.

Below is my code:

Main.js

const { app, BrowserWindow } = require('electron');
const path = require('path');

let mainWindow;

const createWindow = () => {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    show: false,
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,  // Ensuring context isolation is enabled
      preload: path.join(__dirname, 'preload.js'), // Path to preload script
    },
  });

  const localFilePath = path.join(__dirname, 'dist', 'frontend-installers', 'index.html');
  const localFileURL = `file://${path.normalize(localFilePath)}`;

  mainWindow.loadURL(localFileURL);
  console.log('Main window loaded');

  mainWindow.webContents.openDevTools();
};

app.whenReady().then(createWindow);

Preload.js

console.log('preload running');

const { contextBridge, ipcRenderer } = require('electron');

console.log('Context Isolated:', process.contextIsolated);

if (process.contextIsolated) {
  try {
    contextBridge.exposeInMainWorld('electron', {
      ipcRenderer: ipcRenderer
    });
    console.log("ipcRenderer exposed successfully!");
  } catch (error) {
    console.error("Error exposing ipcRenderer:", error);
  }
}

window.addEventListener('DOMContentLoaded', () => {
  const replaceText = (selector, text) => {
    const element = document.getElementById(selector);
    if (element) element.innerText = text;
  };

  for (const dependency of ['chrome', 'node', 'electron']) {
    replaceText(`${dependency}-version`, process.versions[dependency]);
  }

  try {
    console.log('window:', window);  
    console.log('window.electron:', window.electron); // window.electron is undefined here
  } catch (error) {
    console.error('Error accessing window.electron:', error);
  }
});

What Works

The preload.js script runs successfully (I see the preload running log in the console). process. contextIsolated is true, meaning context isolation is correctly enabled. ipcRenderer is successfully exposed to window.electron (as per the log inside preload.js).

Why is window.electron undefined even after ipcRenderer is exposed with contextBridge? And how can I ensure that window.electron is accessible in the renderer process after it's exposed?


Solution

  • First, you should never expose the whole IPC API for security reasons. The purpose of the bridge is to expose only what you need. You can find plenty of correct examples on the IPC tutorial documentation.

    The reason window.electron is undefined on your preload is because the bridge exposes on the renderer process, not on the preload. You don't need a bridge on the preload since you can already use IPC directly on it.