electron 在执行渲染器上的任何JavaScript之前,将变量注入渲染器的窗口对象

uinbv5nw  于 2023-04-03  发布在  Electron
关注(0)|答案(2)|浏览(278)

bounty已结束,回答此问题可获得+50声望奖励,奖励宽限期2小时后结束,sasidhar希望引起更多关注此问题:我需要一个工作的例子。我可以阻止渲染器,直到收到此配置。

我有一个Electron应用程序(electron v23),它可以读取配置文件并确定一些配置。我有一个单独的react项目,一旦配置确定,我的Electron窗口就会打开react应用程序的URL。
Electron应用程序需要将config对象放在React应用程序的窗口对象(渲染器的窗口对象)中,然后才能执行任何客户端代码。
我尝试了几种方法,但似乎都不起作用:

方法1:

const validChannels = ['something'];
const { contextBridge, ipcRenderer } = require("electron");
const { getConfig } = require("./config");

contextBridge.exposeInMainWorld("electron", {
    getConfig: () => {
        return getConfig();
    },
    send: (channel, data) => {
        if (validChannels.includes(channel)) {
            ipcRenderer.send(channel, data);
        }
    },
    receive: (channel, func) => {
        if (validChannels.includes(channel)) {
            // Deliberately strip event as it includes `sender` and is a security risk
            ipcRenderer.on(channel, (event, ...args) => func(...args));
        }
    },
});

以下是我打开窗口的方式:

const win = new BrowserWindow({
    width: 1600,
    height: 1000,
    webPreferences: {
        nodeIntegration: false,
        devTools: true,
        contextIsolation: true,
        sandbox: false,
            preload: path.join(__dirname, "preload.js"),
        }
    }
});

当我使用这种方法时,我在一些内部脚本electron.app.isPackaged无法访问时得到一个错误,因为electron.app未定义。我尝试了一些其他选项,如设置nodeIntegration: true,但到目前为止没有任何效果。

方法2

win.webContents.on("did-finish-load", () => {
    win.webContents.executeJavaScript(`window.__configFromElectron = ${JSON.stringify(getConfig())};`);
});

这种方法确实设置了变量__configFromElectron,但这是在代码中设置的。React中需要此配置的初始化脚本会收到undefined,但很久以后它们会得到实际的配置。我在这里尝试了不同的选项,如did-start-loadingdom-ready。它们都没有使变量首先加载。
我尝试了一些其他的方法,我试图阻止组件的React渲染,直到这个变量可用,但是这个配置是在单例中预期的,并且它会事先进行评估,即使我阻止渲染过程。(我使用了像ipcMain.handleipcRenderer.invoke这样的方法)但这些解决方案都不是优雅的。
对React应用程序进行重构,使其配置为async,所有依赖项都必须为await,这是一个非常大的变化。正确的方法是什么?

7d7tgy0s

7d7tgy0s1#

你可以在你的方法2中做类似的事情。
您需要确保在依赖于它的任何代码运行之前设置config对象。您可以使用Promise来确保在其他代码执行之前设置config对象。

let configPromise;

win.webContents.on("did-finish-load", () => {
  configPromise = new Promise((resolve) => {
    win.webContents.executeJavaScript(`window.__configFromElectron = ${JSON.stringify(getConfig())};`, () => {
      resolve();
    });
  });
});

// In your React app:
async function init() {
  await configPromise;
  const config = window.__configFromElectron;
  // Use config here
}

init();

这种方法将确保在任何依赖于它的代码运行之前设置config对象,但它确实需要修改React应用程序以使用异步初始化方法。

azpvetkf

azpvetkf2#

有几种方法可以做到这一点,但我首选的方法是使用BrowserWindowadditionalArguments选项。

**注意:**此方法只能发送字符串
主流程

const yourValue = 'any string value';
const mainWindow = new BrowserWindow({
  ...opts
  webPreferences: {
    additionalArguments: ['--yourKey=${yourValue}']
  }
})

预加载脚本

const {argv} = require('yargs-parser');

const yourPassedValue = argv.yourKey; // 'any string value'

相关问题