最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Error packaging electron app that uses local files - Stack Overflow

programmeradmin4浏览0评论

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
  • Did you happen to solve this? I'm hitting the exact same issue. – andrew Commented Mar 26 at 21:09
  • Why are you using CJS in 2025, with Node 22 and Electron 35? Get on the proper, normal ESM train already =) – Mike 'Pomax' Kamermans Commented Mar 27 at 2:27
  • @Mike'Pomax'Kamermans Most developers don't have the latitude to make that call. Many more cannot afford to abandon some old code or legacy library without time/money investment on things management probably consider "Working" – Llama D'Attore Commented Mar 29 at 2:35
  • @LlamaD'Attore Except for the part where Node 22 literally gives you that latitude, because writing ESM yourself still lets you import downstream CJS without any problems using the 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
  • 1 I understand you and use ESM when I can. You asked why OP doesn't "get on the proper train" which implies the question is because OP is doing something improper. Your opinion about what's proper and how people should code are not relevant or helpful. – Llama D'Attore Commented Mar 30 at 1:37
 |  Show 4 more comments

1 Answer 1

Reset to default 2

As 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:

  1. Use ESM yourself. (preferred)
    Use import foo from 'foo' instead of const foo = require('foo') to import the package. You also need to put "type": "module" in your package.json and more. Follow the below guide.
  2. If the package is used in an async context, you could use await import(…) from CommonJS instead of require(…).
  3. Stay on the existing version of the package until you can move to ESM.
  4. 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.

发布评论

评论列表(0)

  1. 暂无评论