Cache-bust .sx files, optimize stepper back/hydration

Platform:
- sx-platform.js: extract ?v= query from script tag URL, append to
  all .sx file XHR requests. Prevents stale cached .sx files.

Stepper performance:
- do-back: use rebuild-preview (pure SX→DOM render) instead of
  replaying every do-step from 0. O(1) instead of O(n).
- Hydration effect: same rebuild-preview instead of step replay.
- Cookie save moved from do-step to button on-click handlers only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 14:54:43 +00:00
parent 1a3ee40e0d
commit 0c8c0b6426
3 changed files with 715 additions and 18 deletions

View File

@@ -219,17 +219,24 @@
;; Component expressions handled by lake's reactive render
nil))
(swap! step-idx inc)
(update-code-highlight)
(set-cookie "sx-home-stepper" (freeze-to-sx "home-stepper")))))
(update-code-highlight)))))
(rebuild-preview (fn (target)
;; Rebuild preview DOM directly from steps, without replaying do-step
(let ((container (get-preview)))
(when container
(dom-set-prop container "innerHTML" "")
(let ((expr (steps-to-preview (deref steps) target)))
(when expr
(let ((rendered (render-to-dom expr (get-render-env nil) nil)))
(when rendered (dom-append container rendered)))))
(set-stack (list container))))))
(do-back (fn ()
(when (> (deref step-idx) 0)
(let ((target (- (deref step-idx) 1))
(container (get-preview)))
(when container (dom-set-prop container "innerHTML" ""))
(set-stack (list (get-preview)))
(reset! step-idx 0)
(for-each (fn (_) (do-step)) (slice (deref steps) 0 target))
(set-cookie "sx-home-stepper" (freeze-to-sx "home-stepper")))))))
(let ((target (- (deref step-idx) 1)))
(rebuild-preview target)
(reset! step-idx target)
(update-code-highlight)
(set-cookie "sx-home-stepper" (freeze-to-sx "home-stepper"))))))))
;; Freeze scope for persistence — same mechanism, cookie storage
(freeze-scope "home-stepper" (fn ()
(freeze-signal "step" step-idx)))
@@ -254,13 +261,7 @@
(let ((_eff (effect (fn ()
(schedule-idle (fn ()
(build-code-dom)
(let ((preview (get-preview)))
(when preview (dom-set-prop preview "innerHTML" "")))
(batch (fn ()
(let ((target (deref step-idx)))
(reset! step-idx 0)
(set-stack (list (get-preview)))
(for-each (fn (_) (do-step)) (slice (deref steps) 0 target)))))
(rebuild-preview (deref step-idx))
(update-code-highlight)
(run-post-render-hooks)))))))
(div :class "space-y-4"
@@ -282,7 +283,9 @@
(deref code-tokens)))
;; Controls
(div :class "flex items-center justify-center gap-2 md:gap-3"
(button :on-click (fn (e) (do-back))
(button :on-click (fn (e)
(do-back)
(set-cookie "sx-home-stepper" (freeze-to-sx "home-stepper")))
:class (str "px-2 py-1 rounded text-3xl "
(if (> (deref step-idx) 0)
"text-stone-600 hover:text-stone-800 hover:bg-stone-100"
@@ -290,7 +293,9 @@
"\u25c0")
(span :class "text-sm text-stone-500 font-mono tabular-nums"
(deref step-idx) " / " (len (deref steps)))
(button :on-click (fn (e) (do-step))
(button :on-click (fn (e)
(do-step)
(set-cookie "sx-home-stepper" (freeze-to-sx "home-stepper")))
:class (str "px-2 py-1 rounded text-3xl "
(if (< (deref step-idx) (len (deref steps)))
"text-violet-600 hover:text-violet-800 hover:bg-violet-50"