Reputation: 12296
I am attempting to call require('electron')
from a .svelte file. It is not defined. I am using webpack with target: 'electron-renderer
.
How do I include or require node modules from my electron renderer thread?
Upvotes: 1
Views: 650
Reputation: 9479
I've written about this in other questions, so you may want to look there. The answer is not using svelte, but can be ported.
Electron apps used to include and recommend using require
in the renderer process. This, however leads to security problems so the team has been slowly transitioning away from this. The new and better way is to require
everything in your main process and whenever the renderer process needs a require
'd module, it communicates to the main process via IPC. The response from the main process is then sent to the renderer process back via IPC.
This is a rough example of how this works
main.js
const {
app,
BrowserWindow,
ipcMain
} = require("electron");
const path = require("path");
const fs = require("fs");
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;
async function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false, // is default value after Electron v5
contextIsolation: true, // protect against prototype pollution
enableRemoteModule: false, // turn off remote
preload: path.join(__dirname, "preload.js") // use a preload script
}
});
// Load app
win.loadFile(path.join(__dirname, "dist/index.html"));
// rest of code..
}
app.on("ready", createWindow);
ipcMain.on("toMain", (event, args) => {
fs.readFile("path/to/file", (error, data) => {
// Do something with file contents
// Send result back to renderer process
win.webContents.send("fromMain", responseObj);
});
});
preload.js
const {
contextBridge,
ipcRenderer
} = require("electron");
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld(
"api", {
send: (channel, data) => {
// whitelist channels
let validChannels = ["toMain"];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel, func) => {
let validChannels = ["fromMain"];
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => func(...args));
}
}
}
);
index.html
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8"/>
<title>Title</title>
</head>
<body>
<script>
window.api.receive("fromMain", (data) => {
console.log(`Received ${data} from main process`);
});
window.api.send("toMain", "some data");
</script>
</body>
</html>
I'm the author of secure-electron-template
which has this pattern built out into a nice starter template, with security practices built in. (This sample was derived from this template).
Upvotes: 2
Reputation: 515
To require electron this way from a renderer file, you need to double-check the webPreferences
options of BrowserWindow
from within the main process js file, it should have those props set to true :
const mainWindow = new BrowserWindow({
//...
webPreferences: {
enableRemoteModule: true, // <-- You probably want this but note this is going through a severe deprecation process
nodeIntegration: true,
contextIsolation: false,
// ...
}
});
Upvotes: 0