Files
koring-launcher/plans/tauri-to-electron.md
T
2026-07-11 23:33:44 +08:00

15 KiB
Raw Permalink Blame History

迁移计划:Tauri 2 → Electron 已完成

状态:已全部完成。 所有阶段已执行,Tauri 后端和 sidecar 已移除,Electron 主进程已正常运行。

概述

将 koring-launcher 从 Tauri 2Rust 后端 + Node.js sidecar)迁移到 ElectronNode.js 主进程)。sidecar 的 @xmcl/* 包直接集成到 Electron 主进程中,不再需要独立的 sidecar 二进制文件和 stdin/stdout IPC。


架构变更

迁移前(Tauri

前端 (React) ←→ Rust (Tauri) ←→ Sidecar (Node.js/@xmcl)
       ↕ invoke()         ↕ spawn stdin/stdout
       ↕ listen events    ↕ emit events

迁移后(Electron

前端 (React) ←→ Electron 主进程 (Node.js/@xmcl)
       ↕ ipcRenderer.invoke()      ↕ ipcMain.handle()
       ↕ ipcRenderer.on()          ↕ webContents.send()

Rust 后端和 sidecar 完全移除。所有功能都在 Electron 主进程中以 ipcMain.handle() 处理器的形式存在。


阶段一:项目初始化

1.1 初始化 Electron

  • 在项目根目录创建 electron/ 目录
  • 创建 electron/main.tsElectron 主进程入口)
  • 创建 electron/preload.tscontext bridge 用于 IPC
  • 更新根目录 package.json
    • 移除 @tauri-apps/api@tauri-apps/plugin-*
    • 添加 electronelectron-builderelectron-vite
    • 添加 electron-store(用于配置/认证持久化)
    • 添加 electron-updater(用于自动更新)
    • 更新脚本:devbuildbuild:winbuild:macbuild:linux
  • 创建 electron-builder.yml 用于打包配置
  • 更新 vite.config.ts 兼容 Electron(移除 Tauri 相关配置)

1.2 清理 Tauri 相关文件

  • 完全删除 src-tauri/ 目录
  • 完全删除 sidecar/ 目录
  • 删除 .tauri/ 签名密钥
  • 删除 build-all.cmdbuild-arch.cmdbuild-vs.cmddev-vs.cmd
  • 保留 scripts/switch-icon.js(已重写为 Electron 风格)
  • 清理 package.json 脚本(移除所有 tauri 相关脚本)
  • 更新 .gitignore 移除 Tauri 相关条目

阶段二:Electron 主进程

2.1 主进程入口(electron/main.ts

import { app, BrowserWindow, ipcMain, dialog } from 'electron';
import path from 'path';

// 窗口管理
// Splash → Main 过渡(4秒计时器)
// 单实例锁定
// 应用生命周期事件

核心职责:

  • 创建 splash 窗口(480x320,透明,无边框)
  • 创建主窗口(1000x700,透明,无边框,初始隐藏)
  • 4秒后关闭 splash,显示主窗口
  • 处理应用退出(终止所有运行中的 MC 进程)

2.2 IPC 处理器

将所有 16 个 Tauri 命令替换为 ipcMain.handle()

Tauri 命令 Electron IPC 频道 说明
sidecar_request 已移除 不再需要,直接调用具体处理器
install_minecraft install:minecraft 直接使用 @xmcl/installer
install_mod_loader install:mod-loader 直接使用 @xmcl/installer
get_version_list install:version-list 直接使用 @xmcl/installer
launch_game launch:launch 直接使用 @xmcl/core
offline_login auth:offline-login 直接使用 @xmcl/user
search_mods mods:search 直接使用 @xmcl/modrinth
install_mod mods:install 直接使用 @xmcl/modrinth
create_instance instance:create 直接文件 I/O
list_instances instance:list 直接文件 I/O
get_config config:get electron-store 或 YAML 文件
save_config config:save electron-store 或 YAML 文件
get_auth auth:get electron-store(替代注册表)
save_auth auth:save electron-store(替代注册表)
delete_auth_cmd auth:delete electron-store
get_system_info system:info process.versionsos 模块

新增频道(替代 sidecar 事件转发):

  • install:progresswebContents.send('install:progress', data)
  • install:completewebContents.send('install:complete', data)
  • launch:eventswebContents.send('launch:events', data)
  • task:progresswebContents.send('task:progress', data)
  • task:completedwebContents.send('task:completed', data)

2.3 配置系统(electron/config.ts

从 Rust config.rs 迁移到 Node.js

  • 保持 YAML 格式(使用 js-yaml 库)
  • 保持稀疏保存逻辑(与默认值做 diff,只保存非默认值)
  • 存储路径:打包后使用 app.getPath('exe') 父目录

2.4 认证系统(electron/auth.ts

从 Windows 注册表迁移到 electron-store

  • 使用 electron-store 存储认证数据(跨平台 JSON
  • 可选使用 safeStorage 加密

2.5 Sidecar → 主进程集成

将所有 sidecar 模块直接移入主进程:

  • electron/core/auth.tssidecar/src/core/auth.tsMicrosoft OAuth、离线登录)
  • electron/core/installer.tssidecar/src/core/installer.ts@xmcl/installer
  • electron/core/launcher.tssidecar/src/core/launcher.ts@xmcl/core
  • electron/core/modrinth.tssidecar/src/core/modrinth.tsMod API
  • electron/handlers/sidecar/src/handlers/(将 stdin/stdout 改为 IPC
  • electron/utils/paths.tssidecar/src/utils/paths.ts

关键变更sidecar 使用 sendResult(id, data) / sendProgress(id, data) 通过 stdout 发送。现在改用 webContents.send(channel, data) 直接发送。

2.6 窗口管理

替换 Tauri 窗口 API

  • @tauri-apps/api/window → Electron BrowserWindow 方法
  • 自定义标题栏:移除 data-tauri-drag-region,改用 CSS -webkit-app-region: drag 实现无边框窗口拖拽
  • 窗口控制按钮:ipcRenderer.invoke('window:minimize')ipcRenderer.invoke('window:maximize')ipcRenderer.invoke('window:close')

阶段三:前端迁移

3.1 API 层重写

src/api/sidecar.tssrc/api/ipc.ts

  • 替换 invoke("sidecar_request", ...)window.electronAPI.invoke('channel', payload)
  • 替换 listen("sidecar-response", ...)window.electronAPI.on('channel', callback)
  • 移除基于 requestId 的事件过滤(每个 IPC 频道是独立的)

src/api/config.ts

  • invoke("get_config")window.electronAPI.invoke('config:get')
  • invoke("save_config", { cfg })window.electronAPI.invoke('config:save', config)

src/api/auth-registry.ts

  • invoke("get_auth")window.electronAPI.invoke('auth:get')
  • invoke("save_auth", { auth })window.electronAPI.invoke('auth:save', auth)
  • invoke("delete_auth_cmd")window.electronAPI.invoke('auth:delete')

src/api/update.ts

  • 替换 @tauri-apps/plugin-updaterelectron-updater
  • checkForUpdates()window.electronAPI.invoke('update:check')
  • downloadAndInstall()window.electronAPI.invoke('update:install')
  • relaunchApp()window.electronAPI.invoke('app:relaunch')

src/api/system.ts

  • invoke("get_system_info")window.electronAPI.invoke('system:info')

3.2 移除 Tauri 导入

需要更新的文件(移除所有 @tauri-apps/* 导入):

文件 Tauri 导入 替换为
src/api/sidecar.ts @tauri-apps/api/core, @tauri-apps/api/event window.electronAPI
src/api/config.ts @tauri-apps/api/core window.electronAPI
src/api/auth-registry.ts @tauri-apps/api/core window.electronAPI
src/api/update.ts @tauri-apps/plugin-updater, @tauri-apps/plugin-process window.electronAPI
src/api/system.ts @tauri-apps/api/core window.electronAPI
src/hooks/useTheme.ts @tauri-apps/api/window window.electronAPI
src/components/system/WindowControls.tsx @tauri-apps/api/window window.electronAPI
src/components/system/TitleBar.tsx @tauri-apps/api/window window.electronAPI
src/components/system/SystemLayer.tsx @tauri-apps/api/window window.electronAPI

3.3 Preload 脚本 / Context Bridge

创建 electron/preload.ts

import { contextBridge, ipcRenderer } from 'electron';

contextBridge.exposeInMainWorld('electronAPI', {
  invoke: (channel: string, ...args: unknown[]) =>
    ipcRenderer.invoke(channel, ...args),
  on: (channel: string, callback: (...args: unknown[]) => void) => {
    ipcRenderer.on(channel, (_event, ...args) => callback(...args));
    return () => ipcRenderer.removeListener(channel, callback);
  },
  send: (channel: string, ...args: unknown[]) =>
    ipcRenderer.send(channel, ...args),

  // 窗口控制
  minimize: () => ipcRenderer.invoke('window:minimize'),
  maximize: () => ipcRenderer.invoke('window:maximize'),
  close: () => ipcRenderer.invoke('window:close'),
  isMaximized: () => ipcRenderer.invoke('window:isMaximized'),
  onResized: (callback: () => void) => {
    ipcRenderer.on('window:resized', callback);
    return () => ipcRenderer.removeListener('window:resized', callback);
  },

  // 主题
  getTheme: () => ipcRenderer.invoke('window:getTheme'),
});

src/types/electron.d.ts 中添加 TypeScript 类型声明。

3.4 窗口控制更新

src/components/system/WindowControls.tsx

  • 移除 getCurrentWindow() from @tauri-apps/api/window
  • 使用 window.electronAPI.minimize().maximize().close()
  • 使用 window.electronAPI.isMaximized()window.electronAPI.onResized()

src/components/system/TitleBar.tsx

  • 移除 getCurrentWindow() 拖拽区域
  • 使用 CSS -webkit-app-region: drag 实现无边框窗口拖拽
  • 移除 appWindow.startDragging() 调用

src/hooks/useTheme.ts

  • 移除 getCurrentWindow().theme() from @tauri-apps/api/window
  • 使用 window.electronAPI.getTheme() 替代
  • 保留 matchMedia 回退方案

3.5 Splash 屏幕

splash.html:无需更改(纯 HTML/CSS src/components/splash/Splash.tsx:无需更改(纯 React

3.6 Vite 配置更新

更新 vite.config.ts

  • 移除 ignore 中的 src-tauri/
  • 如果使用 electron-vite,添加 Electron 特定配置
  • 确保 base: './' 以支持 Electron 的 file:// 协议

阶段四:构建与打包

4.1 Electron Builder 配置

创建 electron-builder.yml

appId: com.lingke.koring.launcher
productName: Koring Launcher
directories:
  output: dist-electron
files:
  - dist/**          # Vite 构建输出
  - electron/**      # 主进程代码
win:
  target: nsis
  icon: public/run.ico
mac:
  target: dmg
  icon: public/run.png
linux:
  target: AppImage
nsis:
  oneClick: false
  allowToChangeInstallationDirectory: true

4.2 开发脚本

# 开发
pnpm dev:renderer    # Vite 开发服务器
pnpm dev:main        # electron-vite 启动 Electron
pnpm dev             # 同时运行两个(concurrently

# 构建
pnpm build           # Vite 构建 + Electron 打包
pnpm build:win       # Windows 安装程序

4.3 构建模式(dev/beta/run

  • 保留 VITE_BUILD_MODE 环境变量
  • 使用 electron-builder 不同配置:
    • electron-builder.dev.yml — 不签名,不更新
    • electron-builder.beta.yml — beta 更新通道
    • electron-builder.yml — 正式版

阶段五:自动更新

@tauri-apps/plugin-updater 替换为 electron-updater

5.1 主进程

import { autoUpdater } from 'electron-updater';

ipcMain.handle('update:check', async () => {
  return autoUpdater.checkForUpdates();
});

ipcMain.handle('update:install', async () => {
  autoUpdater.downloadUpdate();
});

autoUpdater.on('update-available', (info) => {
  mainWindow.webContents.send('update:available', info);
});

autoUpdater.on('download-progress', (progress) => {
  mainWindow.webContents.send('update:progress', progress);
});

5.2 前端

// src/api/update.ts
export async function checkForUpdates() {
  return window.electronAPI.invoke('update:check');
}

export function onUpdateAvailable(callback: (info: any) => void) {
  return window.electronAPI.on('update:available', callback);
}

export function onUpdateProgress(callback: (progress: any) => void) {
  return window.electronAPI.on('update:progress', callback);
}

阶段六:测试与清理

6.1 测试清单

  • Splash 屏幕显示 1.5 秒后主窗口出现
  • 自定义标题栏正常工作(最小化/最大化/关闭)
  • 无边框窗口拖拽正常
  • 暗色模式跟随系统同步
  • 配置正确加载/保存(Koring.yml
  • 认证正确存储/加载(JSON 文件)
  • Microsoft OAuth 流程正常(打开浏览器 → 回调)
  • 离线登录正常
  • Minecraft 安装带进度条正常
  • 游戏启动带事件流正常
  • Mod 搜索/安装正常(Modrinth/CurseForge
  • 实例 创建/列表/删除 正常
  • 自动更新 检查/下载 正常
  • 任务队列正常(进度、取消、重试)
  • 构建模式(dev/beta/run)显示正确的图标/徽章
  • NSIS 安装程序正确构建
  • 打包后应用正常运行

6.2 文件清理

  • 删除 src-tauri/ 目录
  • 删除 sidecar/ 目录
  • 删除 .tauri/ 目录
  • 删除 *.cmd 构建脚本
  • 保留 scripts/ 目录(switch-icon.js 已重写)
  • 移除 .vscode/extensions.json 中的 src-tauri 引用
  • 更新 AGENTS.md 为新的 Electron 架构
  • 更新 DEV.md 为 Electron 开发说明
  • 更新 README.md

6.3 新文件结构

koring-launcher/
├── electron/                    # Electron 主进程
│   ├── main.ts                  # 主入口
│   ├── preload.ts               # Context bridge
│   ├── config.ts                # 配置(YAML)管理
│   ├── auth.ts                  # 认证(electron-store)管理
│   ├── core/                    # 从 sidecar 迁移
│   │   ├── auth.ts              # @xmcl/user 认证
│   │   ├── installer.ts         # @xmcl/installer 安装
│   │   ├── launcher.ts          # @xmcl/core 启动
│   │   └── modrinth.ts          # @xmcl/modrinth Mod API
│   ├── handlers/                # IPC 处理器
│   │   ├── install.ts
│   │   ├── launch.ts
│   │   ├── auth.ts
│   │   ├── mods.ts
│   │   ├── instance.ts
│   │   ├── background.ts
│   │   └── task.ts
│   └── utils/
│       └── paths.ts
├── src/                         # 前端(基本不变)
├── dist/                        # Vite 构建输出
├── electron-builder.yml
├── vite.config.ts
├── package.json
└── index.html

迁移顺序

  1. 阶段一 — 项目初始化(Electron 脚手架、移除 Tauri 依赖)
  2. 阶段二 — 主进程(IPC 处理器、配置、认证、sidecar 集成)
  3. 阶段三 — 前端迁移(API 层、导入、preload bridge
  4. 阶段四 — 构建与打包(electron-builder、开发脚本)
  5. 阶段五 — 自动更新(electron-updater
  6. 阶段六 — 测试与清理

预计工作量:大规模重构。每个阶段应独立测试后再进入下一阶段。