I've been experiencing some issues with an Electron + Create React App app I'm making. It's an offline app for cost calculation, I need to persist a couple user settings, for this I used https://github.com/sindresorhus/electron-store. Like with most electron's modules, I have to import it as:
const Store = window.require("electron-store");
To avoid webpack's conflicts. By searching I found that for most people setting nodeIntegration: true when creating electron's BrowserWindow would avoid the problem, but it's not my case, I keep getting the same error.
What I've already tried:
Using plain require: It results in TypeError: fs.existsSync is not a function, and in console: Can't resolve 'worker_threads' in '...\node_modules\write-file-atomic'
Use a module to override webpack config: I used craco to set target to electron-renderer. It results in a blank page when I launch the app, with an error in devtools telling ReferenceError: require is not defined
Additional info is that I'm not using typescript but plain js so using "declare global" and such won't work
My public/electron.js file:
const electron = require("electron");
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const path = require("path");
const isDev = require("electron-is-dev");
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 900,
height: 680,
webPreferences: {
nodeIntegration: true
}
});
mainWindow.loadURL(
isDev
? "http://localhost:3000"
: `file://${path.join(__dirname, "../build/index.html")}`
);
mainWindow.on("closed", () => (mainWindow = null));
if (!isDev) mainWindow.setMenu(null);
}
app.on("ready", createWindow);
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
electron.app.allowRendererProcessReuse = true;
app.on("activate", () => {
if (mainWindow === null) {
createWindow();
}
});
2 Answers 2
You have tu create a preoload script on electron.
Create a file named preload.js on the directory where you have de electron main script, Put this code on it:
window.require = require;
Go to your electron main script and type this in the code where you create the window:
win = new BrowserWindow({ width: 1280, height: 720, webPreferences: { nodeIntegration: false, preload: __dirname + '/preload.js' },
}) With this you will preload the script before all, this fixed the problem for me, I hope also for you.
3 Comments
webPreferences.contextIsolation = false. An alternative that seems like it should work (in newer electron versions) is require("electron").contextBridge.exposeInMainWorld("require", require), but that didn't actually work when I tried it. (it said Cannot find module 'XXX' in renderer; not a good idea anyway to expose the require function in renderer, but wanted to try it)Electron 12 changed the default setting of contextIsolation for webPreferences, as documented in their breaking changes for Electron 12. Setting it to false will allow you access to require() again, as per their notes:
In Electron 12, contextIsolation will be enabled by default. To restore the previous behavior, contextIsolation: false must be specified in WebPreferences.
We recommend having contextIsolation enabled for the security of your application.
Another implication is that require() cannot be used in the renderer process unless nodeIntegration is true and contextIsolation is false.
mainWindow = new BrowserWindow({
width: 900,
height: 680,
webPreferences: {
contextIsolation: false,
nodeIntegration: true
}
}
BrowserWindowincluding all it's configuration.