How to access DOM of BrowserWindow from remote in Electron - javascript

I'm trying to create an electron app that contains a button on the main process which loads a new BrowserWindow with the remote module on click.
I want a second button in this new BrowserWindow to use the exec command from child_process.
I try to addEventListener to the second button but it isn't able to access the DOM (only able to getElementByID of index.html)
main.js snippet
const {app, BrowserWindow} = require('electron')
require('electron-reload')(__dirname)
.
.
.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration:true
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
index.html
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
<button id="1" onclick="render()">Primary Click</button>
<script src="./renderer.js"></script>
<script src="./main.js"></script>
</body>
renderer script (within main.js)
function render(){
const { BrowserWindow } = require('electron').remote
const { exec } = require("child_process")
let win = new BrowserWindow({ width: 800, height: 600 })
win.loadFile('index2.html')
win.webContents.openDevTools()
win.webContents.once("dom-ready", ()=>{
document.getElementById("2").addEventListener("click", function(){
exec("echo hello >> hello.txt")
})
})
}
index2.html
<head>
<meta charset="UTF-8">
<title>Hello World2!</title>
</head>
<body>
<button id="2">Secondary Click</button>
<script src="./renderer.js"></script>
</body>
I get the error:
Cannot read property 'addEventListener' of null

Related

Electron shows blank window

My HTML file isn't loading at the tutorial says it would've. This is what I have. Yes, I've tried doing all sorts of funky stuff involving paths and it doesn't fix the issue.
main.js
const { app, BrowserWindow } = require('electron');
const path = require("path");
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile("index.html")
}
app.whenReady().then(() => {
createWindow()
})
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
</body>
</html>
You might have to change your JavaScript code to have a full path to the HTML file.
Try with the code below, it will configure Electron. In the event listening, it is creating a new BrowserWindow with no configuration (although you can add it if you like). Then, it is loading the full path to the HTML file.
const electron = require("electron");
const {
app,
BrowserWindow
} = electron;
app.on("ready", () => {
const mainWindow = new BrowserWindow({});
mainWindow.loadURL(`file://${__dirname}\\index.html`);
});

How do I make button close Electron-JS app?

Code:
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<link rel="stylesheet" type="text/css" href="index.css">
<title>Youtify</title>
</head>
<body>
<div id = "leftBar"></div>
<div id = "rightBar"></div>
<div id = "bottomBar"><hr></div>
<div id = "toolButtons">
<div id ="closeBtn"><a data-text="✖"></a></div>
<div id="maxBtn"><a data-text="❐" ></a></div>
<div id="minBtn"><a data-text="─" ></a></div>
</div>
<script src="./renderer.js"></script>
</body>
</html>
main.js
const {app, BrowserWindow, ipcMain} = require('electron') const path = require('path')
function createWindow () { const mainWindow = new BrowserWindow({
width: 800,
height: 600,
frame: false, })
mainWindow.loadFile('index.html') }
app.whenReady().then(() => { createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow() }) })
renderer.js
// close app
function closeApp(e) {
e.preventDefault();
app.quit();
}
document.getElementById("closeBtn").addEventListener("click", closeApp);
What I want is to click on the button with the id "closeBtn" to close the app, I was looking for it, but I just can't make it working.
Can anyone please help?
Try using ipcRenderer to send the close command to main.js
In your main.js:
ipcMain.on('close', () => {
app.quit()
})
Then, in your renderer.js:
const ipc = require('electron').ipcRenderer
// close app
function closeApp(e) {
e.preventDefault()
ipc.send('close')
}
document.getElementById("closeBtn").addEventListener("click", closeApp);

How can I send data from my main.js to my index.html (Electron)

I am a complete beginner to JavaScript and Electron just so you know.
I think I've looked most places, and I haven't found a thing.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>??</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="main">
<button id="get-data" type="submit">Get Data</button>
</div>
<script src="script.js"></script>
</body>
</html>
main.js
const { app, BrowserWindow } = require("electron");
const ipc = require("electron").ipcMain;
app.whenReady().then(() => {
const window = new BrowserWindow({
"center": true,
"width": 500,
"height": 800,
"webPreferences": {
"nodeIntegration": true
}
});
window.loadFile("index.html");
});
ipc.on("uhhm", event => {
event.sender.send("ok", "Hello World!");
});
script.js
const ipc = require("electron").ipcRenderer;
const getDataBtn = document.getElementById("get-data");
getDataBtn.addEventListener("click", () => {
ipc.send("uhhm");
ipc.once("ok", data => {
getDataBtn.innerHTML = "Moving On... " + data;
});
});
I get this error:
Uncaught ReferenceError: require is not defined
at script.js:1
IDK what to do
Have any suggestions?
if you are using a >= 5 version of Electron, you need to enable the nodeIntegration and contextIsolation parameters as follows:
app.on('ready', () => {
mainWindow = new BrowserWindow({
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
}
});
});
I had that issue when I worked for a while with Electron Framework, where I need IPC communication between a renderer process and the main process. The renderer process sits in an HTML file between script tags and generates the same error.
const {ipcRenderer} = require('electron')
//throws the Uncaught ReferenceError: require is not defined
In your case :
const ipc = require("electron").ipcRenderer;
You must to work around that by specifying Node.js integration as true when the browser window (where this HTML file is embedded) was originally created in the main process.
function createWindow() {
// Create a new window
const window = new BrowserWindow({
width: 300,
height: 200,
// The lines below solved the issue
webPreferences: {
nodeIntegration: true
}
})}
That solved the issue for me. The solution was proposed here.

How to enable nodeintegration in electron webview?

I build an app with Electron an i try to use a webview to display a file loaded from my disk and i need nodeintegration in the webview. Although it is documented in the Electron Documentation here i can`t get it working.
I created a test project with the main.js file, which creates a BrowserWindow, where i load my index.html and index.js files. The index.js file creates a webview with my file loaded and the file is webview.html with webview.js. I call require in webview.js and i can see in the DevTools, that it is giving the error
Uncaught ReferenceError: require is not defined
at webview.js:2
Here are my testfiles, what am i missing or got this feature removed?
I am using Electron ^12.0.2
main.js
const { app, BrowserWindow, BrowserView } = require('electron')
function createWindow () {
let win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
webviewTag: true,
nodeIntegrationInWorker: true,
nodeIntegrationInSubFrames: true
}
})
win.loadFile('index.html')
return win;
}
app.whenReady().then(() => {
let win = createWindow();
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
}
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
<div class="root">
</div>
<script src="index.js" charset="utf-8"></script>
</body>
</html>
index.js
function createWebview(id, url) {
//creates a webview with the id of the tab and the url loaded
let webview = document.createElement("webview");
webview.setAttribute("id", id);
webview.setAttribute("src", url);
webview.setAttribute("nodeintegration", "");
webview.setAttribute("preload", "./pre.js")
webview.addEventListener('dom-ready', () => {
webview.openDevTools();
});
console.log(webview);
return webview;
}
document.querySelector(".root").appendChild(createWebview("web", `file://${__dirname}/webview.html`));
webview.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
test
<script src="webview.js" charset="utf-8"></script>
</body>
</html>
webview.js
console.log("test");
//a require to test the functionality
const { app, BrowserWindow, ipcMain, Menu, MenuItem } = require('electron');
Edit 1: The preload script is empty.
After thinking much more i came to the solution, that if the webview is similar to the BrowserWindow, then i need to disable contextIsolation in the webPreferences object of the webview. This is definitely something that needs to be added to electron documenten.
I change my index.js file like this
function createWebview(id, url) {
//creates a webview with the id of the tab and the url loaded
let webview = document.createElement("webview");
webview.setAttribute("id", id);
webview.setAttribute("src", url);
webview.setAttribute("nodeintegration", "");
webview.setAttribute("webpreferences", "contextIsolation=false");
webview.addEventListener('dom-ready', () => {
webview.openDevTools();
});
console.log(webview);
return webview;
}
document.querySelector(".root").appendChild(createWebview("web", `file://${__dirname}/webview.html`));
Just add below two attributes in webPreference object to enable nodeIntegration in all js file which contains webView
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
nativeWindowOpen: true,
enableRemoteModule: true,
sandbox:false,
nodeIntegrationInSubFrames:true, //for subContent nodeIntegration Enable
webviewTag:true //for webView
}
don't use webview is not good idea to show external content using webView
it affects performance.!
See docs about webView below

Unable to use Node.js APIs in renderer process

Unable to use any electron or node related operations in electron .
Getting error process not defined.
I Checked at various places they guide to add node Support but that is already Done so stucked here
My Main Application code is
const electron = require("electron");
const { app, BrowserWindow } = electron;
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: { nodeIntegration: true },
});
win.loadFile("index.html");
}
app.whenReady().then(createWindow);
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
And Index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World!</title>
</head>
<body style="background: white">
<h1>Hello World!</h1>
<p>
We are using node
<script>
document.write(process.versions.node);
</script>
, Chrome
<script>
document.write(process.versions.chrome);
</script>
, and Electron
<script>
document.write(process.versions.electron);
</script>
.
</p>
</body>
</html>
Update: the answer below is a workaround. You should not disable contextIsolation and you should not enable nodeIntegration. Instead you should use a preload script and the contextBridge API.
In Electron 12, contextIsolation is now by default true
If you set it to false, you will have access to Node.js APIs in the renderer process
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
contextIsolation: false,
nodeIntegration: true
},
});
win.loadFile("index.html");
}
⚠️ It's important to note that this is not recommended!
There's a good reason why Electron maintainers changed the default value. See this discussion
Without contextIsolation any code running in a renderer process can quite easily reach into Electron internals or your preload script and perform privileged actions that you don't want arbitrary websites to be doing.
There is no reason to elevate the privileges of your renderer. Any third-party scripts on that page would run with the same privileges and that's definitely not what you want.
Instead you should use a preload script which has that privilege (i.e. can use Node.js APIs by default) but keep contextIsolation=true (which is the default value anyway). If you need to share data between your preload script and your renderer script use contextBridge.
In my example I have exposed data from the preload script to the renderer script under a rather silly namespace (window.BURRITO) to make it obvious that you're in charge:
main.js
const {app, BrowserWindow} = require('electron'); //<- v13.1.7
const path = require('path');
app.whenReady().then(() => {
const preload = path.join(__dirname, 'preload.js');
const mainWindow = new BrowserWindow({ webPreferences: { preload }});
mainWindow.loadFile('index.html');
});
preload.js
const {contextBridge} = require('electron');
contextBridge.exposeInMainWorld('BURRITO', {
getNodeVer: () => process.versions.node,
getChromeVer: () => process.versions.chrome,
getElectronVer: () => process.versions.electron
});
renderer.js
const onClick = (sel, fn) => document.querySelector(sel).addEventListener('click', fn);
onClick('#btn1', () => alert(BURRITO.getNodeVer()));
onClick('#btn2', () => alert(BURRITO.getChromeVer()));
onClick('#btn3', () => alert(BURRITO.getElectronVer()));
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<button id="btn1">Node?</button>
<button id="btn2">Chrome?</button>
<button id="btn3">Electron?</button>
<script src="./renderer.js"></script>
</body>
</html>

Categories