electron 5.0.0 "Uncaught ReferenceError: require is not defined" - javascript

I had initially been using electron stable (4.x.x), and was able to use require in both my browser and renderer processes. I upgraded to electron beta (5.0.0) because I needed a newer version of node and encountered this error message in my renderer process, Uncaught ReferenceError: require is not defined.
Googling and looking through the electron docs, I found comments saying the error could be caused by setting webPreferences.nodeIntegration to false when initializing the BrowserWindow; e.g.: new BrowserWindow({width, height, webPreferences: {nodeIntegration: false}});. But I was not doing this, so I thought something else must be the issue and continued searching for a resolution.

For Electron version 12 and above
const electron = require("electron");
const { app, BrowserWindow } = electron;
app.on("ready", () => {
const mainWindow = new BrowserWindow({
width: 1000,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true,
},
});
mainWindow.loadURL(`file://${__dirname}/index.html`);
});

It turns out, nodeIntegration was true by default in previous electron versions, but false by default in 5.0.0. Consequently, setting it to true resolved my issue. Not finding this change documented online in comments or on electrons page, I thought I'd make this self-answered SO post to make it easier to find for future people who encounter this issue.

Like junvar said, nodeIntegration is now false by default in 5.0.0.
The electronjs FAQ has some sample code on how to set this value.
let win = new BrowserWindow({
webPreferences: {
nodeIntegration: true
}
})
win.show()

set nodeIntegration to true when creating new browser window.
app.on('ready', () => {
mainWindow = new BrowserWindow({
webPreferences: {
nodeIntegration: true
}
});
});

Readers of this post should read the Do not enable Node.js Integration for Remote Content section from the Security, Native Capabilities, and Your Responsibility Guide before making a decision.
// Bad
const mainWindow = new BrowserWindow({
webPreferences: {
nodeIntegration: true,
nodeIntegrationInWorker: true
}
})
mainWindow.loadURL('https://example.com')
// Good
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(app.getAppPath(), 'preload.js')
}
})
mainWindow.loadURL('https://example.com')

Assuming electron 12.0.0
set contextIsolation: false
keep below code in main.js
new BrowserWindow({
width: 800, height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true,
}
})

For electron 13.0.0
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true
}

Add contextIsolation: false in webPreferences

You should not set contextIsolation: false.
If you do so, as several answers suggest, then certainly your code will no longer fail with "Uncaught ReferenceError: require is not defined."
But that's only because you have disabled the entire security feature!
Context Isolation has been on by default since Electron 12 because it's an important security feature for all Electron applications. If you set contextIsolation: false, that's like removing the lock on the front door of your house to make it possible for your family to get in and out, rather than providing a key to those who are allowed access.
Instead, you should set contextIsolation: true (the default value) and use a preload script to expose whitelisted wrappers for any module your app may need to require. You can read more about it at the Context Isolation link, and there's a detailed example in this stackoverflow answer.

junvar is right, nodeIntegration is false by default in v5.0.0.
It's the last statement in the Other Changes section of Release Notes for v5.0.0 and was also mentioned in this PR

Related

Cannot use module "dotenv" in my preload.js even if I have it in my dependencies

I have just started using Electron.
This is the start of my preload.js:
const { contextBridge } = require('electron');
require('dotenv').config();
// ...
When I used npm start, the app started normally, except that the preload.js didn't do anything. I opened the developer tools and saw this error:
Error: module not found: dotenv
at preloadRequire (...)
...
Then I checked my npm-shrinkwrap.json:
"devDependencies": {
// ...
"dotenv": "^16.0.3",
"electron": "^22.1.0"
}
Well, it sure had dotenv.
So, how can I make preload.js be able to use dotenv?
Thanks to Alexander Leithner, I worked out the problem.
In the documentation, it says the 'sandbox' limits what I can 'require' from preload.js; so to disable it, set sandbox: false or nodeIntegration: true in webPreferences in the BrowserWindow options.
Example
app.whenReady().then(() => {
const win = new BrowserWindow({
webPreferences: {
nodeIntegration: true
}
})
win.loadURL('https://google.com')
})

Electron set cookie with a url not working

I want to build an electron + React app with login feature using a external login module.
I've loaded the login module inside a React page (currently on dev server http://localhost:8080) with a webview and it is a html hosted as https://login.example.com/login.html
And the login module requires a cookie which I have to set it in electron programmely.
So in main.js I tried this:
mainWindow = new BrowserWindow({
width: windowWidth,
height: 480,
titleBarStyle: 'hidden',
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true,
webviewTag:true,
}
});
mainWindow.webContents.session.cookies.set({ url: "https://login.example.com", key: key, value: value })
// I've also tried this
const { session } = require("electron")
session.defaultSession.cookies.set({ url: "https://login.example.com", key: key, value: value })
and the cookie was not succeessfully set.
However, it does work when I change the url to http://localhost:8080, but this won't work for the login module.
Is it still possible to set the cookie with a url different from the website that I'm loading with?

Preload scripts not being executed in webview iframes

Webview tag that is present in the renderer process, somewhere in <body>:
<webview src="http://somewebpage.com" preload="somescript.js">
somescript.js is executed in somewebpage, but if somewebpage has <iframe>s in it, the script will not run in the iframe.
How can I make it run? And before any other script in the iframe?
I found this issue on github that seems related:
https://github.com/electron/electron/pull/19260
but it doesn't make any sense...
I tried adding nodeintegrationinsubframes and changing values from false to true
<webview src="somewebpage" preload="somescript.js" nodeintegrationinsubframes="false">
but it has no effect :(
main.js
mainWindow = new BrowserWindow({
width: 1024,
height: 728,
webPreferences: {
nodeIntegrationInSubFrames: true,
webviewTag: true,
nodeIntegration: true
}
});
renderer
<webview
src="https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_iframe"
preload="./preload.js"
style='width: 100%; height: 800px'
nodeIntegrationInSubFrames
/>
preload.js
process.once("loaded", () => {
alert(window.location);
});
You can specify where you are going to execute javascript based on the window.location This above code will show the locations of every sub iframes.
This works for me very well.
I was having the same problems with my project and updating the electron to the latest beta version solved for me.
I assume you know how to do this:
npm install electron#11.0.0-beta.6
You still have to consider the stability concerns of using a development version of the package.
By scratching on electron's documentation perhaps this could be helpful as an alternative.
app.js
let win
app.whenReady().then(() => {
win = new BrowserWindow({
webPreferences: {
nodeIntegrationInSubFrames: true,
webviewTag: true,
nodeIntegration: false,
preload: path.join(app.getAppPath(), 'preload.js') // Specifies a script that will be loaded before other scripts run in the page. This script will always have access to node APIs no matter whether node integration is turned on or off. The value should be the absolute file path to the script. When node integration is turned off, the preload script can reintroduce Node global symbols back to the global scope.
}
})
...
})
renderrer
<webview
src="https://somewebpage.com"
preload="./preload.js"
nodeintegrationinsubframes>
preload.js
/* It can be used by the preload script to add removed Node global symbols back to the global scope when node integration is turned off */
const _setImmediate = setImmediate
const _clearImmediate = clearImmediate
process.once('loaded', () => {
global.setImmediate = _setImmediate
global.clearImmediate = _clearImmediate
})
My answer is based on the following resources:
Electron Documentation: Tag
Electron Documentation:
BrowserWindow
Electron Documentation: process
Electron
Documentation: Web embeds in Electron - WebViews
Electron
Documentation: Preload Example

TypeError: window.require is not a function

Im trying to build an electron app and want to use window.require. Unfortunately the compiler says "TypeError: window.require is not a function". Ironically require works only in main.js.
Here the code Im trying to run:
const electron = window.require('electron')
const low = window.require('lowdb')
const FileSync = window.require('lowdb/adapters/FileSync')
I read in another post that somebody have had the same problem and it was fixed by adding this code into the .html file:
<script type="text/javascript" src="../../../Gehaltseinstellungen_Hinzufügen.js">
window.nodeRequire = require;
delete window.require;
delete window.exports;
delete window.module;
</script>
Also the author said using "nodeRequire" instead of require would solve the problem but it doesn't...
Another option I read about is that the NodeIntegration is set to false while the rendering process is activated, but I don't know how to activate Node while rendering.
you can set the webPreferences.contextIsolation to be false like this
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
it maybe works
It is unclear what version of Electron you are using. The syntax you are using is non-standard.
First – if you are using Electron 5.0, nodeIntegration is false by default in BrowserWindows so you need to specify it explicitly when you create your window:
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
Given the above, the syntax below works fine (i.e. no 'window' reference needed):
const { ipcRenderer, remote } = require('electron');
Needed all 3 setup like so to make this work:
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: false,
},
note: macbook m1, big sur 11.4, maybe it has to do something about OS, idk.
P.s. As mentioned in comments, before using nodeIntegration - check the Electron docs to understand when it may be a security issue:
Isolation For Untrusted Content A security issue exists whenever you
receive code from an untrusted source (e.g. a remote server) and
execute it locally. As an example, consider a remote website being
displayed inside a default BrowserWindow. If an attacker somehow
manages to change said content (either by attacking the source
directly, or by sitting between your app and the actual destination),
they will be able to execute native code on the user's machine.
⚠️ Under no circumstances should you load and execute remote code with
Node.js integration enabled. Instead, use only local files (packaged
together with your application) to execute Node.js code. To display
remote content, use the tag or BrowserView, make sure to
disable the nodeIntegration and enable contextIsolation.
Source: https://www.electronjs.org/docs/latest/tutorial/security#isolation-for-untrusted-content
I also met this issue in Electron + Angular.
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
Configuration above works for me.
Same issue in Electron + React + Typescript. This solved it for me
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: false
}
I was stuck with this problem for a couple of days.
Could not figure out for the life of me.
Went through a lot of docs and stackoverflow and finally!!!!
I fixed this error the following way :
create a file preload.js :
const { remote } = require('electron');
window.ipcRenderer = require('electron').ipcRenderer;
then in main.js/electron.js:
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
//this line is crucial
preload: path.join(app.getAppPath(), '/path-to-file/preload.js'),
contextIsolation: false
}
})
and finally in App.js:
const { ipcRenderer } = window
I got ipcRenderer in window from electron.
I'm pretty sure you can get anything else that you would want.
You don't need to modify web preferences as has been suggested, and I would recommend not doing it unless you have a better reason to because of the implied security issues (https://www.electronjs.org/docs/latest/tutorial/security#isolation-for-untrusted-content).
Instead, what you can do is use the preload script to add any functionality you need to window. Like this for example:
preload.js (located in the root folder):
contextBridge.exposeInMainWorld('ipcRenderer', {
invoke: (event) => ipcRenderer.invoke(event),
});
webPreferences in main.js:
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
}
Now in your code you can reference it:
const { ipcRenderer } = window as any;
const response = await ipcRenderer.invoke(...);
Reference documentation here: https://www.electronjs.org/docs/latest/tutorial/tutorial-preload#communicating-between-processes

'Require is not defined' when adding electron-renderer to webpack

I am developing an electron app. All good and nice until I wanted to use IPC from the renderer to call some native features. I understand that adding the following line to my Webpack config would allow me to import electron on the renderer side.
module.exports = {
// ...
target: 'electron-renderer',
}
I get the following error when adding this line
Uncaught ReferenceError: require is not defined
And the offending line is
module.exports = require("querystring");
Which sort of makes sense, since the browser does not understand "requires".
Note that without the electron-renderer target the application works well, except I cannot do things like
import {ipcRenderer} from 'electron';
Any thoughts what I could be doing wrong? Thank you!
Just recently ran into this. One thing to look out for is to ensure nodeIntegration is set to true when creating your renderer windows.
mainWindow = new electron.BrowserWindow({
width: width,
height: height,
webPreferences: {
nodeIntegration: true
}
});
Also faced this issue, new answer:
mainWindow = new electron.BrowserWindow({
width: width,
height: height,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
AFAIU the recommended way is to use contextBridge module (in the preload.js script). It allows you to keep the context isolation enabled but safely expose your APIs to the context the website is running in.
https://www.electronjs.org/docs/latest/tutorial/context-isolation
Following this way, I also found that it was no longer necessary to specify target property in the Webpack config.

Categories