From 826be4c347602d57ea5b04ca729d8515ebc3f029 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Sun, 22 Mar 2026 01:26:08 +0300 Subject: [PATCH] perf: lazy-load @mdi/js to reduce Vite dev server memory usage Replace `import * as mdi from '@mdi/js'` (loads ~5MB of SVG paths synchronously into every HMR update) with a lazy async import that loads once and caches. MdiIcon and IconPicker now use getMdiPath() and getAllMdiNames() from the shared mdi-lookup module. --- frontend/src/lib/components/IconPicker.svelte | 93 +++++++++++++++++++ frontend/src/lib/components/MdiIcon.svelte | 9 ++ frontend/src/lib/mdi-lookup.ts | 36 +++++++ 3 files changed, 138 insertions(+) create mode 100644 frontend/src/lib/components/IconPicker.svelte create mode 100644 frontend/src/lib/components/MdiIcon.svelte create mode 100644 frontend/src/lib/mdi-lookup.ts diff --git a/frontend/src/lib/components/IconPicker.svelte b/frontend/src/lib/components/IconPicker.svelte new file mode 100644 index 0000000..b0714b8 --- /dev/null +++ b/frontend/src/lib/components/IconPicker.svelte @@ -0,0 +1,93 @@ + + + + +
+ +
+ +{#if open} +
{ open = false; search = ''; }}>
+ +
+ +
+ + {#each filtered() as iconName} + + {/each} +
+
+{/if} diff --git a/frontend/src/lib/components/MdiIcon.svelte b/frontend/src/lib/components/MdiIcon.svelte new file mode 100644 index 0000000..79ee0ca --- /dev/null +++ b/frontend/src/lib/components/MdiIcon.svelte @@ -0,0 +1,9 @@ + + +{#if name && getMdiPath(name)} + +{/if} diff --git a/frontend/src/lib/mdi-lookup.ts b/frontend/src/lib/mdi-lookup.ts new file mode 100644 index 0000000..277a795 --- /dev/null +++ b/frontend/src/lib/mdi-lookup.ts @@ -0,0 +1,36 @@ +/** + * Lazy MDI icon path lookup. + * + * Instead of `import * as mdi from '@mdi/js'` (which loads ~5MB of SVG paths + * into memory), this module loads the full set once on first use and caches it. + * Vite only processes the import once, reducing HMR memory pressure. + */ + +let _cache: Record | null = null; + +async function _load(): Promise> { + if (_cache) return _cache; + const mod = await import('@mdi/js'); + _cache = mod as unknown as Record; + return _cache; +} + +// Eagerly load on module init (runs once) +let _ready: Record | null = null; +_load().then(m => { _ready = m; }); + +/** + * Get SVG path for an icon name. Returns empty string if not found or not yet loaded. + */ +export function getMdiPath(name: string): string { + if (!name || !_ready) return ''; + return (_ready as any)[name] || ''; +} + +/** + * Get all icon names (for IconPicker search). Returns empty array if not yet loaded. + */ +export function getAllMdiNames(): string[] { + if (!_ready) return []; + return Object.keys(_ready).filter(k => k.startsWith('mdi') && k !== 'default'); +}