Reputation: 73
I am currently making a desktop application that is a ReactJS application bundled or built with Electron and I want to use node modules that come with electron in my app, specifically exec or spawn from the child process module. My goal is to have a button press that executes a set of commands from command prompt as a sub/side process and return the stdout.
My app follows the typical app creation process as the tutorials online for first making a react app, get some dependencies and package.json alterations, get electron, make an electron.js or main.js type of file with all the basic window configs in it.
In the main entry point file, for me that is electron.js, I have:
webPreferences: {
nodeIntegration: true
},
However, I cannot use the child process node module in my react code even though I have allowed it in the create window function on electron's side. In my react component, when I do
import { exec } from 'child_process';
react seems to recognize it and displays all the exec function information when hovered over (parameters, overloads, found in child_process module, etc).
However, if I run the this example command from a button click, I get the error: "TypeError: Object(...) is not a function". Here the error is referring to exec.
import { exec } from 'child_process';
...
const run = () => {
exec('ls -lh', (error, stdout, stderr) => {
if (error) {
console.log(`error123: ${error.message}`);
return;
}
if (stderr) {
console.log(`stderr123: ${stderr}`);
return;
}
console.log(`stdout:\n${stdout}`);
})
};
....
return (
<div>
<button onClick={run}>Run Command!</button>
</div>
)
export ....
Does anybody know how to give the react side access to the node modules within the directory or how to import/access them correctly, either directly from the react side or maybe pass them from electron to react? Or maybe I am just running it incorrectly? I am new to javascript and stuff in general so understanding the issue and debugging is really hard for me.
Upvotes: 2
Views: 3948
Reputation: 73
Thanks to Badal for putting me in the right direction.
The answer I found involves setting contextisolation to false, nodeIntegration to true, and using the ipcMain handler (electron main process) and ipcRenderer handler (rendering, in this case react, process). The first link below shows how to use the handlers (look at the newer answers in the thread) and the second link is more detailed documentation on the inner workings. Note that if you search this 'node modules in react electron app' online, a lot of people are using remote, etc. but electron.remote is for the most deprecated at v12 or 13 and onwards, using it and other deprecated modules WILL NOT tell you its deprecated. Instead it will give the fs.filereadsync or wtvr error (I forgot) because it will not be able to understand it during building. The handlers for ipcMain and ipcRenderer handle all app internal communication and processes now, as the name ipc implies.
How to import ipcRenderer in react?
https://www.electronjs.org/docs/api/ipc-main
(new changes to electron) https://www.electronjs.org/docs/breaking-changes
With this, you can have a run button to execute a certain command and use ipcrenderer to send it to the electron side of things. In the electron side (defaults to sending to the main process file, so electron or main.js), you can import whatever node modules you want and use them. For me, I made a new file, did const {exec} = require('child process'), and then had a function which executed certain command line operations. The function call to exec was placed in the ipcMain handler.
This is insecure. For my purpose, security is not a concern, but for others it might be. Make sure to perform input cleaning and other precautions that prevent people from abusing the app and doing things like making calls without proper handles that can infiltrate the system. If you are using child process, OS subsystem modules, etc. this is especially important. As long as the front end can abstract the nature of how the internal communication is performed, that should be a good start.
Electron, as a framework, is highkey changing very fast. If you want to do well in creating applications with it, I highly recommend staying very attentive with version changes. I am new to it, and through my search on this matter and more, I have seen many small but major changes to how electron's internal process works and a lot of search results yield deprecated/outdated information.
Upvotes: 3
Reputation: 3655
It is preferred to access Node APIs from the Main process. Hence, you need to communicate from the Renderer to the Main process to execute such actions.
To access Node APIs from the Renderer process, you also need to set contextIsolation
to false
along with nodeIntegration
set to true
. This is again very insecure, to do because
..it helps prevent the website from accessing Electron internals or the powerful APIs your preload script has access to. [1]
So try to avoid doing in production, as for development you are free to experiment.
Reference:
[1] https://www.electronjs.org/docs/tutorial/context-isolation
Upvotes: 1