- Is it possible to use ipcRenderer without enabling nodeIntegration?
It is possible, but fiddly. It can be done by using a preload script.
- If it is, how do I do it, and why would so many resources exclude this information?
It is possible, using the preload script as indicated below. However, this is not considered secure. Most of the existing documentation does not show best security practices.
A more secure example is given afterwards.
// preload.js
const electron = require('electron');
process.once('loaded', () => {
global.ipcRenderer = electron.ipcRenderer;
});
// main.js
const {app, BrowserWindow} = require('electron');
app.on('ready', () => {
// Create the browser window.
win = new BrowserWindow({
backgroundColor: '#fff', // always set a bg color to enable font antialiasing!
webPreferences: {
preload: path.join(__dirname, './preload.js'),
nodeIntegration: false,
enableRemoteModule: false,
// contextIsolation: true,
// nativeWindowOpen: true,
// sandbox: true,
}
});
win.loadURL(`file://${path.join(__dirname, 'index.html')}`);
NOTE That the path to the preload script must be absolute and this can also
get complicated when using webpack/babel, as the output file may be a different path.
- If it is not, what do I use?
Edit
As @Yannic pointed out, there is now another option supported by Electron, called contextBridge. This new option may solve the problem more simply. For info on contextBridge, check the electron docs: https://www.electronjs.org/docs/tutorial/context-isolation
However, even with contextBridge you should not be try to expose entire electron APIs, just a limited API you have designed for your app
As mentioned, although it is possible to use ipcRenderer as shown above, the current electron security recommendations recommend also enabling contextIsolation. This will make the above approach unusable as you can no longer add data to the global scope.
The most secure recommendation, AFAIK is to use addEventListener and postMessage instead, and use the preload script as a bridge between the renderer and the main scripts.
// preload.js
const { ipcRenderer } = require('electron');
process.once('loaded', () => {
window.addEventListener('message', event => {
// do something with custom event
const message = event.data;
if (message.myTypeField === 'my-custom-message') {
ipcRenderer.send('custom-message', message);
}
});
});
// main.js
const {app, ipcMain, BrowserWindow} = require('electron');
app.on('ready', () => {
ipcMain.on('custom-message', (event, message) => {
console.log('got an IPC message', e, message);
});
// Create the browser window.
win = new BrowserWindow({
backgroundColor: '#fff', // always set a bg color to enable font antialiasing!
webPreferences: {
preload: path.join(__dirname, './preload.js'),
nodeIntegration: false,
enableRemoteModule: false,
contextIsolation: true,
sandbox: true,
// nativeWindowOpen: true,
}
});
win.loadURL(`file://${path.join(__dirname, 'index.html')}`);
// renderer.js
window.postMessage({
myTypeField: 'my-custom-message',
someData: 123,
});
nodeIntegrationenables/disables the use of NodeJS and since Electron is a NodeJS module, you can't use it without NodeJS. So, no, if you want to use Electron'sipcRenderer, you will have to enable NodeJS. - Alexander LeithnernodeIntergationset tofalseone simply cannot communicate betweenmainandrendererprocesses. I actually wonder what the real-world usage of electron will be for cases when it is set tofalse, now that they make it default. - jayarjonodeIntegrationis set tofalseby default, so it must not be required? - oldboynodeIntegrationis disabled. For example, you can establish a WebSocket connection or standard HTTP methods (e.g.GET/POSTJSON in background). The answer below by Luke H provides detailed explanations and solutions for all 3 of your questions, and I recommend marking it as the accepted answer. - jacobq