I created an App using electron that interacts with local files using IPC. When i run it using npm start
, éverything works as excpected, but when i try to package the app into an .exe
file using the steps provided in the docs (), the App wont start and i get this error:
Error
× A JavaScript error occurred in the main process
Uncaught Exception:
X
Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: Only URLs with a scheme in: file and data are supported by the default ESM loader. Received protocol 'electron:'
at getSourceSync (node:internal/modules/esm/load:74:11)
at defaultLoadSync (node:internal/modules/esm/load:172:32)
at ModuleLoader.getModuleJobForRequire (node:internal/modules/esm/loader:410:24)
at new ModuleJobSync (node:internal/modules/esm/module_job:341:34)
at
ModuleLoader.importSyncForRequire (node:internal/modules/esm/loader:357:11)
at loadESMFromCJS (node:internal/modules/cjs/loader:1392:24)
at Module._compile (node:internal/modules/cjs/loader: 1543:5)
at Module._extensions..js (node:internal/modules/cjs/loader:1722:10)
at Module.load (node:internal/modules/cjs/loader: 1296:32)
at Module._load (node:internal/modules/cjs/loader:1115:12)
OK
Electron version: 35.0.1
Node version: v22.14.0
I suspect it has to do something with the way i handle paths, so here are some example codes
// main.js
const { app, BrowserWindow, dialog, ipcMain, shell} = require('electron');
const path = require('path');
const fs = require('fs');
const pdf = require('pdf-parse');
const ElectronStore = require('electron-store');
const store = new ElectronStore.default();
function createWindow() {
let win = new BrowserWindow({
width: 1200,
height: 700,
icon: path.join(__dirname,'assets/icon.png'),
webPreferences: {
nodeIntegration: false, // Security best practice
contextIsolation: true, // Isolate main and renderer processes
enableRemoteModule: false,
devTools: true,
preload: path.join(__dirname, 'preload.js') // Use a preload script
}
});
// win.removeMenu()
win.loadFile(path.join(__dirname, 'index.html'));
}
ipcMain.handle("fs:readdir",(event, path) =>{
return fs.promises.readdir(path)
});
ipcMain.handle("fs:isDir", (event, filePath, document) =>{
return fs.lstatSync(path.join(filePath,document)).isDirectory()
});
//preload.js
contextBridge.exposeInMainWorld('fs',{
readdir: (path) => ipcRenderer.invoke("fs:readdir",path),
isDir: (path, document) => ipcRenderer.invoke("fs:isDir",path,document)
})
I already updated my Node.js version
I created an App using electron that interacts with local files using IPC. When i run it using npm start
, éverything works as excpected, but when i try to package the app into an .exe
file using the steps provided in the docs (https://www.electronjs./docs/latest/tutorial/tutorial-packaging), the App wont start and i get this error:
Error
× A JavaScript error occurred in the main process
Uncaught Exception:
X
Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: Only URLs with a scheme in: file and data are supported by the default ESM loader. Received protocol 'electron:'
at getSourceSync (node:internal/modules/esm/load:74:11)
at defaultLoadSync (node:internal/modules/esm/load:172:32)
at ModuleLoader.getModuleJobForRequire (node:internal/modules/esm/loader:410:24)
at new ModuleJobSync (node:internal/modules/esm/module_job:341:34)
at
ModuleLoader.importSyncForRequire (node:internal/modules/esm/loader:357:11)
at loadESMFromCJS (node:internal/modules/cjs/loader:1392:24)
at Module._compile (node:internal/modules/cjs/loader: 1543:5)
at Module._extensions..js (node:internal/modules/cjs/loader:1722:10)
at Module.load (node:internal/modules/cjs/loader: 1296:32)
at Module._load (node:internal/modules/cjs/loader:1115:12)
OK
Electron version: 35.0.1
Node version: v22.14.0
I suspect it has to do something with the way i handle paths, so here are some example codes
// main.js
const { app, BrowserWindow, dialog, ipcMain, shell} = require('electron');
const path = require('path');
const fs = require('fs');
const pdf = require('pdf-parse');
const ElectronStore = require('electron-store');
const store = new ElectronStore.default();
function createWindow() {
let win = new BrowserWindow({
width: 1200,
height: 700,
icon: path.join(__dirname,'assets/icon.png'),
webPreferences: {
nodeIntegration: false, // Security best practice
contextIsolation: true, // Isolate main and renderer processes
enableRemoteModule: false,
devTools: true,
preload: path.join(__dirname, 'preload.js') // Use a preload script
}
});
// win.removeMenu()
win.loadFile(path.join(__dirname, 'index.html'));
}
ipcMain.handle("fs:readdir",(event, path) =>{
return fs.promises.readdir(path)
});
ipcMain.handle("fs:isDir", (event, filePath, document) =>{
return fs.lstatSync(path.join(filePath,document)).isDirectory()
});
//preload.js
contextBridge.exposeInMainWorld('fs',{
readdir: (path) => ipcRenderer.invoke("fs:readdir",path),
isDir: (path, document) => ipcRenderer.invoke("fs:isDir",path,document)
})
I already updated my Node.js version
Share Improve this question asked Mar 24 at 5:15 MabMabMabMab 431 silver badge5 bronze badges 9 | Show 4 more comments1 Answer
Reset to default 2As I noted in the comments I was having the same issue as you. I removed my includes one-by-one until I narrowed it down to electron-store
. I don't think it's compatible with require()
syntax when bundled for some reason (yet, it works in dev mode).
I found this gist which describes the problem: https://gist.github/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
The package that linked you here is now pure ESM. It cannot be
require()
'd from CommonJS.This means you have the following choices:
- Use ESM yourself. (preferred)
Useimport foo from 'foo'
instead ofconst foo = require('foo')
to import the package. You also need to put"type": "module"
in your package.json and more. Follow the below guide.- If the package is used in an async context, you could use
await import(…)
from CommonJS instead ofrequire(…)
.- Stay on the existing version of the package until you can move to ESM.
- Since Node.js 22, you may be able to
require()
ESM modules. However, I strongly recommend moving to ESM instead.You also need to make sure you're on the latest minor version of Node.js. At minimum Node.js 16.
I would strongly recommend moving to ESM. ESM can still import CommonJS packages, but CommonJS packages cannot import ESM packages synchronously.
So, stubborn devs lol. I fixed this by doing:
"electron-store": "v8.2.0"
in my package.json
and reinstalling the packages. 8.2.0 seems to be the last release before 9.0.0 which forces ESM modules.
Hope this helps.
import * as thing from "thing"
syntax. If we were still in the Node 14 era, sure, but Node's been able to cross import for years now, and 23 even finally removes the need for"type":"module"
in package.json and just autodetects what it's loading. – Mike 'Pomax' Kamermans Commented Mar 29 at 15:12