Skip to content

窗口加载模式

概述

本项目支持两种窗口加载模式,以适应不同的开发和部署场景:

  • 远程模式 (Remote): 加载远程 URL 地址
  • 本地模式 (Local): 启动本地 HTTP 服务器加载静态资源

模式配置

resources/config/config.ini 中配置加载模式:

ini
# 窗口加载模式: remote 或 local
loadMode = remote

# 远程 URL 地址(remote 模式使用)
electronUrl = http://localhost:5173

远程模式 (Remote)

适用场景

  • 开发环境: 连接 Vite 开发服务器,支持热更新
  • 测试环境: 连接测试服务器进行集成测试
  • 在线部署: 加载云端部署的应用

配置示例

ini
loadMode = remote
electronUrl = http://localhost:5173

实现原理

javascript
async function windowLoadRemoteURL(win, url) {
  try {
    if (!url) throw new Error('远程URL不能为空');

    logger.info(`开始加载远程URL: ${url}`);
    await win.loadURL(url);
    openDevToolsIfNeeded(win);
    logger.info(`远程URL加载成功: ${url}`);
  } catch (error) {
    logger.error(`当前模式: remote模式; 加载URL地址为: ${url}`);
    throw error;
  }
}

优点

  • ✅ 开发时支持热更新 (HMR)
  • ✅ 无需打包,开发体验好
  • ✅ 可以连接任意 HTTP 服务器
  • ✅ 适合快速迭代开发

缺点

  • ❌ 依赖网络连接
  • ❌ 启动需要额外运行开发服务器
  • ❌ 不适合离线环境

本地模式 (Local)

适用场景

  • 生产环境: 打包后的应用,完全离线运行
  • 演示环境: 无需网络连接的演示
  • 封闭网络: 内网环境或离线环境

配置示例

ini
loadMode = local
# electronUrl 可选,作为降级备用
electronUrl = http://localhost:5173

实现原理

本地模式通过启动内置的 Express HTTP 服务器来提供静态资源:

javascript
async function windowLoadLocalServer(win) {
  try {
    // 获取 dist 目录路径
    const distPath = path.dirname(LOCAL_WEB_INDEX_FILE);

    // 检查目录和文件是否存在
    if (!fs.existsSync(distPath)) {
      throw new Error(`本地资源目录不存在: ${distPath}`);
    }
    if (!fs.existsSync(LOCAL_WEB_INDEX_FILE)) {
      throw new Error(`index.html 文件不存在: ${LOCAL_WEB_INDEX_FILE}`);
    }

    logger.info(`本地资源目录: ${distPath}`);

    // 启动本地 Express 服务器
    const localServer = LocalServer.getInstance();
    const serverUrl = await localServer.start(distPath);

    logger.info(`开始通过本地服务器加载: ${serverUrl}`);
    await win.loadURL(serverUrl);
    openDevToolsIfNeeded(win);
    logger.info('本地服务器页面加载成功');
  } catch (error) {
    logger.error('启动本地服务器失败:', error);
    throw error;
  }
}

本地服务器实现

javascript
class LocalServer {
  constructor() {
    this.app = express();
    this.server = null;
    this.port = 0; // 使用随机端口
  }

  async start(distPath) {
    // 配置静态资源目录
    this.app.use(express.static(distPath));

    // 启动服务器
    await new Promise((resolve) => {
      this.server = this.app.listen(0, () => {
        this.port = this.server.address().port;
        resolve();
      });
    });

    return `http://localhost:${this.port}`;
  }

  async stop() {
    if (this.server) {
      await new Promise((resolve) => {
        this.server.close(resolve);
      });
      this.server = null;
    }
  }
}

优点

  • ✅ 完全离线运行
  • ✅ 不依赖外部服务器
  • ✅ 启动更稳定可靠
  • ✅ 适合生产环境

缺点

  • ❌ 需要先打包渲染进程
  • ❌ 不支持热更新
  • ❌ 修改代码需要重新打包

加载流程

统一加载入口

javascript
async function windowLoadByMode(win, url) {
  const loadMode = getConfigValue('loadMode', LOAD_MODE.REMOTE);

  logger.info(`窗口加载模式: ${loadMode} - ${loadMode === LOAD_MODE.REMOTE ? '远程' : '本地'}模式`);

  try {
    if (loadMode === LOAD_MODE.REMOTE) {
      // 远程模式:加载远程URL
      await windowLoadRemoteURL(win, url);
    } else {
      // 本地模式:启动本地HTTP服务器并加载
      await windowLoadLocalServer(win);
    }
  } catch (error) {
    // 统一的降级处理
    logger.warn(`${loadMode}模式加载失败,尝试降级处理`);

    if (loadMode === LOAD_MODE.LOCAL && url) {
      // 本地模式失败,尝试远程URL作为备用
      logger.info(`尝试使用远程URL作为备用: ${url}`);
      try {
        await windowLoadRemoteURL(win, url);
      } catch (fallbackError) {
        logger.error('备用远程URL加载也失败:', fallbackError);
        throw new Error('所有加载方式均失败');
      }
    } else {
      // 远程模式失败或没有备用URL,加载错误兜底页面
      logger.error('远端地址暂时无法加载,将使用内置错误页面进行显示');
      throw new Error(`错误详细信息: ${error.message}`);
    }
  }
}

降级策略

尝试主要加载方式

  失败?

检查是否有备用方案

  有备用?

尝试备用加载方式

  还是失败?

加载错误兜底页面

降级规则:

  1. 本地模式失败 + 有 electronUrl → 尝试加载远程 URL
  2. 远程模式失败 → 加载错误页面
  3. 所有方式失败 → 加载错误页面

使用建议

开发环境

ini
# 推荐:远程模式 + Vite 开发服务器
loadMode = remote
electronUrl = http://localhost:5173

启动流程:

bash
# 1. 启动渲染进程开发服务器
pnpm dev:renderer

# 2. 启动 Electron 主进程
pnpm dev:electron

生产环境

ini
# 推荐:本地模式
loadMode = local

# 可选:提供备用 URL(用于降级)
electronUrl = https://your-backup-server.com

打包流程:

bash
# 1. 打包渲染进程
pnpm build:renderer

# 2. 打包整个应用
pnpm electron:dist

测试环境

ini
# 方式1: 本地打包 + 本地模式
loadMode = local

# 方式2: 远程测试服务器
loadMode = remote
electronUrl = http://test-server:8080

开发工具

自动打开开发工具

开发环境下(!app.isPackaged)会自动打开开发工具:

javascript
function openDevToolsIfNeeded(win) {
  if (!app.isPackaged) {
    win.webContents.openDevTools();
  }
}

生产环境

生产环境默认不打开开发工具,但可以通过托盘菜单手动打开:

右键托盘图标 → 开发工具 → 打开开发者工具

常见问题

Q1: 本地模式找不到资源文件?

原因: 渲染进程未打包或路径配置错误

解决方案:

bash
# 先打包渲染进程
pnpm build:renderer

# 检查配置文件中的路径
# packages/main/src/config/reader-config.js

Q2: 远程模式连接失败?

原因: 开发服务器未启动或 URL 配置错误

解决方案:

bash
# 1. 确保 Vite 开发服务器已启动
pnpm dev:renderer

# 2. 检查配置文件中的 electronUrl
# resources/config/config.ini
electronUrl = http://localhost:5173

Q3: 如何切换模式?

修改配置文件后重启应用:

ini
# resources/config/config.ini

# 切换到远程模式
loadMode = remote

# 或切换到本地模式
loadMode = local

Q4: 生产环境能用远程模式吗?

可以,但需要注意:

  • ⚠️ 依赖网络连接
  • ⚠️ 需要确保远程服务器稳定性
  • ⚠️ 建议配置本地模式作为降级方案
ini
# 主要使用远程,本地作为备用
loadMode = remote
electronUrl = https://your-server.com
# 确保 dist 目录有打包好的资源

最佳实践

1. 开发阶段

  • 使用远程模式连接 Vite 开发服务器
  • 享受热更新带来的快速迭代
  • 渲染进程和主进程分别启动

2. 测试阶段

  • 使用本地模式测试打包效果
  • 验证离线运行能力
  • 确保资源路径正确

3. 生产部署

  • 优先使用本地模式
  • 如需在线更新,可配置远程模式
  • 建议同时打包本地资源作为降级

4. 混合方案

ini
# 主要用本地,远程作为降级或更新通道
loadMode = local
electronUrl = https://update-server.com/latest

相关文件

  • packages/main/src/core/window.js - 窗口加载逻辑
  • packages/main/src/utils/local-server.js - 本地服务器实现
  • packages/main/src/config/reader-config.js - 配置读取
  • resources/config/config.ini - 配置文件

相关文档

基于 MIT 许可发布