diff --git a/src/hooks/use-verge.ts b/src/hooks/use-verge.ts index 7385438ad..8750eaaec 100644 --- a/src/hooks/use-verge.ts +++ b/src/hooks/use-verge.ts @@ -1,18 +1,15 @@ import useSWR from "swr"; import { getVergeConfig, patchVergeConfig } from "@/services/cmds"; -import { - getInitialVergeConfig, - setInitialVergeConfig, -} from "@/services/preloaded-verge-config"; +import { getPreloadConfig, setPreloadConfig } from "@/services/preload"; export const useVerge = () => { - const initialVergeConfig = getInitialVergeConfig(); + const initialVergeConfig = getPreloadConfig(); const { data: verge, mutate: mutateVerge } = useSWR( "getVergeConfig", async () => { const config = await getVergeConfig(); - setInitialVergeConfig(config); + setPreloadConfig(config); return config; }, { diff --git a/src/main.tsx b/src/main.tsx index 5db9a594a..2ef58c97b 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -14,15 +14,12 @@ import { BaseErrorBoundary } from "./components/base"; import { router } from "./pages/_routers"; import { AppDataProvider } from "./providers/app-data-provider"; import { WindowProvider } from "./providers/window"; -import { getVergeConfig } from "./services/cmds"; +import { FALLBACK_LANGUAGE, initializeLanguage } from "./services/i18n"; import { - FALLBACK_LANGUAGE, - cacheLanguage, - getCachedLanguage, - initializeLanguage, - resolveLanguage, -} from "./services/i18n"; -import { setInitialVergeConfig } from "./services/preloaded-verge-config"; + preloadAppData, + resolveThemeMode, + getPreloadConfig, +} from "./services/preload"; import { LoadingCacheProvider, ThemeModeProvider, @@ -56,42 +53,6 @@ document.addEventListener("keydown", (event) => { } }); -let cachedVergeConfig: IVergeConfig | null = null; - -const detectSystemTheme = (): "light" | "dark" => { - if (typeof window === "undefined" || typeof window.matchMedia !== "function") - return "light"; - return window.matchMedia("(prefers-color-scheme: dark)").matches - ? "dark" - : "light"; -}; - -const getInitialThemeModeFromWindow = (): - | IVergeConfig["theme_mode"] - | undefined => { - if (typeof window === "undefined") return undefined; - const mode = ( - window as typeof window & { - __VERGE_INITIAL_THEME_MODE?: unknown; - } - ).__VERGE_INITIAL_THEME_MODE; - if (mode === "light" || mode === "dark" || mode === "system") { - return mode; - } - return undefined; -}; - -const resolveInitialThemeMode = ( - vergeConfig?: IVergeConfig | null, -): "light" | "dark" => { - const initialMode = - vergeConfig?.theme_mode ?? getInitialThemeModeFromWindow(); - if (initialMode === "dark" || initialMode === "light") { - return initialMode; - } - return detectSystemTheme(); -}; - const initializeApp = (initialThemeMode: "light" | "dark") => { const contexts = [ , @@ -115,80 +76,8 @@ const initializeApp = (initialThemeMode: "light" | "dark") => { ); }; -const determineInitialLanguage = async ( - vergeConfig?: IVergeConfig | null, - loadVergeConfig?: () => Promise, -) => { - const cachedLanguage = getCachedLanguage(); - if (cachedLanguage) { - return cachedLanguage; - } - - let resolvedConfig = vergeConfig; - - if (resolvedConfig === undefined) { - if (loadVergeConfig) { - try { - resolvedConfig = await loadVergeConfig(); - } catch (error) { - console.warn( - "[main.tsx] Failed to read language from Verge config:", - error, - ); - resolvedConfig = null; - } - } else { - try { - resolvedConfig = await getVergeConfig(); - cachedVergeConfig = resolvedConfig; - } catch (error) { - console.warn( - "[main.tsx] Failed to read language from Verge config:", - error, - ); - resolvedConfig = null; - } - } - } - - const languageFromConfig = resolvedConfig?.language; - if (languageFromConfig) { - const resolved = resolveLanguage(languageFromConfig); - cacheLanguage(resolved); - return resolved; - } - - const browserLanguage = resolveLanguage( - typeof navigator !== "undefined" ? navigator.language : undefined, - ); - cacheLanguage(browserLanguage); - return browserLanguage; -}; - -const fetchVergeConfig = async () => { - try { - const config = await getVergeConfig(); - cachedVergeConfig = config; - setInitialVergeConfig(config); - return config; - } catch (error) { - console.warn("[main.tsx] Failed to read Verge config:", error); - setInitialVergeConfig(null); - return null; - } -}; - const bootstrap = async () => { - const vergeConfigPromise = fetchVergeConfig(); - const initialLanguage = await determineInitialLanguage( - undefined, - () => vergeConfigPromise, - ); - const [vergeConfig] = await Promise.all([ - vergeConfigPromise, - initializeLanguage(initialLanguage), - ]); - const initialThemeMode = resolveInitialThemeMode(vergeConfig); + const { initialThemeMode } = await preloadAppData(); initializeApp(initialThemeMode); }; @@ -205,7 +94,7 @@ bootstrap().catch((error) => { ); }) .finally(() => { - initializeApp(resolveInitialThemeMode(cachedVergeConfig)); + initializeApp(resolveThemeMode(getPreloadConfig())); }); }); diff --git a/src/services/preload.ts b/src/services/preload.ts new file mode 100644 index 000000000..daeca5e56 --- /dev/null +++ b/src/services/preload.ts @@ -0,0 +1,106 @@ +import { getVergeConfig } from "./cmds"; +import { + cacheLanguage, + getCachedLanguage, + initializeLanguage, + resolveLanguage, +} from "./i18n"; + +let vergeConfigCache: IVergeConfig | null | undefined; + +const detectSystemTheme = (): "light" | "dark" => { + if (typeof window === "undefined" || typeof window.matchMedia !== "function") + return "light"; + return window.matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light"; +}; + +const getThemeModeFromWindow = (): IVergeConfig["theme_mode"] | undefined => { + if (typeof window === "undefined") return undefined; + const mode = ( + window as typeof window & { + __VERGE_INITIAL_THEME_MODE?: unknown; + } + ).__VERGE_INITIAL_THEME_MODE; + if (mode === "light" || mode === "dark" || mode === "system") { + return mode; + } + return undefined; +}; + +export const resolveThemeMode = ( + vergeConfig?: IVergeConfig | null, +): "light" | "dark" => { + const initialMode = vergeConfig?.theme_mode ?? getThemeModeFromWindow(); + if (initialMode === "dark" || initialMode === "light") { + return initialMode; + } + return detectSystemTheme(); +}; + +export const setPreloadConfig = (config: IVergeConfig | null) => { + vergeConfigCache = config; +}; + +export const getPreloadConfig = () => vergeConfigCache; + +export const preloadConfig = async () => { + try { + const config = await getVergeConfig(); + setPreloadConfig(config); + return config; + } catch (error) { + console.warn("[preload.ts] Failed to read Verge config:", error); + setPreloadConfig(null); + return null; + } +}; + +export const preloadLanguage = async ( + vergeConfig?: IVergeConfig | null, + loadConfig: () => Promise = preloadConfig, +) => { + const cachedLanguage = getCachedLanguage(); + if (cachedLanguage) { + return cachedLanguage; + } + + let resolvedConfig = vergeConfig; + + if (resolvedConfig === undefined) { + try { + resolvedConfig = await loadConfig(); + } catch (error) { + console.warn( + "[preload.ts] Failed to read language from Verge config:", + error, + ); + resolvedConfig = null; + } + } + + const languageFromConfig = resolvedConfig?.language; + if (languageFromConfig) { + const resolved = resolveLanguage(languageFromConfig); + cacheLanguage(resolved); + return resolved; + } + + const browserLanguage = resolveLanguage( + typeof navigator !== "undefined" ? navigator.language : undefined, + ); + cacheLanguage(browserLanguage); + return browserLanguage; +}; + +export const preloadAppData = async () => { + const configPromise = preloadConfig(); + const initialLanguage = await preloadLanguage(undefined, () => configPromise); + const [config] = await Promise.all([ + configPromise, + initializeLanguage(initialLanguage), + ]); + const initialThemeMode = resolveThemeMode(config); + return { initialThemeMode }; +}; diff --git a/src/services/preloaded-verge-config.ts b/src/services/preloaded-verge-config.ts deleted file mode 100644 index 96e76070b..000000000 --- a/src/services/preloaded-verge-config.ts +++ /dev/null @@ -1,7 +0,0 @@ -let initialVergeConfig: IVergeConfig | null | undefined; - -export const setInitialVergeConfig = (config: IVergeConfig | null) => { - initialVergeConfig = config; -}; - -export const getInitialVergeConfig = () => initialVergeConfig;