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

Electron使用electron-serve预览静态网站遇ERR_FILE_NOT_FOUND错误求助

静态网站预览功能实现问题(Electron + electron-serve)

(node:12068) electron: Failed to load URL: app://-/ with error: ERR_FILE_NOT_FOUND
(Use electron --trace-warnings ... to show where the warning was created)
(node:12068) UnhandledPromiseRejectionWarning: Error: ERR_FILE_NOT_FOUND (-6) loading 'app://-/'
at rejectAndCleanup (node:electron/js2c/browser_init:165:7510)
at EventEmitter.failListener (node:electron/js2c/browser_init:165:7723)
at EventEmitter.emit (node:events:527:28)
(node:12068) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict. (rejection id: 1)
[12068:1117/094334.336:ERROR:interface_endpoint_client.cc(689)] Message 3 rejected by interface blink.mojom.Widget
[12068:1117/094334.339:ERROR:interface_endpoint_client.cc(689)] Message 6 rejected by interface blink.mojom.WidgetHost
[12068:1117/094334.339:ERROR:interface_endpoint_client.cc(689)] Message 7 rejected by interface blink.mojom.WidgetHost

main.js 代码

const { app, BrowserWindow, BrowserView, ipcMain, protocol } = require("electron");
const serve = require('electron-serve');
const path = require("path");
const url = require('url');
const isDiv = process.eventNames.NODE_ENV !== "production";
const isMac = process.platform === "darwin";
let loadURL = serve({ directory : path.join(__dirname, "./compressedFolder") });

let mainWindow;
// let view;

// create main window
function createMainWindow() {
  mainWindow = new BrowserWindow({
    icon: path.join(__dirname, "src/img/greenieweb.icns"),
    width: 1200,
    height: 800,
    minHeight: 600,
    minWidth: 1000,
    webPreferences: {
      title: "GreenieWeb",
      preload: path.join(__dirname, "/src/preload/preload.js"),
      devTools: true /*Disables Devtools*/,
      nodeIntegration: true,
    },
  });

  // open dev tools if in dev env
  if (isDiv) {
    mainWindow.webContents.openDevTools();
  }

  ipcMain.on('app-topreview-loaded', async (event) => {
    const previewWindow = new BrowserWindow({
      parent: mainWindow,
      show: false,
      width: 1200,
      height: 800,
      minHeight: 600,
      minWidth: 1000,
      webPreferences: {
        title: "Preview",
      },
    })
    await loadURL(previewWindow);
    previewWindow.once('ready-to-show', () => {
        previewWindow.show()
      })
  })
  // load main html file
  mainWindow.loadFile(path.join(__dirname, "./index.html"));
}

// App is ready
app.whenReady().then(() => {
  // create the main window
  createMainWindow();

  // Disable menu
  // Menu.setApplicationMenu(null);

  // remove mainwindow from memory on close
  mainWindow.on('closed', () => {
    mainWindow = null;
  });

  // create window if none is created when app is active
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createMainWindow();
    }
  });
});

renderer.js 代码

let previewBtn = document.getElementById("preview-btn");

const fs = versions.fs;

let gFRWRPCounter = 0;
let isEmptyDir = true

previewBtn.addEventListener("click", () => {
    if(!isEmptyDir){
        removeFolderFromDir()
    }
    addFolderToThePlace()
    
    window.electronAPI.showWebApp()
})

function removeFolderFromDir(){
    fs.rmSync('./compressedFolder', { recursive: true, force: true });
    fs.mkdir("./compressedFolder", (err) => {
        if(err){
            console.log("Something went wrong")
        }
    })
    isEmptyDir = true;
    gFRWRPCounter = 0;
}

async function addFolderToThePlace(){
    if(directoryHandle===undefined){
        new Notification(emptyFolderNOTIFICATION_TITLE, {
            body: emptyFolderNOTIFICATION_BODY,
        }).show();
        return;
    }
    for await (const file of getFilesRecursivelyWithRP("", directoryHandle)) {
        const content = await file.text()
        await fs.mkdir(
            "./compressedFolder" + file.relativePath,
            { recursive: true },
            (err) => {
                if (err) {
                    console.log(err);
                } else {
                    fs.writeFileSync(
                        "./compressedFolder" + file.relativePath + "/" + file.name,
                        content
                    );
                }
            }
        );
    }
    isEmptyDir = false
}

async function* getFilesRecursivelyWithRP(fPath, entry) {
    if (entry.kind === "file") {
        const file = await entry.getFile();
        if (file !== null) {
            file.relativePath = fPath;
            yield file;
        }
    } else if (entry.kind === "directory") {
        let nFPath = "";
        if(gFRWRPCounter>0){
            nFPath = fPath + "/" + entry.name;
        }else{
            nFPath = fPath
            gFRWRPCounter++;
        }
        for await (const handle of entry.values()) {
            yield* getFilesRecursivelyWithRP(nFPath, handle);
        }
    }
}

preload.js 代码

const { contextBridge, ipcRenderer } = require("electron");
const fs = require('fs')

// this is just an example
contextBridge.exposeInMainWorld("versions", {
  fs: fs,
});

contextBridge.exposeInMainWorld('electronAPI', {
  showWebApp: () => ipcRenderer.send('app-topreview-loaded')
})

我要实现一个静态网站(HTML/CSS/JS)预览功能,流程是上传包含静态文件的文件夹、保存文件,点击按钮后在新窗口预览网站。用electron-serve库实现,但运行时出现上述错误,预览窗口为空白。

代码逻辑是将待预览文件夹上传到项目目录下的compressedFolder,触发app-topreview-loaded事件后打开预览窗口。错误原因应该是初始化serve({ directory : path.join(__dirname, "./compressedFolder") })时该文件夹为空,但把这个函数调用放到ipcMain.on事件处理里会报错,提示必须在app ready前调用。求解决这个问题的方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 22:10:48