问题
I have an application in Electron JS that is calling a python function to execute a python script. When the script executes it should send the data back to the Electron JS GUI and display it.
The issue I am having is that it is saying that join is undefined:
weather.js:9 Uncaught TypeError: Cannot read property 'join' of undefined at get_weather (weather.js:9) at HTMLButtonElement.onclick (weather.html:14)
here is my JavaScript file:
let {PythonShell} = require('python-shell')
var path = require("path")
function get_weather() {
var city = document.getElementById("city").value
var options = {
scriptPath : path.join(__dirname, '/../engine/'),
args : [city]
}
let pyshell = new PythonShell('weatherApp.py', options);
pyshell.on('message', function(message) {
swal(message);
})
document.getElementById("city").value = "";
}
The line "scriptPath : path.join(__dirname, '/../engine/')," seems to be the offending piece of code.
My gui.html file is as follows:
<html>
<head>
<title></title>
<meta charset="UTF-8">
</head>
<body>
<h1>Get your local weather ...</h1>
<br>
<br>
<label>Enter city name here: <label>
<input id="city" type = "text" placeholder="City">
<button type = "button" value="clickme" onclick="get_weather()">Get Weather</button>
<!--- <button class="btn btn-success" onclick="get_weather();">Go!</button> -->
<br>
<br>
<br>
<script src="/home/ironmantis7x/Documents/BSSLLC/projects/node_electron/electronDemoApps/guiApp/gui/linkers/weather.js"></script>
<p><button type="button"><a href="gui.html">Back to Main Page</a></button>
</body>
</html>
What error(s) do I need to fix to get this working correctly?
Thank you.
回答1:
The Problem
Since Electron 5 nodeIntegration
is disabled by default in the window. Since normal browser API does not know require
or join
, you get errors when you try.
Reenabling nodeIntegration
You could enable nodeIntegration
again, but it was disabled for a reason. Be sure you read and understand the electron security tutorial.
Using a preload script
Another way is to use a preload script. Let's have a look at the BrowserWindow
documentation.
When creating a new BrowserWindow you can add several options. For this case we need the webPreferences.preload
option:
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.
Be aware that the preload script is run in the renderer process.
Example
Following is an example app, that opens a window with a button that uses the electron dialog
to select files. This would not work with disabled nodeIntegration
but thanks to our preload script, we reintroduced dialog.showOpenDialog()
to our window.
main.js
const { app, BrowserWindow } = require("electron");
const { join } = require("path");
let win;
app.on("ready", () => {
win = new BrowserWindow({
webPreferences: {
//this is the default since electron 5
nodeIntegration: false,
//here you load your preload script
preload: join(__dirname, "preload.js")
}
});
win.loadURL(join(__dirname, "index.html"));
});
preload.js
const { dialog } = require("electron").remote;
window.mystuff = {
selectFile
};
async function selectFile() {
const files = await dialog.showOpenDialog({
properties: ["openFile", "multiSelections"]
});
return files;
}
index.html
<html>
<body>
<main>
<button onclick="myFunction()">select file</button>
<ul id="foo"></ul>
</main>
<script>
async function myFunction() {
//the function provided by the preload script
const files = await window.mystuff.selectFile();
const list = document.getElementById("foo");
for (const file of files) {
const node = document.createElement("LI");
const textNode = document.createTextNode(file);
node.appendChild(textNode);
list.appendChild(node);
}
}
</script>
</body>
</html>
Sending events via IPC
If you are unsure your functionality should be exposed in the window, you can also send events via ipcRenderer
.
preload.js
const { ipcRenderer } = require("electron");
window.mystuff = {
selectFile
};
function selectFile() {
return new Promise(resolve => {
ipcRenderer.on("selected-files", (e, files) => {
resolve(files);
});
ipcRenderer.send("select-files");
});
}
Additional part in main.js
ipcMain.on("select-files", async () => {
const files = await dialog.showOpenDialog({
properties: ["openFile", "multiSelections"]
});
win.webContents.send("selected-files", files);
});
来源:https://stackoverflow.com/questions/57546385/cannot-read-property-join-of-undefined-in-javascript-file-electron-js