Fix reactive islands client-side navigation and hydration
Three bugs prevented islands from working during SX wire navigation: 1. components_for_request() only bundled Component and Macro defs, not Island defs — client never received defisland definitions during navigation (components_for_page for initial HTML shell was correct). 2. hydrate-island used morph-children which can't transfer addEventListener event handlers from freshly rendered DOM to existing nodes. Changed to clear+append so reactive DOM with live signal subscriptions is inserted directly. 3. asyncRenderToDom (client-side async page eval) checked _component but not _island on ~-prefixed names — islands fell through to generic eval which failed. Now delegates to renderDomIsland. 4. setInterval_/setTimeout_ passed SX Lambda objects directly to native timers. JS coerced them to "[object Object]" and tried to eval as code, causing "missing ] after element list". Added _wrapSxFn to convert SX lambdas to JS functions before passing to timers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,15 @@
|
||||
;; (set-tracking-context! c) → void
|
||||
;; (get-tracking-context) → context or nil
|
||||
;;
|
||||
;; Runtime callable dispatch:
|
||||
;; (invoke f &rest args) → any — call f with args; handles both
|
||||
;; native host functions AND SX lambdas
|
||||
;; from runtime-evaluated code (islands).
|
||||
;; Transpiled code emits direct calls
|
||||
;; f(args) which fail on SX lambdas.
|
||||
;; invoke goes through the evaluator's
|
||||
;; dispatch (call-fn) so either works.
|
||||
;;
|
||||
;; ==========================================================================
|
||||
|
||||
|
||||
@@ -112,7 +121,7 @@
|
||||
(let ((ctx (make-tracking-context recompute)))
|
||||
(let ((prev (get-tracking-context)))
|
||||
(set-tracking-context! ctx)
|
||||
(let ((new-val (compute-fn)))
|
||||
(let ((new-val (invoke compute-fn)))
|
||||
(set-tracking-context! prev)
|
||||
;; Save discovered deps
|
||||
(signal-set-deps! s (tracking-context-deps ctx))
|
||||
@@ -144,7 +153,7 @@
|
||||
(fn ()
|
||||
(when (not disposed)
|
||||
;; Run previous cleanup if any
|
||||
(when cleanup-fn (cleanup-fn))
|
||||
(when cleanup-fn (invoke cleanup-fn))
|
||||
|
||||
;; Unsubscribe from old deps
|
||||
(for-each
|
||||
@@ -156,7 +165,7 @@
|
||||
(let ((ctx (make-tracking-context run-effect)))
|
||||
(let ((prev (get-tracking-context)))
|
||||
(set-tracking-context! ctx)
|
||||
(let ((result (effect-fn)))
|
||||
(let ((result (invoke effect-fn)))
|
||||
(set-tracking-context! prev)
|
||||
(set! deps (tracking-context-deps ctx))
|
||||
;; If effect returns a function, it's the cleanup
|
||||
@@ -169,7 +178,7 @@
|
||||
;; Return dispose function
|
||||
(fn ()
|
||||
(set! disposed true)
|
||||
(when cleanup-fn (cleanup-fn))
|
||||
(when cleanup-fn (invoke cleanup-fn))
|
||||
(for-each
|
||||
(fn (dep) (signal-remove-sub! dep run-effect))
|
||||
deps)
|
||||
@@ -189,7 +198,7 @@
|
||||
(define batch
|
||||
(fn (thunk)
|
||||
(set! *batch-depth* (+ *batch-depth* 1))
|
||||
(thunk)
|
||||
(invoke thunk)
|
||||
(set! *batch-depth* (- *batch-depth* 1))
|
||||
(when (= *batch-depth* 0)
|
||||
(let ((queue *batch-queue*))
|
||||
@@ -308,7 +317,7 @@
|
||||
(let ((registry *store-registry*))
|
||||
;; Only create the store once — subsequent calls return existing
|
||||
(when (not (has-key? registry name))
|
||||
(set! *store-registry* (assoc registry name (init-fn))))
|
||||
(set! *store-registry* (assoc registry name (invoke init-fn))))
|
||||
(get *store-registry* name))))
|
||||
|
||||
(define use-store
|
||||
@@ -367,7 +376,7 @@
|
||||
(fn (e)
|
||||
(let ((detail (event-detail e))
|
||||
(new-val (if transform-fn
|
||||
(transform-fn detail)
|
||||
(invoke transform-fn detail)
|
||||
detail)))
|
||||
(reset! target-signal new-val))))))
|
||||
;; Return cleanup — removes listener on dispose/re-run
|
||||
|
||||
Reference in New Issue
Block a user