You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

编译后Electron应用存于网络共享文件夹无法启动问题

问题

我开发了一款管理NeDB数据库的Electron应用,在VS Code中启动运行完全正常。但执行npm run package打包后,将输出文件夹移至网络共享路径,运行.exe文件时窗口短暂空白后无提示闪退。

  • 已确认文件夹权限无问题,该.exe在本地及其他PC均可正常运行。
  • 闪退之后文件夹无法删除,提示文件被占用但任务管理器无对应进程。
  • 测试通过Electron Forge新建的项目打包后放共享文件夹也出现相同问题。
  • 通过终端启动时,输出显示GPU进程启动失败(error_code=18),最终因GPU进程不可用退出。
解决方案

针对网络共享路径下GPU进程启动失败的问题,可尝试以下几种修复方式:

1. 禁用GPU硬件加速

在Electron主进程初始化前添加禁用GPU的参数,绕过GPU进程启动问题:

// 在main.js最顶部添加
app.commandLine.appendSwitch('disable-gpu');
app.commandLine.appendSwitch('disable-software-rasterizer');

或者在创建BrowserWindow时添加webPreferences配置:

win = new BrowserWindow({
    // 其他配置...
    webPreferences: {
        // 其他配置...
        disableHardwareAcceleration: true
    }
});

2. 修改asar打包配置

网络共享路径可能对asar包的读取存在兼容性问题,可尝试禁用asar或指定部分文件不打包进asar:
在forge.config.js的packagerConfig中修改:

packagerConfig: {
    // 其他配置...
    asar: false, // 直接禁用asar
    // 或者保留asar但解压native模块
    // asar: {
    //   unpack: "**/*.node"
    // }
}

3. 调整应用临时文件路径

Electron默认会在系统临时目录创建缓存,网络路径下可能存在权限异常,手动指定临时目录到本地路径:

// 在main.js的app.whenReady()之前添加
app.setPath('userData', path.join(process.env.LOCALAPPDATA, 'gestione-marcature-laser'));
app.setPath('temp', path.join(process.env.TEMP, 'gestione-marcature-laser'));

4. 检查共享路径权限配置

确保网络共享路径支持文件锁定和执行权限,部分SMB共享配置可能限制了可执行文件的运行环境,可尝试开启"允许网络用户更改我的文件"权限,或使用SMBv3协议连接共享。


相关配置文件

package.json

{"name": "gestione-marcature-laser","version": "2.0.0","description": "Gestore Marcature Laser","main": "index.js","scripts": {"start": "electron-forge start","package": "electron-forge package","make": "electron-forge make"},"author": "Nemanja G.","license": "ISC","dependencies": {"bcryptjs": "^2.4.3","electron-prompt": "^1.7.0","electron-squirrel-startup": "^1.0.0","jquery": "^3.5.1","moment": "^2.29.1","nedb-async": "^0.1.6","select2": "^4.0.13","xlsx": "^0.16.9"},"devDependencies": {"@electron-forge/cli": "^6.2.1","@electron-forge/maker-deb": "^6.2.1","@electron-forge/maker-rpm": "^6.2.1","@electron-forge/maker-squirrel": "^6.2.1","@electron-forge/maker-zip": "^6.2.1","@electron-forge/plugin-auto-unpack-natives": "^6.2.1","electron": "^25.2.0"}}

forge.config.js

const path = require('path')

module.exports = {
  packagerConfig: {
    icon: './assets/logo',
    asar: {
      //unpack: "**/node_modules/pdf-to-printer/**/*"
    },
    out: "gestione-marcature"
  },
  rebuildConfig: {},
  makers: [
    {
      name: '@electron-forge/maker-squirrel',
      config: {
        iconUrl: path.resolve(__dirname, './assets/logo.ico'),
        setupIcon: path.resolve(__dirname, './assets/logo.ico'),
      },
    },
    {
      name: '@electron-forge/maker-zip',
      platforms: ['darwin'],
    },
    {
      name: '@electron-forge/maker-deb',
      config: {
        icon: './Styles/static/icon.png',
      },
    },
    {
      name: '@electron-forge/maker-rpm',
      config: {},
    },
  ],
  plugins: [
    {
      name: '@electron-forge/plugin-auto-unpack-natives',
      config: {},
    },
  ]
};

main.js

const { app, BrowserWindow, dialog } = require('electron');
const path = require('path');
const url = require('url');
const { ipcMain } = require('electron');
const bcrypt = require('bcryptjs');
const prompt = require('electron-prompt');

/* SEZIONE PASSWORD, attualmente quella di sap. Usare codice sotto per generare hash */
/*
const password = "PASS"
const saltRounds = 10

bcrypt.genSalt(saltRounds, function (err, salt) {
    if (err) {
        throw err
    } else {
        bcrypt.hash(password, salt, function (err, hash) {
            if (err) {
                throw err
            } else {
                console.log(hash);
                dialog.showErrorBox('Errore', hash);
                //$2a$10$FEBywZh8u9M0Cec/0mWep.1kXrwKeiWDba6tdKvDfEBjyePJnDT7K
            }
        })
    }
})
*/
//hash = "$2b$10$6OT.h/W3EnHAxiRC15OfR.BdEseDilja8m5Z2LPtEeed3pNYNsJwO";
hash = "$2b$10$OMZlnwGs8av1Kwhbx5ya5uUU2HMCdU.Gyn//s0.J2/mSklzoBEjny";

let win = null;
let win2 = null;

function createWindow() {
    // Create the browser window.
    win = new BrowserWindow({
        width: 1000,
        height: 720,
        webPreferences: {
            nodeIntegration: true,
            preload: path.join(__dirname, 'preload.js')
        },
        icon: path.join(__dirname, './assets/logo.png'),
        show: false
    });

    // maximize it
    win.maximize();

    // and load the index.html of the app.
    win.loadURL(url.format({
        pathname: path.join(__dirname, 'index.html'),
        protocol: 'file:',
        slashes: true
    }));

    win.once('ready-to-show', () => {
        win.show()
    });

    win.on("close", (evt) => {
        //Cancel the current event to prevent window from closing


        //options object for dialog.showMessageBox(...)
        let options = {
            type: "question",
            buttons: ["&Sì", "&No", "&Cancella"],
            defaultId: 2,
            title: "Attenzione!",
            message: "Confermi la chiusura del programma Gestione Database Marcature?",
            detail: "Potrai riaprirlo dall'icona nel desktop.",
            icon: path.join(__dirname, './assets/logo.png'),
            cancelId: 2,
            noLink: true,
            normalizeAccessKeys: true
        };

        let res = dialog.showMessageBoxSync(win, options);
        if (res === 0) {
            //Yes button pressed
        } else if (res === 1) {
            //No button pressed
            evt.preventDefault();
        } else if (res === 2) {
            //Cancel button pressed
            evt.preventDefault();
        }

    });

    // Open the DevTools.
    win.removeMenu();
    //win.webContents.openDevTools();
}

ipcMain.on('openPage', async (_, arg) => {
    if (!win2) {
        let pwd = await prompt({
            title: 'Attenzione!',
            label: 'Inserire la password:',
            type: 'input',
            height: 200,
            inputAttrs: { type: 'password', required: true },
            icon: path.join(__dirname, './assets/logo.png'),
            menuBarVisible: false,
            buttonLabels: 'ok',
            customStylesheet: path.join(__dirname, 'styles', 'prompt-styles.css')
        });

        bcrypt.compare(pwd, hash).then(res => {
            if (res) {
                win2 = new BrowserWindow({
                    parent: win,
                    webPreferences: {
                        nodeIntegration: true,
                        preload: path.join(__dirname, 'preload.js')
                    },
                    frame: false,
                    width: 1000,
                    height: 720,
                    show: false
                });

                win2.maximize();

                win2.loadURL(url.format({
                    pathname: path.join(__dirname, arg.page),
                    protocol: 'file:',
                    slashes: true
                }));

                win2.once('ready-to-show', () => {
                    win2.show()
                });

                win2.on('close', _ => { win2 = null });

                //win2.webContents.openDevTools();
            } else {
                dialog.showErrorBox('Errore', 'Password non corretta!');
            }
        });
    }
});

ipcMain.on('closePage', _ => {
    win2.close();
});

ipcMain.on('showMessageBox', (_, arg) => {
    dialog.showMessageBox({
        title: arg.title,
        message: arg.message
    })
});

const gotTheLock = app.requestSingleInstanceLock();

if (!gotTheLock) {
    app.quit();
} else {
    app.on('second-instance', (event, commandLine, workingDirectory) => {
        // Someone tried to run a second instance, we should focus our window.
        if (win) {
            if (win.isMinimized()) {
                win.restore();
            }
            win.focus();
        }
    })

    // This method will be called when Electron has finished
    // initialization and is ready to create browser windows.
    // Some APIs can only be used after this event occurs.
    app.whenReady().then(createWindow);

    // Quit when all windows are closed.
    app.on('window-all-closed', () => {
        // On macOS it is common for applications and their menu bar
        // to stay active until the user quits explicitly with Cmd + Q
        if (process.platform !== 'darwin') {
            app.quit();
        }
    });
}

内容的提问来源于stack exchange,提问作者Nemanja Gavranovic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 04:55:59