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

Electron加载Angular应用文件异常问题排查与修复求助

问题描述

Angular应用在Web环境下(ng serve或ng build部署)运行正常,但经electron-builder打包安装后出现以下异常:

  • 启动时页面空白,DOM中无index.html内容(DevTools的app.asar资源内可找到该文件)
  • 首次刷新页面后,所有静态资源(index.html、.js、.css、assets文件)加载正常,应用可正常使用
  • 再次刷新时,Electron会尝试访问当前路由对应的文件路径(如/path/to/app.asar/home),而非加载app.asar中的index.html,导致页面无法运行

补充:在main.js中添加mainWindow.webContents.session.clearStorageData();后,启动加载恢复正常,但再次刷新的问题依然存在。


相关代码

main.js

const { app, BrowserWindow } = require('electron');
const isWindows = process.platform === 'win32';
const { exec } = require('child_process');
const path = require('path');

let mainWindow;
let childProcess

async function createMainWindow() {
    openExternalApp();
    mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        show: false,
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false,
            enableRemoteModule: true,
            webviewTag: true
        }
    });

    mainWindow.loadUrl(`file://${path.join(__dirname, 'index.html')}`);
    //mainWindow.removeMenu();
    mainWindow.webContents.openDevTools();
        mainWindow.once('ready-to-show', () => {
            console.log('Main window ready to show');
            mainWindow.show();
        })
}

app.on('ready', () => {
    createMainWindow; // 此处存在调用错误
})

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

app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
        createMainWindow()
    }
});

function openExternalApp() {
    const appPath = path.join(app.getAppPath(), '..','..');

    var api
    if (process.platform === 'win32') {
        api = `${appPath}\\resources\\subprocess.exe`
    }
    else if (process.platform === 'darwin') {
        throw new Error('Not Implemented')
    }
    else {
        api = `${appPath}/resources/subprocess`;
    }
    childProcess = exec(api, { stdio: 'ignore' });
}

function killChildProcess(child) {
    if (isWindows) {
      // For Windows: Terminate the process tree using taskkill
      exec(`taskkill /pid ${child.pid} /T /F`);
    } else {
      // For Linux and POSIX systems: Use the negative PID to kill the process group
      process.kill(-child.pid);
    }
  }

Electron构建配置(package.json片段)

"build": {
    "directories": {
      "output": "dist/electron"
    },
    "files": [
      {
        "from": "electron",
        "to": "./"
      },
      {
        "from": "dist/",
        "to": "./"
      }
    ],
    "extraResources": [
      {
        "from": "resourcces/subprocess",
        "to": "subprocess"
      },
      {
        "from": "resourcces/subprocess.exe",
        "to": "subprocess.exe"
      }
    ]
  }

Angular路由配置

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

// Importiere die Komponenten, die du routen möchtest
import {COMPONENTS} from **;

const routes: Routes = [
  { path: 'home', component: LoginComponent },
  { path: 'ROUTE', component: COMPONENT},
  { path: 'ROUTE/SUB', component: COMPONENT},
  { path: 'ROUTE2', component: COMPONENT},
  { path: 'ROUTE3', component: COMPONENT},
  { path: 'ROUTE3/SUB', component: COMPONENT},
  { path: 'ROUTE4', component: COMPONENT},
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

解决方案

1. 修复main.js的函数调用错误

在app.on('ready')回调中,仅引用了createMainWindow函数但未执行,导致窗口未创建。修改为:

app.on('ready', () => {
    createMainWindow(); // 补充括号执行函数
})

2. 切换Angular路由为Hash模式

Electron使用file://协议,不支持HTML5 History模式的路由刷新(刷新时会尝试查找对应路径的物理文件,而非交由Angular路由处理)。修改Angular路由配置,启用Hash模式:

@NgModule({
  imports: [RouterModule.forRoot(routes, { useHash: true })], // 添加useHash: true
  exports: [RouterModule]
})
export class AppRoutingModule { }

启用后路由会变为/#/home形式,刷新时Electron会加载index.html,再由Angular解析Hash部分完成路由跳转。

3. (可选)拦截Electron路由请求(无需Hash模式)

若不想使用Hash模式,可在Electron中拦截导航请求,将非物理文件的请求重定向到index.html。在createMainWindow函数中添加以下代码(需先引入fs模块):

const fs = require('fs'); // 顶部添加fs模块引入

// 在mainWindow.loadUrl之后添加
mainWindow.webContents.on('will-navigate', (event, url) => {
  const parsedUrl = new URL(url);
  // 拼接本地文件路径
  const filePath = path.join(__dirname, parsedUrl.pathname);
  // 检查路径是否存在,且不是index.html则重定向
  if (!fs.existsSync(filePath) && !url.endsWith('index.html')) {
    event.preventDefault();
    mainWindow.loadURL(`file://${path.join(__dirname, 'index.html')}`);
  }
});

4. 修正electron-builder配置的路径拼写错误

构建配置中extraResources的from路径存在拼写错误(resourcces应为resources),修正后避免子进程找不到:

"extraResources": [
  {
    "from": "resources/subprocess",
    "to": "subprocess"
  },
  {
    "from": "resources/subprocess.exe",
    "to": "subprocess.exe"
  }
]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 03:12:05