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

Electron-Vite+React生产环境加载video.html本地资源失败求助

Electron-Vite + React生产环境加载第二个BrowserWindow的video.html失败问题

基于Electron-Vite + React开发应用,开发环境执行npm run dev时能正常在第二个BrowserWindow加载本地video.html,但切换到生产环境预览(执行npm start)时,调用loadFile或loadURL都会抛出“Unable to load local resource”错误,主窗口加载index.html则完全正常。

主进程文件index.js

import { app, shell, BrowserWindow, ipcMain } from 'electron'
import { join } from 'path'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'

let mainWindow, secondWindow

function createWindow() {
  mainWindow = new BrowserWindow({
    width: 900,
    height: 670,
    show: false,
    autoHideMenuBar: true,
    ...(process.platform === 'linux' ? { icon } : {}),
    webPreferences: {
      preload: join(__dirname, '../preload/index.js'),
      sandbox: false,
      contextIsolation: true,
      enableRemoteModule: false,
      webSecurity: true
    }
  })

  mainWindow.on('ready-to-show', () => {
    mainWindow.show()
  })

  mainWindow.webContents.setWindowOpenHandler((details) => {
    shell.openExternal(details.url)
    return { action: 'deny' }
  })

  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    mainWindow.loadURL(`${process.env['ELECTRON_RENDERER_URL']}/index.html`)
  } else {
    mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
  }
}

function createSecondWindow() {
  secondWindow = new BrowserWindow({
    width: 1080,
    height: 720,
    autoHideMenuBar: true,
    ...(process.platform === 'linux' ? { icon } : {}),
    webPreferences: {
      preload: join(__dirname, '../preload/index.js'),
      sandbox: false,
      contextIsolation: true,
      enableRemoteModule: false,
      webSecurity: true
    }
  })

  secondWindow.on("ready-to-show", () => {
    secondWindow.show();
  });

  secondWindow.webContents.setWindowOpenHandler((details) => {
    shell.openExternal(details.url)
    return { action: 'deny' }
  })

  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    secondWindow.loadURL(`${process.env['ELECTRON_RENDERER_URL']}/video.html`)
  } else {
    secondWindow.loadFile(join(__dirname, '../renderer/video.html'));
  }
}


app.whenReady().then(() => {
  electronApp.setAppUserModelId('com.electron')

  app.on('browser-window-created', (_, window) => {
    optimizer.watchWindowShortcuts(window)
  })

  createWindow()
  createSecondWindow()

  app.on('activate', function () {
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

ipcMain.on("play-video", (event, videoPath) => {
  if (secondWindow) {
    secondWindow.webContents.send("start-video", videoPath);
  }
})

Electron.vite.config.js

import { resolve } from 'path'
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  main: {
    plugins: [externalizeDepsPlugin()]
  },
  preload: {
    plugins: [externalizeDepsPlugin()]
  },
  renderer: {
    resolve: {
      alias: {
        '@renderer': resolve('src/renderer/src')
      }
    },
    plugins: [react()]
  },
})

应用结构

├── build
├── out
└─┬ src
  ├── preload
  ├─┬ main
  │ └── index.js
  ├─┬ renderer
  │ ├── index.html
  │ ├── video.html
  │ ├── public
  │ └─┬ src
  │   ├── App.jsx (React component used in main.jsx)
  │   ├── VideoApp.jsx (React component used in video.jsx)
  │   ├── main.jsx (src for index.html)
  │   └── video.jsx (src for video.html)
  ├── electron.vite.config.js
  └── package.json

已尝试方案

  • 使用loadFile和loadURL方法加载video.html,均出现相同错误
  • 调整Electron的webSecurity等安全配置,问题仍未解决

解决方案

核心问题

Electron-Vite默认仅将index.html作为渲染入口打包,生产环境下video.html没有被复制到输出目录,导致loadFile找不到对应文件。

修复步骤

  1. 修改electron.vite.config.js,配置多页面入口
    在renderer的build选项中添加rollupOptions.input,显式指定所有需要打包的HTML文件:
import { resolve } from 'path'
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  main: {
    plugins: [externalizeDepsPlugin()]
  },
  preload: {
    plugins: [externalizeDepsPlugin()]
  },
  renderer: {
    resolve: {
      alias: {
        '@renderer': resolve('src/renderer/src')
      }
    },
    plugins: [react()],
    build: {
      rollupOptions: {
        input: {
          main: resolve(__dirname, 'src/renderer/index.html'),
          video: resolve(__dirname, 'src/renderer/video.html')
        }
      }
    }
  },
})
  1. 确认生产环境路径正确性
    打包后渲染资源会输出到out/renderer目录,主进程中__dirname在生产环境对应out/main目录,原代码中的join(__dirname, '../renderer/video.html')路径是正确的,无需修改。

  2. 验证打包结果
    执行npm run build后,检查out/renderer目录是否同时存在index.html和video.html,若存在则配置生效。

额外说明

  • 开发环境下Electron-Vite的dev server会自动处理所有静态文件,因此video.html能正常访问,但生产环境必须显式配置多页面入口才能让Vite打包该文件。
  • 保持webSecurity: true即可,路径问题解决后不会出现资源加载或跨域问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 20:44:52