8

I'm using create-react-app (react-scripts v3.0.0) and electronjs (v5.0.1). I'm trying to pass events from the renderer to main process using the 'icpMain' module as described here, but get the error window.require is not a function for the line

const { ipcRenderer } = window.require('electron');

How can I get require into the global scope in the renderer process? Or is there another way of communicating between the main and renderer process?

Edit:

I've tried removing the react build entirely and get the same results simply using the electron example code in index.html.

nicholas
  • 14,184
  • 22
  • 82
  • 138

6 Answers6

20

Since Electron 12, contextIsolation is be enabled by default, the implication being that require() cannot be used in the renderer process unless contextIsolation is false, more info in this link https://www.electronjs.org/docs/breaking-changes#default-changed-contextisolation-defaults-to-true

So include the following:

webPreferences: {
    nodeIntegration: true,
    contextIsolation: false,
}
J Weller
  • 498
  • 8
  • 11
13

It looks like adding the preference:

var mainWindow = new electron.BrowserWindow({
  ...
  webPreferences: {
    nodeIntegration: true,
  }
});

is needed to enable require in the renderer process.

nicholas
  • 14,184
  • 22
  • 82
  • 138
5

Make sure webpreferences is like this.

 webPreferences: {
      nodeIntegration: true,
      enableRemoteModule: true,
      contextIsolation: false,
    },
Ravi Kandala
  • 51
  • 1
  • 3
2

Indeed, you have to set nodeIntegration to true in your BrowserWindow webPreferences since the version 5.0.0 the default values of nodeIntegration and webviewTag are false to improve security. Electron associated PR: 16235

Damien
  • 3,915
  • 1
  • 17
  • 18
2

I fix this issue to add webPreferences:{ nodeIntegration: true,preload: '${__dirname}/preload.js}', in electron.js file and add preload.js file in your directory (I added in /public directory where my electron.js file exists)

electron.js

mainWindow = new BrowserWindow({
 title: 'Electron App',
 height: 650,
 width: 1140,
 webPreferences: { 
  nodeIntegration: true,
  preload: `${__dirname}/preload.js`,
  webSecurity: false 
 },
 show: false,
 frame: true,
 closeable: false,
 resizable: false,
 transparent: false,
 center: true,
});

ipcMain.on('asynchronous-message', (event, arg) => {
  console.log(arg); // prints "ping"
  event.reply('asynchronous-reply', 'pong');
});

preload.js

in preload.js file just add below line:

window.ipcRenderer = require('electron').ipcRenderer;

ReactComponent.js

Write below code in your component function i.e: myTestHandle()

myTestHandle = () => {
  window.ipcRenderer.on('asynchronous-reply', (event, arg) => {
    console.log(arg); // prints "pong"
  });
  window.ipcRenderer.send('asynchronous-message', 'ping');
}
myTestHandle();

or call myTestHandle function anywhere in your component

Azhar
  • 693
  • 9
  • 22
0

Don't set contextIsolation to false! But use the contextBridge.exposeInMainWorld to add all what you need into the window object.

main.js

webPreferences: { 
  contextIsolation: true,
  preload: path.join(__dirname, '../preload.js')
}

preload.js

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

contextBridge.exposeInMainWorld("electron", {
  ipcRenderer,
  ...
});

Don't use require() in your React app.

If you are using React with typescript you should declare all extra fields like this:

declare global {
  interface Window {
    electron: any;
    require: any;  // this is a fix for the "window.require is not a function" error. But you don't need it anymore.
  }
}

Usage:

const { ipcRenderer } = window.electron;

Important: Don't try to expose the whole lib. Expose only what you need.

contextBridge.exposeInMainWorld("electron", electron); // Error
Dmitry Grinko
  • 13,806
  • 14
  • 62
  • 86