From a1d5aebc05f77594c604aed6b8d4de873dbc453f Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 02:31:46 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9A=A1=20Bolt:=20WasmJs=20ThemeCache=20O?= =?UTF-8?q?ptimization?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: himattm <6266621+himattm@users.noreply.github.com> --- .jules/bolt.md | 3 +++ .../halogen/engine/LocalStorageThemeCache.kt | 18 ++++++++++++++---- 2 files changed, 17 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..303f8fd --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2024-05-18 - WasmJs ThemeCache Optimization +**Learning:** JSON decoding in Kotlin Multiplatform for WasmJs targets carries significant overhead. The existing LocalStorageThemeCache reads from `localStorage` and decodes a JSON manifest of strings every time `readManifest()` is called. This is a very common operation because it's called on almost every write and cache query operation (`put`, `evict`, `clear`, `keys`, `size`, `entries`). +**Action:** Implement an in-memory `manifestCache: MutableSet?` initialized via `lazy` or checked and set so we don't have to parse JSON from localStorage every time. diff --git a/halogen-engine/src/wasmJsMain/kotlin/halogen/engine/LocalStorageThemeCache.kt b/halogen-engine/src/wasmJsMain/kotlin/halogen/engine/LocalStorageThemeCache.kt index aba1f32..b34898f 100644 --- a/halogen-engine/src/wasmJsMain/kotlin/halogen/engine/LocalStorageThemeCache.kt +++ b/halogen-engine/src/wasmJsMain/kotlin/halogen/engine/LocalStorageThemeCache.kt @@ -48,19 +48,28 @@ public class LocalStorageThemeCache( private val _changes = MutableSharedFlow(extraBufferCapacity = 64) private val json = Json { ignoreUnknownKeys = true } private val manifestKey = "${prefix}__keys__" + private var manifestCache: MutableSet? = null // ── Manifest helpers ──────────────────────────────────────────────── private fun readManifest(): MutableSet { - val raw = jsGetItem(manifestKey.toJsString())?.toString() ?: return mutableSetOf() - return try { - json.decodeFromString>(raw).toMutableSet() - } catch (_: Exception) { + manifestCache?.let { return it } + val raw = jsGetItem(manifestKey.toJsString())?.toString() + val parsed = if (raw == null) { mutableSetOf() + } else { + try { + json.decodeFromString>(raw).toMutableSet() + } catch (_: Exception) { + mutableSetOf() + } } + manifestCache = parsed + return parsed } private fun writeManifest(keys: Set) { + manifestCache = keys.toMutableSet() val encoded = json.encodeToString(keys) jsSetItem(manifestKey.toJsString(), encoded.toJsString()) } @@ -154,6 +163,7 @@ public class LocalStorageThemeCache( for (key in manifest) { removeEntry("$prefix$key") } + manifestCache = mutableSetOf() jsRemoveItem(manifestKey.toJsString()) _changes.tryEmit(CacheEvent.Cleared) } From 2e61fdcc6dbde1e6e3f51309bb5d36e8db2fae13 Mon Sep 17 00:00:00 2001 From: Matt Mckenna Date: Thu, 7 May 2026 09:05:54 -0400 Subject: [PATCH 2/2] chore: drop generated bolt notes --- .jules/bolt.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .jules/bolt.md diff --git a/.jules/bolt.md b/.jules/bolt.md deleted file mode 100644 index 303f8fd..0000000 --- a/.jules/bolt.md +++ /dev/null @@ -1,3 +0,0 @@ -## 2024-05-18 - WasmJs ThemeCache Optimization -**Learning:** JSON decoding in Kotlin Multiplatform for WasmJs targets carries significant overhead. The existing LocalStorageThemeCache reads from `localStorage` and decodes a JSON manifest of strings every time `readManifest()` is called. This is a very common operation because it's called on almost every write and cache query operation (`put`, `evict`, `clear`, `keys`, `size`, `entries`). -**Action:** Implement an in-memory `manifestCache: MutableSet?` initialized via `lazy` or checked and set so we don't have to parse JSON from localStorage every time.