Electron Remote process with user input width and height not working - javascript

I am having a problem with using remote windows in electron I am trying to process user input ans use that input to create a new window with a certain width and height yet when I press submit nothing happens
I am not sure why its not working in theory everything looks fine i am not getting any errors and testt.html is loading up just fine when i press submit it just resets
here is my code:
testt.html
<script src="./renderer.js"></script>
<form onsubmit="SetAction(this)">
<label for="fname">Width</label><br>
<input type="text" id="fname" name="fname"><br>
<label for="lname">Height</label><br>
<input type="text" id="lname" name="lname"><br>
<input type="submit">
</form>
renderer.js
function SetAction(form) {
const { BrowserWindow } = require('#electron/remote/main')
//const remote = require('electron').remote;
//const BrowserWindow = remote.BrowserWindow;
const w = form.fname.value;
const h = form.lname.value;
const win = new BrowserWindow({
height: w,
width: h,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
contextIsolation: false,
webSecurity: false
}
});
window.require("#electron/remote/main").enable(win.webContents);
win.loadFile('index.html')
// var w = form.fname.value;
// alert(w)
}
cleint.js
const WindowPosition = require( 'electron-window-position' );
const path = require('path')
const prompt = require('electron-prompt');
const fs = require('fs')
function createWindow () {
// Create the browser window.
const position = new WindowPosition();
var pos = position.getActiveScreenCenter(0,0);
const mainWindow = new BrowserWindow({
x: pos.x,
y: pos.y,
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: false,
webSecurity: false
}
})
require("#electron/remote/main").initialize(); require("#electron/remote/main").enable(mainWindow.webContents);
console.log(app.getPath('userData'))
mainWindow.loadFile('index.html')
mainWindow.setBackgroundColor("#000F1A")
}
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})

There are many ways to implement this functionality. Choosing a particular way and fine-tuning it would be based on
personal preference and desired functionality.
In the example below, I have not used nodeIntegration: true and contextIsolation: false. Instead, I have these
settings reversed. IE: nodeIntegration: false and contextIsolation: true. This ensures that "both your preload
scripts and Electron's internal logic run in a separate context to the website you load in a webContents".
See Context Isolation for more information.
To keep things simple, I have the below preload.js script only managing the definition of "channel names" and
implementation of Inter-Process Communication. Apart from
the preload.js script, all other files shown below should give you a good idea on how to implement an answer.
preload.js (main process)
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// White-listed channels.
const ipc = {
'render': {
// From render to main.
'send': [
'openWindow'
],
// From main to render.
'receive': [],
// From render to main and back again.
'sendReceive': []
}
};
// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods.
'ipcRender', {
// From render to main.
send: (channel, args) => {
let validChannels = ipc.render.send;
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
},
// From main to render.
receive: (channel, listener) => {
let validChannels = ipc.render.receive;
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`.
ipcRenderer.on(channel, (event, ...args) => listener(...args));
}
},
// From render to main and back again.
invoke: (channel, args) => {
let validChannels = ipc.render.sendReceive;
if (validChannels.includes(channel)) {
return ipcRenderer.invoke(channel, args);
}
}
}
);
Within your main.js script, create the main window and listed for a call on the channel name openWindow. When
received, pass on the form options (width and height) to create the newIndex.html window.
main.js (main process)
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronIpcMain = require('electron').ipcMain;
const nodePath = require("path");
// Prevent garbage collection.
let mainWindow;
let newWindow;
function createWindow(options) {
return new electronBrowserWindow({
x: 0,
y: 0,
width: options.width,
height: options.height,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, 'preload.js')
}
});
}
electronApp.on('ready', () => {
mainWindow = createWindow({width: 800, height: 600});
mainWindow.loadFile('index.html')
.then(() => { mainWindow.show(); });
});
electronApp.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electronApp.quit();
}
});
electronApp.on('activate', () => {
if (electronBrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// ----------------
electronIpcMain.on('openWindow', (event, options) => {
newWindow = createWindow(options);
newWindow.loadFile('newIndex.html')
.then(() => { newWindow.show(); });
})
This is the main window that will be displayed on application start-up, along with form logic and an IPC
call (openWindow) from the render to the main process.
index.html (render process)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Main Window</title>
</head>
<body>
<label for="width">Width: </label>
<input type="number" id="width" min="400" max="800" step="50" value="800">
<label for="height">Height: </label>
<input type="number" id="height" min="200" max="600" step="50" value="600">
<input type="button" id="button" value="Open Window">
</body>
<script>
document.getElementById('button').addEventListener('click', () => {
let options = {
// Convert values from strings to integers
width: parseInt(document.getElementById('width').value),
height: parseInt(document.getElementById('height').value)
};
window.ipcRender.send('openWindow', options);
});
</script>
</html>
And finally, the second window that will be created on form submission.
newIndex.html (render process)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>New Window</title>
</head>
<body>
<h1>New Window</h1>
</body>
</html>

Related

electron, how to make my custom title button work

I'm trying to make my custom title button but it seems like some error has occur-ed. I tried the method from this one but not working with error message.
main.js:
const { app, BrowserWindow } = require('electron');
const path = require('path');
const electronIpcMain = require('electron').ipcMain;
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
// eslint-disable-next-line global-require
if (require('electron-squirrel-startup')) {
app.quit();
}
const createWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 1370,
height: 755,
resizable: false,
autoHideMenuBar: true,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false,
},
icon: path.join(__dirname, 'res/applogo.png'),
frame: false,
movable: false,
});
// and load the index.html of the app.
mainWindow.loadFile(path.join(__dirname, 'index.html'));
// Open the DevTools.
mainWindow.webContents.openDevTools();
};
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
//set applogo.png to every window
app.on("browser-window-created", (event, window) => {
window.setIcon(path.join(__dirname, 'res/applogo.png'))
});
//win btns
electronIpcMain.on('window:minimize', () => {
window.minimize();
})
electronIpcMain.on('window:maximize', () => {
window.maximize();
})
electronIpcMain.on('window:restore', () => {
window.restore();
})
electronIpcMain.on('window:close', () => {
window.close();
})
preload.js:
// Import the necessary Electron components.
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// White-listed channels.
const ipc = {
'render': {
// From render to main.
'send': [
'window:minimize', // Channel names
'window:maximize',
'window:restore',
'window:close'
],
// From main to render.
'receive': [],
// From render to main and back again.
'sendReceive': []
}
};
// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods.
'ipcRender', {
// From render to main.
send: (channel, args) => {
let validChannels = ipc.render.send;
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
},
// From main to render.
receive: (channel, listener) => {
let validChannels = ipc.render.receive;
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`.
ipcRenderer.on(channel, (event, ...args) => listener(...args));
}
},
// From render to main and back again.
invoke: (channel, args) => {
let validChannels = ipc.render.sendReceive;
if (validChannels.includes(channel)) {
return ipcRenderer.invoke(channel, args);
}
}
}
);
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>my app</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="title-container">
<img src="res/applogo.png" style="width: 22px; height: 22px;">
<div style="width: 5px; height: 22px;"></div>
<p class="title-text">Phigros Fanmade - Editor - Chart Name</p>
<div class="title-button" id="min-btn">
<img src="res/icons/titleButton/minimize_button.png" style="width: 20px; height: 20px; margin: 1px;">
</div>
<div class="title-button" id="res-btn">
<img src="res/icons/titleButton/restore_button.png" style="width: 20px; height: 20px; margin: 1px;">
</div>
<div class="title-button" id="max-btn">
<img src="res/icons/titleButton/maximize_button.png" style="width: 20px; height: 20px; margin: 1px;">
</div>
<div class="title-button" id="clo-btn">
<img src="res/icons/titleButton/close_button.png" style="width: 20px; height: 20px; margin: 1px;">
</div>
</div>
<div class="application-container">
<!-- ... -->
</div>
<script>
//developer tool open command
document.querySelector("div[data-title='Developer Tool']").addEventListener('click', () => {
window.open('devTool.html', "_blank", "width=1200,height=714,resizable=false,autoHideMenuBar=true,frame=false");
})
</script>
<script src="index.js"></script>
</body>
<script>
//title buttons call commands
document.getElementById('min-btn').addEventListener('click', () => {
window.ipcRender.send('window:minimize');
});
document.getElementById('max-btn').addEventListener('click', () => {
window.ipcRender.send('window:maximize');
});
document.getElementById('res-btn').addEventListener('click', () => {
window.ipcRender.send('window:restore');
});
document.getElementById('clo-btn').addEventListener('click', () => {
window.ipcRender.send('window:close');
});
</script>
</html>
index.js is empty and index.css is just basic stylings.
Error Message:
A JavaScript error occurred in the main process
Uncaught Exception:
ReferenceError: window is not defined
at IpcMainImpl. (C:\Users...\src\main.js:64:3)
at IpcMainImpl.emit (node:events:527:28)
at EventEmitter. (node:electron/js2c/browser_init:161:11014)
at EventEmiiter.emit (node:events:527:28)
Thank you for reading so far, please help me if you're able to. If you need me to provide more info, I'll update it as soon as possible when I see it. Thank you.
The primary problem is the scope of window within your main.js file.
The variable window is used within your electronIpcMain.on() functions, but it is not declared prior. As a result, you receive the window is not defined at error message.
To rectify this, you will need to add let window; before the createWindow() const.
Additionally, I would just declare the createWindow object as a function and not a const. This will simplify things. Additionally, this createWindow() function should return the Electron window object, allowing you to manipulate it further at a late time should you need to do so, like when you are minimizing, maximizing, restoring and closing. Other manipulations may be x, y, width, height, etc.
I have simplified the below main.js file to only include the above stated changes and code needed for a minimum working example.
main.js (main process)
const { app, BrowserWindow } = require('electron');
const path = require('path');
const electronIpcMain = require('electron').ipcMain;
// Declare window in the (file) scope, so it can be accessed by other functions in this file
let window;
function createWindow() {
// This window const is function scoped, therefore not accessible outside this function
const window = new BrowserWindow({
width: 1370,
height: 755,
resizable: false,
autoHideMenuBar: true,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false,
},
frame: false,
movable: false,
});
window.loadFile(path.join(__dirname, 'index.html'))
// The loadFile() function returns a promise, so let's use it correctly below
.then(() => {window.webContents.openDevTools();})
// Return this function scoped window const
return window;
}
app.on('ready', () => {
// Assign the returned value of the createWindow() function to this (file) scoped variable.
window = createWindow();
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
// Assign the returned value of the createWindow() function to this (file) scoped variable.
window = createWindow();
}
});
app.on('browser-window-created', (event, window) => {
window.setIcon(path.join(__dirname, 'res/applogo.png'));
});
electronIpcMain.on('window:minimize', () => {
// Now we can access the window variable
window.minimize();
})
electronIpcMain.on('window:maximize', () => {
// Now we can access the window variable
window.maximize();
})
electronIpcMain.on('window:restore', () => {
// Now we can access the window variable
window.restore();
})
electronIpcMain.on('window:close', () => {
// Now we can access the window variable
window.close();
})
Your preload.js script remains unchanged.
preload.js (main process)
// Import the necessary Electron components.
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// White-listed channels.
const ipc = {
'render': {
// From render to main.
'send': [
'window:minimize',
'window:maximize',
'window:restore',
'window:close'
],
// From main to render.
'receive': [],
// From render to main and back again.
'sendReceive': []
}
};
// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods.
'ipcRender', {
// From render to main.
send: (channel, args) => {
let validChannels = ipc.render.send;
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
},
// From main to render.
receive: (channel, listener) => {
let validChannels = ipc.render.receive;
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`.
ipcRenderer.on(channel, (event, ...args) => listener(...args));
}
},
// From render to main and back again.
invoke: (channel, args) => {
let validChannels = ipc.render.sendReceive;
if (validChannels.includes(channel)) {
return ipcRenderer.invoke(channel, args);
}
}
}
);
Lastly, I have simplified the index.html file for a minimum reproducible example.
index.html (render process)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>my app</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';"/>
</head>
<body>
<div>
<div class="title-button" id="min-btn"> Minimize </div>
<div class="title-button" id="res-btn"> Restore </div>
<div class="title-button" id="max-btn"> Maximize </div>
<div class="title-button" id="clo-btn"> Close </div>
</div>
</body>
<script>
document.getElementById('min-btn').addEventListener('click', () => {
window.ipcRender.send('window:minimize');
});
document.getElementById('res-btn').addEventListener('click', () => {
window.ipcRender.send('window:restore');
});
document.getElementById('max-btn').addEventListener('click', () => {
window.ipcRender.send('window:maximize');
});
document.getElementById('clo-btn').addEventListener('click', () => {
window.ipcRender.send('window:close');
});
</script>
</html>

I want close electron app from another html page with button

We are currently improve a project with electronjs: We have main.js for electron as you know and we have another html page that javascripts codes in it. We created a close button in this html page and this button should close the app but we cant reach main.js for close the app. Can you help me?
This code is from html page :
<div class="background-three link-container">
<button class="link-three" onclick="kapat()" id="kptbtn">Kapat</button>
</div>
<script>
function kapat(){
//what should I write here.
}
</script>
and this main.js
const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow() {
const win = new BrowserWindow({
transparent: true,
frame: false,
resizable: false,
width: 500,
height: 700,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('girisEkrani.html')
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
You must use ipcMain and ipcRenderer. Main for reading message and Renderer for sending message.
.html page
<script>
function kapat() {
const { ipcRenderer } = require('electron')
const ipc = ipcRenderer;
ipc.send('kapat');
}
...
</script>
if you define ipc stuff out of the function it will not work and effect other functions.
main.js
const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')
const ipc = ipcMain;
function createWindow() {
const win = new BrowserWindow({
transparent: true,
frame: false,
resizable: false,
width: 500,
height: 700,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
}
})
ipc.on('kapat', () => { win.close() })
win.loadFile('girisEkrani.html')
}

Why electron defaultPath is not opening the provided directory path

Hi i'm not able to open the provided directory path(/home/userxyz/Releases/alpha) with electron
What i'm trying
i have a path like this on ubuntu /home/userxyz/Releases/alpha
when i try to open this path with below code
const files = await dialog.showOpenDialog({
title:'Browse mapped drive',
defaultPath: "/home/userxyz/Releases/alpha",
properties: ['openFile', 'multiSelections']
});
it is opening some junk directory
Note: i will be having variable let openDirectory = "/home/userxyz/Releases/alpha" which will change based on config value.
Question: i want to open a directory with the provided path let say the path will be /home/userxyz/Releases/alpha
Regarding successfully opening a defaultPath, I have noticed that if the passed-in path does not exist, then either
the last opened path or the valid part of the defaultPath (starting from the left) is opened. Therefore, you would want to confirm that
the defaultPath exists prior to opening a dialog.
I have included a full but minimised example on how to implement your desired action. Note the use of the preload.js
script (via whitelisted channel names only) and
the ipcRenderer.invoke(channel, ...args)
method in the render process and
the ipcMain.handle(channel, listener)
method in the main process.
I have used the channel name openFileDialog.
preload.js (main process)
// Import the necessary Electron components.
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// White-listed channels.
const ipc = {
'render': {
// From render to main.
'send': [],
// From main to render.
'receive': [],
// From render to main and back again.
'sendReceive': [
'openFileDialog' // Channel name
]
}
};
// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods.
'ipcRender', {
// From render to main.
send: (channel, args) => {
let validChannels = ipc.render.send;
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, args);
}
},
// From main to render.
receive: (channel, listener) => {
let validChannels = ipc.render.receive;
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`.
ipcRenderer.on(channel, (event, ...args) => listener(...args));
}
},
// From render to main and back again.
invoke: (channel, args) => {
let validChannels = ipc.render.sendReceive;
if (validChannels.includes(channel)) {
return ipcRenderer.invoke(channel, args);
}
}
}
);
See below for further use of the preload.js script.
/**
* Render --> Main
* ---------------
* Render: window.ipcRender.send('channel', data); // Data is optional.
* Main: electronIpcMain.on('channel', (event, data) => { methodName(data); })
*
* Main --> Render
* ---------------
* Main: windowName.webContents.send('channel', data); // Data is optional.
* Render: window.ipcRender.receive('channel', (data) => { methodName(data); });
*
* Render --> Main (Value) --> Render
* ----------------------------------
* Render: window.ipcRender.invoke('channel', data).then((result) => { methodName(result); });
* Main: electronIpcMain.handle('channel', (event, data) => { return someMethod(data); });
*
* Render --> Main (Promise) --> Render
* ------------------------------------
* Render: window.ipcRender.invoke('channel', data).then((result) => { methodName(result); });
* Main: electronIpcMain.handle('channel', async (event, data) => {
* return await promiseName(data)
* .then(() => { return result; })
* });
*/
In this main.js file, one would want to check that the defaultPath exists first, else when the dialog
opens it may be unreliable / appear as a random path.
main.js (main process)
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronDialog = require('electron').dialog;
const electronIpcMain = require('electron').ipcMain;
const nodePath = require("path");
// Prevent garbage collection
let window;
function createWindow() {
const window = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, 'preload.js')
}
});
window.loadFile('index.html')
.then(() => { window.show(); });
return window;
}
electronApp.on('ready', () => {
window = createWindow();
});
electronApp.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electronApp.quit();
}
});
electronApp.on('activate', () => {
if (electronBrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// ---
// Only pass in a valid defaultPath
let defaultPath = '/home/user/Releases/alpha'; // Ubuntu
// let defaultPath = 'C:\\Users\\user\\invalid\\path'; // Windows
electronIpcMain.handle('openFileDialog', () => {
// Dialog options
let options = {
title: 'Browse mapped drive',
defaultPath: defaultPath,
properties: ['openFile', 'multiSelections']
};
// Open dialog
return electronDialog.showOpenDialog(window, options)
.then((result) => {
// Bail early if user cancelled dialog
if (result.canceled) { return }
return result.filePaths;
})
})
Detect button click, send an IPC message to the main thread which opens the dialog. Upon the dialog returning a value,
it is returned to the render process and displayed as <li> items.
index.html (render process)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Electron Test</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';"/>
</head>
<body>
<input type="button" id="button" value="Open File Dialog">
<ul id="paths"></ul>
</body>
<script>
document.getElementById('button').addEventListener('click', () => {
window.ipcRender.invoke('openFileDialog')
.then((paths) => {
if (paths === undefined) { return } // Dialog was cancelled
let result = '';
for (let path of paths) {
result += '<li>' + path + '</li>';
}
document.getElementById('paths').innerHTML = result;
})
})
</script>
</html>

Electron - How to pass data to renderer from a new opened window?

I'm struggling to pass a data from newly opened site window to renderer. What I want to achieve is to find a login button on site and listen on click event. I was reading about webview in electron, but I couldn't make It work. For now I'm stuck on window.open() method. Can you please point me what aspect I am missing? Here are my files:
//main.js
const {app, BrowserWindow, ipcMain} = require('electron')
const path = require('path')
function createWindow () {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true
}
})
mainWindow.loadFile('index.html')
// Open the DevTools.
mainWindow.webContents.openDevTools()
}
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
ipcMain.on("open-login-window", () => {
console.info('dostal');
});
//renderer.js
const electron = require("electron");
const ipc = electron.ipcRenderer
const button = document.getElementById("login-button");
button.addEventListener("click", () => {
ipc.send("open-login-window")
const windowProxy = window.open('https://www.somesite.com/login', null, 'minimizable=false')
windowProxy.postMessage('hi', '*')
});

Window object in renderer script in Electron app does not contain data from preload script

I am completely new to Electron so please forgive me if I am doing this completely wrong.
Apparently for security reasons I need to use a contextBridge to communicate between the preload and renderer scripts and the main script. I could not find a clear example for how to set this up so I took the provided answer to this stack overflow question: How to use preload.js properly in Electron. However, when I try to access window.api.receive I get the error Cannot read property 'receive' of undefined. So my window.api is undefined but I can not figure out why.
I also tried to simply set window.isWorking = true in my preload.js script and tried to print it in my renderer script like I have seen others do, but this also just prints undefined.
I use the following code:
main.js
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
let win;
function createWindow() {
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
contextIsolation: true,
nodeIntegration: false,
enableRemoteModule: false,
preload: 'preload.js'
}
});
win.loadFile('index.html');
}
app.whenReady().then(() => {
createWindow();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
ipcMain.on("test", (event, args) => {
console.log("received test request");
win.webContents.send("test", "some data");
});
preload.js
import { ipcRenderer, contextBridge } from "electron";
contextBridge.exposeInMainWorld(
"api", {
send: (channel, data) => {
let validChannels = ["test"];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel, func) => {
let validChannels = ["test"];
if (validChannels.includes(channel)) {
ipcRenderer.on(channel, (event, ...args) => func(...args));
}
}
}
);
window.isWorking = true;
renderer.js
console.log(window.isWorking); // prints undefined
window.api.receive("test", (data) => { // exception on trying to access window.api.receive
console.log("data", data);
});
window.api.send("test", "some data");
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body style="background: white;">
<h1>Hello World!</h1>
<script src="renderer.js"></script>
</body>
</html>
I think { contextIsolation: false; nodeIntegration: true } allows importing electron and allows to set window.something
So try writing:
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
contextIsolation: false,
nodeIntegration: true,
preload: 'preload.js'
}
});

Categories

Resources