从Clash-Verge-Rev源码构建专属自己的版本


从 Clash Verge Rev 2.3.1 定制 CV-Damao:隔离、排错与 Windows 打包记录

本文记录将 Clash Verge Rev 2.3.1 定制为独立 Windows 客户端 CV-Damao 的过程。目标不只是修改名称,而是让定制版能够和官方版本同时安装、同时运行,并解决打包后一直停留在 Loading CV-Damao... 的问题。

最终目标

定制版需要满足以下要求:

  • 应用名称为 CV-Damao,程序名为 cv-damao.exe
  • 不覆盖官方版本的配置、快捷方式、自启动项和 URL 协议。
  • 不停止、卸载或调用官方的 Windows 服务。
  • 两套 GUI、数据目录、普通代理内核和控制端口可以并行运行。
  • 不使用官方自动更新渠道。
  • 能生成可正常安装的 Windows NSIS 安装包。

需要提前说明:Windows 系统代理和 TUN 都是系统级资源,无法由两个客户端同时独立接管。

一、品牌与应用标识隔离

首先修改应用的基础标识:

  • 产品名称:CV-Damao
  • 可执行文件:cv-damao.exe
  • Tauri Identifier:app.cv-damao.desktop
  • URL 协议:cv-damao://
  • 单实例端口:从 33331 改为 33332
  • Mihomo 控制端口:从 9097 改为 19097
  • 默认使用随机 mixed port

同时修改了窗口标题、托盘提示、启动加载文字、PE 元数据、便携包名称和安装包名称。

应用数据目录也随 Identifier 隔离到:

%APPDATA%\app.cv-damao.desktop

备份目录、自启动快捷方式和 URL 协议注册项均使用新的名称,避免和官方版本互相覆盖。

侧栏原本使用带有 Clash Verge 字样的 SVG 字标,最后也替换为 CV-Damao 文本,确保主要用户界面不再显示旧品牌。

二、安装器不能操作官方版本

原始 NSIS 脚本包含停止进程、管理服务、删除快捷方式和清理数据的逻辑。对于定制版,这些操作可能误伤已经安装的官方客户端。

因此修改 src-tauri/packages/windows/installer.nsi,移除了可能执行以下操作的代码:

  • 停止官方 GUI 或代理内核。
  • 停止、卸载官方 Windows 服务。
  • 删除官方自启动项。
  • 删除官方快捷方式或数据目录。

安装和卸载 CV-Damao 时,只处理自己的文件和注册项。

三、Windows 服务隔离

这是整个定制过程中最需要注意的部分。

上游预编译的 clash-verge-service.exe 将以下内容硬编码在二进制中:

服务名:clash_verge_service
IPC:\\.\pipe\clash-verge-service

仅修改 Rust 客户端里的名称不能得到第二套独立服务,反而可能让定制版连接并管理官方服务。实测中,官方服务还会代替定制版启动仓库内的 Mihomo,导致 GUI 退出后进程仍然存在,并占用 release 目录中的文件。

最终方案是:Windows 定制版完全禁用共享服务模式,固定使用自身 sidecar。

src-tauri/src/core/core.rs 中,Windows 下的初始化和重启都直接调用:

start_core_by_sidecar()

src-tauri/src/cmd/service.rs 中:

  • 安装、卸载、重装和修复服务的命令直接返回禁用提示。
  • 服务可用性检测固定返回 false

这样定制版不会探测、调用或管理官方的 clash_verge_service

代价是:sidecar 在普通用户权限下运行,需要管理员权限的 TUN 功能可能不可用。要实现真正独立的第二套 Windows 服务,需要重新构建服务程序,并修改其服务名和 IPC,而不是只修改 GUI 仓库。

四、Loading 卡死的定位过程

最棘手的问题是:release 程序能够启动,后端配置验证和 Mihomo 也正常,但界面一直停留在:

Loading CV-Damao...

后端日志显示窗口已经创建,但前端始终没有调用 update_ui_stage,因此初始化遮罩没有被移除。这说明问题不在 Mihomo 或 Rust 初始化,而在 React 启动阶段。

为了捕获 release WebView 的错误,临时在窗口创建代码中加入:

window.open_devtools();

DevTools 控制台显示真正的异常:

Uncaught TypeError: Cannot set properties of undefined (setting 'AsyncMode')

继续检查构建产物后发现,Vite 的自定义 manualChunks 生成了两个互相导入的块:

react-*.js
small-vendors-*.js

这造成循环依赖和模块初始化顺序错误,React 还未完成初始化就被其他 vendor 代码使用,最终导致整个前端入口崩溃。

修复方法很简单:删除 vite.config.mts 中自定义的 vendor manualChunks,让 Rollup 自动分块。

重新构建后:

  • 循环导入消失。
  • React 正常挂载。
  • initial-loading-overlay 被移除。
  • 日志依次出现 LoadingDomReadyResourcesLoaded 和“UI已完全加载”。

确认问题解决后,临时加入的 open_devtools() 也被删除。

五、自动更新处理

定制版没有上游项目的 updater 私钥,也不应该下载官方更新包。因此进行了以下调整:

  • 默认关闭自动更新。
  • 更新地址改为无效的保留域名。
  • createUpdaterArtifacts 设置为 false

否则 Tauri 可能在构建阶段要求更新签名私钥,运行后也可能错误接收官方版本的更新。

六、构建过程中的 Windows 缓存问题

主要构建命令为:

pnpm install --frozen-lockfile --force
pnpm prebuild
pnpm web:build
pnpm exec tauri build --bundles nsis --ci

Rust release 编译成功后,NSIS 阶段曾多次报错:

对象管理器在检索对象时遇到重分析点。 (os error 4395)

问题来自 Tauri 的 NSIS 工具缓存,而不是项目代码。缓存位置为:

%LOCALAPPDATA%\tauri\NSIS

处理方法是将损坏缓存移动到备份目录,让 Tauri 重新下载和解压 NSIS:

Move-Item "$env:LOCALAPPDATA\tauri\NSIS" \
  "$env:LOCALAPPDATA\tauri\NSIS.stale-$(Get-Date -Format yyyyMMddHHmmss)"

如果 release 主程序已经编译完成,不必重新编译 Rust,可以直接重新打包:

pnpm exec tauri bundle --bundles nsis --ci

这能明显节省重试时间。

另一个构建问题是 verge-mihomo.exe 被运行中的定制版占用。清理时必须根据可执行文件完整路径筛选,只结束仓库目录下的进程,不能按进程名直接结束,以免影响官方版本。

七、验证方式

最终不能只看“编译成功”,还需要实际启动 release 程序验证。

检查内容包括:

  1. 主窗口不再停留在 Loading。
  2. 首页和设置页可以正常渲染。
  3. 日志出现完整的 UI 加载阶段。
  4. verge-mihomo.exe 的父进程是 cv-damao.exe
  5. 官方 clash-verge-service.exe 的启动时间和进程状态没有被定制版改变。
  6. 测试结束时只关闭仓库路径下的定制版进程。
  7. PE 产品名称和文件描述均为 CV-Damao

最终运行关系如下:

cv-damao.exe
└── verge-mihomo.exe

clash-verge-service.exe  # 官方服务,独立存在,未被调用

格式和构建检查也全部通过:

pnpm prettier --check src/pages/_layout.tsx vite.config.mts
cargo fmt --manifest-path src-tauri/Cargo.toml --check
git diff --check
pnpm web:build

Rust 编译仍有上游已有的生命周期提示,但不影响构建和运行。

八、最终产物

安装文件:

src-tauri\target\release\bundle\nsis\CV-Damao_2.3.1_x64-setup.exe

最终信息:

大小:47,984,833 字节
SHA-256:e475a578e8126ee8ee0b866c3d423f4b98cf61d79e58bb8441f4cf394c9c1bc8
产品名称:CV-Damao
文件描述:CV-Damao

主程序:

src-tauri\target\release\cv-damao.exe
SHA-256:d9d1157007dcd22ac358e54a6ecabf75f9c7bffaeac74fbbb8832cc08fc8cbe6

安装时应运行 CV-Damao_2.3.1_x64-setup.exe,而不是直接运行构建目录中的主程序。

当前安装包没有 Authenticode 签名,因此 Windows 可能显示“未知发布者”或 SmartScreen 提示。

总结

这次定制的重点并不是换图标和名称,而是处理三类真正影响可用性的隔离问题:

  • 身份隔离:应用 ID、数据目录、协议、端口、快捷方式和自启动项全部独立。
  • 运行隔离:Windows 下固定使用自身 sidecar,不连接或管理官方服务。
  • 构建修复:移除导致 React 初始化异常的 manualChunks,解决 release 界面 Loading 卡死。

最终 CV-Damao 可以与官方客户端同时安装和运行,两套普通代理内核互不干扰。仍需注意系统代理和 TUN 属于 Windows 全局资源,使用时应由用户明确选择其中一个客户端接管。


  目录