Commite33f8560Recorded16 Jul 2026Repositorysigil-web-client

web-client: simplify reconcile-children

Message

Use map for the target node list and fold the empty->populated branch into the general moves path: first populate is now the same prune+moves flow with a preceding bulk clear (dropping possible pre-existing static markup), removing the duplicated append loop.

Changed
 src/sigil/web/client.sgl | 64 +++++++++++++++++++++++++++++-----------------------------------
 1 file changed, 29 insertions(+), 35 deletions(-)
Diff
src/sigil/web/client.sglmodified
@@ -465,41 +465,35 @@
465
;; dropped nodes, then insert-before only the nodes whose position
466
;; actually changed. The unchanged common case makes zero DOM calls.
467
(define (web-client-reconcile-children! parent old-records ordered)
−468
(let ((target (let collect ((rest ordered) (acc '()))
−469
(if (null? rest)
−470
(reverse acc)
−471
(collect (cdr rest)
−472
(cons (web-client-record-node (car rest)) acc))))))
−473
(cond
−474
;; populated -> empty: one bulk clear beats N removals.
−475
((null? target)
−476
(when (pair? old-records)
−477
(wasm-dom-replace-children parent)))
−478
;; empty -> populated (first populate of this parent): clear any
−479
;; pre-existing content (e.g. static placeholder markup in a root
−480
;; that was never rendered into) and append in order, exactly like
−481
;; the old path did on initial render.
−482
((null? old-records)
−483
(wasm-dom-replace-children parent)
−484
(for-each
−485
(lambda (node) (wasm-dom-append-child parent node))
−486
target))
−487
(else
−488
;; Drop old top-level nodes not carried into the new set, keeping
−489
;; the still-attached nodes in their current DOM order.
−490
(let ((current (let prune ((rest old-records) (acc '()))
−491
(if (null? rest)
−492
(reverse acc)
−493
(let ((node (web-client-record-node (car rest))))
−494
(if (memv node target)
−495
(prune (cdr rest) (cons node acc))
−496
(begin
−497
(wasm-dom-remove-child parent node)
−498
(prune (cdr rest) acc))))))))
−499
(for-each
−500
(lambda (op)
−501
(wasm-dom-insert-before parent (car op) (cdr op)))
−502
(web-client-child-moves current target)))))))
+468
(let ((target (map web-client-record-node ordered)))
+469
(if (null? target)
+470
;; populated -> empty: one bulk clear beats N removals. (When both
+471
;; sides are empty nothing is touched, so a childless element costs
+472
;; no bridge call per render.)
+473
(when (pair? old-records)
+474
(wasm-dom-replace-children parent))
+475
(begin
+476
;; empty -> populated (first populate of this parent): clear any
+477
;; pre-existing content first (e.g. static placeholder markup in
+478
;; a root that was never rendered into), like the old path did on
+479
;; initial render. The moves below then append every node.
+480
(when (null? old-records)
+481
(wasm-dom-replace-children parent))
+482
;; Drop old top-level nodes not carried into the new set, keeping
+483
;; the still-attached nodes in their current DOM order.
+484
(let ((current (let prune ((rest old-records) (acc '()))
+485
(if (null? rest)
+486
(reverse acc)
+487
(let ((node (web-client-record-node (car rest))))
+488
(if (memv node target)
+489
(prune (cdr rest) (cons node acc))
+490
(begin
+491
(wasm-dom-remove-child parent node)
+492
(prune (cdr rest) acc))))))))
+493
(for-each
+494
(lambda (op)
+495
(wasm-dom-insert-before parent (car op) (cdr op)))
+496
(web-client-child-moves current target)))))))
497
498
(define (web-client-patch-children parent old-records new-values)
499
(let loop ((rest (web-client-normalize-children new-values))