New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Requiring electron outside of main.js causes a TypeError #7300

Closed
nukeop opened this Issue Sep 21, 2016 · 54 comments

Comments

Projects
None yet
@nukeop

nukeop commented Sep 21, 2016

  • Electron version: 1.3.5
  • Operating system: Mint 17

Hello

I am using Electron with React.js and babelify, among other plugins (list at the bottom).
Attempting to use require('electron'), for example to gain access to electron's BrowserWindow, results in the console showing the following error:
index.js:4 Uncaught TypeError: fs.readFileSync is not a function

I can, however, use const electron = require('electron'); in main.js. For what it's worth, I am also using watchify to pack everything into a js bundle.

Here is the complete list of dependencies in my package.json:

"devDependencies": {
        "axios": "^0.9.1",
        "babel-preset-es2015": "^6.6.0",
        "babel-preset-react": "^6.5.0",
        "babelify": "^7.2.0",
        "classnames": "^2.2.3",
        "electron": "^1.3.5",
        "electron-reload": "^0.2.0",
        "jquery": "^2.2.3",
        "react": "^0.14.8",
        "react-autocomplete": "^1.0.0-rc2",
        "react-dom": "^0.14.7",
        "react-sound": "^0.4.0",
        "soundmanager2": "^2.97.20150601-a"
    },
@kevinsawicki

This comment has been minimized.

Contributor

kevinsawicki commented Sep 21, 2016

index.js:4 Uncaught TypeError: fs.readFileSync is not a function

Can you include line 4 of index.js here? Or a fuller stack trace?

@nukeop

This comment has been minimized.

nukeop commented Sep 21, 2016

I believe it is referring to index.js of electron, which is itself located in node-modules of the project. Here are the contents of this file:


var fs = require('fs')
var path = require('path')

module.exports = path.join(__dirname, fs.readFileSync(path.join(__dirname, 'path.txt'), 'utf-8'))

The entire stack trace suggests a conflict with React.js:

Stack trace

@kevinsawicki

This comment has been minimized.

Contributor

kevinsawicki commented Sep 21, 2016

What happens if you run require('fs').readFileSync from the Console tab of the dev tools?

It looks like the electron-prebuilt node module (the file you pasted) is ending up in your packaged app which I don't think you want since it should use the built-in electron require instead.

@MarshallOfSound

This comment has been minimized.

Member

MarshallOfSound commented Sep 21, 2016

@nukeop How are you launching your app. Your `start script should look like.

"scripts": {
  "start": "electron ."
}

I have a feeling you are attempting to run your main.js with node

node main.js

Which won't work

@nukeop

This comment has been minimized.

nukeop commented Sep 21, 2016

What happens if you run require('fs').readFileSync from the Console tab of the dev tools?

Right after this error is thrown, I am able to run require('fs').existsSync in console to print a definition of the function. It also works before the error.

It looks like the electron-prebuilt node module (the file you pasted) is ending up in your packaged app which I don't think you want since it should use the built-in electron require instead.

I have a watchify instance running in the background as I'm developing which is continually updating my package. I defined it in scripts section of package.json like this:

"watch": "watchify app/app.js -t babelify -o public/js/bundle.js --debug --verbose"

Any advice on avoiding bundling electron-prebuilt?

@MarshallOfSound

This comment has been minimized.

Member

MarshallOfSound commented Sep 21, 2016

@nukeop Electron supports require internally so you don't need to use browserify.

As far as I am aware, I'd you want to use browserify, you have to exclude "electron".

@nukeop

This comment has been minimized.

nukeop commented Sep 21, 2016

Interesting, could it be that watchify/browserify is ruining this? It has worked ok so far.

Now I am not sure how to run the program without it.

@MarshallOfSound

This comment has been minimized.

Member

MarshallOfSound commented Sep 21, 2016

Literally just run

electron .

From your main app folder, you don't need to bundle anything when using Electron as it has a full node environment internally.

I'm going to close this out as it is a Browserify issue

@nukeop

This comment has been minimized.

nukeop commented Sep 21, 2016

That's what I've been doing all along, packing the program into a single .js file, which is included in a simple html file with:

  <script src="public/js/bundle.js">
  </script>

And everything works, except when I use require. This is a problem with interaction between the two modules.

If I do not pack the whole program into a bundle, I have no easy way of running it, as my main.js only starts electron and loads the html file that includes the bundle.

@MarshallOfSound

This comment has been minimized.

Member

MarshallOfSound commented Sep 21, 2016

@nukeop The renderer process inside Electron has access to a full node/commonjs environment as well, so you don't need to bundle anything.

If I do not pack the whole program into a bundle, I have no easy way of running it, as my main.js only starts electron and loads the html file that includes the bundle.

I'm not sure I understand here, any script you load in your HTML file has a full commonjs environment and can therefore use require to load in extra files without browserifying anything

@nukeop

This comment has been minimized.

nukeop commented Sep 21, 2016

For anyone encountering this problem in the future and reading this thread, using window.require instead of require is one possibility of avoiding the conflict between electron's and browserify's require function.

@srinathh

This comment has been minimized.

srinathh commented Jan 21, 2017

FWIW, I ran into the same issue trying to use electron in the renderer process with create-react-app that uses webpack in the backend instead of browserify. window.require seems to solve it for me too though I'm not entirely clear why.

Edit: I figured out why :-) We want to require electron during runtime from the nodejs environment provided at the runtime rather than the nodejs environment used during compilation by webpack. By default, globals are bound to window and webpack compilation ignores the window global - hence window.require works.

Another way to tell webpack to ignore a global name is to use a comment like /*global Android*/ in the JS file. In another project using CRA built app in an Android WebView, I used the above to get access to a Java object exposed to JS through the JavaScript interface provided by Webview.

@Grandclosing

This comment has been minimized.

Grandclosing commented Mar 2, 2017

@nukeop - thanks for your last post; it helped me a lot. window.require worked for me.

@basiclaser

This comment has been minimized.

basiclaser commented Mar 11, 2017

yep fixed my create react app / webpack issue.
change

import electron, { ipcRenderer } from 'electron'

to

const electron = window.require("electron")

@srinathh how are you exposing/loading your CRA app as renderer in your main? are you building first (and modifying the html static resource paths)

@srinathh

This comment has been minimized.

srinathh commented Mar 12, 2017

Yes my workflow currently is to basically run npm run build using the CRA scripts and then run the output in the build folder with electron. You don't need to modify the static resource paths by hand. In the package.json for CRA scripts, you just need to set the homepage like this and the paths will be appropriately set.

    "homepage": "./"

Additionally, I have main.js and package.json for the electron app in the public folder. So running the build automatically copies them over & you can just run electron build/ to start your app.

I'd actually like to be able to do the npm start with electron for development but I haven't gotten around to figuring how to make that work. I'm guessing i'll have to do an eject and modify the script by hand.

If you'd like to seen an example of the setup - take a look at https://github.com/srinathh/snippetfu

@sebastian-marinescu

This comment has been minimized.

sebastian-marinescu commented Apr 17, 2017

I'm not using Electron, but Node-Webkit (nw.js).
Using window.require did also fix my issue. Thanks very much for this!

@Alxmerino

This comment has been minimized.

Alxmerino commented Apr 27, 2017

@nukeop window.require did the trick for me as well thank you very much! 🎉

@tashxii

This comment has been minimized.

tashxii commented May 14, 2017

@nukeop I got same error, but it is solved window.require trick, thanks a lot!

@steric85

This comment has been minimized.

steric85 commented May 29, 2017

window.require did solve the issue of fs.existsSync is not a function but it lead to another error : window.require is not a function. How shall I solve it?

@Alxmerino

This comment has been minimized.

Alxmerino commented May 29, 2017

@steric85 are you using browserify, babel or webpack? you might need to transpile your code

@steric85

This comment has been minimized.

steric85 commented May 29, 2017

@Alxmerino I am using webpack.

@Alxmerino

This comment has been minimized.

Alxmerino commented May 29, 2017

make sure you're compiling your code

@petervojtek

This comment has been minimized.

petervojtek commented Jun 5, 2017

@steric85, I faced the window.require is not a function in typescript, I managed to fix it this way:

declare global {
  interface Window {
    require: any;
  }
}

const electron = window.require('electron');
@seanmahan

This comment has been minimized.

seanmahan commented Jun 22, 2017

I'm using the above method for accessing the ipcRenderer from electron in my Angular app but Angular change detection is not working when I update an Observable using an ipcRenderer message handler.
Is it because Angular doesn't know that ipcRenderer is an EventEmitter and that it needs to run change detection when ipcRenderer events come in?

@petervojtek

This comment has been minimized.

petervojtek commented Jun 22, 2017

in Angular 2 I used to call applicationRef.tick() to explicitly tell angular to refresh its state. https://angular.io/api/core/ApplicationRef

@axelkennedal

This comment has been minimized.

axelkennedal commented Aug 25, 2017

I'm facing a very similar problem to @nukeop and @srinathh: I set up my Electron + React + Webpack project following this article guide, where the author at the end mentions the trick with window.require. I only require('electron') two places in my project; in the entry point for Electron, and in a JavaScript controller class that is required by some React components. In my Electron entry point file I simply do const electron = require('electron');, since it should be running in the main process (right?), and in my controller class I do const Electron = window.require('electron').remote; followed by const Jsonfile = Electron.require('jsonfile');, which should be the way to do it since it's running in the renderer process. But I get the same error as @nukeop ("TypeError: fs.ExistsSync is not a function") at line six in node_modules/electron/index.js which looks like this:

var fs = require('fs')
var path = require('path')

var pathFile = path.join(__dirname, 'path.txt')

if (fs.existsSync(pathFile)) {
  module.exports = path.join(__dirname, fs.readFileSync(pathFile, 'utf-8'))
} else {
  throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again')
}

I've tried deleting node_modules/electron and installing again.
I'm using Electron 1.7.5 on macOS 10.12.6, and start my project using npm run dev as setup in the article.

@holgersindbaek

This comment has been minimized.

holgersindbaek commented Sep 20, 2017

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 ipcRenderer in 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?

@solominh

This comment has been minimized.

solominh commented Sep 20, 2017

@holgersindbaek You shouldn't view your app in browser like Chrome, Firefox, etc. It won't work because it is the webpage environment.
You should view your app in an Electron window.

@holgersindbaek

This comment has been minimized.

holgersindbaek commented Sep 20, 2017

I am, but I'm using Electron in a way, where I'm loading my app from the website on each launch. Essentially I'm showing a website in my electron app. See the above file. I just want to make sure that there's really nothing I can do?!

@solominh

This comment has been minimized.

solominh commented Sep 20, 2017

Electron can load any URLs. In order to load a URL you should use this function mainWindow.loadURL(url)
=> In electron window view, that URL javascript code can access require, ipc, etc.

@holgersindbaek

This comment has been minimized.

holgersindbaek commented Sep 21, 2017

Ok. I'll try that.

@PixelTom

This comment has been minimized.

PixelTom commented Nov 5, 2017

window.require on electron didn't work, but window.require for fs did.

Not really sure why. But it's working and since it's a small personal project I'm not going to push the issue.

Thanks @nukeop

@Ferigit

This comment has been minimized.

Ferigit commented Nov 6, 2017

Hi, This is my package.json, I am using webpack, none of these did solve my problem, does anybody have a solution? After I use window.require, I got error "window is not defined"

'use strict';

var electron = require('electron')
var app = electron.app;
var BrowserWindow = electron.BrowserWindow;
var mainWindow = null;

app.on('ready', function() {
mainWindow = new BrowserWindow({width: 800, height: 600});

mainWindow.loadURL('file://' + __dirname + '/index.electron.html');

mainWindow.webContents.openDevTools();

});

tao-cumplido added a commit to stimonm/Bike3S that referenced this issue Nov 15, 2017

@JWTappert

This comment has been minimized.

JWTappert commented Nov 16, 2017

I'm using typescript and I had to use

const electron = (<any>window).require("electron");

to get my renderer to communicate with my main. Hope this helps someone.

@micsel

This comment has been minimized.

micsel commented Dec 3, 2017

This worked for me.
For e.g. if you want to require remote, then

declare const window: any;
const { remote } = window.require('electron');

@Ferigit

This comment has been minimized.

Ferigit commented Dec 4, 2017

@amaurymartiny

This comment has been minimized.

amaurymartiny commented Jan 16, 2018

@solominh Thanks for your explanations here. However I have a similar configuration as @holgersindbaek, which environment is a preload script in a webview?

Info:

  • My electron entry runs mainWindow.loadURL(url), where url is a local index.html
  • This index.html has a <webview>
  • The webview has a preload field which loads inject.js, and this script does the window.require('electron').

Remarks:

  • If I use const electron = require('electron'), I have the error fs.readFileSync is not a function
  • If I use const electron = window.require('electron'), I have the error window.require is not a function.
  • inject.js is bundled through webpack (can paste config if relevant).

EDIT: Solved for me using <webview nodeintegration="true"> and window.require. Leaving note here for future reference.

@Daniel-Griffiths

This comment has been minimized.

Daniel-Griffiths commented Jan 22, 2018

window.require worked for me! Thanks guys!

@andrewsrahn

This comment has been minimized.

andrewsrahn commented Mar 1, 2018

https://imgur.com/a/ekWwD

error message in browser when i tried this

@phil294

This comment has been minimized.

phil294 commented Apr 5, 2018

Forgot to revert nodeIntegration: false which disables even window.require()... stupid mistake. Hope this spares someone an hour of researching.

@Vishal1419

This comment has been minimized.

Vishal1419 commented Apr 7, 2018

@phil294 Thanks man! you really saved an hour of researching.

@mahipalsaran

This comment has been minimized.

mahipalsaran commented Apr 18, 2018

Hi @micsel ,
I included declare const window: any;
but it is throwing syntax error.
Any ideas why?

@micsel

This comment has been minimized.

micsel commented Apr 18, 2018

Ya, put declare const window: any; at the top, just after where the imports are.

@pappacurds

This comment has been minimized.

pappacurds commented Apr 25, 2018

If you get window.require is not a function and you are using Angular-CLI, use the following to instantiate the Window interface:

./src/typings.d.ts

declare var window: Window;
interface Window {
	require: any;
}

Then you can use this to include electron:
const { ipcRenderer } = window.require('electron');

@kundan1116

This comment has been minimized.

kundan1116 commented May 25, 2018

if you are using angular 2+ in electron app then import "ngx-electron" lib and use this in any.componets.ts

import { ElectronService } from 'ngx-electron';

//constructor
constructor(
    private elt: ElectronService
  ){
  var fs = this.elt.remote.require('fs');
}

@mnjsnj

This comment has been minimized.

mnjsnj commented Jul 18, 2018

I am using react js with electron and when i run this line into terminal yarn run start it provides me error Uncaught Type Error: window.require is not a function i am not using typescript how declare window in React Js

@vishal-android-freak

This comment has been minimized.

vishal-android-freak commented Jul 22, 2018

People who are still facing the issue, somehow doing a window.require() spoils the consistency of using import statements throughout the codebase. An easy alternative is to set your webpack target to electron-renderer. If using Create React App, ejecting can be a mess. Hence, you can use this package which does the webpack hooking for you and you can use for eg., import fs from 'fs' in your React components (or any other node module ), happily in your life :)

@cperthuis

This comment has been minimized.

cperthuis commented Jul 24, 2018

On windows with Vue CLI 3, window.require will work but will require a full path instead of a relative path from "node_modules/".

But similar to the React case, webpack can be configured properly for Vue by editing vue.config.js. "require" will then work as expected.

vue.config.js:

module.exports = {
    configureWebpack: config => {
      if (process.env.NODE_ENV === 'production') {
        config.output.publicPath = `${process.cwd()}/dist/`
      }
      config.target = 'electron-renderer'
    }
  }

router.js (this is just an example, it would work in any other vue js file)

const Store = require("electron-store");
const store = new Store();
@joshuapinter

This comment has been minimized.

joshuapinter commented Sep 8, 2018

I almost don't want to add this but it would have saved me an hour or two of debugging.

I had to rm -rf node_modules && npm install to fix this issue. I was then able to remove the window from window.require and things started working again. Hopefully that helps somebody else.

@agrublev

This comment has been minimized.

agrublev commented Sep 18, 2018

@cperthuis I just want to say THANK YOU!! Hahah I am not even using Vue, but logical thinking led me to figure out that i can change my webpack.config.js to have a target property :)
image
WORKED LIKE A CHARM.

@firestar300

This comment has been minimized.

firestar300 commented Oct 29, 2018

Hi,

window.require works in a dev local server environment but doesn't in a prod environment after building React app to a minified HTML file.

function createWindow() {
  win = new BrowserWindow({
    width: 1280,
    height: 720,
    icon: path.join(__dirname, 'assets/icons/png/64x64.png'),
    webPreferences: {
      nodeIntegration: true,
      preload: __dirname + '/preload.js'
    }
  })

  win.setPosition(0, 0)

  win.loadURL(isDev ? 'http://localhost:3000' : `file://${path.join(__dirname, 'build/index.html')}`)
}

It works with localhost:3000 but not with file://${path.join(__dirname, 'build/index.html')}

https://imgur.com/EE7jxZq

@Lilanga

This comment has been minimized.

Lilanga commented Nov 3, 2018

@cperthuis, your fix worked for un-ejected CRA app using 'react-app-rewired'. thank you.
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment