mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-13 05:20:28 +08:00
Compare commits
3 Commits
62f1599fea
...
acf7ddf896
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acf7ddf896 | ||
|
|
1005baabe6 | ||
|
|
3aa39bff94 |
@ -92,8 +92,9 @@
|
|||||||
"@types/validator": "^13.15.10",
|
"@types/validator": "^13.15.10",
|
||||||
"@vitejs/plugin-legacy": "^8.0.0",
|
"@vitejs/plugin-legacy": "^8.0.0",
|
||||||
"@vitejs/plugin-react": "^6.0.1",
|
"@vitejs/plugin-react": "^6.0.1",
|
||||||
"axios": "^1.13.6",
|
|
||||||
"adm-zip": "^0.5.16",
|
"adm-zip": "^0.5.16",
|
||||||
|
"axios": "^1.13.6",
|
||||||
|
"babel-plugin-react-compiler": "^1.0.0",
|
||||||
"cli-color": "^2.0.4",
|
"cli-color": "^2.0.4",
|
||||||
"commander": "^14.0.3",
|
"commander": "^14.0.3",
|
||||||
"cross-env": "^10.1.0",
|
"cross-env": "^10.1.0",
|
||||||
|
|||||||
785
pnpm-lock.yaml
generated
785
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@ use crate::{
|
|||||||
core::{CoreManager, handle, tray},
|
core::{CoreManager, handle, tray},
|
||||||
feat::clean_async,
|
feat::clean_async,
|
||||||
process::AsyncHandler,
|
process::AsyncHandler,
|
||||||
utils::{self, resolve::reset_resolve_done},
|
utils,
|
||||||
};
|
};
|
||||||
use clash_verge_logging::{Type, logging};
|
use clash_verge_logging::{Type, logging};
|
||||||
use serde_yaml_ng::{Mapping, Value};
|
use serde_yaml_ng::{Mapping, Value};
|
||||||
@ -42,7 +42,6 @@ pub async fn restart_app() {
|
|||||||
if cleanup_result { 0 } else { 1 }
|
if cleanup_result { 0 } else { 1 }
|
||||||
);
|
);
|
||||||
|
|
||||||
reset_resolve_done();
|
|
||||||
let app_handle = handle::Handle::app_handle();
|
let app_handle = handle::Handle::app_handle();
|
||||||
app_handle.restart();
|
app_handle.restart();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -251,7 +251,6 @@ pub fn run() {
|
|||||||
resolve::resolve_setup_async();
|
resolve::resolve_setup_async();
|
||||||
resolve::resolve_setup_sync();
|
resolve::resolve_setup_sync();
|
||||||
resolve::init_signal();
|
resolve::init_signal();
|
||||||
resolve::resolve_done();
|
|
||||||
|
|
||||||
logging!(info, Type::Setup, "初始化已启动");
|
logging!(info, Type::Setup, "初始化已启动");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -62,14 +62,9 @@ pub fn resolve_setup_async() {
|
|||||||
init_system_proxy_guard().await;
|
init_system_proxy_guard().await;
|
||||||
});
|
});
|
||||||
|
|
||||||
let tray_init = async {
|
|
||||||
init_tray().await;
|
|
||||||
refresh_tray_menu().await;
|
|
||||||
};
|
|
||||||
|
|
||||||
let _ = futures::join!(
|
let _ = futures::join!(
|
||||||
core_init,
|
core_init,
|
||||||
tray_init,
|
init_tray(),
|
||||||
init_timer(),
|
init_timer(),
|
||||||
init_hotkey(),
|
init_hotkey(),
|
||||||
init_auto_lightweight_boot(),
|
init_auto_lightweight_boot(),
|
||||||
@ -79,6 +74,7 @@ pub fn resolve_setup_async() {
|
|||||||
|
|
||||||
Handle::refresh_clash();
|
Handle::refresh_clash();
|
||||||
refresh_tray_menu().await;
|
refresh_tray_menu().await;
|
||||||
|
resolve_done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +216,3 @@ pub fn resolve_done() {
|
|||||||
pub fn is_resolve_done() -> bool {
|
pub fn is_resolve_done() -> bool {
|
||||||
RESOLVE_DONE.load(Ordering::Acquire)
|
RESOLVE_DONE.load(Ordering::Acquire)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_resolve_done() {
|
|
||||||
RESOLVE_DONE.store(false, Ordering::Release);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -129,7 +129,7 @@ impl WindowManager {
|
|||||||
logging!(info, Type::Window, "窗口不存在,创建新窗口");
|
logging!(info, Type::Window, "窗口不存在,创建新窗口");
|
||||||
if Self::create_window(true).await {
|
if Self::create_window(true).await {
|
||||||
logging!(info, Type::Window, "窗口创建成功");
|
logging!(info, Type::Window, "窗口创建成功");
|
||||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
|
||||||
WindowOperationResult::Created
|
WindowOperationResult::Created
|
||||||
} else {
|
} else {
|
||||||
logging!(warn, Type::Window, "窗口创建失败");
|
logging!(warn, Type::Window, "窗口创建失败");
|
||||||
@ -286,11 +286,11 @@ impl WindowManager {
|
|||||||
|
|
||||||
/// 创建新窗口,防抖避免重复调用
|
/// 创建新窗口,防抖避免重复调用
|
||||||
/// 窗口创建后保持隐藏,由前端 index.html 在 overlay 渲染后调用 show,避免主题闪烁
|
/// 窗口创建后保持隐藏,由前端 index.html 在 overlay 渲染后调用 show,避免主题闪烁
|
||||||
pub fn create_window(is_show: bool) -> Pin<Box<dyn Future<Output = bool> + Send>> {
|
pub fn create_window(should_create: bool) -> Pin<Box<dyn Future<Output = bool> + Send>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
logging!(info, Type::Window, "开始创建/显示主窗口, is_show={}", is_show);
|
logging!(info, Type::Window, "开始创建主窗口, should_create={}", should_create);
|
||||||
|
|
||||||
if !is_show {
|
if !should_create {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useQuery } from '@tanstack/react-query'
|
import { useQuery } from '@tanstack/react-query'
|
||||||
import { listen } from '@tauri-apps/api/event'
|
import { listen } from '@tauri-apps/api/event'
|
||||||
import React, { useCallback, useEffect, useMemo } from 'react'
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
|
||||||
import {
|
import {
|
||||||
getBaseConfig,
|
getBaseConfig,
|
||||||
getRuleProviders,
|
getRuleProviders,
|
||||||
@ -79,106 +79,45 @@ export const AppDataProvider = ({
|
|||||||
...TQ_MIHOMO,
|
...TQ_MIHOMO,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const refreshProxyRef = useRef(refreshProxy)
|
||||||
|
const refreshRulesRef = useRef(refreshRules)
|
||||||
|
const refreshRuleProvidersRef = useRef(refreshRuleProviders)
|
||||||
|
useEffect(() => {
|
||||||
|
refreshProxyRef.current = refreshProxy
|
||||||
|
}, [refreshProxy])
|
||||||
|
useEffect(() => {
|
||||||
|
refreshRulesRef.current = refreshRules
|
||||||
|
}, [refreshRules])
|
||||||
|
useEffect(() => {
|
||||||
|
refreshRuleProvidersRef.current = refreshRuleProviders
|
||||||
|
}, [refreshRuleProviders])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let lastProfileId: string | null = null
|
let lastProfileId: string | null = null
|
||||||
let lastUpdateTime = 0
|
let lastUpdateTime = 0
|
||||||
const refreshThrottle = 800
|
const refreshThrottle = 800
|
||||||
|
|
||||||
let isUnmounted = false
|
|
||||||
const scheduledTimeouts = new Set<number>()
|
|
||||||
const cleanupFns: Array<() => void> = []
|
const cleanupFns: Array<() => void> = []
|
||||||
|
|
||||||
const registerCleanup = (fn: () => void) => {
|
|
||||||
if (isUnmounted) {
|
|
||||||
try {
|
|
||||||
fn()
|
|
||||||
} catch (error) {
|
|
||||||
console.error('[DataProvider] Immediate cleanup failed:', error)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cleanupFns.push(fn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const addWindowListener = (eventName: string, handler: EventListener) => {
|
|
||||||
// eslint-disable-next-line @eslint-react/web-api-no-leaked-event-listener
|
|
||||||
window.addEventListener(eventName, handler)
|
|
||||||
return () => window.removeEventListener(eventName, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
const scheduleTimeout = (
|
|
||||||
callback: () => void | Promise<void>,
|
|
||||||
delay: number,
|
|
||||||
) => {
|
|
||||||
if (isUnmounted) return -1
|
|
||||||
|
|
||||||
const timeoutId = window.setTimeout(() => {
|
|
||||||
scheduledTimeouts.delete(timeoutId)
|
|
||||||
if (!isUnmounted) {
|
|
||||||
void callback()
|
|
||||||
}
|
|
||||||
}, delay)
|
|
||||||
|
|
||||||
scheduledTimeouts.add(timeoutId)
|
|
||||||
return timeoutId
|
|
||||||
}
|
|
||||||
|
|
||||||
const clearAllTimeouts = () => {
|
|
||||||
scheduledTimeouts.forEach((timeoutId) => clearTimeout(timeoutId))
|
|
||||||
scheduledTimeouts.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleProfileChanged = (event: { payload: string }) => {
|
const handleProfileChanged = (event: { payload: string }) => {
|
||||||
const newProfileId = event.payload
|
const newProfileId = event.payload
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
|
|
||||||
if (
|
if (
|
||||||
lastProfileId === newProfileId &&
|
lastProfileId === newProfileId &&
|
||||||
now - lastUpdateTime < refreshThrottle
|
now - lastUpdateTime < refreshThrottle
|
||||||
) {
|
) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lastProfileId = newProfileId
|
lastProfileId = newProfileId
|
||||||
lastUpdateTime = now
|
lastUpdateTime = now
|
||||||
|
refreshRulesRef.current().catch(() => {})
|
||||||
scheduleTimeout(() => {
|
refreshRuleProvidersRef.current().catch(() => {})
|
||||||
refreshRules().catch((error) =>
|
|
||||||
console.warn('[DataProvider] Rules refresh failed:', error),
|
|
||||||
)
|
|
||||||
refreshRuleProviders().catch((error) =>
|
|
||||||
console.warn('[DataProvider] Rule providers refresh failed:', error),
|
|
||||||
)
|
|
||||||
}, 200)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleRefreshClash = () => {
|
|
||||||
const now = Date.now()
|
|
||||||
if (now - lastUpdateTime <= refreshThrottle) return
|
|
||||||
|
|
||||||
lastUpdateTime = now
|
|
||||||
scheduleTimeout(async () => {
|
|
||||||
await Promise.all([
|
|
||||||
refreshProxy().catch((error) =>
|
|
||||||
console.error('[DataProvider] Proxy refresh failed:', error),
|
|
||||||
),
|
|
||||||
refreshClashConfig().catch((error) =>
|
|
||||||
console.error('[DataProvider] Clash config refresh failed:', error),
|
|
||||||
),
|
|
||||||
])
|
|
||||||
}, 200)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRefreshProxy = () => {
|
const handleRefreshProxy = () => {
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
if (now - lastUpdateTime <= refreshThrottle) return
|
if (now - lastUpdateTime <= refreshThrottle) return
|
||||||
|
|
||||||
lastUpdateTime = now
|
lastUpdateTime = now
|
||||||
scheduleTimeout(() => {
|
refreshProxyRef.current().catch(() => {})
|
||||||
refreshProxy().catch((error) =>
|
|
||||||
console.warn('[DataProvider] Proxy refresh failed:', error),
|
|
||||||
)
|
|
||||||
}, 200)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const initializeListeners = async () => {
|
const initializeListeners = async () => {
|
||||||
@ -187,62 +126,34 @@ export const AppDataProvider = ({
|
|||||||
'profile-changed',
|
'profile-changed',
|
||||||
handleProfileChanged,
|
handleProfileChanged,
|
||||||
)
|
)
|
||||||
registerCleanup(unlistenProfile)
|
cleanupFns.push(unlistenProfile)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[AppDataProvider] 监听 Profile 事件失败:', error)
|
console.error('[AppDataProvider] 监听 Profile 事件失败:', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const unlistenClash = await listen(
|
|
||||||
'verge://refresh-clash-config',
|
|
||||||
handleRefreshClash,
|
|
||||||
)
|
|
||||||
const unlistenProxy = await listen(
|
const unlistenProxy = await listen(
|
||||||
'verge://refresh-proxy-config',
|
'verge://refresh-proxy-config',
|
||||||
handleRefreshProxy,
|
handleRefreshProxy,
|
||||||
)
|
)
|
||||||
|
cleanupFns.push(unlistenProxy)
|
||||||
registerCleanup(() => {
|
|
||||||
unlistenClash()
|
|
||||||
unlistenProxy()
|
|
||||||
})
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('[AppDataProvider] 设置 Tauri 事件监听器失败:', error)
|
console.warn('[AppDataProvider] 设置 Tauri 事件监听器失败:', error)
|
||||||
|
|
||||||
const fallbackHandlers: Array<[string, EventListener]> = [
|
|
||||||
['verge://refresh-clash-config', handleRefreshClash],
|
|
||||||
['verge://refresh-proxy-config', handleRefreshProxy],
|
|
||||||
]
|
|
||||||
|
|
||||||
fallbackHandlers.forEach(([eventName, handler]) => {
|
|
||||||
registerCleanup(addWindowListener(eventName, handler))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initializeListeners()
|
void initializeListeners()
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
isUnmounted = true
|
cleanupFns.forEach((fn) => {
|
||||||
clearAllTimeouts()
|
|
||||||
|
|
||||||
const errors: Error[] = []
|
|
||||||
cleanupFns.splice(0).forEach((fn) => {
|
|
||||||
try {
|
try {
|
||||||
fn()
|
fn()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
errors.push(error instanceof Error ? error : new Error(String(error)))
|
console.error('[DataProvider] Cleanup error:', error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (errors.length > 0) {
|
|
||||||
console.error(
|
|
||||||
`[DataProvider] ${errors.length} errors during cleanup:`,
|
|
||||||
errors,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, [refreshProxy, refreshClashConfig, refreshRules, refreshRuleProviders])
|
}, [])
|
||||||
|
|
||||||
const { data: sysproxy, refetch: refreshSysproxy } = useQuery({
|
const { data: sysproxy, refetch: refreshSysproxy } = useQuery({
|
||||||
queryKey: ['getSystemProxy'],
|
queryKey: ['getSystemProxy'],
|
||||||
|
|||||||
@ -10,7 +10,11 @@ export default defineConfig({
|
|||||||
server: { port: 3000 },
|
server: { port: 3000 },
|
||||||
plugins: [
|
plugins: [
|
||||||
svgr(),
|
svgr(),
|
||||||
react(),
|
react({
|
||||||
|
babel: {
|
||||||
|
plugins: ['babel-plugin-react-compiler'],
|
||||||
|
},
|
||||||
|
} as any),
|
||||||
legacy({
|
legacy({
|
||||||
modernTargets: ['edge>=109', 'safari>=14'],
|
modernTargets: ['edge>=109', 'safari>=14'],
|
||||||
renderLegacyChunks: false,
|
renderLegacyChunks: false,
|
||||||
@ -26,6 +30,24 @@ export default defineConfig({
|
|||||||
outDir: '../dist',
|
outDir: '../dist',
|
||||||
emptyOutDir: true,
|
emptyOutDir: true,
|
||||||
chunkSizeWarningLimit: 4000,
|
chunkSizeWarningLimit: 4000,
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
manualChunks: (id) => {
|
||||||
|
if (id.includes('monaco-yaml')) return 'monaco-yaml'
|
||||||
|
if (
|
||||||
|
id.includes('node_modules/react/') ||
|
||||||
|
id.includes('node_modules/react-dom/')
|
||||||
|
)
|
||||||
|
return 'react'
|
||||||
|
if (id.includes('node_modules/react-router')) return 'router'
|
||||||
|
if (
|
||||||
|
id.includes('node_modules/i18next') ||
|
||||||
|
id.includes('node_modules/react-i18next')
|
||||||
|
)
|
||||||
|
return 'i18n'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
@ -36,4 +58,13 @@ export default defineConfig({
|
|||||||
define: {
|
define: {
|
||||||
OS_PLATFORM: `"${process.platform}"`,
|
OS_PLATFORM: `"${process.platform}"`,
|
||||||
},
|
},
|
||||||
|
optimizeDeps: {
|
||||||
|
include: [
|
||||||
|
'react',
|
||||||
|
'react-dom',
|
||||||
|
'react-router-dom',
|
||||||
|
'i18next',
|
||||||
|
'react-i18next',
|
||||||
|
],
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user