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?
Related
I've built a Vue app and added Electron to it. I used Vue CLI Plugin Electron Builder
It's ok in development mode, all API requests fall on address which is written in my vue.config.js:
proxy: {
'^/api': {
target: 'http://my-api:3000',
changeOrigin: true
},
},
For example, Axios POST request /api/open_session/ falls to http://my-api/api/open_session as needed.
When I build the project it creates an app:// protocol to open the index.html file.
But it also makes all url paths beginning with app:// including API requests.
My background.js:
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) win.webContents.openDevTools()
}
else {
createProtocol('app');
// Load the index.html when not in development
win.loadURL('app://./index.html');
}
I want these paths to be directed to my API, while open all my files as usual (via app protocol)
Well, it's been a longer time and I coped with that on my own. However, here's an answer I came across some forums for those who are struggling with the same issue:
Firstly, I modified my vue.config.js:
proxy: {
'^/api': {
target: 'http://127.0.0.1:3000',
changeOrigin: true
},
},
Then, I made some changes in main.js - added a session variable:
const sesh = session.defaultSession.webRequest.onBeforeSendHeaders({
urls: ['*://*/*']
}, (details, callback) => {
// eslint-disable-next-line prefer-destructuring
details.requestHeaders.Host = details.url.split('://')[1].split('/')[0]
callback({
requestHeaders: details.requestHeaders
})
})
that defines app's behavior when requests get called. Also, I've added a session value to webPreferences:
const win = new BrowserWindow({
width: 1500,
height: 700,
title: "Title",
webPreferences: {
session: sesh,
nodeIntegration: true,
webSecurity: false
}
})
And, finally, load my index.html via app protocol
createProtocol('app');
win.loadURL('app://./index.html');
In result, all my requests got redirected to my server.
Forgive me for not knowing the source, if the author of the code is reading this, you can surely mark yourself in comments :)
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
I trying to build an Electron app. For that I'm using the following respos:
https://github.com/electron/electron-quick-start
https://github.com/electron-userland/electron-builder
In devoplement mode (electron .) everything works fine. But when I build the app and starting it, it just shows me a blank page without any errors in the dev console or build log.
Why doesn't it work in production? All my files are in one direction:
index.html
main.js
renderer.js
package.json
I didn't changed much in the base main.js file:
// Modules to control application life and create native browser window
const {app, BrowserWindow} = require('electron')
const path = require('path')
const url = require('url')
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
frame: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
webSecurity: false
}
})
// and load the index.html of the app.
//mainWindow.loadFile('index.html')
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}));
// Open the DevTools.
mainWindow.webContents.openDevTools();
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') app.quit()
})
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
That's because your output html in production should be located elsewhere, btw I'm using angular with electron and the output is in the dist folder, but I don't use url.format: try with mainWindow.loadURL(`file://$_dirname/index.html`)
or if you have a dist folder mainWindow.loadURL(`file://$_dirname/dist/index.html')
Try changing also
app.whenReady() by app.on("ready",createWindow)
Hope it works afterwards
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
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