perf(configurator): rAF-coalesce preview iframe writes during rapid drags (SL-020) - #480
Conversation
…verride changes SL-020: PreviewPanel.svelte's two $effects that write to the preview iframe(s) and call bumpPreviewVersion() re-run on every overrides tick — e.g. every input event while dragging a slider, often several times per animation frame. Deferred the DOM-writing work (style/attribute mutation, font injection, resolver cache invalidation) inside each effect to a requestAnimationFrame callback that captures the latest values, cancelling any not-yet-fired frame from a superseded run via the effect's cleanup. This collapses a same-frame burst down to one apply using the last state, instead of one apply per keystroke. Reactive dependency tracking is unaffected — overrides/previewTheme/ loadCount/etc. are still read synchronously at the top of each effect, so Svelte's re-run triggering is unchanged; only the actual DOM writes are deferred. previewResolver.svelte.ts's bumpPreviewVersion() itself is untouched, preserving its existing "pure write, no reactive read" invariant. Verified via a manual rapid-drag simulation against a real built preview server (40 input events fired faster than one per frame): zero console/ page errors (no effect_update_depth loop), and the preview iframe's applied CSS exactly matched the last dragged value with no dropped trailing frame.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PR Summary by Qodoperf(configurator): rAF-coalesce preview iframe DOM writes during rapid drags
AI Description
Diagram
High-Level Assessment
Files changed (1)
|
Code Review by Qodo
Context used✅ Compliance rules (platform):
6 rules 1.
|
…it-mode effect when inactive
Qodo review on PR6 flagged two real, pre-existing (not introduced by the
rAF-coalescing itself) inefficiencies in the two effects this PR touches:
1. The single-iframe effect called bumpPreviewVersion() explicitly right
after registerPreviewDoc(doc), but registerPreviewDoc() already bumps
internally on every path (both its activeDoc-unchanged early-return and
its replace-doc branch) — the explicit call double-bumped
previewVersion and double-cleared resolveCache on every apply.
2. The split-mode effect unconditionally scheduled an rAF, computed CSS,
and bumped previewVersion even when splitMode is false and no split
iframes exist in the DOM (they're gated behind {#if splitMode}),
making every apply pure overhead outside split mode.
Fixed both: dropped the explicit bump in the single-iframe effect, added
an early return on !splitMode in the split effect, and made its trailing
bump conditional (only fires when the dark pane updated without the light
pane also updating, since registerPreviewDoc's internal bump already
covers the light-pane case) so consumers are still notified exactly once
whenever a split pane actually changed.
Re-verified via the same rapid-drag simulation as the original PR6
commit, now covering both single- and split-preview modes: zero console/
page errors, and both modes' applied CSS exactly matched the last
dragged value.
|
Both good catches — fixed in 0515efa:
Re-verified with the same rapid-drag simulation as the original commit, now covering both single- and split-preview modes: zero console/page errors, both modes' applied CSS matched the last dragged value exactly. Generated by Claude Code |
92f2a4c
into
claude/pr-469-audit-rebase-ggp0e4
Summary
Sixth themed PR from the SLASHED technical-debt audit (PR #469): the configurator preview debounce. Targets the long-lived integration branch
claude/pr-469-audit-rebase-ggp0e4, after PR5 per the remediation plan's ordering.PreviewPanel.svelte's two$effects that write to the preview iframe(s) (style/attribute mutation, font injection) and callbumpPreviewVersion()re-run on everyoverridestick — e.g. everyinputevent while dragging a slider, often several times per animation frame. Deferred the DOM-writing work inside each effect to arequestAnimationFramecallback that closes over the latest captured values, with the effect's cleanup (return () => cancelAnimationFrame(rafId)) cancelling any not-yet-fired frame from a superseded run before scheduling the next one. This collapses a same-frame burst of reruns into a single apply using the last state, instead of one apply per keystroke.overrides/previewTheme/loadCount/etc. are still read synchronously at the top of each effect (unchanged from before), so Svelte's re-run triggering is untouched — only the actual DOM-writing work is deferred.previewResolver.svelte.ts'sbumpPreviewVersion()itself is untouched, preserving its existing documented invariant ("pure write, no reactive read" — avoids aneffect_update_depthinfinite loop). The coalescing lives entirely at the call site inPreviewPanel.svelte, per the plan.persistence.ts's separateinjectLivePreviewcall path (used for the App-level live<style>tag, not this iframe preview) has no debounce either — that's a different path, addressed independently in SLASHED-Plugins' PR-C3 for the frontend-overlay case.Test plan
npx tsc --noEmit— cleannpx svelte-check --tsconfig ./tsconfig.json— 0 errors, 0 warningsnpm run test:unit— 72/72 passednpm run test:components— 17/17 passednpm run build— succeedsvite preview), then drove a real headless Chromium session to rapid-fire 40 syntheticinputevents on a slider — faster than one per animation frame — simulating an aggressive drag:effect_update_depth/"Maximum update depth"/infinite-loop patterns<style id="slashed-overrides">content exactly matched the last dispatched value (--sf-code-font-size: 1.1em, the final value in the simulated drag) — confirming no dropped trailing frame after the burst settlestests-e2e/shell.spec.jssmoke suite: 5/6 passing against the built preview server (the 1 failure is the same pre-existing/favicon.ico404 noted in PR5, unrelated to this change)Generated by Claude Code