我正在构建一个电子+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();
}
});
preload.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);
renderer.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);
config.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、electronic forge运行这个应用程序时。执行后,webpack编译我的代码,并启动开发服务器。应用程序窗口加载。
我希望看到开发工具控制台显示一条消息,其中包含注销的javascript对象。相反,我看到的是:
undefined renderer.js:19
{my javascript object} renderer.js:14
总的来说,控制台记录“config”对象表明它确实正确加载。
在渲染器中,它正确地记录在第14行。我的理解是,因为我们在记录之前等待async函数返回,所以第14行应该在第19行之前执行。我考虑过的一个选项是“.then()”不会阻止脚本执行,这就是为什么会出现此错误。
我的问题是:
我如何将配置对象从main转移到渲染器,并在继续执行该脚本的其余部分之前等待其加载(注意,将有6000多行代码,所以我拒绝了将所有内容都放在.then()范围内的恶心想法)。
只是一个想法:我以前在这个项目的上一次迭代中做过这个。我只是通过不使用main加载配置来管理它,而是使用config.js
const fs = require('fs');
,并定义了一个函数将其加载到那里,然后使用preload来公开它。这在这里不再有效,因为现在除了main.js之外,没有其他东西可以访问fs。我真的不知道该怎么办。
如果有人能帮助我理解我在这里错过了什么,以及如何解决这个问题,我将不胜感激。谢谢!