Skip to content

Commit 243253a

Browse files
committed
perf(frontend): preview only when the selected rule actually changed
Raised in review of #61, and my comment was the weaker claim: it said the trigger fires on each keystroke, when it fires on ANY document mutation. `rules` is rebuilt whenever `script` is reassigned, so adding, deleting or reordering some OTHER rule rescheduled a preview of the selected one and spent a request to be told the same bytes it was already showing. Comparing the wire payload rather than the array reference makes those free, and covers the keystroke that leaves wire content unchanged too. The payload compared is the one that gets posted, so the two cannot drift. An error clears the remembered payload, so the next mutation retries rather than matching it and leaving the message up for good. The comment now says what actually happens. Not unit-tested: the logic is inside a .svelte file and this repo has no component test harness. svelte-check, vitest and the build are clean. Refs areyousievious-8fg.17
1 parent 623fcc8 commit 243253a

1 file changed

Lines changed: 24 additions & 5 deletions

File tree

frontend/src/routes/RuleEditor.svelte

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,33 @@
3939
const PREVIEW_DEBOUNCE_MS = 200;
4040
let previewSeq = 0;
4141
let previewTimer;
42+
// The wire payload the preview on screen was rendered from. The trigger
43+
// below fires on ANY document mutation — `rules` is rebuilt whenever
44+
// `script` is reassigned, so adding, deleting or reordering some OTHER rule
45+
// reschedules the selected one too. Comparing payloads rather than array
46+
// references means those cost nothing, and so does a keystroke that leaves
47+
// the wire content unchanged.
48+
let previewedWire = '';
4249
4350
function schedulePreview(rule) {
44-
clearTimeout(previewTimer);
45-
const wanted = (previewSeq += 1);
4651
if (!rule) {
52+
clearTimeout(previewTimer);
53+
previewSeq += 1;
4754
preview = '';
4855
previewError = '';
56+
previewedWire = '';
4957
return;
5058
}
59+
const payload = doc.entryToWire(rule);
60+
const identity = JSON.stringify(payload);
61+
if (identity === previewedWire) return;
62+
previewedWire = identity;
63+
64+
clearTimeout(previewTimer);
65+
const wanted = (previewSeq += 1);
5166
previewTimer = setTimeout(async () => {
5267
try {
53-
const { sieve } = await api.previewRule(doc.entryToWire(rule));
68+
const { sieve } = await api.previewRule(payload);
5469
if (wanted !== previewSeq) return;
5570
preview = sieve;
5671
previewError = '';
@@ -61,6 +76,9 @@
6176
// in a different shape.
6277
preview = '';
6378
previewError = e?.message || 'Preview unavailable';
79+
// Forget what we asked for, so the next trigger retries instead of
80+
// matching `identity` and leaving the error up forever.
81+
previewedWire = '';
6482
}
6583
}, PREVIEW_DEBOUNCE_MS);
6684
}
@@ -92,8 +110,9 @@
92110
93111
$: dirty = !!(script && pristine) && !doc.sameWire(script, pristine);
94112
95-
// Every document mutation makes a fresh `rules`, so this fires on each
96-
// keystroke and the debounce inside does the rest.
113+
// Fires on every document mutation, including ones to other rules — see
114+
// `schedulePreview`, which is what decides whether the selected rule
115+
// actually changed.
97116
$: schedulePreview(rules[selectedIdx]);
98117
99118
function addRule() {

0 commit comments

Comments
 (0)