如何在 Electron + webpack 中从主进程获取 javascript 对象到渲染进程

问题描述 投票:0回答:1

我正在构建一个电子 + webpack 应用程序。我想要实现的结果是将“config.yaml”作为主进程中的javascript对象加载(我认为必须这样做,因为渲染器无法访问节点的“fs”),然后使用IPC来移动它转移到我真正需要它的渲染器。文件结构如下所示:

- .webpack/
- node_modules/
- src/
+-- config.js
+-- header.js
+-- index.css
+-- index.html
+-- main.js
+-- preload.js
+-- renderer.js
+-- theme.js
- static/
+-- cfg/
  +-- config.yaml
+-- themes/
  +-- ...
- .gitignore
- forge.config.js
- package-lock.json
- package.json
- webpack.main.config.js
- webpack.renderer.config.js
- webpack.rules.js

main.js

const { app, BrowserWindow, Menu, ipcMain } = require('electron');
const fs = require('fs');
const yaml = require('yaml');
const theme = require('./theme.js');

// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) {
  app.quit();
}

let config = fs.readFileSync('./static/cfg/config.yaml', 'utf8');
config = yaml.parse(config);

const createWindow = () => {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    width: config.cl_win_width,
    height: config.cl_win_height,
    webPreferences: {
      preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
    },
  });

  // Remove the menu bar
  Menu.setApplicationMenu(null);

  // and load the index.html of the app.
  mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);

  // Open the DevTools.
  mainWindow.webContents.openDevTools();
};

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {

  // Config
  ipcMain.handle('config', () => {
    return config;
  })

  // Theme API
  ipcMain.handle('get-themes', () => {
    const fileList = fs.readdirSync('./static/themes');
    let themeList = theme.getThemes(fileList);
    return themeList;
  })

  createWindow();

  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
});

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

预加载.js

// See the Electron documentation for details on how to use preload scripts:
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
const { ipcRenderer, contextBridge } = require('electron');
const header = require('./header.js');

contextBridge.exposeInMainWorld('mainAPI', {
    getConfig: () => ipcRenderer.invoke('config'),
});

contextBridge.exposeInMainWorld('themeAPI', {
    listThemes: () => ipcRenderer.invoke('get-themes'),
});

contextBridge.exposeInMainWorld('headerAPI', header);

渲染器.js

import './index.css';

let headerAPI = window.headerAPI;

// Load config
let config;
window.mainAPI.getConfig().then(res => {
    console.log(res);
    config = res;
});

// Test this
console.log(config);

const content = document.querySelector('#content');

// Create Header
headerAPI.createHeader(content);

配置.js

export async function getConfig() {
    // Makes call to main process and returns the config object
    let config = await window.mainAPI.getConfig();
    console.log(config);
    return config
}

Webpack 配置为对我的静态文件使用文件加载器。

当我使用 npm run、 electro-forge 运行此应用程序时。执行后,webpack 编译我的代码,并启动开发服务器。应用程序窗口加载。

我希望看到开发工具控制台显示一条包含已注销的 javascript 对象的消息。这就是我所看到的:

undefined                        renderer.js:19

{my javascript object}           renderer.js:14

在主窗口中,控制台记录“config”对象表明它确实加载正确。

在渲染器中,它在第 14 行正确记录。我的理解是,因为我们在记录之前等待异步函数返回,所以第 14 行应该在第 19 行之前执行。我考虑过的一个选项是“.then()”不会阻止脚本执行,这就是发生此错误的原因。

我的问题是:

如何将配置对象从 main 获取到渲染器,并在继续执行该脚本的其余部分之前等待它被加载(注意,将有超过 6000 行代码,所以我已经取消了令人作呕的代码)将所有内容放入 .then() 范围的想法)。

只是一个想法:我之前在该项目的上一次迭代中已经这样做过。我只是通过不使用 main 来加载配置,而是让 config.js 使用

const fs = require('fs');
来管理它,并定义一个在那里加载它的函数,然后使用 preload 来公开它。这在这里不再起作用,因为现在除了 main.js 之外没有任何东西可以访问 fs。我真的不知道如何继续。

如果有人可以帮助我理解我在这里缺少什么,以及如何解决这个问题,我将不胜感激。谢谢!

javascript node.js webpack electron
1个回答
0
投票

在下面的代码中,执行不会等待从

Promise
返回的
window.mainAPI.getConfig()
解决后再继续执行。传递到
then()
函数的回调会被异步执行,这就是为什么首先调用第二个
console.log()
语句。

let config;
window.mainAPI.getConfig().then(res => {
    console.log(res);
    config = res;
});

console.log(config);

除了将所有其余代码放入

then()
回调中之外,还有许多选项可以解决此问题。对于您的具体情况,最方便的方法是使用 top level
await
语句 (ES2022) 等待
Promise
解决后再继续执行。幸运的是,这在 Node.js ESM 中可用,因此可以在 Electron 中使用: const config = await window.mainAPI.getConfig(); console.log(config);

	
© www.soinside.com 2019 - 2024. All rights reserved.