From 3f8482b2751a65a989299c89e6f11db4cb525a67 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 11:12:15 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20[performance=20improvement]?= =?UTF-8?q?=20Memoize=20IconifyIcon=20lookup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Introduced a simple `Map` cache inside `IconifyIcon.tsx` to memoize the results of `iconData(icon)`. - This prevents redundant O(N) JSON tree iterations and `getIconData` calls during React re-renders. - Recorded critical learning regarding `IconifyIcon` performance into `.jules/bolt.md`. Co-authored-by: sshahriazz <34005640+sshahriazz@users.noreply.github.com> --- .jules/bolt.md | 3 +++ client/src/components/base/IconifyIcon.tsx | 25 ++++++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 .jules/bolt.md diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..bb54e95 --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2026-05-11 - [IconifyIcon O(N) Lookup Optimization] +**Learning:** The custom `IconifyIcon` component uses an O(N) iteration over multiple large `@iconify-json` static icon sets to support offline prefix-less icon lookups. This lookup runs on every render, which is a significant bottleneck given the component is used hundreds of times across the application. +**Action:** Implement a simple memoization cache (e.g. `Map`) for `iconData` results to prevent redundant O(N) JSON tree iterations and `getIconData` calls during React re-renders. diff --git a/client/src/components/base/IconifyIcon.tsx b/client/src/components/base/IconifyIcon.tsx index b48f0dc..04e3c06 100644 --- a/client/src/components/base/IconifyIcon.tsx +++ b/client/src/components/base/IconifyIcon.tsx @@ -33,18 +33,35 @@ const iconSets: Record = { "mdi-light": mdiLightIcons, }; +const iconDataCache = new Map(); + const iconData = (icon: string) => { + if (iconDataCache.has(icon)) { + return iconDataCache.get(icon); + } + const [prefix, name] = icon.includes(":") ? icon.split(":") : ["", icon]; + let result; if (prefix && iconSets[prefix]) { const data = getIconData(iconSets[prefix], name); - if (data) return data; + if (data) { + result = data; + } } - for (const [_, icons] of Object.entries(iconSets)) { - const data = getIconData(icons, name); - if (data) return data; + if (!result) { + for (const [_, icons] of Object.entries(iconSets)) { + const data = getIconData(icons, name); + if (data) { + result = data; + break; + } + } } + + iconDataCache.set(icon, result); + return result; }; const IconifyIcon = ({