返回笔记首页

Electron 桌面端项目简历示例

主题配置

示例一:企业 IM 桌面客户端(Electron)

项目名称

XX 企业即时通讯桌面端(Electron)

项目背景

公司内部沟通使用 Web 版 IM,但员工反馈 Web 版功能受限,体验差,需要桌面客户端。选择 Electron 复用现有 Web 技术栈,快速开发 Windows/Mac 双平台客户端。

业务场景

  • 即时通讯:单聊、群聊、文件传输、屏幕共享
  • 视频会议:多人音视频、屏幕演示、会议录制
  • 组织架构:部门管理、员工通讯录、在线状态
  • 工作协同:日程安排、任务管理、公告通知
  • 文件管理:企业云盘、文件同步、版本管理

核心职责

1. 本地缓存 - 聊天记录

业务场景: 员工需要查询历史聊天记录、搜索文件

问题
  • Web 版刷新后聊天记录丢失
  • 查询历史消息需要请求服务器,慢
  • 无法离线查看聊天记录
解决方案
  • 使用 better-sqlite3 本地数据库存储
  • 消息实时保存到本地
  • 支持全文搜索、按时间筛选
  • 媒体文件存储到用户文档目录
技术实现
javascript
// main.js (主进程)
const Database = require('better-sqlite3');
const path = require('path');
const { app } = require('electron');

class MessageDB {
  constructor() {
    const dbPath = path.join(app.getPath('userData'), 'messages.db');
    this.db = new Database(dbPath);
    this.init();
  }

  init() {
    this.db.exec(`
      CREATE TABLE IF NOT EXISTS messages (
        id TEXT PRIMARY KEY,
        conversation_id TEXT,
        sender_id TEXT,
        content TEXT,
        timestamp INTEGER,
        type TEXT,
        media_path TEXT
      );
      CREATE INDEX IF NOT EXISTS idx_conversation ON messages(conversation_id);
      CREATE INDEX IF NOT EXISTS idx_timestamp ON messages(timestamp);
    `);
  }

  saveMessage(msg) {
    const stmt = this.db.prepare(`
      INSERT OR REPLACE INTO messages
      (id, conversation_id, sender_id, content, timestamp, type, media_path)
      VALUES (?, ?, ?, ?, ?, ?, ?)
    `);
    stmt.run(msg.id, msg.conversationId, msg.senderId, msg.content,
             msg.timestamp, msg.type, msg.mediaPath);
  }

  getMessages(conversationId, limit = 50) {
    const stmt = this.db.prepare(`
      SELECT * FROM messages
      WHERE conversation_id = ?
      ORDER BY timestamp DESC
      LIMIT ?
    `);
    return stmt.all(conversationId, limit);
  }

  searchMessages(keyword) {
    const stmt = this.db.prepare(`
      SELECT * FROM messages
      WHERE content LIKE ?
      ORDER BY timestamp DESC
    `);
    return stmt.all(`%${keyword}%`);
  }
}

module.exports = new MessageDB();
项目成果
  • 聊天记录加载时间从 2 秒降到 100ms
  • 支持离线查看所有历史消息
  • 全文搜索 1 万条消息只需 200ms

2. 启动优化 - 快速启动

业务场景: 员工上班打开客户端,需要快速进入工作状态

问题
  • 冷启动需要 5 秒,白屏时间长
  • 首次加载资源多,渲染慢
  • 登录后还要加载大量数据
解决方案
  • 窗口预创建,提前初始化主窗口
  • 使用 v8-compile-cache 加速 JS 加载
  • 资源本地化,减少网络请求
  • 数据预加载,并行请求关键数据
技术实现
javascript
// main.js
require('v8-compile-cache');
const { app, BrowserWindow } = require('electron');

let mainWindow = null;

// 预创建窗口
app.on('ready', () => {
  mainWindow = new BrowserWindow({
    width: 1200,
    height: 800,
    show: false,  // 先不显示
    backgroundColor: '#fff',
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false,
      enableRemoteModule: true
    }
  });

  // 加载本地文件
  mainWindow.loadFile('index.html');

  // 首次渲染完成后显示
  mainWindow.once('ready-to-show', () => {
    mainWindow.show();
  });

  // 优化渲染进程
  mainWindow.webContents.on('did-finish-load', () => {
    mainWindow.webContents.send('preload-data');
  });
});

// 预加载子窗口
function preloadWindows() {
  const videoWindow = new BrowserWindow({
    width: 800,
    height: 600,
    show: false
  });
  videoWindow.loadFile('video.html');
}

app.on('ready', () => {
  setTimeout(preloadWindows, 3000);
});
项目成果
  • 启动时间从 5 秒优化到 1.2 秒
  • 窗口切换瞬间响应
  • 登录到工作台 2 秒内完成

3. 离线存储 - 文件同步

业务场景: 员工发送的文件需要本地保存,支持离线访问

问题
  • 文件每次都从服务器下载,浪费流量
  • 大文件下载慢,影响使用
  • 无法离线查看文件
解决方案
  • 文件自动下载到本地目录
  • 使用文件 hash 去重,节省空间
  • 支持大文件断点续传
  • 定期清理过期文件
技术实现
javascript
// file-manager.js
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const { app } = require('electron');

class FileManager {
  constructor() {
    this.cacheDir = path.join(app.getPath('userData'), 'files');
    if (!fs.existsSync(this.cacheDir)) {
      fs.mkdirSync(this.cacheDir, { recursive: true });
    }
  }

  async downloadFile(url, fileId) {
    const filePath = path.join(this.cacheDir, fileId);

    // 已存在直接返回
    if (fs.existsSync(filePath)) {
      return filePath;
    }

    // 下载文件
    const response = await fetch(url);
    const buffer = await response.arrayBuffer();

    // 保存到本地
    fs.writeFileSync(filePath, Buffer.from(buffer));

    return filePath;
  }

  getFileHash(filePath) {
    const buffer = fs.readFileSync(filePath);
    return crypto.createHash('md5').update(buffer).digest('hex');
  }

  cleanOldFiles(days = 30) {
    const files = fs.readdirSync(this.cacheDir);
    const now = Date.now();
    const maxAge = days * 24 * 60 * 60 * 1000;

    files.forEach(file => {
      const filePath = path.join(this.cacheDir, file);
      const stats = fs.statSync(filePath);

      if (now - stats.mtimeMs > maxAge) {
        fs.unlinkSync(filePath);
      }
    });
  }

  getCacheSize() {
    let totalSize = 0;
    const files = fs.readdirSync(this.cacheDir);

    files.forEach(file => {
      const filePath = path.join(this.cacheDir, file);
      const stats = fs.statSync(filePath);
      totalSize += stats.size;
    });

    return totalSize;
  }
}

module.exports = new FileManager();
项目成果
  • 文件加载速度提升 90%
  • 流量消耗减少 70%
  • 支持离线查看所有文件

4. Native 能力 - 系统集成

业务场景: 新消息通知、截图、文件拖拽、托盘图标

问题
  • Web 版无法实现系统级功能
  • 需要调用 Windows/Mac 原生 API
  • 双平台差异需要处理
解决方案
  • 封装统一的 Native API
  • 使用 Electron API 实现跨平台
  • 平台差异通过 process.platform 判断
  • 第三方库补充不支持的功能
技术实现
javascript
// native-api.js
const { Notification, clipboard, nativeImage, screen, desktopCapturer } = require('electron');
const screenshot = require('screenshot-desktop');

class NativeAPI {
  // 显示通知
  showNotification(title, body, onclick) {
    const notification = new Notification({ title, body });
    notification.onclick = onclick;
    notification.show();
  }

  // 复制到剪贴板
  copyToClipboard(text) {
    clipboard.writeText(text);
  }

  // 截图
  async takeScreenshot() {
    try {
      if (process.platform === 'darwin') {
        // Mac 使用 screencapture
        return await this._macScreenshot();
      } else {
        // Windows 使用 screenshot-desktop
        const img = await screenshot({ format: 'png' });
        return img;
      }
    } catch (error) {
      console.error('截图失败:', error);
      return null;
    }
  }

  // 获取屏幕信息
  getScreens() {
    return screen.getAllDisplays();
  }

  // 文件拖拽
  setupFileDrop(window) {
    window.webContents.on('will-navigate', (event, url) => {
      event.preventDefault();
    });

    window.webContents.on('drop-files', (event, files) => {
      event.preventDefault();
      window.webContents.send('files-dropped', files);
    });
  }
}

module.exports = new NativeAPI();
项目成果
  • 支持系统通知、托盘、快捷键
  • 截图功能使用率 80%
  • 文件拖拽发送效率提升 60%

5. 崩溃监控 - 稳定性保障

业务场景: 客户端偶尔崩溃,影响员工工作

问题
  • 崩溃后无日志,无法定位
  • 不知道哪些用户遇到问题
  • 修复缺少数据支持
解决方案
  • 接入 electron-sentry 收集崩溃
  • 主进程和渲染进程分别监控
  • 记录用户操作路径
  • 崩溃后自动重启
技术实现
javascript
// main.js
const { app, crashReporter } = require('electron');
const Sentry = require('@sentry/electron');

// 初始化 Sentry
Sentry.init({
  dsn: 'https://xxx@sentry.io/xxx',
  beforeSend(event) {
    // 添加额外信息
    event.user = {
      id: global.userId,
      username: global.username
    };
    return event;
  }
});

// 崩溃报告
crashReporter.start({
  productName: 'XX IM',
  companyName: 'XX Company',
  submitURL: 'https://crash.example.com/report',
  uploadToServer: true
});

// 未捕获异常
process.on('uncaughtException', (error) => {
  Sentry.captureException(error);

  // 崩溃后重启
  app.relaunch();
  app.exit(0);
});

// 渲染进程崩溃
app.on('render-process-gone', (event, webContents, details) => {
  Sentry.captureMessage('Renderer crashed', {
    level: 'error',
    extra: { details }
  });

  // 重新加载
  if (details.reason !== 'clean-exit') {
    webContents.reload();
  }
});
项目成果
  • 崩溃率从 5% 降到 0.5%
  • 问题定位时间从 1 天缩短到 30 分钟
  • 发现并修复 20+ 个稳定性问题

6. 自动更新 - 版本管理

业务场景: 客户端需要更新功能、修复 bug

问题
  • 员工版本不一致,支持困难
  • 手动下载安装繁琐
  • 更新覆盖率低
解决方案
  • 使用 electron-updater 自动更新
  • 支持全量更新和增量更新
  • 静默更新 + 强制更新
  • 更新失败自动回滚
技术实现
javascript
// updater.js
const { autoUpdater } = require('electron-updater');
const { dialog } = require('electron');

class Updater {
  constructor(mainWindow) {
    this.mainWindow = mainWindow;
    this.init();
  }

  init() {
    // 设置更新服务器
    autoUpdater.setFeedURL({
      provider: 'generic',
      url: 'https://update.example.com/releases'
    });

    // 检查更新
    autoUpdater.on('checking-for-update', () => {
      console.log('检查更新...');
    });

    // 发现新版本
    autoUpdater.on('update-available', (info) => {
      dialog.showMessageBox(this.mainWindow, {
        type: 'info',
        title: '发现新版本',
        message: `版本 ${info.version} 可用`,
        buttons: ['立即更新', '稍后']
      }).then(result => {
        if (result.response === 0) {
          autoUpdater.downloadUpdate();
        }
      });
    });

    // 无可用更新
    autoUpdater.on('update-not-available', () => {
      console.log('已是最新版本');
    });

    // 下载进度
    autoUpdater.on('download-progress', (progress) => {
      this.mainWindow.webContents.send('download-progress', progress.percent);
    });

    // 下载完成
    autoUpdater.on('update-downloaded', () => {
      dialog.showMessageBox(this.mainWindow, {
        type: 'info',
        title: '更新完成',
        message: '新版本已下载,是否立即重启?',
        buttons: ['立即重启', '稍后']
      }).then(result => {
        if (result.response === 0) {
          autoUpdater.quitAndInstall();
        }
      });
    });

    // 错误处理
    autoUpdater.on('error', (error) => {
      console.error('更新失败:', error);
    });
  }

  checkForUpdates() {
    autoUpdater.checkForUpdates();
  }
}

module.exports = Updater;
项目成果
  • 更新覆盖率从 60% 提升到 95%
  • 版本统一,降低支持成本
  • 关键 bug 修复后 24 小时内全员更新

技术栈

Electron、React、TypeScript、better-sqlite3、electron-updater、Sentry

项目成果

  • 支持 Windows 7+ 和 macOS 10.12+
  • 装机量 10 万+,日活 8 万+
  • 启动时间 1.2 秒,接近原生
  • 包体积 80MB(含运行时)
  • 崩溃率 0.5%,行业领先
  • 开发周期 3 个月,节省 60% 成本

示例二:代码编辑器(Electron)

项目名称

XX 轻量级代码编辑器(Electron)

项目背景

开发者需要轻量级的代码编辑器,VSCode 太重,记事本功能太弱。基于 Electron 打造一款启动快、占用少的编辑器。

业务场景

  • 代码编辑:语法高亮、代码补全、多光标
  • 文件管理:目录树、文件搜索、快速打开
  • 终端集成:内置终端、命令执行
  • 插件系统:主题、语言支持、功能扩展
  • 版本控制:Git 集成、差异对比

核心职责

1. 文件缓存 - 最近打开

业务场景: 记录最近打开的文件和项目

解决方案
  • 使用 electron-store 存储配置
  • 记录文件路径、打开时间、光标位置
  • 下次打开自动恢复
技术实现
javascript
const Store = require('electron-store');

const store = new Store({
  defaults: {
    recentFiles: [],
    recentProjects: [],
    editorSettings: {}
  }
});

function addRecentFile(filePath, cursorPos) {
  const recentFiles = store.get('recentFiles');

  // 去重
  const filtered = recentFiles.filter(f => f.path !== filePath);

  // 添加到最前面
  filtered.unshift({
    path: filePath,
    openedAt: Date.now(),
    cursorPos
  });

  // 只保留最近 20 个
  store.set('recentFiles', filtered.slice(0, 20));
}
项目成果
  • 最近文件秒开
  • 自动恢复编辑状态
  • 提升开发效率 30%

2. 启动优化 - 极速启动

业务场景: 快速打开编辑器写代码

解决方案
  • 延迟加载插件
  • 窗口预创建
  • 使用 Web Worker 解析文件
项目成果
  • 启动时间 0.5 秒
  • 打开 10MB 文件不卡顿
  • 内存占用 < 100MB

3. 文件监听 - 自动刷新

业务场景: 文件被外部修改时自动刷新

解决方案
  • 使用 chokidar 监听文件变化
  • 检测到变化后提示用户
  • 支持自动重载
项目成果
  • 文件同步准确率 100%
  • 避免编辑冲突
  • 团队协作效率提升

技术栈

Electron、Monaco Editor、React、chokidar

项目成果

  • 启动时间 0.5 秒,比 VSCode 快 10 倍
  • 内存占用 < 100MB,比 VSCode 少 5 倍
  • 支持 20+ 种编程语言
  • GitHub Stars 5000+

面试话术(Electron 项目)

开场(30 秒)

"我做的是一个企业 IM 的桌面客户端,用的是 Electron。选择 Electron 主要是因为我们已经有 Web 版,可以复用现有代码。而且 Electron 可以调用系统 API,实现系统通知、截图、文件管理这些 Web 做不到的功能。"

亮点展开

如果问 Electron 性能: "Electron 确实比原生重一些,但通过优化可以做得很好。我主要做了三方面:一是启动优化,通过窗口预创建和资源本地化,启动时间从 5 秒降到 1.2 秒;二是内存优化,使用本地数据库缓存数据,避免内存堆积;三是进程通信优化,减少主进程和渲染进程的通信次数。"

如果问技术难点: "最难的是跨平台适配。Windows 和 Mac 很多 API 不一样,比如截图功能,Mac 可以用 screencapture 命令,Windows 需要用第三方库。我封装了一层统一接口,根据 process.platform 判断调用哪个实现。还有就是文件路径,Windows 用反斜杠,Mac 用斜杠,需要统一处理。"

如果问和 Web 的区别: "Electron 最大的优势是可以访问系统 API。比如我们实现了系统通知、托盘图标、全局快捷键、文件系统访问,这些 Web 做不到。而且 Electron 可以做多窗口,我们的视频会议就是独立窗口,可以最小化到托盘后台运行。"

数据记忆

  • 启动时间 5s → 1.2s
  • 聊天记录加载 2s → 100ms
  • 崩溃率 5% → 0.5%
  • 更新覆盖率 60% → 95%
  • 装机量 10 万+
  • 日活 8 万+
  • 包体积 80MB