electrobun-debugging

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Electrobun Debugging

Electrobun调试

Comprehensive debugging and troubleshooting guide for Electrobun applications.
Electrobun应用的全面调试与故障排除指南。

Development Environment

开发环境

Basic Development Setup

基础开发环境搭建

bash
undefined
bash
undefined

Development mode with hot reload

启用热重载的开发模式

bun run dev
bun run dev

Development mode with verbose logging

启用详细日志的开发模式

DEBUG=* bun run dev
DEBUG=* bun run dev

Development mode with specific debug namespace

启用特定调试命名空间的开发模式

DEBUG=electrobun:* bun run dev
undefined
DEBUG=electrobun:* bun run dev
undefined

Environment Configuration

环境配置

.env.development:
bash
undefined
.env.development:
bash
undefined

Enable development features

启用开发功能

NODE_ENV=development DEBUG=electrobun:*
NODE_ENV=development DEBUG=electrobun:*

DevTools always open

始终打开DevTools

ELECTRON_ENABLE_DEVTOOLS=1
ELECTRON_ENABLE_DEVTOOLS=1

Disable security warnings in dev

禁用开发环境中的安全警告

ELECTRON_DISABLE_SECURITY_WARNINGS=true
ELECTRON_DISABLE_SECURITY_WARNINGS=true

Custom dev server port

自定义开发服务器端口

DEV_SERVER_PORT=3000
undefined
DEV_SERVER_PORT=3000
undefined

Debugging Main Process

主进程调试

Console Logging

控制台日志

ts
// Main process logs appear in terminal
console.log("Main process started");
console.error("Error in main process");
console.warn("Warning in main process");

// Structured logging
const logger = {
  debug: (msg: string, data?: any) => {
    if (process.env.DEBUG) {
      console.log(`[DEBUG] ${msg}`, data || "");
    }
  },
  info: (msg: string, data?: any) => {
    console.log(`[INFO] ${msg}`, data || "");
  },
  error: (msg: string, error?: any) => {
    console.error(`[ERROR] ${msg}`, error || "");
    if (error?.stack) {
      console.error(error.stack);
    }
  }
};

logger.info("Window created", { width: 1200, height: 800 });
logger.error("Failed to load file", error);
ts
// 主进程日志会显示在终端中
console.log("Main process started");
console.error("Error in main process");
console.warn("Warning in main process");

// 结构化日志
const logger = {
  debug: (msg: string, data?: any) => {
    if (process.env.DEBUG) {
      console.log(`[DEBUG] ${msg}`, data || "");
    }
  },
  info: (msg: string, data?: any) => {
    console.log(`[INFO] ${msg}`, data || "");
  },
  error: (msg: string, error?: any) => {
    console.error(`[ERROR] ${msg}`, error || "");
    if (error?.stack) {
      console.error(error.stack);
    }
  }
};

logger.info("Window created", { width: 1200, height: 800 });
logger.error("Failed to load file", error);

Bun Debugger

Bun调试器

bash
undefined
bash
undefined

Start with Bun debugger

启动Bun调试器

bun --inspect run dev
bun --inspect run dev

With breakpoint on first line

在第一行设置断点启动

bun --inspect-brk run dev
bun --inspect-brk run dev

Connect with Chrome DevTools

连接Chrome DevTools

Open chrome://inspect in Chrome

在Chrome中打开chrome://inspect

Click "inspect" on your process

点击进程对应的"inspect"

undefined
undefined

Error Handling in Main

主进程错误处理

ts
// Global error handlers
process.on("uncaughtException", (error) => {
  logger.error("Uncaught exception", error);
  
  // Show error dialog
  dialog.showMessageBox({
    type: "error",
    title: "Application Error",
    message: "An unexpected error occurred",
    detail: error.message,
  });
  
  // Optional: restart or quit
  // app.relaunch();
  // app.quit();
});

process.on("unhandledRejection", (reason, promise) => {
  logger.error("Unhandled rejection", { reason, promise });
});

// Window error handler
win.on("error", (error) => {
  logger.error("Window error", error);
});

// RPC error handling
win.defineRpc({
  handlers: {
    async someHandler(args: any) {
      try {
        // Handler logic
        return { success: true };
      } catch (error) {
        logger.error("RPC handler error", error);
        throw error; // Re-throw to send to webview
      }
    }
  }
});
ts
// 全局错误处理器
process.on("uncaughtException", (error) => {
  logger.error("Uncaught exception", error);
  
  // 显示错误对话框
  dialog.showMessageBox({
    type: "error",
    title: "Application Error",
    message: "An unexpected error occurred",
    detail: error.message,
  });
  
  // 可选:重启或退出应用
  // app.relaunch();
  // app.quit();
});

process.on("unhandledRejection", (reason, promise) => {
  logger.error("Unhandled rejection", { reason, promise });
});

// 窗口错误处理器
win.on("error", (error) => {
  logger.error("Window error", error);
});

// RPC错误处理
win.defineRpc({
  handlers: {
    async someHandler(args: any) {
      try {
        // 处理器逻辑
        return { success: true };
      } catch (error) {
        logger.error("RPC handler error", error);
        throw error; // 重新抛出错误至webview
      }
    }
  }
});

Debugging Webview

Webview调试

Chrome DevTools

Chrome DevTools

ts
// Open DevTools programmatically
win.openDevTools();

// Open DevTools detached
win.openDevTools({ mode: "detach" });

// Toggle DevTools
win.toggleDevTools();

// Close DevTools
win.closeDevTools();

// Menu item to toggle DevTools
{
  label: "Toggle Developer Tools",
  accelerator: "CmdOrCtrl+Shift+I",
  action: () => win.toggleDevTools()
}
ts
// 以编程方式打开DevTools
win.openDevTools();

// 以分离模式打开DevTools
win.openDevTools({ mode: "detach" });

// 切换DevTools显示状态
win.toggleDevTools();

// 关闭DevTools
win.closeDevTools();

// 用于切换DevTools的菜单项
{
  label: "Toggle Developer Tools",
  accelerator: "CmdOrCtrl+Shift+I",
  action: () => win.toggleDevTools()
}

Console Logging in Webview

Webview控制台日志

ts
// Webview console logs appear in DevTools
console.log("Webview initialized");
console.error("Error in webview");
console.warn("Warning in webview");
console.table({ user: "Alice", age: 30 });

// Custom logger
const logger = {
  log: (msg: string, ...args: any[]) => {
    console.log(`[${new Date().toISOString()}] ${msg}`, ...args);
  },
  group: (label: string) => {
    console.group(label);
  },
  groupEnd: () => {
    console.groupEnd();
  }
};

logger.group("User Login");
logger.log("Validating credentials");
logger.log("Fetching user data");
logger.groupEnd();
ts
// Webview控制台日志会显示在DevTools中
console.log("Webview initialized");
console.error("Error in webview");
console.warn("Warning in webview");
console.table({ user: "Alice", age: 30 });

// 自定义日志器
const logger = {
  log: (msg: string, ...args: any[]) => {
    console.log(`[${new Date().toISOString()}] ${msg}`, ...args);
  },
  group: (label: string) => {
    console.group(label);
  },
  groupEnd: () => {
    console.groupEnd();
  }
};

logger.group("User Login");
logger.log("Validating credentials");
logger.log("Fetching user data");
logger.groupEnd();

Capturing Webview Errors

捕获Webview错误

ts
// Global error handler
window.addEventListener("error", (event) => {
  console.error("Uncaught error:", event.error);
  
  // Send to main process for logging
  electroview.rpc.logError({
    message: event.error.message,
    stack: event.error.stack,
    url: event.filename,
    line: event.lineno,
    column: event.colno,
  });
});

// Unhandled promise rejections
window.addEventListener("unhandledrejection", (event) => {
  console.error("Unhandled rejection:", event.reason);
  
  electroview.rpc.logError({
    message: "Unhandled rejection",
    reason: event.reason,
  });
});

// Main process handler
win.defineRpc({
  handlers: {
    async logError(error: any) {
      logger.error("Webview error", error);
      
      // Optional: save to file
      await saveErrorLog(error);
    }
  }
});
ts
// 全局错误处理器
window.addEventListener("error", (event) => {
  console.error("Uncaught error:", event.error);
  
  // 将错误发送至主进程记录
  electroview.rpc.logError({
    message: event.error.message,
    stack: event.error.stack,
    url: event.filename,
    line: event.lineno,
    column: event.colno,
  });
});

// 未处理的Promise拒绝
window.addEventListener("unhandledrejection", (event) => {
  console.error("Unhandled rejection:", event.reason);
  
  electroview.rpc.logError({
    message: "Unhandled rejection",
    reason: event.reason,
  });
});

// 主进程处理器
win.defineRpc({
  handlers: {
    async logError(error: any) {
      logger.error("Webview error", error);
      
      // 可选:将错误保存至文件
      await saveErrorLog(error);
    }
  }
});

Debugging RPC Communication

RPC通信调试

RPC Logging

RPC日志

ts
// Main process RPC logger
class RpcLogger {
  wrap(handlers: any) {
    const wrapped: any = {};
    
    for (const [name, handler] of Object.entries(handlers)) {
      wrapped[name] = async (...args: any[]) => {
        const callId = Math.random().toString(36).slice(2);
        
        logger.debug(`[RPC:${callId}] → ${name}`, args);
        const startTime = Date.now();
        
        try {
          const result = await (handler as Function)(...args);
          const duration = Date.now() - startTime;
          logger.debug(`[RPC:${callId}] ← ${name} (${duration}ms)`, result);
          return result;
        } catch (error) {
          const duration = Date.now() - startTime;
          logger.error(`[RPC:${callId}] ✗ ${name} (${duration}ms)`, error);
          throw error;
        }
      };
    }
    
    return wrapped;
  }
}

const rpcLogger = new RpcLogger();

win.defineRpc({
  handlers: rpcLogger.wrap({
    async getUser(id: string) {
      return await database.users.findById(id);
    },
    async saveFile(path: string, content: string) {
      await Bun.write(path, content);
      return { success: true };
    }
  })
});
ts
// 主进程RPC日志器
class RpcLogger {
  wrap(handlers: any) {
    const wrapped: any = {};
    
    for (const [name, handler] of Object.entries(handlers)) {
      wrapped[name] = async (...args: any[]) => {
        const callId = Math.random().toString(36).slice(2);
        
        logger.debug(`[RPC:${callId}] → ${name}`, args);
        const startTime = Date.now();
        
        try {
          const result = await (handler as Function)(...args);
          const duration = Date.now() - startTime;
          logger.debug(`[RPC:${callId}] ← ${name} (${duration}ms)`, result);
          return result;
        } catch (error) {
          const duration = Date.now() - startTime;
          logger.error(`[RPC:${callId}] ✗ ${name} (${duration}ms)`, error);
          throw error;
        }
      };
    }
    
    return wrapped;
  }
}

const rpcLogger = new RpcLogger();

win.defineRpc({
  handlers: rpcLogger.wrap({
    async getUser(id: string) {
      return await database.users.findById(id);
    },
    async saveFile(path: string, content: string) {
      await Bun.write(path, content);
      return { success: true };
    }
  })
});

Testing RPC in DevTools

在DevTools中测试RPC

ts
// In webview DevTools console:

// Test RPC call
await electroview.rpc.getUser("123")

// Test error handling
try {
  await electroview.rpc.invalidMethod()
} catch (error) {
  console.error("Expected error:", error);
}

// Measure RPC performance
console.time("RPC call");
const result = await electroview.rpc.getUser("123");
console.timeEnd("RPC call");
ts
// 在webview的DevTools控制台中:

// 测试RPC调用
await electroview.rpc.getUser("123")

// 测试错误处理
try {
  await electroview.rpc.invalidMethod()
} catch (error) {
  console.error("Expected error:", error);
}

// 测量RPC性能
console.time("RPC call");
const result = await electroview.rpc.getUser("123");
console.timeEnd("RPC call");

Performance Profiling

性能分析

CPU Profiling

CPU分析

ts
// Main process CPU profiling
const { performance, PerformanceObserver } = require("perf_hooks");

const obs = new PerformanceObserver((items) => {
  items.getEntries().forEach(entry => {
    logger.debug(`${entry.name}: ${entry.duration}ms`);
  });
});

obs.observe({ entryTypes: ["measure"] });

// Measure operation
performance.mark("operation-start");
await expensiveOperation();
performance.mark("operation-end");
performance.measure("operation", "operation-start", "operation-end");
Webview CPU profiling:
ts
// Use Chrome DevTools Performance tab
// Or programmatically:
console.profile("My Operation");
await performOperation();
console.profileEnd("My Operation");

// Simple timing
const start = performance.now();
await operation();
const duration = performance.now() - start;
console.log(`Operation took ${duration}ms`);
ts
// 主进程CPU分析
const { performance, PerformanceObserver } = require("perf_hooks");

const obs = new PerformanceObserver((items) => {
  items.getEntries().forEach(entry => {
    logger.debug(`${entry.name}: ${entry.duration}ms`);
  });
});

obs.observe({ entryTypes: ["measure"] });

// 测量操作耗时
performance.mark("operation-start");
await expensiveOperation();
performance.mark("operation-end");
performance.measure("operation", "operation-start", "operation-end");
Webview CPU分析:
ts
// 使用Chrome DevTools的Performance面板
// 或通过编程方式:
console.profile("My Operation");
await performOperation();
console.profileEnd("My Operation");

// 简单计时
const start = performance.now();
await operation();
const duration = performance.now() - start;
console.log(`Operation took ${duration}ms`);

Memory Profiling

内存分析

ts
// Main process memory usage
function logMemoryUsage() {
  const usage = process.memoryUsage();
  logger.info("Memory usage", {
    heapUsed: `${Math.round(usage.heapUsed / 1024 / 1024)}MB`,
    heapTotal: `${Math.round(usage.heapTotal / 1024 / 1024)}MB`,
    external: `${Math.round(usage.external / 1024 / 1024)}MB`,
    rss: `${Math.round(usage.rss / 1024 / 1024)}MB`,
  });
}

// Monitor memory over time
setInterval(logMemoryUsage, 10000);

// Force garbage collection (development only)
if (global.gc) {
  global.gc();
  logMemoryUsage();
}
Webview memory profiling:
ts
// Use Chrome DevTools Memory tab
// Or programmatically:
if (performance.memory) {
  console.log("Memory:", {
    used: `${Math.round(performance.memory.usedJSHeapSize / 1024 / 1024)}MB`,
    total: `${Math.round(performance.memory.totalJSHeapSize / 1024 / 1024)}MB`,
    limit: `${Math.round(performance.memory.jsHeapSizeLimit / 1024 / 1024)}MB`,
  });
}
ts
// 主进程内存使用情况
function logMemoryUsage() {
  const usage = process.memoryUsage();
  logger.info("Memory usage", {
    heapUsed: `${Math.round(usage.heapUsed / 1024 / 1024)}MB`,
    heapTotal: `${Math.round(usage.heapTotal / 1024 / 1024)}MB`,
    external: `${Math.round(usage.external / 1024 / 1024)}MB`,
    rss: `${Math.round(usage.rss / 1024 / 1024)}MB`,
  });
}

// 定期监控内存使用情况
setInterval(logMemoryUsage, 10000);

// 强制垃圾回收(仅开发环境可用)
if (global.gc) {
  global.gc();
  logMemoryUsage();
}
Webview内存分析:
ts
// 使用Chrome DevTools的Memory面板
// 或通过编程方式:
if (performance.memory) {
  console.log("Memory:", {
    used: `${Math.round(performance.memory.usedJSHeapSize / 1024 / 1024)}MB`,
    total: `${Math.round(performance.memory.totalJSHeapSize / 1024 / 1024)}MB`,
    limit: `${Math.round(performance.memory.jsHeapSizeLimit / 1024 / 1024)}MB`,
  });
}

Common Issues & Solutions

常见问题与解决方案

Build Errors

构建错误

Issue: "Cannot find module 'electrobun'"
bash
undefined
问题:"Cannot find module 'electrobun'"
bash
undefined

Solution: Install dependencies

解决方案:安装依赖

bun install
bun install

Verify electrobun is installed

验证electrobun是否已安装

bun pm ls electrobun

**Issue: Native module compilation fails**
```bash
bun pm ls electrobun

**问题:原生模块编译失败**
```bash

macOS: Install Xcode Command Line Tools

macOS:安装Xcode命令行工具

xcode-select --install
xcode-select --install

Windows: Install Visual Studio Build Tools

Windows:安装Visual Studio构建工具

Download from visualstudio.microsoft.com

从visualstudio.microsoft.com下载

Linux: Install build essentials

Linux:安装构建必备组件

sudo apt install build-essential

**Issue: "WebView2 not found" (Windows)**
```bash
sudo apt install build-essential

**问题:"WebView2 not found"(Windows)**
```bash

Install WebView2 Runtime

安装WebView2运行时

Download from microsoft.com/edge/webview2

从microsoft.com/edge/webview2下载

undefined
undefined

Runtime Errors

运行时错误

Issue: Window not showing
ts
// Debug checklist:
// 1. Check window is created
console.log("Window created:", win);

// 2. Explicitly show window
win.show();

// 3. Check window bounds
console.log("Window bounds:", win.getBounds());

// 4. Check if window is minimized/hidden
console.log("Window visible:", win.isVisible());
console.log("Window minimized:", win.isMinimized());
Issue: RPC not working
ts
// Debug checklist:
// 1. Verify RPC handlers defined
console.log("RPC handlers:", Object.keys(handlers));

// 2. Check webview loaded
win.on("did-finish-load", () => {
  console.log("Webview loaded");
});

// 3. Test RPC with try-catch
try {
  const result = await electroview.rpc.testMethod();
  console.log("RPC working:", result);
} catch (error) {
  console.error("RPC error:", error);
}

// 4. Check for CORS issues in webview
// 5. Verify Electroview initialized in webview
Issue: High memory usage
ts
// Common causes:
// 1. Memory leaks from event listeners
window.removeEventListener("resize", handler);

// 2. Large data stored in closures
// Use WeakMap/WeakSet for object references

// 3. Not cleaning up resources
win.on("close", () => {
  // Clean up timers
  clearInterval(intervalId);
  // Close connections
  ws.close();
  // Release resources
  cache.clear();
});
问题:窗口未显示
ts
// 调试检查清单:
// 1. 检查窗口是否已创建
console.log("Window created:", win);

// 2. 显式显示窗口
win.show();

// 3. 检查窗口边界
console.log("Window bounds:", win.getBounds());

// 4. 检查窗口是否最小化/隐藏
console.log("Window visible:", win.isVisible());
console.log("Window minimized:", win.isMinimized());
问题:RPC无法工作
ts
// 调试检查清单:
// 1. 验证RPC处理器是否已定义
console.log("RPC handlers:", Object.keys(handlers));

// 2. 检查webview是否已加载完成
win.on("did-finish-load", () => {
  console.log("Webview loaded");
});

// 3. 使用try-catch测试RPC
try {
  const result = await electroview.rpc.testMethod();
  console.log("RPC working:", result);
} catch (error) {
  console.error("RPC error:", error);
}

// 4. 检查webview中的CORS问题
// 5. 验证Electroview是否已在webview中初始化
问题:内存占用过高
ts
// 常见原因:
// 1. 事件监听器导致的内存泄漏
window.removeEventListener("resize", handler);

// 2. 闭包中存储了大量数据
// 使用WeakMap/WeakSet存储对象引用

// 3. 未清理资源
win.on("close", () => {
  // 清理定时器
  clearInterval(intervalId);
  // 关闭连接
  ws.close();
  // 释放缓存
  cache.clear();
});

Platform-Specific Issues

平台特定问题

macOS:
ts
// Issue: App won't open (Gatekeeper)
// Solution: Code sign and notarize

// Issue: Permissions denied
// Solution: Add Info.plist entries
<key>NSCameraUsageDescription</key>
<string>App needs camera access</string>
<key>NSMicrophoneUsageDescription</key>
<string>App needs microphone access</string>
Windows:
ts
// Issue: SmartScreen warning
// Solution: Code sign with trusted certificate

// Issue: Antivirus blocking
// Solution: Code sign and submit to vendors
Linux:
ts
// Issue: WebKit crashes
// Solution: Install webkit2gtk-4.1
sudo apt install libwebkit2gtk-4.1-dev

// Issue: Missing libraries
// Solution: Check dependencies
ldd dist/MyApp
macOS:
ts
// 问题:应用无法打开(Gatekeeper限制)
// 解决方案:进行代码签名与公证

// 问题:权限被拒绝
// 解决方案:在Info.plist中添加权限条目
<key>NSCameraUsageDescription</key>
<string>App needs camera access</string>
<key>NSMicrophoneUsageDescription</key>
<string>App needs microphone access</string>
Windows:
ts
// 问题:SmartScreen警告
// 解决方案:使用可信证书进行代码签名

// 问题:被杀毒软件拦截
// 解决方案:进行代码签名并提交至厂商
Linux:
ts
// 问题:WebKit崩溃
// 解决方案:安装webkit2gtk-4.1
sudo apt install libwebkit2gtk-4.1-dev

// 问题:缺少依赖库
// 解决方案:检查依赖项
ldd dist/MyApp

Debugging Tools

调试工具

Network Inspection

网络检查

ts
// Intercept network requests
win.on("will-navigate", (event) => {
  logger.debug("Navigating to:", event.url);
  
  // Block navigation if needed
  if (event.url.includes("blocked.com")) {
    event.preventDefault();
  }
});

// Monitor requests in DevTools Network tab
// Or programmatically:
win.webContents.session.webRequest.onBeforeRequest((details, callback) => {
  logger.debug("Request:", details.url);
  callback({});
});
ts
// 拦截网络请求
win.on("will-navigate", (event) => {
  logger.debug("Navigating to:", event.url);
  
  // 如有需要可阻止导航
  if (event.url.includes("blocked.com")) {
    event.preventDefault();
  }
});

// 在DevTools的Network面板中监控请求
// 或通过编程方式:
win.webContents.session.webRequest.onBeforeRequest((details, callback) => {
  logger.debug("Request:", details.url);
  callback({});
});

Source Maps

源映射

Ensure source maps are enabled for better debugging:
ts
// tsconfig.json
{
  "compilerOptions": {
    "sourceMap": true,
    "inlineSourceMap": false,
    "inlineSources": true
  }
}
确保启用源映射以提升调试体验:
ts
// tsconfig.json
{
  "compilerOptions": {
    "sourceMap": true,
    "inlineSourceMap": false,
    "inlineSources": true
  }
}

Systematic Debugging Approach

系统化调试方法

ts
// 1. Reproduce the issue consistently
// 2. Isolate the problem (main vs webview)
// 3. Add logging around suspected code
// 4. Use breakpoints in DevTools/debugger
// 5. Check error messages and stack traces
// 6. Review recent changes (git diff)
// 7. Test in isolation (minimal reproduction)
// 8. Check documentation and examples
// 9. Search issues on GitHub
// 10. Ask on Discord

// Debugging template
async function debugIssue() {
  logger.info("=== Debug Session Started ===");
  logger.info("Environment:", {
    platform: process.platform,
    version: app.getVersion(),
    development: process.env.NODE_ENV === "development",
  });
  
  try {
    logger.info("Step 1: Initialize");
    // ...
    
    logger.info("Step 2: Execute");
    // ...
    
    logger.info("Step 3: Verify");
    // ...
    
    logger.info("=== Debug Session Complete ===");
  } catch (error) {
    logger.error("=== Debug Session Failed ===", error);
    throw error;
  }
}
ts
// 1. 稳定复现问题
// 2. 隔离问题(主进程vs webview)
// 3. 在可疑代码周围添加日志
// 4. 在DevTools/调试器中使用断点
// 5. 查看错误信息与堆栈跟踪
// 6. 检查最近的代码变更(git diff)
// 7. 隔离测试(最小化复现案例)
// 8. 查阅文档与示例
// 9. 在GitHub上搜索相关问题
// 10. 在Discord上求助

// 调试模板
async function debugIssue() {
  logger.info("=== Debug Session Started ===");
  logger.info("Environment:", {
    platform: process.platform,
    version: app.getVersion(),
    development: process.env.NODE_ENV === "development",
  });
  
  try {
    logger.info("Step 1: Initialize");
    // ...
    
    logger.info("Step 2: Execute");
    // ...
    
    logger.info("Step 3: Verify");
    // ...
    
    logger.info("=== Debug Session Complete ===");
  } catch (error) {
    logger.error("=== Debug Session Failed ===", error);
    throw error;
  }
}

Resources

资源

For more on Electrobun:
更多关于Electrobun的资源: