From 02994a3f0d68a9ff7f037946bd249eddb91ed3cf Mon Sep 17 00:00:00 2001 From: Pedro Lamas Date: Thu, 11 Jun 2026 14:31:55 +0100 Subject: [PATCH 1/7] perf(console): freeze immutable entries Console entries are append-only and never mutated after creation. Freezing them on insert and bulk init makes Vue 2.7's observe() skip deep reactive conversion of each entry and of the retained backlog (up to CONSOLE_HISTORY_RETENTION), matching the charts/printer stores. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Pedro Lamas --- src/store/console/mutations.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/store/console/mutations.ts b/src/store/console/mutations.ts index 0ec321014d..94dd0c2ff4 100644 --- a/src/store/console/mutations.ts +++ b/src/store/console/mutations.ts @@ -36,7 +36,7 @@ export const mutations = { while (state.console.length >= Globals.CONSOLE_HISTORY_RETENTION) { state.console.shift() } - state.console.push(entry) + state.console.push(Object.freeze(entry)) }, /** @@ -45,6 +45,7 @@ export const mutations = { setAllEntries (state, payload: ConsoleEntry[]) { state.consoleEntryCount = payload.length state.console = payload + .map(entry => Object.freeze(entry)) }, setResetPromptDialog (state, payload: string) { From 08b648f70c514440f9b40edf0d220b1c446a4a64 Mon Sep 17 00:00:00 2001 From: Pedro Lamas Date: Thu, 11 Jun 2026 14:32:12 +0100 Subject: [PATCH 2/7] perf(sensors): freeze sensor values Sensor values are replaced wholesale on each update and never mutated in place, so freezing them lets Vue 2.7 skip deep reactive conversion on every sensor notification, as well as on the one-time list load. Also drop Vue.set in favour of a plain assignment, since 'values' is always an existing reactive property on the entry. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Pedro Lamas --- src/store/sensors/mutations.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/store/sensors/mutations.ts b/src/store/sensors/mutations.ts index b5a83c6fdf..2656afd1ee 100644 --- a/src/store/sensors/mutations.ts +++ b/src/store/sensors/mutations.ts @@ -1,4 +1,3 @@ -import Vue from 'vue' import type { MutationTree } from 'vuex' import type { MoonrakerSensorsState } from './types' import { defaultState } from './state' @@ -12,12 +11,15 @@ export const mutations = { }, setSensorsList (state, payload: Moonraker.Sensor.ListResponse) { + for (const sensorKey in payload.sensors) { + payload.sensors[sensorKey].values = Object.freeze(payload.sensors[sensorKey].values) + } state.sensors = payload.sensors }, setSensorUpdate (state, payload: Record) { for (const sensorKey in payload) { - Vue.set(state.sensors[sensorKey], 'values', payload[sensorKey]) + state.sensors[sensorKey].values = Object.freeze(payload[sensorKey]) } } } satisfies MutationTree From d7151330dd7c452a85e1ba46ff03c8d3dad3ecc6 Mon Sep 17 00:00:00 2001 From: Pedro Lamas Date: Thu, 11 Jun 2026 15:16:56 +0100 Subject: [PATCH 3/7] refactor(store): remove redundant Vue.set calls Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Pedro Lamas --- src/store/announcements/mutations.ts | 3 +-- src/store/config/mutations.ts | 14 ++++++-------- src/store/console/mutations.ts | 2 +- src/store/database/mutations.ts | 3 +-- src/store/files/mutations.ts | 2 +- src/store/macros/mutations.ts | 2 +- src/store/notifications/mutations.ts | 2 +- src/store/power/mutations.ts | 3 +-- 8 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/store/announcements/mutations.ts b/src/store/announcements/mutations.ts index a657d6edf6..ce6bc0c26c 100644 --- a/src/store/announcements/mutations.ts +++ b/src/store/announcements/mutations.ts @@ -1,4 +1,3 @@ -import Vue from 'vue' import type { MutationTree } from 'vuex' import { defaultState } from './state' import type { AnnouncementsState } from './types' @@ -36,6 +35,6 @@ export const mutations = { } } - Vue.set(state, 'entries', entries) + state.entries = entries } } satisfies MutationTree diff --git a/src/store/config/mutations.ts b/src/store/config/mutations.ts index 8826580103..b756a7d44e 100644 --- a/src/store/config/mutations.ts +++ b/src/store/config/mutations.ts @@ -51,7 +51,7 @@ export const mutations = { (dest, src) => Array.isArray(dest) ? src : undefined ) - Vue.set(state, 'uiSettings', mergedSettings) + state.uiSettings = mergedSettings } }, @@ -107,7 +107,7 @@ export const mutations = { }) } localStorage.setItem(Globals.LOCAL_INSTANCES_STORAGE_KEY, JSON.stringify(instances)) - Vue.set(state, 'instances', instances) + state.instances = instances }, setUpdateInstanceName (state, payload) { @@ -120,12 +120,10 @@ export const mutations = { }, setRemoveInstance (state, payload) { - const instances = state.instances - const i = instances.findIndex((instance: InstanceConfig) => instance.apiUrl === payload.apiUrl) - if (i >= 0) { - instances.splice(i, 1) - Vue.set(state, 'instances', instances) - localStorage.setItem(Globals.LOCAL_INSTANCES_STORAGE_KEY, JSON.stringify(instances)) + const index = state.instances.findIndex((instance: InstanceConfig) => instance.apiUrl === payload.apiUrl) + if (index >= 0) { + state.instances.splice(index, 1) + localStorage.setItem(Globals.LOCAL_INSTANCES_STORAGE_KEY, JSON.stringify(state.instances)) } }, diff --git a/src/store/console/mutations.ts b/src/store/console/mutations.ts index 94dd0c2ff4..438cffd680 100644 --- a/src/store/console/mutations.ts +++ b/src/store/console/mutations.ts @@ -163,6 +163,6 @@ export const mutations = { }, setLastCleared (state) { - Vue.set(state, 'lastCleared', Date.now()) + state.lastCleared = Date.now() } } satisfies MutationTree diff --git a/src/store/database/mutations.ts b/src/store/database/mutations.ts index 225bf4d02c..ae89ebfd77 100644 --- a/src/store/database/mutations.ts +++ b/src/store/database/mutations.ts @@ -1,4 +1,3 @@ -import Vue from 'vue' import type { MutationTree } from 'vuex' import { defaultState } from './state' import type { DatabaseInfo, DatabaseState } from './types' @@ -10,7 +9,7 @@ export const mutations = { }, setServerDatabaseList (state, payload: DatabaseInfo) { - Vue.set(state, 'info', payload) + state.info = payload }, setServerDatabasePostBackup (state, payload: { backup_path: string }) { diff --git a/src/store/files/mutations.ts b/src/store/files/mutations.ts index 6c8c5d6e43..cbe3439b80 100644 --- a/src/store/files/mutations.ts +++ b/src/store/files/mutations.ts @@ -21,7 +21,7 @@ export const mutations = { } if (state.currentPaths[root]) { - Vue.set(state.currentPaths, root, undefined) + Vue.delete(state.currentPaths, root) } }, diff --git a/src/store/macros/mutations.ts b/src/store/macros/mutations.ts index d65235ed16..e1ee375fb3 100644 --- a/src/store/macros/mutations.ts +++ b/src/store/macros/mutations.ts @@ -93,6 +93,6 @@ export const mutations = { }, setExpanded (state, expanded: number[]) { - Vue.set(state, 'expanded', expanded) + state.expanded = expanded } } satisfies MutationTree diff --git a/src/store/notifications/mutations.ts b/src/store/notifications/mutations.ts index 2b3c68ec25..8ae73a6cf1 100644 --- a/src/store/notifications/mutations.ts +++ b/src/store/notifications/mutations.ts @@ -34,6 +34,6 @@ export const mutations = { }, setClearAllNotifications (state) { - Vue.set(state, 'notifications', [...state.notifications.filter(n => !n.clear)]) + state.notifications = [...state.notifications.filter(n => !n.clear)] } } satisfies MutationTree diff --git a/src/store/power/mutations.ts b/src/store/power/mutations.ts index 6193a11fed..3b7451e5bf 100644 --- a/src/store/power/mutations.ts +++ b/src/store/power/mutations.ts @@ -1,4 +1,3 @@ -import Vue from 'vue' import type { MutationTree } from 'vuex' import type { DevicePowerState } from './types' import { defaultState } from './state' @@ -19,7 +18,7 @@ export const mutations = { for (const key in payload) { const i = state.devices.findIndex(device => device.device === key) if (i >= 0) { - Vue.set(state.devices[i], 'status', payload[key]) + state.devices[i].status = payload[key] } } } From 9b1cbe9d7e9667f30cc2149ffc8bee6913195b63 Mon Sep 17 00:00:00 2001 From: Pedro Lamas Date: Thu, 11 Jun 2026 15:37:16 +0100 Subject: [PATCH 4/7] fix(sensors): correct sensor update payload type Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Pedro Lamas --- src/store/sensors/actions.ts | 2 +- src/store/sensors/mutations.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/store/sensors/actions.ts b/src/store/sensors/actions.ts index 3c7ee6878f..4f5278b580 100644 --- a/src/store/sensors/actions.ts +++ b/src/store/sensors/actions.ts @@ -18,7 +18,7 @@ export const actions = { } }, - async onSensorUpdate ({ commit }, payload: Record) { + async onSensorUpdate ({ commit }, payload: Record) { if (payload) { commit('setSensorUpdate', payload) } diff --git a/src/store/sensors/mutations.ts b/src/store/sensors/mutations.ts index 2656afd1ee..f3b1baec66 100644 --- a/src/store/sensors/mutations.ts +++ b/src/store/sensors/mutations.ts @@ -17,7 +17,7 @@ export const mutations = { state.sensors = payload.sensors }, - setSensorUpdate (state, payload: Record) { + setSensorUpdate (state, payload: Record) { for (const sensorKey in payload) { state.sensors[sensorKey].values = Object.freeze(payload[sensorKey]) } From 06417c1ac6b68f0c6be45ac28bf399bfa8138bc6 Mon Sep 17 00:00:00 2001 From: Pedro Lamas Date: Thu, 11 Jun 2026 15:58:45 +0100 Subject: [PATCH 5/7] refactor(sensors): avoid mutating payload in setSensorsList Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Pedro Lamas --- src/store/sensors/mutations.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/store/sensors/mutations.ts b/src/store/sensors/mutations.ts index f3b1baec66..595ec98bce 100644 --- a/src/store/sensors/mutations.ts +++ b/src/store/sensors/mutations.ts @@ -11,10 +11,16 @@ export const mutations = { }, setSensorsList (state, payload: Moonraker.Sensor.ListResponse) { - for (const sensorKey in payload.sensors) { - payload.sensors[sensorKey].values = Object.freeze(payload.sensors[sensorKey].values) - } - state.sensors = payload.sensors + state.sensors = Object.fromEntries( + Object.entries(payload.sensors) + .map(([key, entry]) => [ + key, + { + ...entry, + values: Object.freeze(entry.values) + } + ]) + ) }, setSensorUpdate (state, payload: Record) { From 241e25dd200007c9a1fe5694b1b61512c63e0690 Mon Sep 17 00:00:00 2001 From: Pedro Lamas Date: Thu, 11 Jun 2026 16:02:47 +0100 Subject: [PATCH 6/7] refactor(notifications): simplify setClearAllNotifications Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Pedro Lamas --- src/store/notifications/mutations.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/store/notifications/mutations.ts b/src/store/notifications/mutations.ts index 8ae73a6cf1..eab243d7aa 100644 --- a/src/store/notifications/mutations.ts +++ b/src/store/notifications/mutations.ts @@ -34,6 +34,7 @@ export const mutations = { }, setClearAllNotifications (state) { - state.notifications = [...state.notifications.filter(n => !n.clear)] + state.notifications = state.notifications + .filter(n => !n.clear) } } satisfies MutationTree From 73451b17df7205a652b334a06201749ee5990059 Mon Sep 17 00:00:00 2001 From: Pedro Lamas Date: Thu, 11 Jun 2026 16:09:29 +0100 Subject: [PATCH 7/7] fix(sensors): correct onSensorsList action payload type Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Pedro Lamas --- src/store/sensors/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/sensors/actions.ts b/src/store/sensors/actions.ts index 4f5278b580..79009cd7e8 100644 --- a/src/store/sensors/actions.ts +++ b/src/store/sensors/actions.ts @@ -12,7 +12,7 @@ export const actions = { SocketActions.serverSensorsList() }, - async onSensorsList ({ commit }, payload: { sensors: Moonraker.Sensor.ListResponse }) { + async onSensorsList ({ commit }, payload: Moonraker.Sensor.ListResponse) { if (payload) { commit('setSensorsList', payload) }