有什么方法可以让我在 electronjs 中 运行 child_process 并发送 json 文件来对 child_process 创建的文件做出反应?
Is there any way that I can run child_process in electronjs and send json file to react that is being created by that child_process?
我有一个使用 nodejs 构建的 CLI 应用程序,我可以传递一些标志,它会输出到 JSON 文件。现在我想让它成为一个桌面应用程序,它将 JSON 文件数据显示为 UI。我正在尝试将 reactjs 用于 UI。此外,必须存储一些将用于 运行 CLI 的信息。
我尝试使用 child_process (exec(), spawn()
) 将 CLI 应用程序集成到 electronjs,但它不起作用,我也不知道为什么。此外,我尝试使用将生成 CLI 应用程序 child_process 并使用 JSON 响应发送输出的 expressjs 服务器包装器,但似乎无法创建 JSON 文件。
-
const timestamp = Date.now();
const child = childProcess.exec(`node ./index.js --config ./config.js ${flags} --json ${timestamp}.json --console none`);
child.stdout.on('data', (d) => console.log(d.toString()));
child.on('close', () =>{
res.status(200).json({file: `${timestamp}.json`}); // I want to send this data to frontend
});
我也有兴趣使用 javascript 的其他 library/framework 来实现这一点。
为了在线程之间安全地通信,Electron 前段时间引入了 prelaod.js
脚本的使用。该脚本实际上是主线程和渲染线程之间的看门人。 Electron 的 Context Isolation 页面将对此进行更详细的解释。
除此之外,线程之间的通信由Inter-Process Communication执行。这些 IPC 命令用于启动和侦听 'channels' 上的通信。频道只是您选择的名称以及可以附加的数据(如果需要)。
需要理解和实施的主要组件是 preload.js
脚本。
在这里,您包括 whitelisted 个频道名称。可以使用任何名称格式。任何未包含在这些列表中的频道名称都将被拒绝线程之间的通信。
PS:许多人(包括一些 Electron 文档)直接在预加载脚本中包含实际功能实现。虽然这没有任何问题,但它确实使事情变得比必要的更复杂。使用预加载脚本仅 管理 频道名称,释放在其他地方实施频道名称,这大大简化了事情。 IE:关注点分离。
preload.js
(主线程)
// 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': [
'config:data'
],
// 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);
}
}
}
);
请注意,在列入白名单的 receive
数组中,我包含了频道名称 config:data
。
现在,在您的主线程中,通过先前指定的通道发送 json 文件的内容。
main.js
(主线程)
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.show(); });
.then(() => { runConfig(); }); // Now, run your config.js file
return window;
}
function runConfig() {
const timestamp = Date.now();
const child = childProcess.exec(`node ./index.js --config ./config.js ${flags} --json ${timestamp}.json --console none`);
child.stdout.on('data', (d) => console.log(d.toString()));
child.on('close', () => {
let jsonData = JSON.parse(nodeFs.readFileSync(`${timestamp}.json`, 'utf8'));
console.log(jsonData);
window.webContents.send('config:data', jsonData); // Send the data to the render thread
});
}
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
(渲染线程)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body></body>
<script>
window.ipcRender.receive('config:data', (jsonData) => {
console.log(jsonData);
});
</script>
</html>
我有一个使用 nodejs 构建的 CLI 应用程序,我可以传递一些标志,它会输出到 JSON 文件。现在我想让它成为一个桌面应用程序,它将 JSON 文件数据显示为 UI。我正在尝试将 reactjs 用于 UI。此外,必须存储一些将用于 运行 CLI 的信息。
我尝试使用 child_process (
exec(), spawn()
) 将 CLI 应用程序集成到 electronjs,但它不起作用,我也不知道为什么。此外,我尝试使用将生成 CLI 应用程序 child_process 并使用 JSON 响应发送输出的 expressjs 服务器包装器,但似乎无法创建 JSON 文件。-
const timestamp = Date.now(); const child = childProcess.exec(`node ./index.js --config ./config.js ${flags} --json ${timestamp}.json --console none`); child.stdout.on('data', (d) => console.log(d.toString())); child.on('close', () =>{ res.status(200).json({file: `${timestamp}.json`}); // I want to send this data to frontend });
我也有兴趣使用 javascript 的其他 library/framework 来实现这一点。
为了在线程之间安全地通信,Electron 前段时间引入了 prelaod.js
脚本的使用。该脚本实际上是主线程和渲染线程之间的看门人。 Electron 的 Context Isolation 页面将对此进行更详细的解释。
除此之外,线程之间的通信由Inter-Process Communication执行。这些 IPC 命令用于启动和侦听 'channels' 上的通信。频道只是您选择的名称以及可以附加的数据(如果需要)。
需要理解和实施的主要组件是 preload.js
脚本。
在这里,您包括 whitelisted 个频道名称。可以使用任何名称格式。任何未包含在这些列表中的频道名称都将被拒绝线程之间的通信。
PS:许多人(包括一些 Electron 文档)直接在预加载脚本中包含实际功能实现。虽然这没有任何问题,但它确实使事情变得比必要的更复杂。使用预加载脚本仅 管理 频道名称,释放在其他地方实施频道名称,这大大简化了事情。 IE:关注点分离。
preload.js
(主线程)
// 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': [
'config:data'
],
// 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);
}
}
}
);
请注意,在列入白名单的 receive
数组中,我包含了频道名称 config:data
。
现在,在您的主线程中,通过先前指定的通道发送 json 文件的内容。
main.js
(主线程)
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.show(); });
.then(() => { runConfig(); }); // Now, run your config.js file
return window;
}
function runConfig() {
const timestamp = Date.now();
const child = childProcess.exec(`node ./index.js --config ./config.js ${flags} --json ${timestamp}.json --console none`);
child.stdout.on('data', (d) => console.log(d.toString()));
child.on('close', () => {
let jsonData = JSON.parse(nodeFs.readFileSync(`${timestamp}.json`, 'utf8'));
console.log(jsonData);
window.webContents.send('config:data', jsonData); // Send the data to the render thread
});
}
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
(渲染线程)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body></body>
<script>
window.ipcRender.receive('config:data', (jsonData) => {
console.log(jsonData);
});
</script>
</html>