我目前使用的是电子v16。显然,在这个版本上,我们不能再使用渲染线程中内置的Node模块了。
唯一的方法是使用电子预加载. is。
我阅读了以下资源:https://whoisryosuke.com/blog/2022/using-nodejs-apis-in-electron-with-react/,其中作者通过使用ipcMain
将实现代码放置在电子-main.js中,代码通过电子预加载. is contextBridge
调用。
我的问题是:如果将整个实现代码放在electron-preload
中而不是需要从这里调用事件并将其发送到ipcMain?
中,会有什么区别吗?
这是作者的代码:
electron-preload.js:
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electron', {
blenderVersion: async (blenderPath) =>
ipcRenderer.invoke('blender:version', blenderPath),
},
});
electron-main.js
ipcMain.handle('blender:version', async (_, args) => {
console.log('running cli', _, args)
let result
if (args) {
const blenderExecutable = checkMacBlender(args)
// If MacOS, we need to change path to make executable
const checkVersionCommand = `${blenderExecutable} -v`
result = execSync(checkVersionCommand).toString()
}
return result
})
我在想,如果这样做是可以接受的(利弊?):
electron-preload.js:
const { contextBridge } = require('electron');
contextBridge.exposeInMainWorld('electron', {
blenderVersion: async (blenderPath) =>
console.log('running cli', _, args)
let result
if (args) {
const blenderExecutable = checkMacBlender(args)
// If MacOS, we need to change path to make executable
const checkVersionCommand = `${blenderExecutable} -v`
result = execSync(checkVersionCommand).toString()
}
return result
},
});
发布于 2022-04-08 05:47:31
在功能上,两者之间没有任何区别.
也就是说,将代码的调用与其实现分开,在“分离您的关注点”方面起了很大的作用。如果您有很多从render到main的调用(反之亦然),那么您的preload.js
脚本将变得巨大。试图管理这样大小的文件,特别是如果您是电子应用程序中的使用打字本,可能会出现问题。这种声明的开销将不断增加。
我采取了更彻底的方法,但在我看来,简化的方法.
我将preload.js
脚本纯粹用作声明“通道名称”的地方,并通过使用纯IPC句柄实现主进程和呈现进程(Es)之间的通信,例如:
拥有这样一个简单的脚本意味着我只需要管理一个preload.js
脚本,并且在我创建的每个窗口中都使用它。
这是我的preload.js
脚本。要使用,只需将您的“通道名称”添加到任何您需要的白名单中。例:在这种情况下,我添加了通道名test:channel
,只在主进程之间使用。
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': [],
// From main to render.
'receive': [
'test:channel' // Our channel name
],
// 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);
}
}
}
);
在我的main.js
脚本中,只有带有通道名称和任何相关数据的IPC (如果有的话)。
main.js
(主进程)
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const nodePath = require("path");
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.webContents.send('test:channel', 'Hello from the main thread') })
.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();
}
});
最后,在您的呈现中,只需侦听通道名称,并在调用时实现功能。
index.html
(渲染过程)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Electron Test</title>
</head>
<body>
<div id="test"></div> // Outputs "Hello from the main thread"
</body>
<script>
window.ipcRender.receive('test:channel', (text) => {
document.getElementById('test').innerText = text;
})
</script>
</html>
若要在主进程和呈现过程中使用此preload.js
枕,将应用以下实现。
/**
* 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; })
* });
*/
https://stackoverflow.com/questions/71791530
复制相似问题