perf+fix: sprint B — async I/O, before-quit, immutable getState, lucide tree-shake

#2  atomicWrite spin-loop → async setTimeout. Раньше при retry на
    EBUSY/EPERM (антивирус, OneDrive) main process замораживался на
    50/200/800ms × до 3 итераций ≈ секунда залипания UI. Сейчас async
    sleep — event-loop живёт. Сохранён atomicWriteSync для flushNow
    (вызывается из before-quit когда event-loop уже умирает).
    Аналогичный фикс в games/steam-launch-options.ts.
#5  before-quit теперь дожидается stopGamesRegistry через
    e.preventDefault() + app.exit(0). Раньше GSI HTTP server не успевал
    closeAllConnections до exit, и следующий запуск получал
    EADDRINUSE на port 4701 (TIME_WAIT) — GSI молча не работал.
#10 IPC.getState возвращает поверхностную копию settings вместо мутации
    кэша. Раньше startWithWindows писалось напрямую в state.settings,
    разъезжаясь с persisted-disk-значением до следующего mutation.
#19 lib/icon.tsx: `import * as Lucide` (wildcard, ~500KB в bundle,
    1500+ иконок) → explicit named imports + ICON_MAP. В bundle
    остаются только 18 ICON_CHOICES.
This commit is contained in:
AnRil
2026-05-22 01:15:31 +07:00
parent a41dce511b
commit 4745f5e091
5 changed files with 137 additions and 35 deletions

View File

@@ -1,11 +1,51 @@
import * as Lucide from 'lucide-react'
// Explicit-named imports — НЕ wildcard. Wildcard `* as Lucide` ломает
// tree-shaking: в bundle попадает вся библиотека (~500KB minified, 1500+
// иконок). Сейчас в bundle только 18 ICON_CHOICES.
import {
Activity,
Dumbbell,
StretchHorizontal,
PersonStanding,
Heart,
Footprints,
Hand,
Eye,
Brain,
Bike,
Waves,
Wind,
Sun,
Coffee,
Apple,
GlassWater,
BookOpen,
Sparkles
} from 'lucide-react'
import type { LucideProps } from 'lucide-react'
import { ICON_CHOICES, type IconName } from './icon-choices'
// Re-export для обратной совместимости с импортёрами icon.tsx.
export { ICON_CHOICES, type IconName }
const ICON_SET = new Set<string>(ICON_CHOICES)
const ICON_MAP: Record<IconName, React.ComponentType<LucideProps>> = {
Activity,
Dumbbell,
StretchHorizontal,
PersonStanding,
Heart,
Footprints,
Hand,
Eye,
Brain,
Bike,
Waves,
Wind,
Sun,
Coffee,
Apple,
GlassWater,
BookOpen,
Sparkles
}
/**
* Render a Lucide icon by name. Restricted to the curated ICON_CHOICES set —
@@ -17,15 +57,12 @@ export function Icon({
name,
...props
}: { name: string } & LucideProps): JSX.Element {
if (!ICON_SET.has(name)) {
const Cmp = ICON_MAP[name as IconName]
if (!Cmp) {
if (import.meta.env.DEV) {
console.warn(`[Icon] unknown icon name "${name}" — falling back`)
}
return <Lucide.Activity {...props} />
return <Activity {...props} />
}
const Cmp = (
Lucide as unknown as Record<string, React.ComponentType<LucideProps>>
)[name]
if (!Cmp) return <Lucide.Activity {...props} />
return <Cmp {...props} />
}