首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >电子预加载与电子主

电子预加载与电子主
EN

Stack Overflow用户
提问于 2022-04-08 03:59:36
回答 1查看 424关注 0票数 0

我目前使用的是电子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:

代码语言:javascript
运行
复制
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electron', {
  blenderVersion: async (blenderPath) =>
    ipcRenderer.invoke('blender:version', blenderPath),
  },
});

electron-main.js

代码语言:javascript
运行
复制
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:

代码语言:javascript
运行
复制
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
  },
});
EN

回答 1

Stack Overflow用户

发布于 2022-04-08 05:47:31

在功能上,两者之间没有任何区别.

也就是说,将代码的调用与其实现分开,在“分离您的关注点”方面起了很大的作用。如果您有很多从render到main的调用(反之亦然),那么您的preload.js脚本将变得巨大。试图管理这样大小的文件,特别是如果您是电子应用程序中的使用打字本,可能会出现问题。这种声明的开销将不断增加。

我采取了更彻底的方法,但在我看来,简化的方法.

我将preload.js脚本纯粹用作声明“通道名称”的地方,并通过使用纯IPC句柄实现主进程和呈现进程(Es)之间的通信,例如:

拥有这样一个简单的脚本意味着我只需要管理一个preload.js脚本,并且在我创建的每个窗口中都使用它。

这是我的preload.js脚本。要使用,只需将您的“通道名称”添加到任何您需要的白名单中。例:在这种情况下,我添加了通道名test:channel,只在主进程之间使用。

preload.js (主进程)

代码语言:javascript
运行
复制
// 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 (主进程)

代码语言:javascript
运行
复制
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 (渲染过程)

代码语言:javascript
运行
复制
<!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枕,将应用以下实现。

代码语言:javascript
运行
复制
/**
 * 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; })
 *          });
 */

请记住,您不能返回不能用结构化克隆算法序列化的函数、承诺或其他对象。有关详细信息,请参阅对象序列化

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71791530

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档