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 :)
Related
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?
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
So I have 2 applications:
an Adonis API server accessible via http://10.10.120.4:3333
A SSR app using Nuxt.js accessible via http://10.10.120.4:80
The Nuxt.js app is accessible outside using url http://my-website.com. I have axios module with this config
axios: {
baseURL: '0.0.0.0:3333/api',
timeout: 5000
}
Now the problem is, when I am requesting data with asyncData it works, but when the request was made from outside asyncData, say created() for example, it throws an error saying the url http:0.0.0.0:3333 is missing which is true since it's already running in the browser and not in the server.
The first solution that I've tried is to change the baseURL of the axios module to this
axios: {
baseURL: 'http://my-website.com/api',
timeout: 5000
}
But it seems nuxt server can't find it, so I think the solution is to make proxy and installed #nuxtjs/proxy.
And this is my proxy config in nuxt.config.js
{
proxy: {
'/api': 'http://my-website.com:3333',
}
}
and then I just changed my axios baseURL to
http://my-website.com/api
But again it didn't work.
My question is, how do you deal with this kind of scenario? Accessing different server from browser?
When using Proxy in a nuxt project you need to remove baseUrl and set proxy to true as seen below.
axios: {
// Do away with the baseUrl when using proxy
proxy: true
},
proxy: {
// Simple proxy
"/api/": {
target: "https://test.com/",
pathRewrite: { "^/api/": "" }
}
},
when making a call to your endpoint do:
// append /api/ to your endpoints
const data = await $axios.$get('/api/users');
checkout Shealan article
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'm using Webpack Dev Server to proxy my files from an external url, that's because I'm using it to develop locally and proxying the PHP/Twig files from the server, so that way I don't need to set up all the back-end locally.
But the problem is that I need to rewrite the assets urls to pull these files from my local machine, not from the proxy. Right now, when I open my localhost, all the assets are being loaded from the server. i.e: http://mycoolwebsite.com/core/somefolder/assets/styles.css
And I need to replace that to pull from my localhost, like this:
/assets/styles.css
This is what I have now:
devServer: {
compress: true,
port: 9000,
proxy: {
'*': {
target: 'http://mycoolwebsite.com',
changeOrigin: true,
secure: false
}
}
Any clue?
Thanks!
you want all request that go to your server "http://mycoolwebsite.com/**"
to go to your local machine: "http://localhost:9000/" (assuming its running on port 9000)
so try this:
proxy: {
'/assets/**': {
target: 'http://localhost:9000',
secure: false,
pathRewrite: function(req, path) {
//use the pathRewrite to modify your path if needed
return path;
}
}
now it shouldn't make any difference what server you are actually calling. every request that includes '/assets/' should go to your localhost. (I can not test it atm)