diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..9d04031 --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2024-04-22 - WasmJs JSON Decoding Overhead +**Learning:** JSON decoding in Kotlin Multiplatform for WasmJs targets carries significant overhead when accessing localStorage. Re-parsing the same JSON structure repeatedly (e.g., manifest keys) negatively impacts performance on Web. +**Action:** Use an in-memory cache initialized when needed (or standard memory properties) to keep a parsed copy of frequently accessed data, thus minimizing redundant `localStorage` operations and `kotlinx.serialization` parsing penalties on WasmJs targets. diff --git a/halogen-engine/src/wasmJsMain/kotlin/halogen/engine/LocalStorageThemeCache.kt b/halogen-engine/src/wasmJsMain/kotlin/halogen/engine/LocalStorageThemeCache.kt index aba1f32..198e464 100644 --- a/halogen-engine/src/wasmJsMain/kotlin/halogen/engine/LocalStorageThemeCache.kt +++ b/halogen-engine/src/wasmJsMain/kotlin/halogen/engine/LocalStorageThemeCache.kt @@ -49,18 +49,23 @@ public class LocalStorageThemeCache( private val json = Json { ignoreUnknownKeys = true } private val manifestKey = "${prefix}__keys__" + // Memory cache for manifest to avoid JSON decoding on every operation + private var manifestCache: MutableSet? = null + // ── Manifest helpers ──────────────────────────────────────────────── private fun readManifest(): MutableSet { - val raw = jsGetItem(manifestKey.toJsString())?.toString() ?: return mutableSetOf() + manifestCache?.let { return it } + val raw = jsGetItem(manifestKey.toJsString())?.toString() ?: return mutableSetOf().also { manifestCache = it } return try { - json.decodeFromString>(raw).toMutableSet() + json.decodeFromString>(raw).toMutableSet().also { manifestCache = it } } catch (_: Exception) { - mutableSetOf() + mutableSetOf().also { manifestCache = it } } } private fun writeManifest(keys: Set) { + manifestCache = keys.toMutableSet() val encoded = json.encodeToString(keys) jsSetItem(manifestKey.toJsString(), encoded.toJsString()) }