我正在构建一个电子 + 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。我真的不知道如何继续。
如果有人可以帮助我理解我在这里缺少什么,以及如何解决这个问题,我将不胜感激。谢谢!
在下面的代码中,执行不会等待从
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);