Within an Electron-React-Typescript app I managed to send message from renderer process to main through contextBridge.exposeInMainWorld in preload, but on the way back, the processed output from main, it actually passes thorugh and reaches preload.ts, but it doesn't reach renderer process. It must be something really "stupid", but I do not know what is the "culprit". So, I ask you your kind help.
preload.ts :
const {
contextBridge,
ipcRenderer
} = require("electron")
contextBridge.exposeInMainWorld(
"api", {
send: (channel, data) => {
ipcRenderer.invoke(channel, data).catch(e => console.log(e))
},
receive: (channel, func) => {
ipcRenderer.on(channel, (event, ...args) => func(...args))
//ipcRenderer.on(channel, (event, ...args) => {
//console.log("ipcRenderer.on-args: ", args);
//});
}
)
index.d.ts :
declare interface Window {
api: {
send: (channel: string, ...arg: any) => void;
receive: (channel: string, func: (event: any, ...arg: any) => void) => void;
}
}
main.ts :
ipcMain.handle("path-to-url", (IpcMainEvent, path) => {
console.log("received a request from viewerDemo");
if (mainWindow) {
let urlified = url.pathToFileURL(path);
console.log("urlified = url.pathToFileURL(path) : ", urlified);
console.log("urlified.href= ", urlified.href);
console.log("urlified.pathname= ", url.pathToFileURL(path).pathname);
mainWindow.webContents.on("dom-ready", () => {
mainWindow.webContents.send("path-to-url", "ohhhhhhhhhhhhhhhh");
mainWindow.webContents.send("path-to-url", url.pathToFileURL(path).pathname);
});
}
});
Renderer process (where the data doesn't show up properly!) :
viewerDemo.tsx
import * as React from 'react';
import Viewer from 'react-viewer';
let path_1 = './images/natural-scene.jpeg';
let url_path;
const pathToUrlFunc = (path): string => {
console.log("pathToUrlFunc called");
window.api.send("path-to-url", path);
let urlPath;
window.api.receive("path-to-url", (event, args) => {
console.log("window.api.receive called!");
console.log("window.api.receive-args[0]: ", args[0]);
urlPath = args[0];
});
return urlPath;
}
function ViewerDemo() {
const [ visible, setVisible ] = React.useState(false);
let urlpath = pathToUrlFunc(path_1);
console.log("urlpath: ", urlpath);
return (
<div>
<button onClick={() => { setVisible(true); } }>show</button>
<Viewer
visible={visible}
onClose={() => { setVisible(false); } }
images={[{src: 'https://www.fotolip.com/wp-content/uploads/2016/05/Nature-Scenes-
21.jpg', alt: ''}]}
//images={[{src: urlpath, alt: ''}]}
/>
</div>
);
}
export default ViewerDemo;
In main I get : path received from main: ./images/natural-scene.jpeg
while for the way back from main to renderer I get: Cannot read property '0' of undefined
If in contextBridge.exposeInMainWorld in the 'receive' part of the api I put:
receive: (channel, func) => {
//ipcRenderer.on(channel, (event, ...args) => func(...args))
ipcRenderer.on(channel, (event, ...args) => {
console.log("ipcRenderer.on-args: ", args);
});
}
I don't get that error anymore, within preload.ts the correct message from main.ts appears, but still the renderer process doesn't get it:
You have probably found the answer to this by now but just in case and for the benefit of anyone coming across this question; although I haven't been able to run the code to prove this is the problem but I think its a problem with the preload receive function:
The ipcRenderer.on proxy method calls your "func" handler with just the spread of the args parameters. But in viewerDemo.tsx the handler method you pass to "receive" to be called as "func" is expecting two parameters "event" and "args". Consequently your single parameter passed in args is probably appearing as a single element array in the "event" parameter.
To test the theory and hopefully fix this, make the methods consistent. You could either change this line in your handler in viewerDemo.tsx from
window.api.receive("path-to-url", (event, args) => {
to
window.api.receive("path-to-url", (args) => {
Or in preload.ts change this line
ipcRenderer.on(channel, (event, ...args) => func(...args))
to
ipcRenderer.on(channel, (event, ...args) => func(event, ...args))
Either should fix the problem.