Use Electron remote from other file - javascript

I have a file that contains a function that opens a file open dialog. I want to call that function from the app's menu. But when I use require to use the function from the file I get an error.
Code:
Main.js:
const { app, BrowserWindow, Menu } = require('electron');
const url = require('url');
const path = require('path');
const { openFile } = require('./index.js');
let win;
function createWindow() {
win = new BrowserWindow({
width: 800,
height: 600,
icon: __dirname + 'src/styles/media/icon.ico',
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
},
});
win.loadURL(
url.format({
pathname: path.join(__dirname, 'src/index.html'),
protocol: 'file:',
slashes: true,
})
);
var menu = Menu.buildFromTemplate([
{
label: 'File',
submenu: [
{
label: 'Open File',
click() {
openFile();
},
accelerator: 'CmdOrCtrl+O',
}
]
}]);
Menu.setApplicationMenu(menu);
}
app.on('ready', createWindow);
index.js:
const { dialog } = require('electron').remote;
function openFile() {
dialog.showOpenDialog({
title: 'Open File',
properties: ['openFile'],
});
}
module.exports = {
openFile,
};
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="styles/style.css" />
<title>Stonecutter</title>
</head>
<body>
<script src="./index.js"></script>
</body>
</html>
Error:
When I do the same thing but without the required the code works fine:
// index.js
// --------
// This code works
function openFile() {
console.log('Open file');
}
module.exports = {
openFile,
};
// Main.js is the same

You're using a remote inside the main process. This is what causes the problem. Remote is what you use from Renderer process (scripts required from a BrowserView). So you need to write two different openFile functions for main and renderer processes.
So when you require index.js from main.js this is what cause the error. You need determine where you are in the main process or in the renderer. Watch open-file.js below to see how to do it.
All together it should look like this:
main.js
const { app, BrowserWindow, Menu } = require('electron');
const url = require('url');
const path = require('path');
const {openFile} = require('./open-file')
let win;
function createWindow() {
win = new BrowserWindow({
width: 800,
height: 600,
icon: __dirname + 'src/styles/media/icon.ico',
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
},
});
win.loadURL(
url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true,
})
);
}
app.on('ready', () => {
createWindow()
var menu = Menu.buildFromTemplate([
{
label: 'File',
submenu: [
{
label: 'Open File',
click() {
openFile();
},
accelerator: 'CmdOrCtrl+O',
}
]
}]);
Menu.setApplicationMenu(menu);
})
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="styles/style.css" />
<title>Stonecutter</title>
</head>
<body>
<button id="open-file">Open file</button>
<script>
const {openFile} = require('./open-file.js')
document.querySelector('#open-file').addEventListener('click', () => openFile())
</script>
</body>
</html>
open-file.js
const electron = require('electron');
// electron.remote for Renderer Process and electron for Main Process
const {dialog} = (electron.remote || electron)
function openFile() {
dialog.showOpenDialog({
title: 'Open File',
properties: ['openFile'],
});
}
module.exports = {
openFile,
};
This examples works as you expect. File open-file.js is what you have in index.js.
This is so because Electron runs its parts in different processes: the first is the Main process. It is where you're getting when running electron main.js. The second is a Renderer process is running in a separate os process. This is where you get calling win.loadURL() and it has slightly different API and set of libraries.

Related

Preload Script not runnning/working properly with Electron

I've been trying to get a preload script to run on my Electron app but it appears to either not be running at all or just not working properly.
I currently have a main file, a preload file, a render file, and a html. I'm just trying to do the stuff from the Electron tutorial on using preload files, so right now my code is something like this:
// main.js
const {app, BrowserWindow, ipcMain, Menu} = require('electron');
const url = require('url');
const path = require('path');
let mainWindow;
const createWindow = () => {
// Create a window
mainWindow = new BrowserWindow({
show: false,
autoHideMenuBar: true,
webPreferences: ({
preload: path.join(__dirname, 'scripts', 'preload.js'),
nodeIntegration: true,
}),
});
mainWindow.maximize();
mainWindow.show();
// Load HTML into window
mainWindow.loadFile('index.html');
// Open Dev Tools
// mainWindow.webContents.openDevTools();
console.log(versions);
}
// preload.js
const {contextBridge} = require('electron');
contextBridge.exposeInMainWorld('versions', {
node: () => process.version.node,
chrome: () => process.version.chrome,
electron: () => process.version.electron,
});
Index.html:
<html lang="en">
<head>
<meta charset="UTF-8">
<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'"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./css/style.css">
<title>Test</title>
</head>
<body>
<h1>Test</h1>
<p id="info"></p>
<script>window.$ = window.jQuery = require('jquery');</script>
<script src="render.js"></script>
</body>
// render.js
const information = document.getElementById('info');
information.innerText = `This app is using Chrome (v${versions.chrome()}),
Node.js (v${versions.node()}), and Electron (v
${versions.electron()})`
Currently my output on the HTML from render.js is "This app is using Chrome (vundefined),Node.js (vundefined), and Electron (vundefined)" and my console.log line in main.js throws up a ReferenceError stating "versions is not defined". Anybody able to shine some light on how I could fix this? Thanks in advance.
I think you made a typo:
In your preload script
contextBridge.exposeInMainWorld('versions', {
node: () => process.version.node,
chrome: () => process.version.chrome,
electron: () => process.version.electron,
});
Should be (add a "s" to process.version
contextBridge.exposeInMainWorld('versions', {
node: () => **process.versions.node,
chrome: () => **process.versions.chrome,
electron: () => **process.versions.electron,
});
Can have a look to the docs:
https://www.electronjs.org/docs/latest/api/process

VSCode does not load .js file in <script> tag

I'm working on setting up my dev machine to do Electron development in VS Code.
I've been following a Hello World sample.
The problem is that the .js file inside a tag isn't being loaded. I put an alert() in an inline tag in the same html file and the alert fired correctly.
When I debug, the index.js file isn't being loaded at all.
This is my main.js
const { app, BrowserWindow, Menu } = require('electron')
const path = require('path')
const url = require('url')
const shell = require('electron').shell
let win
function createWindow () {
win = new BrowserWindow({ width: 800, height: 600})
win.loadURL(url.format({
pathname: path.join(__dirname,'src/index.html'),
protocol: 'file',
slashes: true
}))
// win.webContents.openDevTools()
win.on('closed', () => {
win = null
})
var menu = Menu.buildFromTemplate([
{
label: 'File',
submenu: [
{
label: 'Sign In To SL',
click() {
shell.openExternal('https://stackoverflow.com')
}
},
{type: 'separator'},
{
label: 'Exit',
click() { app.quit() }
}
]
}
]
)
Menu.setApplicationMenu(menu)
}
app.on('ready', createWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
app.on('activate', () => {ok
if (win == null) {
createWindow()
}
})
This is the HTML for 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>Souper Grouper</title>
<link rel="stylesheet" href="../assets/css/main.css">
</head>
<body>
<div class="row">
<div id="userinfo-container">
<p class="subtext">User Name:</p>
<h1 id="username">Not Signed In</h1>
</div>
<div id="signin-container">
<button id="signinBtn">Sign In</button>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
This is index.js
const electron = require('electron')
const path = require('path')
const BrowserWindow = electron.remote.BrowserWindow
const signinBtn = document.getElementById('signinBtn')
signinBtn.addEventListener('click', function(event){
alert("fired")
const modalPath = path.join('file://', __dirname, 'signin.html')
let win = new BrowserWindow({ frame: false, width: 400, height: 200})
win.on('close', function() { win = null})
win.loadURL(modalPath)
win.show()
})
I've double checked the VSCode Trust Center and the folder above my App is Trusted.
Thanks!

Why Electron Vibrancy Effect Not Working At All

This problem is so confusing because i don't know where the issue is.
I used vibrancy in my last project with previous electron versions in same machine and those were work properly but know it does not work, and i don't have any idea what is the problem.
I google it and i did not find any question or github issue.
May be the problem is in electron?!!
Here some information that may needed:
System:
MacOS 11.6 x86_64
Electron Version: 15.0.0
Other Dependencies or DevDependencies: Nothing
This is very simple example, and nothing crazy is going on. very very simple:
// File: index.js
// Process: Main
// Location: Root Directory Of Project
// -----------------------------------
const { app, BrowserWindow } = require('electron');
const { join } = require('path');
const isDarwin = process.platform === 'darwin';
let mainWindow;
app.setName('Electron Sample');
const Ready = () => {
mainWindow = new BrowserWindow({
show: false,
vibrancy: 'content',
visualEffectState: 'followWindow',
title: app.getName(),
backgroundColor: false,
webPreferences: {
contextIsolation: false,
nodeIntegration: true,
nativeWindowOpen: false
}
});
mainWindow.loadFile(join(__dirname, './index.html'));
mainWindow
.once('ready-to-show', () => mainWindow.show())
.once('close', () => (mainWindow = null));
};
app.whenReady().then(Ready);
app.on('window-all-closed', () => {
if (!isDarwin) app.quit();
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) Ready();
});
<!--
File: index.html
Process: Renderer
Location: Root Directory Of Project
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
html,
body {
background-color: transparent;
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<h1>I Confused! 😭</h1>
</body>
</html>
Project Structure:
node_modules
index.js
index.html
yarn.lock
package.json
This is all information.
The problem is in BrowserWindow Options
This is the correct form of options to enable under-window vibrancy on macOS:
new BrowserWindow({
// Other Options...
transparency: true,
backgroundColor: "#00000000" // transparent hexadecimal or anything with transparency,
vibrancy: "under-window", // in my case...
visualEffectState: "followWindow"
})
more info: Electron BrowserWindow Options

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.

App working in dev mode however after packaged the JavaScript wont work

I'm new to Electron and working on creating a basic app, the app itself works great while in dev mode, however once I package the app for windows none of the buttons work correctly. I have tried using the browserify but with no luck. I have also messed around with the nodeIntergration set to true and false but that didn't seem to fix my issue either. I understand that require() module is node a server side thing and that the browser cannot natively support it. Any suggestions would be greatly appreciated! Also if you require any additional information or code please let me know.
The error I'm getting is: "Uncaught ReferenceError: require is not defined at index.html:17"
Main JS
const electron = require('electron');
var app = require('electron').app;
var BrowserWindow = require('electron').BrowserWindow;
var mainWindow = null;
app.on('window-all-closed', function() {
if (process.platform != 'darwin')
app.quit();
});
app.on('ready', function() {
mainWindow = new BrowserWindow({webPrefrences: {nodeIntergration: true, enableRemoteModule: true},
width: 600, height: 410, frame: true, transparent: true, resizable: false, icon:
'C:/Users/cody/Projects/QuickLaunch/app/assets/icons/win' + '/icon.ico'});
mainWindow.loadURL('file://' + __dirname + '/index.html');
mainWindow.on('closed', function() {
mainWindow = null;
});
});
index.html
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="default.css"/>
<title>Quick Launch</title>
<link href="https://fonts.googleapis.com/css2?family=Oswald:wght#700&display=swap" rel="stylesheet">
<body style="-webkit-user-select: none;">
<div id="title-bar">
<div id="title-bar-btns">
<script>
(function () {
const remote = require('electron').remote;
function init() {
document.getElementById("min-btn").addEventListener("click", function (e) {
const window = remote.getCurrentWindow();
window.minimize();
});
document.getElementById("close-btn").addEventListener("click", function (e) {
const window = remote.getCurrentWindow();
window.close();
});
};
document.onreadystatechange = function () {
if (document.readyState == "complete") {
init();
}
};
})();
</script>
<button id="min-btn">-</button>
<button id="close-btn">x</button>
</div>
</div>

Categories