Electron with React- 尝试导入 ipcRenderer - preload.js 未被调用
Electron with React- trying to import ipcRenderer - preload.js is not being called
我正在尝试使用 ipc 将页面中的数据发送到 electron
当我 运行 elctron 应用程序时,window.ipcRenderer 只是未定义(在电子应用程序内部)
这是代码
main.js:
const {app, BrowserWindow, ipcMain} = require('electron')
const path = require('path')
const mainWindow = new BrowserWindow({
width: 1080,
height: 920,
fullscreenable: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
.
ipcMain.on("play-vlc-magnet", (event, magnet) => {
//run_script("webtorrent --vlc " + magnet)
console.log("recevied:", magnet)
})
preload.js(console.log 不会出现在控制台中):
console.log("running preload")
window.ipcRenderer = require('electron').ipcRenderer;
在反应组件内部调用的行:
window.ipcRenderer.send("play-vlc-magnet", r.data)
React 中的元素(写着“ipc 不存在”)
<p>{(typeof window.ipcRenderer !== "undefined") ? "ipc renderer exists" : "ipc doesn't exist"</p>
理解和实施有效的 preload.js
脚本可能很困难。
过去,我发现最好阅读 re-read 以下要点,直到您理解主进程和渲染进程之间的区别,使用 preload.js
脚本的内容和原因以及如何使用实施有效的 preload.js
脚本并与之交互。在那之后,天空才是极限。
在 preload.js
脚本中实现具体功能是常见的做法(如 Electron 文档中所示)。虽然这种方法没有任何问题,但我相信在最初尝试理解和使用这种方法时很容易混淆。
相反,我个人的方法是仅使用一个 preload.js
脚本并通过仅使用列入白名单的通道名称对其进行编码以传输数据。这让我可以:
- 我创建的所有 windows 只使用一个
preload.js
脚本。
- 在一处定义所有列入白名单的频道名称的主列表。
- 脚本文件较小
preload.js
,没有具体实现。
- 分离关注点并将具体功能的实现放回到它们适当的(主进程和渲染进程)域中。
在下面的代码片段中,我向程序员展示了 Electron 文档中显示的 'common' 方法和我常用的替代方法。您可以决定哪个最适合您的理解和编码风格。
让我们从一个有效的 preload.js
脚本开始,这是阻止您在渲染进程和主进程之间进行通信的部分。
preload.js
(主进程)
const {contextBridge, ipcRenderer} = require('electron');
contextBridge.exposeInMainWorld(
'electronAPI', {
playVlcMagnet: (data) => ipcRenderer.send('play-vlc-magnet', data)
}
)
作为上述 'common' preload.js
脚本的替代方案,以下是我个人的偏好。
preload-alt.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': [
'play-vlc-magnet' // Channel name
],
// 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);
}
}
}
);
以及如何使用它。
/**
* Render --> Main
* ---------------
* Render: window.ipcRender.send('channel', data); // Data is optional.
* Main: ipcMain.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: ipcMain.handle('channel', (event, data) => { return someMethod(data); });
*
* Render --> Main (Promise) --> Render
* ------------------------------------
* Render: window.ipcRender.invoke('channel', data).then((result) => { methodName(result); });
* Main: ipcMain.handle('channel', async (event, data) => {
* return await promiseName(data)
* .then(() => { return result; })
* });
*/
接下来是您的 main.js
文件,您似乎已正确实施该文件。
main.js
(主进程)
const app = require('electron').app;
const browserWindow = require('electron').BrowserWindow;
const ipcMain = require('electron').ipcMain;
const path = require('path');
let window;
function createWindow() {
const window = new browserWindow({
width: 1080,
height: 920,
fullscreenable: false,
show: false,
webPreferences: {
nodeIntegration: false, // Default is false
contextIsolation: true, // Default is true
preload: path.join(__dirname, 'preload.js') // Use of preload.js
// preload: path.join(__dirname, 'preload-alt.js') // Use of preload-alt.js
}
});
window.loadFile('index.html')
.then(() => { window.show(); });
return window;
}
app.on('ready', () => {
window = createWindow();
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (browserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// ---
ipcMain.on("play-vlc-magnet", (event, magnet) => {
// run_script("webtorrent --vlc " + magnet)
console.log("received: ", magnet)
})
最后,你的 index.html
文件,我没有它的代码,但你会明白的。
index.html
(渲染过程)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Electron Test</title>
</head>
<body>
<input type="button" id="button" value="Play VLC Magnet">
</body>
<script>
let data = 'This is my data';
document.getElementById('button').addEventListener('click', () => {
window.electronAPI.playVlcMagnet(data); // Use of preload.js
// window.ipcRender.send('play-vlc-magnet', data); // Use of preload-alt.js
})
</script>
</html>
我正在尝试使用 ipc 将页面中的数据发送到 electron 当我 运行 elctron 应用程序时,window.ipcRenderer 只是未定义(在电子应用程序内部)
这是代码
main.js:
const {app, BrowserWindow, ipcMain} = require('electron')
const path = require('path')
const mainWindow = new BrowserWindow({
width: 1080,
height: 920,
fullscreenable: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
.
ipcMain.on("play-vlc-magnet", (event, magnet) => {
//run_script("webtorrent --vlc " + magnet)
console.log("recevied:", magnet)
})
preload.js(console.log 不会出现在控制台中):
console.log("running preload")
window.ipcRenderer = require('electron').ipcRenderer;
在反应组件内部调用的行:
window.ipcRenderer.send("play-vlc-magnet", r.data)
React 中的元素(写着“ipc 不存在”)
<p>{(typeof window.ipcRenderer !== "undefined") ? "ipc renderer exists" : "ipc doesn't exist"</p>
理解和实施有效的 preload.js
脚本可能很困难。
过去,我发现最好阅读 re-read 以下要点,直到您理解主进程和渲染进程之间的区别,使用 preload.js
脚本的内容和原因以及如何使用实施有效的 preload.js
脚本并与之交互。在那之后,天空才是极限。
在 preload.js
脚本中实现具体功能是常见的做法(如 Electron 文档中所示)。虽然这种方法没有任何问题,但我相信在最初尝试理解和使用这种方法时很容易混淆。
相反,我个人的方法是仅使用一个 preload.js
脚本并通过仅使用列入白名单的通道名称对其进行编码以传输数据。这让我可以:
- 我创建的所有 windows 只使用一个
preload.js
脚本。 - 在一处定义所有列入白名单的频道名称的主列表。
- 脚本文件较小
preload.js
,没有具体实现。 - 分离关注点并将具体功能的实现放回到它们适当的(主进程和渲染进程)域中。
在下面的代码片段中,我向程序员展示了 Electron 文档中显示的 'common' 方法和我常用的替代方法。您可以决定哪个最适合您的理解和编码风格。
让我们从一个有效的 preload.js
脚本开始,这是阻止您在渲染进程和主进程之间进行通信的部分。
preload.js
(主进程)
const {contextBridge, ipcRenderer} = require('electron');
contextBridge.exposeInMainWorld(
'electronAPI', {
playVlcMagnet: (data) => ipcRenderer.send('play-vlc-magnet', data)
}
)
作为上述 'common' preload.js
脚本的替代方案,以下是我个人的偏好。
preload-alt.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': [
'play-vlc-magnet' // Channel name
],
// 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);
}
}
}
);
以及如何使用它。
/**
* Render --> Main
* ---------------
* Render: window.ipcRender.send('channel', data); // Data is optional.
* Main: ipcMain.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: ipcMain.handle('channel', (event, data) => { return someMethod(data); });
*
* Render --> Main (Promise) --> Render
* ------------------------------------
* Render: window.ipcRender.invoke('channel', data).then((result) => { methodName(result); });
* Main: ipcMain.handle('channel', async (event, data) => {
* return await promiseName(data)
* .then(() => { return result; })
* });
*/
接下来是您的 main.js
文件,您似乎已正确实施该文件。
main.js
(主进程)
const app = require('electron').app;
const browserWindow = require('electron').BrowserWindow;
const ipcMain = require('electron').ipcMain;
const path = require('path');
let window;
function createWindow() {
const window = new browserWindow({
width: 1080,
height: 920,
fullscreenable: false,
show: false,
webPreferences: {
nodeIntegration: false, // Default is false
contextIsolation: true, // Default is true
preload: path.join(__dirname, 'preload.js') // Use of preload.js
// preload: path.join(__dirname, 'preload-alt.js') // Use of preload-alt.js
}
});
window.loadFile('index.html')
.then(() => { window.show(); });
return window;
}
app.on('ready', () => {
window = createWindow();
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (browserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// ---
ipcMain.on("play-vlc-magnet", (event, magnet) => {
// run_script("webtorrent --vlc " + magnet)
console.log("received: ", magnet)
})
最后,你的 index.html
文件,我没有它的代码,但你会明白的。
index.html
(渲染过程)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Electron Test</title>
</head>
<body>
<input type="button" id="button" value="Play VLC Magnet">
</body>
<script>
let data = 'This is my data';
document.getElementById('button').addEventListener('click', () => {
window.electronAPI.playVlcMagnet(data); // Use of preload.js
// window.ipcRender.send('play-vlc-magnet', data); // Use of preload-alt.js
})
</script>
</html>