This commit is contained in:
2026-07-24 21:31:46 +08:00
commit eea05fdd63
14 changed files with 2021 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
result
result-*
+39
View File
@@ -0,0 +1,39 @@
# Nix 打包说明
本目录把锁定版本的上游桌面项目从源码构建为 Linux Nix Flake,不复用上游预制安装包。界面代码、原生 Node 模块和最终 ASAR 均在 Nix 构建中生成;共享 Electron、稳定运行组件及部分随包资源来自 nixpkgs 或 Flake inputs。版本和来源由 `flake.lock`、pnpm 锁文件及 Cargo 锁文件记录。
## 补丁说明
补丁按 `nix/unwrapped.nix` 中的顺序应用。
### 标识调整
上游构建配置中的可执行文件名、桌面项和图标标识与本地包名不同。补丁统一这些标识,避免生成物保留不匹配的窗口类、图标名和可执行文件元数据。
### 禁用内置更新
Nix store 只读,运行中的程序不能可靠替换自身或随包运行组件;绕过 Flake 锁定下载更新还会产生版本混用。补丁因此在 Linux 上跳过应用更新检查,并拒绝运行组件的内置升级请求,更新统一通过重新构建 Flake 完成。
### 固定稳定运行组件
当前打包只提供 nixpkgs 中的稳定版本,没有随包放入其他发布通道的文件。补丁让 Linux 路径解析始终选择已提供的稳定文件,防止旧配置或界面状态指向不存在的替代文件。
### NixOS 权限包装
上游会检查 setuid 所有权,并尝试通过 `pkexec` 对程序文件执行 `chown` 和 `chmod`;这些操作不适用于只读 Nix store。NixOS 模块改为在 `/run/wrappers` 创建 capability 包装器。补丁在需要额外权限时选择该包装器,并把它的存在视为权限已经配置;未启用模块时则给出明确错误,而不尝试修改 store。
### 共享 Electron 兼容
Nix 启动器使用共享 Electron,并把 `app.asar` 作为参数传入。此方式下 Electron 将进程视为 default app,`app.isPackaged` 为 `false`;而工具库把 `is.dev` 定义为 `!app.isPackaged`。若直接沿用该判断,正式构建会误走开发分支,自动打开 DevTools、选择开发资源目录,并影响静默启动和窗口页面加载。
补丁把“工具库判断为开发环境且应用路径不是 ASAR”作为实际开发状态。另一个差异是共享 Electron 的 `process.resourcesPath` 指向 Electron 自身的 store 路径,而不是应用资源目录;补丁改从 `app.getAppPath()` 所指 ASAR 的父目录定位随包文件和原生模块。主窗口、悬浮窗口、资源复制和原生模块加载共用这一约定,删除其中任一处修改都可能重新造成路径不一致。
## NixOS 模块
模块负责安装软件包和创建上述权限包装器,并提供可选的图形会话自启动及额外 Electron 参数。它不创建常驻系统服务。
默认构建:
```sh
nix build
```
Generated
+128
View File
@@ -0,0 +1,128 @@
{
"nodes": {
"asn": {
"flake": false,
"locked": {
"narHash": "sha256-bYBRUboYCyEixK/jdhPayyKdB0HQegLmiFXvzB7ZFDU=",
"type": "file",
"url": "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb"
},
"original": {
"type": "file",
"url": "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb"
}
},
"clash-party": {
"flake": false,
"locked": {
"lastModified": 1783321592,
"narHash": "sha256-ituoVv/q/aHt3KOt4fHRDGHGEwnF/nb2E73s/oYw74U=",
"owner": "mihomo-party-org",
"repo": "clash-party",
"rev": "1caff4cabd83d0e2768ecadf52c85c5dcc0ed9de",
"type": "github"
},
"original": {
"owner": "mihomo-party-org",
"ref": "v2.0.0",
"repo": "clash-party",
"type": "github"
}
},
"country": {
"flake": false,
"locked": {
"narHash": "sha256-DpM+/Jsyy7R51/AQKDBVhuT8Fgr1crpz0uaX/0xV6bs=",
"type": "file",
"url": "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country-lite.mmdb"
},
"original": {
"type": "file",
"url": "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country-lite.mmdb"
}
},
"geoip": {
"flake": false,
"locked": {
"narHash": "sha256-ov9zEg2tBCpxru5uNzMs6Npaawz0CXthUaBDQIBcOqs=",
"type": "file",
"url": "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat"
},
"original": {
"type": "file",
"url": "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat"
}
},
"geosite": {
"flake": false,
"locked": {
"narHash": "sha256-PAA0zUq0to9HpJ7+sXXcCm6GgvuZvci5HVoH/u41m0k=",
"type": "file",
"url": "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat"
},
"original": {
"type": "file",
"url": "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat"
}
},
"metadb": {
"flake": false,
"locked": {
"narHash": "sha256-UVm3qjQmgmDSzv6zXPgVXfEQsHwDzl3yTWrRXzh9hrs=",
"type": "file",
"url": "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb"
},
"original": {
"type": "file",
"url": "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1784796856,
"narHash": "sha256-wWFrV5/Qbm+lyt5x20E/bSbfJiGKMo4RCxZV8cl/WZI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e2587caef70cea85dd97d7daab492899902dbf5d",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"asn": "asn",
"clash-party": "clash-party",
"country": "country",
"geoip": "geoip",
"geosite": "geosite",
"metadb": "metadb",
"nixpkgs": "nixpkgs",
"sysproxy": "sysproxy"
}
},
"sysproxy": {
"flake": false,
"locked": {
"lastModified": 1781896006,
"narHash": "sha256-z/IlR6kQfzFkg42fmKKTUTFGgcMLobcNZHeHQFDN5kw=",
"owner": "mihomo-party-org",
"repo": "sysproxy-rs-opti",
"rev": "d6fbb3dee696739e7d32ece15479a7770f687c9b",
"type": "github"
},
"original": {
"owner": "mihomo-party-org",
"ref": "main",
"repo": "sysproxy-rs-opti",
"type": "github"
}
}
},
"root": "root",
"version": 7
}
+103
View File
@@ -0,0 +1,103 @@
{
description = "Clash Party, built from source with a reproducible Nix flake";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
clash-party = {
url = "github:mihomo-party-org/clash-party/v2.0.0";
flake = false;
};
sysproxy = {
url = "github:mihomo-party-org/sysproxy-rs-opti/main";
flake = false;
};
country = {
url = "file+https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country-lite.mmdb";
flake = false;
};
geoip = {
url = "file+https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat";
flake = false;
};
geosite = {
url = "file+https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat";
flake = false;
};
metadb = {
url = "file+https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb";
flake = false;
};
asn = {
url = "file+https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb";
flake = false;
};
};
outputs =
inputs@{ self, nixpkgs, ... }:
let
systems = [
"x86_64-linux"
"aarch64-linux"
];
forEachSystem = nixpkgs.lib.genAttrs systems;
mkPkgs =
system:
import nixpkgs {
inherit system;
config.allowUnfree = true;
};
mkPackage =
system:
let
pkgs = mkPkgs system;
in
pkgs.callPackage ./nix/package.nix {
src = inputs.clash-party;
sysproxySrc = inputs.sysproxy;
inherit (inputs)
country
geoip
geosite
metadb
asn
;
subStore = pkgs.sub-store;
subStoreFrontend = pkgs.sub-store-frontend;
notoFontsColorEmoji = pkgs.noto-fonts-color-emoji;
};
in
{
packages = forEachSystem (
system:
let
package = mkPackage system;
in
{
clash-party = package;
default = package;
inherit (package) sysproxy unwrapped;
}
);
apps = forEachSystem (system: {
clash-party = {
type = "app";
program = "${self.packages.${system}.clash-party}/bin/clash-party";
};
default = self.apps.${system}.clash-party;
});
nixosModules = {
clash-party = import ./nix/module.nix { inherit self; };
default = self.nixosModules.clash-party;
};
};
}
+55
View File
@@ -0,0 +1,55 @@
{ self }:
{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.clash-party;
system = pkgs.stdenv.hostPlatform.system;
package = cfg.package.override {
commandLineArgs = cfg.extraArgs;
};
in
{
options.programs.clash-party = {
enable = lib.mkEnableOption "Clash Party";
package = lib.mkOption {
type = lib.types.package;
default = self.packages.${system}.clash-party;
defaultText = lib.literalExpression "clash-party-flake.packages.${system}.clash-party";
description = "Clash Party package to install.";
};
autoStart = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Start Clash Party automatically in graphical sessions.";
};
extraArgs = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
example = [ "--ozone-platform-hint=auto" ];
description = "Additional command-line arguments passed to Electron.";
};
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [ package ];
security.wrappers.clash-party-mihomo = {
source = lib.getExe package.mihomo;
owner = "root";
group = "root";
capabilities = "cap_net_admin,cap_net_raw,cap_net_bind_service=+ep";
};
environment.etc."xdg/autostart/clash-party.desktop" = lib.mkIf cfg.autoStart {
source = "${package}/share/applications/clash-party.desktop";
};
};
}
+132
View File
@@ -0,0 +1,132 @@
{
lib,
callPackage,
stdenv,
electron_41,
makeWrapper,
copyDesktopItems,
makeDesktopItem,
wrapGAppsHook3,
autoPatchelfHook,
alsa-lib,
at-spi2-core,
glib,
libGL,
libayatana-appindicator,
libsecret,
libnotify,
libXScrnSaver,
libXtst,
nspr,
nss,
openssl,
udev,
src,
sysproxySrc,
country,
geoip,
geosite,
metadb,
asn,
subStore,
subStoreFrontend,
notoFontsColorEmoji,
mihomo,
commandLineArgs ? [ ],
}:
let
sysproxy = callPackage ./sysproxy.nix { inherit sysproxySrc; };
unwrapped = callPackage ./unwrapped.nix {
inherit
src
sysproxy
country
geoip
geosite
metadb
asn
subStore
subStoreFrontend
notoFontsColorEmoji
mihomo
;
};
in
stdenv.mkDerivation (finalAttrs: {
pname = "clash-party";
version = "2.0.0";
dontUnpack = true;
nativeBuildInputs = [
autoPatchelfHook
copyDesktopItems
makeWrapper
wrapGAppsHook3
];
buildInputs = [
alsa-lib
at-spi2-core
glib
libGL
libayatana-appindicator
libnotify
libsecret
libXScrnSaver
libXtst
nspr
nss
openssl
stdenv.cc.cc.lib
udev
];
installPhase = ''
runHook preInstall
mkdir -p $out/lib/clash-party
cp -r ${unwrapped}/lib/clash-party/resources $out/lib/clash-party/
cp -r ${unwrapped}/share $out/
chmod -R u+w $out/share
makeWrapper ${lib.getExe electron_41} $out/bin/clash-party \
--inherit-argv0 \
--add-flags "$out/lib/clash-party/resources/app.asar" \
--add-flags ${lib.escapeShellArg (lib.escapeShellArgs commandLineArgs)} \
--set-default ELECTRON_OZONE_PLATFORM_HINT auto
runHook postInstall
'';
desktopItems = [
(makeDesktopItem {
name = "clash-party";
desktopName = "Clash Party";
genericName = "Proxy Client";
comment = "A GUI client based on Mihomo";
exec = "clash-party %U";
icon = "clash-party";
startupWMClass = "clash-party";
categories = [ "Utility" ];
mimeTypes = [
"x-scheme-handler/clash"
"x-scheme-handler/mihomo"
];
})
];
passthru = {
inherit mihomo sysproxy unwrapped;
};
meta = {
description = "Clash Party desktop client built from source";
homepage = "https://github.com/mihomo-party-org/clash-party";
license = lib.licenses.gpl3Only;
mainProgram = "clash-party";
platforms = lib.platforms.linux;
};
})
+1155
View File
File diff suppressed because it is too large Load Diff
+60
View File
@@ -0,0 +1,60 @@
{
lib,
rustPlatform,
fetchPnpmDeps,
nodejs_22,
pnpm_10,
pnpmConfigHook,
sysproxySrc,
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "clash-party-sysproxy";
version = "0.5.1";
src = sysproxySrc;
cargoLock.lockFile = ./sysproxy-Cargo.lock;
pnpmDeps = fetchPnpmDeps {
pname = finalAttrs.pname;
version = finalAttrs.version;
src = sysproxySrc;
pnpm = pnpm_10;
fetcherVersion = 4;
prePnpmInstall = ''
pnpm config set fetch-retries 5
pnpm config set fetch-timeout 120000
pnpm config set network-concurrency 4
'';
hash = "sha256-n/unBCkpSSShYliEeeWOAjM7r7ZUdfROBYyqzw8JLB0=";
};
nativeBuildInputs = [
nodejs_22
pnpmConfigHook
pnpm_10
];
postPatch = ''
rm -f .cargo/config.toml
cp ${./sysproxy-Cargo.lock} Cargo.lock
chmod u+w Cargo.lock
'';
buildPhase = ''
runHook preBuild
pnpm exec napi build --platform --release
runHook postBuild
'';
# N-API symbols are supplied by Node/Electron when the module is loaded, so
# Cargo's standalone test-link step cannot resolve them.
doCheck = false;
installPhase = ''
runHook preInstall
mkdir -p $out
cp sysproxy.*.node $out/
runHook postInstall
'';
})
+139
View File
@@ -0,0 +1,139 @@
{
lib,
stdenv,
autoPatchelfHook,
electron_41,
fetchPnpmDeps,
nodejs_22,
pnpm_10,
pnpmConfigHook,
alsa-lib,
at-spi2-core,
glib,
libGL,
libayatana-appindicator,
libnotify,
libsecret,
libXScrnSaver,
libXtst,
nspr,
nss,
openssl,
pkg-config,
udev,
src,
sysproxy,
country,
geoip,
geosite,
metadb,
asn,
subStore,
subStoreFrontend,
notoFontsColorEmoji,
mihomo,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "clash-party-unwrapped";
version = "2.0.0";
inherit src;
patches = [
../patches/branding.patch
../patches/disable-updater.patch
../patches/stable-core-only.patch
../patches/nix-tun-wrapper.patch
../patches/system-electron-resources.patch
];
pnpmDeps = fetchPnpmDeps {
pname = finalAttrs.pname;
version = finalAttrs.version;
inherit src;
pnpm = pnpm_10;
fetcherVersion = 4;
prePnpmInstall = ''
pnpm config set fetch-retries 5
pnpm config set fetch-timeout 120000
pnpm config set network-concurrency 4
'';
hash = "sha256-plsb9TjmprG5k2kYkqItEunTeyJWopRBH0SzzU/qM/8=";
};
nativeBuildInputs = [
autoPatchelfHook
nodejs_22
pkg-config
pnpmConfigHook
pnpm_10
];
buildInputs = [
alsa-lib
at-spi2-core
glib
libGL
libayatana-appindicator
libnotify
libsecret
libXScrnSaver
libXtst
nspr
nss
openssl
stdenv.cc.cc.lib
udev
];
env = {
ELECTRON_SKIP_BINARY_DOWNLOAD = "1";
npm_config_build_from_source = "true";
};
postPatch = ''
mkdir -p extra/sidecar extra/files
ln -s ${mihomo}/bin/mihomo extra/sidecar/mihomo
cp ${sysproxy}/sysproxy.linux-${if stdenv.hostPlatform.isx86_64 then "x64" else "arm64"}-gnu.node \
extra/sidecar/
install -Dm444 ${country} extra/files/country.mmdb
install -Dm444 ${geoip} extra/files/geoip.dat
install -Dm444 ${geosite} extra/files/geosite.dat
install -Dm444 ${metadb} extra/files/geoip.metadb
install -Dm444 ${asn} extra/files/ASN.mmdb
install -Dm444 ${subStore}/share/sub-store/sub-store.bundle.js \
extra/files/sub-store.bundle.cjs
cp -r ${subStoreFrontend} extra/files/sub-store-frontend
find ${notoFontsColorEmoji} -name NotoColorEmoji.ttf -exec \
install -Dm444 {} src/renderer/src/assets/NotoColorEmoji.ttf \;
'';
buildPhase = ''
runHook preBuild
mkdir .electron-dist
cp -RL ${electron_41.dist}/. .electron-dist/
chmod -R u+w .electron-dist
node_modules/.bin/electron-vite build
npm_config_nodedir=${electron_41.headers} \
node_modules/.bin/electron-builder --dir \
--config=electron-builder.yml \
--config.electronDist=$PWD/.electron-dist \
--config.electronVersion=${electron_41.version}
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p $out/lib/clash-party
cp -r dist/linux-unpacked/resources $out/lib/clash-party/
install -Dm644 build/icon.png $out/share/icons/hicolor/512x512/apps/clash-party.png
runHook postInstall
'';
})
+11
View File
@@ -0,0 +1,11 @@
diff --git a/electron-builder.yml b/electron-builder.yml
--- a/electron-builder.yml
+++ b/electron-builder.yml
@@ -59 +59 @@
- executableName: mihomo-party
+ executableName: clash-party
@@ -68,2 +68,2 @@
- StartupWMClass: mihomo-party
- Icon: mihomo-party
+ StartupWMClass: clash-party
+ Icon: clash-party
+24
View File
@@ -0,0 +1,24 @@
diff --git a/src/main/resolve/autoUpdater.ts b/src/main/resolve/autoUpdater.ts
--- a/src/main/resolve/autoUpdater.ts
+++ b/src/main/resolve/autoUpdater.ts
@@ -48,4 +48,8 @@
export async function checkUpdate(): Promise<IAppVersion | undefined> {
+ if (process.platform === 'linux') {
+ return undefined
+ }
+
const [{ 'mixed-port': mixedPort = DEFAULT_MIHOMO_PORTS.mixed }, { githubProxy = '' }] =
await Promise.all([getControledMihomoConfig(), getAppConfig()])
const githubUrl =
diff --git a/src/main/core/mihomoApi.ts b/src/main/core/mihomoApi.ts
--- a/src/main/core/mihomoApi.ts
+++ b/src/main/core/mihomoApi.ts
@@ -400,4 +400,8 @@
export const mihomoUpgrade = async (): Promise<void> => {
+ if (process.platform === 'linux') {
+ throw new Error('Mihomo is managed by Nix on Linux')
+ }
+
const instance = await getAxios()
return await instance.post('/upgrade', undefined, { timeout: 90000 })
}
+54
View File
@@ -0,0 +1,54 @@
diff --git a/src/main/core/manager.ts b/src/main/core/manager.ts
--- a/src/main/core/manager.ts
+++ b/src/main/core/manager.ts
@@ -79,3 +79,4 @@
const execFilePromise = promisify(execFile)
const ctlParam = process.platform === 'win32' ? '-ext-ctl-pipe' : '-ext-ctl-unix'
+const nixMihomoWrapper = '/run/wrappers/bin/clash-party-mihomo'
const coreHookTimeout = 30000
@@ -370,5 +371,8 @@
return {
- corePath: mihomoCorePath(core),
+ corePath:
+ process.platform === 'linux' && tun?.enable && existsSync(nixMihomoWrapper)
+ ? nixMihomoWrapper
+ : mihomoCorePath(core),
workDir: diffWorkDir ? mihomoProfileWorkDir(current) : mihomoWorkDir(),
safePath: diffWorkDir ? mihomoWorkDir() : undefined,
ipcPath,
diff --git a/src/main/core/permissions.ts b/src/main/core/permissions.ts
--- a/src/main/core/permissions.ts
+++ b/src/main/core/permissions.ts
@@ -14,5 +14,6 @@
const execPromise = promisify(exec)
const execFilePromise = promisify(execFile)
+const nixMihomoWrapper = '/run/wrappers/bin/clash-party-mihomo'
// 内核名称白名单
const ALLOWED_CORES = ['mihomo', 'mihomo-alpha', 'mihomo-smart'] as const
@@ -76,9 +77,13 @@
try {
if (process.platform === 'win32') {
return await checkAdminPrivileges()
}
+ if (process.platform === 'linux' && existsSync(nixMihomoWrapper)) {
+ return true
+ }
+
if (process.platform === 'darwin' || process.platform === 'linux') {
const stats = await stat(corePath)
return (stats.mode & 0o4000) !== 0 && stats.uid === 0
}
@@ -253,4 +258,9 @@
if (process.platform === 'linux') {
- await execFilePromise('pkexec', ['chown', 'root:root', corePath])
- await execFilePromise('pkexec', ['chmod', '+sx', corePath])
+ if (existsSync(nixMihomoWrapper)) {
+ return
+ }
+
+ throw new Error(
+ 'TUN support requires enabling programs.clash-party in the NixOS configuration'
+ )
}
+12
View File
@@ -0,0 +1,12 @@
diff --git a/src/main/utils/dirs.ts b/src/main/utils/dirs.ts
--- a/src/main/utils/dirs.ts
+++ b/src/main/utils/dirs.ts
@@ -79,6 +79,10 @@
export function mihomoCorePath(core: string): string {
+ if (process.platform === 'linux') {
+ core = 'mihomo'
+ }
+
const isWin = process.platform === 'win32'
// 处理 Smart 内核
if (core === 'mihomo-smart') {
+107
View File
@@ -0,0 +1,107 @@
diff --git a/src/native/sysproxy/index.js b/src/native/sysproxy/index.js
--- a/src/native/sysproxy/index.js
+++ b/src/native/sysproxy/index.js
@@ -70,6 +70,12 @@ function getResourcesPath() {
try {
const { app } = require('electron')
const appPath = app.getAppPath()
+ // A shared system Electron keeps process.resourcesPath in Electron's own
+ // store path. The directory containing app.asar is the app resource path.
+ if (appPath.endsWith('.asar') && existsSync(join(dirname(appPath), 'sidecar'))) {
+ return dirname(appPath)
+ }
+
if (existsSync(join(appPath, 'extra', 'sidecar'))) {
return appPath
}
diff --git a/src/main/utils/dirs.ts b/src/main/utils/dirs.ts
--- a/src/main/utils/dirs.ts
+++ b/src/main/utils/dirs.ts
@@ -62,13 +62,16 @@ export function workDir(): string {
}
+export function isDevelopment(): boolean {
+ return is.dev && !app.getAppPath().endsWith('asar')
+}
+
export function resourcesDir(): string {
- if (is.dev) {
+ const appPath = app.getAppPath()
+ if (appPath.endsWith('asar')) {
+ return path.dirname(appPath)
+ } else if (isDevelopment()) {
return path.join(__dirname, '../../extra')
} else {
- if (app.getAppPath().endsWith('asar')) {
- return process.resourcesPath
- } else {
- return path.join(app.getAppPath(), 'resources')
- }
+ return path.join(appPath, 'resources')
}
}
diff --git a/src/main/window.ts b/src/main/window.ts
--- a/src/main/window.ts
+++ b/src/main/window.ts
@@ -1,11 +1,10 @@
import { join } from 'path'
import { readFileSync, writeFileSync } from 'fs'
import { BrowserWindow, Menu, screen, shell } from 'electron'
-import { is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset'
import { getAppConfig } from './config'
import { quitWithoutCore, stopCore } from './core/manager'
import { triggerSysProxy } from './sys/sysproxy'
import { hideDockIcon, showDockIcon } from './resolve/tray'
-import { dataDir } from './utils/dirs'
+import { dataDir, isDevelopment } from './utils/dirs'
import { mainWindowLogger } from './utils/logger'
@@ -172,10 +171,10 @@ export async function createMainWindow(silentStart = false): Promise<void> {
})
- if (is.dev) {
+ if (isDevelopment()) {
mainWindow.webContents.openDevTools()
}
- if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
+ if (isDevelopment() && process.env['ELECTRON_RENDERER_URL']) {
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
} else {
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
@@ -199,7 +198,7 @@ function setupWindowEvents(window: BrowserWindow, config: WindowConfig): void {
}
// 开发模式下始终显示窗口
- if (!silentStart || is.dev) {
+ if (!silentStart || isDevelopment()) {
clearQuitTimeout()
window.show()
window.focusOnWebView()
diff --git a/src/main/resolve/floatingWindow.ts b/src/main/resolve/floatingWindow.ts
--- a/src/main/resolve/floatingWindow.ts
+++ b/src/main/resolve/floatingWindow.ts
@@ -1,8 +1,8 @@
import { join } from 'path'
-import { is } from '@electron-toolkit/utils'
import { BrowserWindow, ipcMain } from 'electron'
import windowStateKeeper from 'electron-window-state'
import { getAppConfig, patchAppConfig } from '../config'
+import { isDevelopment } from '../utils/dirs'
import { floatingWindowLogger } from '../utils/logger'
import { applyTheme } from './theme'
import { buildContextMenu, showTrayIcon } from './tray'
@@ -86,11 +86,11 @@ async function createFloatingWindow(): Promise<void> {
// 加载页面
const url =
- is.dev && process.env['ELECTRON_RENDERER_URL']
+ isDevelopment() && process.env['ELECTRON_RENDERER_URL']
? `${process.env['ELECTRON_RENDERER_URL']}/floating.html`
: join(__dirname, '../renderer/floating.html')
- is.dev ? await floatingWindow.loadURL(url) : await floatingWindow.loadFile(url)
+ isDevelopment() ? await floatingWindow.loadURL(url) : await floatingWindow.loadFile(url)
} catch (error) {
logError('Failed to create floating window', error)
floatingWindow = null