electron: Error while importing electron in react | import { ipcRenderer } from 'electron'
I have created a simple react app with create-react-app and I have integrated it with electron successfully. Everything was working great until I tried to import electron inside the action creator file. If I remove the line below, the app works fine. The problem is that I can’t use the ipcRenderer to communicate from the react side to the electron main process.
This line causes the app to crash:
import { ipcRenderer } from 'electron';
I get the following error:
TypeError: fs.existsSync is not a function (anonymous function) node_modules/electron/index.js:6
3 |
4 | var pathFile = path.join(__dirname, 'path.txt')
5 |
> 6 | if (fs.existsSync(pathFile)) {
7 | module.exports = path.join(__dirname, fs.readFileSync(pathFile, 'utf-8'))
8 | } else {
9 | throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again')
I found out on Google that this is a common problem when trying to import electron.
Thanks for the help
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 51
- Comments: 88 (4 by maintainers)
Links to this issue
Commits related to this issue
- Update how Electron is accessed in app Following this guide: https://github.com/electron/electron/issues/9920#issuecomment-336757899 — committed to cheshire137/competiwatch-desktop by cheshire137 5 years ago
- copied stuff over slight adjustments to file structure. changed webpack configuration to support mp4. when i copied the session screen over, received error locating 'fs'; unsure if this is the same i... — committed to Quantum-Interns-at-Qualcomm-Institiute/POC-Audio-Server by aaron-kirk 2 months ago
2022 edit
I’ve posted a new history / step-by-step understanding of the Electron framework and good secure coding practices with the framework as it stands today as an additional resource here. This resource is a good resource for beginners or those who are not familiar with the Electron framework.
Original reply
I hope that this comment get noticed, because a lot of people are asking about importing
fsoripcRendererin your apps. It’s a common-need for electron apps but I found not many people have got it right, and are using outdated patterns. tl;dr - there is a security vulnerability if you don’t import your node module (ie.fs) or electron module (ie.ipcRenderer) in the correct way. If you are using your app for only yourself you are probably safe, but if you ever want to share or sell your app you should read ahead.Our goal
Before I go into the solution, it’s important to understand why we are doing this in the first place. Electron apps allow us to include node modules in our apps, which gives them amazing power, but security concerns. We want to allow our app to use native-os (ie. node) features, but we don’t want them to be abused.
The easy way
Setting
nodeIntegration: truein your BrowserWindow gives your renderer process access to node modules. Doing this, is vulnerable. You have access torequire("fs")andrequire("electron"), but that means if someone were to find a XSS vulnerability, they could run any command you’ve exposed in your renderer process.The (alternative) easy way
Alongside setting nodeIntegration to true, it’s likely that your app is using webpack to bundle application files. Webpack messes up with certain symbols, so settings like
target: 'electron-renderer'or webpack externals allows you to pass through these variables (ipcRenderer) into your app instead.The (other-alternative) easy way
You can use the remote module which gives you access to
ipcRenderer. It’s basically ‘The easy way’ in a different form. It’s not recommended by Electron’s security recommendations to do this since this type of attack suffers from a prototype pollution vector.The almost right way
@marksyzm has a better solution, although not perfect, where we use IPC to send the
ipcRendererto the renderer process. This type of setup is also vulnerable to prototype pollution attacks. If you want to get your app 80% of the way there, I’d use this method, as it probably won’t require you to do much refactoring.The right way
The right way of importing your
fs/ipcRendererinto your renderer process is with IPC (inter-process-communication). This is Electron’s way of allowing you to talk between main and renderer process. Broken down, this is how your app needs to look:preloadproperty. This property is a js file that loads with access torequire(which means you can require ipcRenderer)contextIsolation: trueto prevent prototype pollution attacks, but this means you need to use the contextBridge to pass the ipcRenderer to your renderer processipcRendererfsmoduleRoughly this is what all these steps look like:
main.js
preload.js
index.html
At the very least, I believe you need electron v7 for these features.
How do I know this?
I care about secure electron apps, and built
secure-electron-templatein order to create an electron application template to bake-in security instead of thinking of security as an afterthought.@MarshallOfSound my mistake.
I found the solution in issue #7300 if it can help anyone.
Please note that this will work when you run the Electron app, but if you just want to test your React code inside the browser it will still crash (window.require is not defined in the browser as it is in Electron).
Right, I have a solution.
preload.js filewith the code:webPreferences:Note - using this: https://github.com/cheton/is-electron for the
isElectron()functionGitHub issues are for feature requests and bug reports, questions about using Electron should be directed to the community or to the Slack Channel.
CRA uses webpack which messes with standard module loading (including fs).
I’d recommend looking into the Electron mode for webpack and ejecting from CRA
just add target: “electron-renderer” in webpack configs. export default { … target: “electron-renderer” … }
And for typescript:
If you want to access app.quit(), you can use this:
const { app } = window.require(‘electron’).remote;
Maybe it helps someone…
I’m still getting
window.require is not a function. I’m using Electron with React Starter Kit (https://github.com/kriasoft/react-starter-kit). Everything is working nicely, except this.I’ve set my Electron app to load my app from the web, so the app is not running locally: https://gist.github.com/holgersindbaek/68f6db82f507967a51ca75c527faeff6
What I’m trying to do, is call the
ipcRendererin one of my React files. I’m not sure if it’s even possible when my app is being loaded from the web though. Any suggestions?Here’s what I did: I used the
preload.jstrick from above, but in there I placed this code:This will make
window.ipcRendereravailable in the app.There is, however, one thing I don’t understand. Why can’t Electron just make it bloody work?! How hard can it be to expose some stuff into javascript? Why do we have to jump trough a billion hoops to get foundational functionality working?? I have just spent 2 goddamn hours gettings this to work. I could have have been infinitely more productive without this nonsense.
Oh and I forgot to add, place this in a sensible file somewhere if you’re using Typescript:
Because I am using Typescript, and this makes it typed. Obviously you will be needing to do this for each thing you expose through the context bridge.
Building on @reZach’s comment above, I’m doing something like the following. The main difference is in preload.js, where my API is closer to that of ipcRenderer.
main.js
preload.js
client.js
And for those using TypeScript, types.d.ts
Try disabling ContextIsolation in Electron v12 EDIT: This is considered a security issue, hence, using context isolation is preferred. See context bridge and the Preload API.
for me only work if
nodeIntegrationistrue;Bantu aku dengan $1 aku dalam kesusahan uang
Kalau berkenan transfer via rekening mandiri
No. 152-00-1748706-3
Terima kasih orang baik
Pada tanggal Jum, 12 Mar 2021 21.30, dragonDScript @.***> menulis:
I tried all of the above to no avail. What worked for me was a giant hack. Modify the file
./node_modules/electron/index.jsand hard code the path toelectron.exee.g.
Im using vuejs and just add the code in vue.config.js
module.exports = { “transpileDependencies”: [ “vuetify” ], pluginOptions: { electronBuilder: { nodeIntegration: true } } }
正解,标记
@genilsonmm Holy crap that worked! I’ve been going crazy for the past 3 hours. Thanks!! The specific piece of that that worked for me was the
For typescript and using @HemalR 's example from above but WITHOUT
nodeIntegration: true: https://github.com/electron/electron/issues/9920#issuecomment-336757899:combined with https://github.com/electron/electron/issues/9920#issuecomment-447157348
I used this:
Hope that helps someone out there! Works with stenciljs, and I imagine react and angular
Here are the steps I used for Vue in-case it’s helpful to someone else.
Ensure node integration is enabled for the renderer process by adding it to the web preferences when creating a browser window:
Configure webpack to package your application for electron renderer by adding a target to your
vue.config.js(or wherever you set your vue settings).Import what you need within your application. I’m importing the shell module into my component like so:
@dragonDScript thank you, that did the trick in v12
If you are running your React app in the browser it won’t work. Run it inside Electron and you should be fine.
For anyone new coming to this thread, @reZach has a comprehensive answer with various solutions (from easy to best) that outline what they are and what the vulnerabilities are.
To summarize the security vulnerability: If you are only using your own code, you are probably fine and can use the easy solutions. If you’re importing third-party code (such as jQuery) from a CDN, you could be exposed to XSS attacks.
The above solutions did not work for me.
Note: I am using typescript I managed to work by the following steps:
An attacker could require a node module to attack the computer or the app (in case you use remote content, such as a CDN to import Jquery, etc.).
Electron’s best way is to use a preload script + context bridge api to only expose logic parts of your app. E.g. you don’t:
This also improves speed, because remote and requiring modules in the renderer process is not very fast 😕
I am running create-react-app with TypeScript an Electron. I followed these very good instructions for a setup. But then I also ran into this error. The solution that works for me is the sum of the things said in this thread:
"electron-renderer"astarget. I userescriptswithrescript-envfor this.package.json.rescriptsrc.jsmodule.exports = [require.resolve(“./webpack.config.js”)];
webpack.config.js:src/typings.d.ts:And theeeen finally in your app
App.tsxwindow.requirewasn’t working for me in my main script with errorwindow is not defined, so I switched toconst electron = eval('require')("electron"). Hope this helps someone. Using webpack, and problem was that webpack was evaluating my require statement at compilation time.I had to downgrade electron to
^11.3.0in order for thisto work.
@LukasBombach This should work too:
Then you will have typing on the required consts
@moshfeu Your solution works fantastic. I don’t need Webpack or Browserfy to use IpcRenderer in my React project. Thanks so much again 😄
Wow, I couldn’t get the IPCRenderer working on my React Components. I’ve tried all of the method above. Did any of you incidentally have any hints that I can use for it to be working? thanks
Got this working with craco, here’s my
craco.config.js:For all the people that have the problem “window.require is not a function”
You have tu create a preoload script on electron.
Create a file named preload.js on the directory where you have de electron main script, Put this code on it:
window.require = require;
Go to your electron main script and type this in the code where you create the window:
win = new BrowserWindow({ width: 1280, height: 720, webPreferences: { nodeIntegration: false, preload: __dirname + ‘/preload.js’ },
}) With this you will preload the script before all, this fixed the problem for me. I hope also for you 😃
To anyone still having the same problem. This is the best solution i have found so far
For me worked setting target: “electron-rendering” for webpack and nodeIntegration: true in BrowserWindow options I’m using webpack+electron+react of today’s last versions
process.once("loaded", () => { contextBridge.exposeInMainWorld("ipcRenderer", ipcRenderer); });@thany thank you very much for this answer. Having pulled hair out with this pile of junk for so long, your solution indeed provided a fix for TS - the contextBridge exposure was the key.
I used https://www.electronforge.io/templates/typescript-+-webpack-template to setup an electron project. None of the solutions above seem to work. Unable to import electron from react.An insecure solution (https://stackoverflow.com/questions/56091343/typeerror-window-require-is-not-a-function/56095485). I wanted to use typeorm with sqlite without signaling through ipc.
Database is a class that instantiates a connection to the sqlite database. In essence:
From within react:
After which this should produce a valid output:
Hope somebody will find it useful.
This is what I came up with today because I need to use BrowserWindow.
I organize my api concerns into topic dedicated modules.
In it, I have my functions to ‘do stuff’. These can be called from preload and from main context.
The renderer process can access it via …
… and the main context (triggered e.g. by context-menu) via a simple:
The topic module itself:
in main I init topic module(s):
and finally preload script
@dragonDScript
I had trouble importing dialog in preload.js it always came out as undefined. The docs also say: https://www.electronjs.org/docs/api/dialog
so I did this in main:
and this in preload:
Still a bit verbose, but it works. Maybe there is another way to do it with node functions.
You could open it directly too, in preload.js. Preload has access to Node functions
I also got stuck in this issue, trying to follow the contextBridge solution suggested above, to no avail… And then I realized I was starting my Electron app using WSL, not a native terminal (I use Windows) 🤦♂️
Just a warning for anyone else that may stumble upon this!
Yes. Now it seems working with:
in main.js
preload.js :
index.d.ts :
and renderer.ts :
@reZach your solution worked for me, but I noticed a mistake that other people might stumble over (because I did, woops!):
you define your callback function as “func” , but then call “fn”, if you change this, it works precisely as you describe it. Big Thank you for the detailed post 👍
Thanks reZach! I think people will come to understand your approach sooner or later
Mark Elphinstone www.oxfordsourceltd.com
@marc2332 neither are secure. I’m just noting, if you use remote assets, you are opening yourself open to injection attacks this way. 😄
work great the @HemalR solution!
now HOW to send FROM electron TO React?
tried with on electron side
but nothing got received from the React listener
is correct to use ipcMain.emit() or should I use something else?
@CiriousJoker these is solutions, thanks!