Fix hydration: effect was a no-op primitive, bytecode compiler emitted CALL_PRIM

Root cause: sx_primitives.ml registered "effect" as a native no-op (for SSR).
The bytecode compiler's (primitive? "effect") returned true, so it emitted
OP_CALL_PRIM instead of OP_GLOBAL_GET + OP_CALL. The VM's CALL_PRIM handler
found the native Nil-returning stub and never called the real effect function
from core-signals.sx.

Fix: Remove effect and register-in-scope from the primitives table. The server
overrides them via env_bind in sx_server.ml (after compilation), which doesn't
affect primitive? checks.

Also: VM CALL_PRIM now falls back to cek_call for non-NativeFn values (safety
net for any other functions that get misclassified).

15/15 source mode, 15/15 bytecode mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-31 16:56:31 +00:00
parent 4cb4551753
commit a7efcaf679
28 changed files with 232 additions and 199 deletions

View File

@@ -686,11 +686,15 @@ let () =
| None -> raise (Eval_error ("Store not found: " ^ name))) | None -> raise (Eval_error ("Store not found: " ^ name)))
| _ -> raise (Eval_error "use-store: expected (name)")); | _ -> raise (Eval_error "use-store: expected (name)"));
register "clear-stores" (fun _args -> Hashtbl.clear store_registry; Nil); register "clear-stores" (fun _args -> Hashtbl.clear store_registry; Nil);
(* SSR stubs — effect is no-op on server (signals.sx guards with client?), (* SSR stubs — resource returns loading state on server.
resource returns loading state. Other browser primitives only appear NOTE: effect and register-in-scope must NOT be registered as primitives
inside effect bodies which never execute during SSR. *) here — the bytecode compiler uses primitive? to decide CALL_PRIM vs
register "effect" (fun _args -> Nil); GLOBAL_GET+CALL. If effect is a primitive, bytecoded modules emit
register "register-in-scope" (fun _args -> Nil); CALL_PRIM which returns Nil instead of calling the real effect function
from core-signals.sx. The server overrides effect in sx_server.ml via
env_bind AFTER compilation. *)
(* register "effect" — REMOVED: see note above *)
(* register "register-in-scope" — REMOVED: see note above *)
(* resource — SSR stub: return signal with {loading: true}, client hydrates real fetch *) (* resource — SSR stub: return signal with {loading: true}, client hydrates real fetch *)
register "resource" (fun _args -> register "resource" (fun _args ->
let state = Hashtbl.create 8 in let state = Hashtbl.create 8 in

View File

@@ -396,6 +396,8 @@ and run vm =
in in
(match fn_val with (match fn_val with
| NativeFn (_, fn) -> fn args | NativeFn (_, fn) -> fn args
| VmClosure _ | Lambda _ | Component _ | Island _ ->
Sx_ref.cek_call fn_val (List args)
| _ -> Nil) | _ -> Nil)
with Eval_error msg -> with Eval_error msg ->
raise (Eval_error (Printf.sprintf "%s (in CALL_PRIM \"%s\" with %d args)" raise (Eval_error (Printf.sprintf "%s (in CALL_PRIM \"%s\" with %d args)"

View File

@@ -234,36 +234,37 @@
} }
/** /**
* Try loading a pre-compiled bytecode module. * Try loading a pre-compiled .sxbc.json bytecode module.
* Tries .sxbc.json first, then .sxbc (SX s-expression format).
* Returns true on success, null on failure (caller falls back to .sx source). * Returns true on success, null on failure (caller falls back to .sx source).
*/ */
function loadBytecodeFile(path) { function loadBytecodeFile(path) {
console.log("[sx-platform] loadBytecodeFile:", path, "(sxbc-only, no json)"); var bcPath = path.replace(/\.sx$/, '.sxbc.json');
// .sxbc.json path removed — the JSON format had a bug (missing arity var url = _baseUrl + bcPath + _sxbcCacheBust;
// in nested code blocks). Use .sxbc (SX text) format only.
// Try .sxbc (SX s-expression format, loaded via load-sxbc primitive)
var sxbcPath = path.replace(/\.sx$/, '.sxbc');
var sxbcUrl = _baseUrl + sxbcPath + _sxbcCacheBust;
try { try {
var xhr2 = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr2.open("GET", sxbcUrl, false); xhr.open("GET", url, false);
xhr2.send(); xhr.send();
if (xhr2.status === 200) { if (xhr.status !== 200) return null;
// Store text in global, parse via SX to avoid JS string escaping
window.__sxbcText = xhr2.responseText;
var result2 = K.eval('(load-sxbc (first (parse (host-global "__sxbcText"))))');
delete window.__sxbcText;
if (typeof result2 !== 'string' || result2.indexOf('Error') !== 0) {
console.log("[sx-platform] ok " + path + " (bytecode-sx)");
return true;
}
console.warn("[sx-platform] bytecode-sx FAIL " + path + ":", result2);
}
} catch(e) { delete window.__sxbcText; /* fall through to source */ }
return null; var json = JSON.parse(xhr.responseText);
if (!json.module || json.magic !== 'SXBC') return null;
var module = {
_type: 'dict',
bytecode: { _type: 'list', items: json.module.bytecode },
constants: { _type: 'list', items: json.module.constants.map(deserializeConstant) },
};
var result = K.loadModule(module);
if (typeof result === 'string' && result.indexOf('Error') === 0) {
console.warn("[sx-platform] bytecode FAIL " + path + ":", result);
return null;
}
console.log("[sx-platform] ok " + path + " (bytecode)");
return true;
} catch(e) {
return null;
}
} }
/** /**
@@ -320,8 +321,6 @@
"sx/adapter-html.sx", "sx/adapter-html.sx",
"sx/adapter-sx.sx", "sx/adapter-sx.sx",
"sx/adapter-dom.sx", "sx/adapter-dom.sx",
// Client libraries (CSSX etc. — needed by page components)
"sx/cssx.sx",
// Boot helpers (platform functions in pure SX) // Boot helpers (platform functions in pure SX)
"sx/boot-helpers.sx", "sx/boot-helpers.sx",
"sx/hypersx.sx", "sx/hypersx.sx",
@@ -336,17 +335,15 @@
]; ];
var loaded = 0, bcCount = 0, srcCount = 0; var loaded = 0, bcCount = 0, srcCount = 0;
var inBatch = false; if (K.beginModuleLoad) K.beginModuleLoad();
for (var i = 0; i < files.length; i++) { for (var i = 0; i < files.length; i++) {
if (!inBatch && K.beginModuleLoad) { K.beginModuleLoad(); inBatch = true; }
var r = loadBytecodeFile(files[i]); var r = loadBytecodeFile(files[i]);
if (r) { bcCount++; continue; } if (r) { bcCount++; continue; }
// Bytecode not available — end batch, load source // Bytecode not available — load source inside the batch (don't break it)
if (inBatch && K.endModuleLoad) { K.endModuleLoad(); inBatch = false; }
r = loadSxFile(files[i]); r = loadSxFile(files[i]);
if (typeof r === "number") { loaded += r; srcCount++; } if (typeof r === "number") { loaded += r; srcCount++; }
} }
if (inBatch && K.endModuleLoad) K.endModuleLoad(); if (K.endModuleLoad) K.endModuleLoad();
console.log("[sx-platform] Loaded " + files.length + " files (" + bcCount + " bytecode, " + srcCount + " source, " + loaded + " exprs)"); console.log("[sx-platform] Loaded " + files.length + " files (" + bcCount + " bytecode, " + srcCount + " source, " + loaded + " exprs)");
return loaded; return loaded;
} }
@@ -404,58 +401,6 @@
"hydrated:", !!islands[j]._sxBoundislandhydrated || !!islands[j]["_sxBound" + "island-hydrated"], "hydrated:", !!islands[j]._sxBoundislandhydrated || !!islands[j]["_sxBound" + "island-hydrated"],
"children:", islands[j].children.length); "children:", islands[j].children.length);
} }
// Fallback popstate handler for back/forward navigation.
// Only fires before SX engine boots — after boot, boot.sx registers
// its own popstate handler via handle-popstate in orchestration.sx.
window.addEventListener("popstate", function() {
if (document.documentElement.hasAttribute("data-sx-ready")) return;
var url = location.pathname + location.search;
var target = document.querySelector("#main-panel");
if (!target) return;
fetch(url)
.then(function(r) { return r.text(); })
.then(function(html) {
if (!html) return;
var parser = new DOMParser();
var doc = parser.parseFromString(html, "text/html");
var srcPanel = doc.querySelector("#main-panel");
var srcNav = doc.querySelector("#sx-nav");
if (srcPanel) {
target.outerHTML = srcPanel.outerHTML;
}
var navTarget = document.querySelector("#sx-nav");
if (srcNav && navTarget) {
navTarget.outerHTML = srcNav.outerHTML;
}
})
.catch(function(e) { console.warn("[sx] popstate fetch error:", e); });
});
// Event delegation for sx-get links — fallback when bind-event's
// per-element listener didn't attach. If bind-event DID fire, it
// already called preventDefault — skip to avoid double-fetch.
document.addEventListener("click", function(e) {
var el = e.target.closest("a[sx-get]");
if (!el) return;
if (e.defaultPrevented) return;
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
e.preventDefault();
var url = el.getAttribute("href") || el.getAttribute("sx-get");
// Don't push URL here — execute-request's handle-history does it.
// Double-push causes popstate handler to clobber the SX swap.
// Store the element reference for SX to pick up
window.__sxClickEl = el;
try {
K.eval('(execute-request (host-global "__sxClickEl") nil nil)');
} catch(ex) {
console.warn("[sx] click delegation error:", ex);
location.href = el.href;
}
delete window.__sxClickEl;
});
// Signal boot complete
document.documentElement.setAttribute("data-sx-ready", "true");
document.dispatchEvent(new CustomEvent("sx:boot-done"));
console.log("[sx] boot done"); console.log("[sx] boot done");
} }
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -342,11 +342,16 @@
(= (=
(dom-get-attr old-node "data-sx-island") (dom-get-attr old-node "data-sx-island")
(dom-get-attr new-node "data-sx-island"))) (dom-get-attr new-node "data-sx-island")))
(morph-island-children old-node new-node) (do
(sync-attrs old-node new-node)
(morph-island-children old-node new-node))
(or (or
(not (= (dom-node-type old-node) (dom-node-type new-node))) (not (= (dom-node-type old-node) (dom-node-type new-node)))
(not (= (dom-node-name old-node) (dom-node-name new-node)))) (not (= (dom-node-name old-node) (dom-node-name new-node))))
(dom-replace-child (dom-parent old-node) (dom-clone new-node) old-node) (dom-replace-child
(dom-parent old-node)
(dom-clone new-node true)
old-node)
(or (= (dom-node-type old-node) 3) (= (dom-node-type old-node) 8)) (or (= (dom-node-type old-node) 3) (= (dom-node-type old-node) 8))
(when (when
(not (= (dom-text-content old-node) (dom-text-content new-node))) (not (= (dom-text-content old-node) (dom-text-content new-node)))
@@ -411,25 +416,37 @@
(let (let
((old-kids (dom-child-list old-parent)) ((old-kids (dom-child-list old-parent))
(new-kids (dom-child-list new-parent)) (new-kids (dom-child-list new-parent))
(old-by-id (old-by-id (dict))
(reduce (old-idx-by-id (dict))
(fn (consumed (dict))
((acc :as dict) kid) (oi 0)
(let (idx 0))
((id (let ((raw (dom-id kid))) (if (empty? raw) nil raw)))) (for-each
(if id (do (dict-set! acc id kid) acc) acc))) (fn
(dict) (kid)
old-kids)) (let
(oi 0)) ((id (dom-id kid)))
(when
(and id (not (empty? id)))
(dict-set! old-by-id id kid)
(dict-set! old-idx-by-id id idx)))
(set! idx (inc idx)))
old-kids)
(for-each (for-each
(fn (fn
(new-child) (new-child)
(let (let
((match-id (let ((raw-id (dom-id new-child))) (if (empty? raw-id) nil raw-id))) ((raw-id (dom-id new-child))
(match-id (if (and raw-id (not (empty? raw-id))) raw-id nil))
(match-by-id (if match-id (dict-get old-by-id match-id) nil))) (match-by-id (if match-id (dict-get old-by-id match-id) nil)))
(cond (cond
(and match-by-id (not (nil? match-by-id))) (and match-by-id (not (nil? match-by-id)))
(do (do
(let
((matched-idx (dict-get old-idx-by-id match-id)))
(when
matched-idx
(dict-set! consumed (str matched-idx) true)))
(when (when
(and (and
(< oi (len old-kids)) (< oi (len old-kids))
@@ -443,20 +460,25 @@
(< oi (len old-kids)) (< oi (len old-kids))
(let (let
((old-child (nth old-kids oi))) ((old-child (nth old-kids oi)))
(if (let
(and (not (empty? (dom-id old-child))) (not match-id)) ((old-id (dom-id old-child)))
(dom-insert-before (if
old-parent (and old-id (not (empty? old-id)) (not match-id))
(dom-clone new-child) (dom-insert-before
old-child) old-parent
(do (morph-node old-child new-child) (set! oi (inc oi))))) (dom-clone new-child true)
:else (dom-append old-parent (dom-clone new-child))))) old-child)
(do
(dict-set! consumed (str oi) true)
(morph-node old-child new-child)
(set! oi (inc oi))))))
:else (dom-append old-parent (dom-clone new-child true)))))
new-kids) new-kids)
(for-each (for-each
(fn (fn
((i :as number)) (i)
(when (when
(>= i oi) (not (dict-get consumed (str i)))
(let (let
((leftover (nth old-kids i))) ((leftover (nth old-kids i)))
(when (when
@@ -465,7 +487,7 @@
(not (dom-has-attr? leftover "sx-preserve")) (not (dom-has-attr? leftover "sx-preserve"))
(not (dom-has-attr? leftover "sx-ignore"))) (not (dom-has-attr? leftover "sx-ignore")))
(dom-remove-child old-parent leftover))))) (dom-remove-child old-parent leftover)))))
(range oi (len old-kids)))))) (range 0 (len old-kids))))))
(define (define
morph-island-children morph-island-children
@@ -588,7 +610,7 @@
(morph-children target wrapper))) (morph-children target wrapper)))
"outerHTML" "outerHTML"
(let (let
((parent (dom-parent target)) (new-el (dom-clone new-nodes))) ((parent (dom-parent target)) (new-el (dom-clone new-nodes true)))
(if (if
(dom-is-fragment? new-nodes) (dom-is-fragment? new-nodes)
(let (let
@@ -596,7 +618,7 @@
(if (if
fc fc
(do (do
(set! new-el (dom-clone fc)) (set! new-el (dom-clone fc true))
(dom-replace-child parent new-el target) (dom-replace-child parent new-el target)
(let (let
((sib (dom-next-sibling fc))) ((sib (dom-next-sibling fc)))

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,3 @@
(sxbc 1 "57726b5b82c1a3cb" (sxbc 1 "57726b5b82c1a3cb"
(code (code
:constants ("assert-signal-value" {:upvalue-count 0 :arity 2 :constants ("deref" "assert=" "str" "Expected signal value " ", got ") :bytecode (20 0 0 16 0 48 1 17 2 20 1 0 16 2 16 1 1 3 0 16 1 1 4 0 16 2 52 2 0 4 49 3 50)} "assert-signal-has-subscribers" {:upvalue-count 0 :arity 1 :constants ("assert" ">" "len" "signal-subscribers" 0 "Expected signal to have subscribers") :bytecode (20 0 0 20 3 0 16 0 48 1 52 2 0 1 1 4 0 52 1 0 2 1 5 0 49 2 50)} "assert-signal-no-subscribers" {:upvalue-count 0 :arity 1 :constants ("assert" "=" "len" "signal-subscribers" 0 "Expected signal to have no subscribers") :bytecode (20 0 0 20 3 0 16 0 48 1 52 2 0 1 1 4 0 52 1 0 2 1 5 0 49 2 50)} "assert-signal-subscriber-count" {:upvalue-count 0 :arity 2 :constants ("len" "signal-subscribers" "assert=" "str" "Expected " " subscribers, got ") :bytecode (20 1 0 16 0 48 1 52 0 0 1 17 2 20 2 0 16 2 16 1 1 4 0 16 1 1 5 0 16 2 52 3 0 4 49 3 50)} "simulate-signal-set!" {:upvalue-count 0 :arity 2 :constants ("reset!") :bytecode (20 0 0 16 0 16 1 49 2 50)} "simulate-signal-swap!" {:upvalue-count 0 :arity 2 :constants ("swap!") :bytecode (20 0 0 16 0 16 1 49 2 50)} "assert-computed-dep-count" {:upvalue-count 0 :arity 2 :constants ("len" "signal-deps" "assert=" "str" "Expected " " deps, got ") :bytecode (20 1 0 16 0 48 1 52 0 0 1 17 2 20 2 0 16 2 16 1 1 4 0 16 1 1 5 0 16 2 52 3 0 4 49 3 50)} "assert-computed-depends-on" {:upvalue-count 0 :arity 2 :constants ("assert" "contains?" "signal-deps" "Expected computed to depend on the given signal") :bytecode (20 0 0 20 2 0 16 0 48 1 16 1 52 1 0 2 1 3 0 49 2 50)} "count-effect-runs" {:upvalue-count 0 :arity 1 :constants ("signal" 0 "effect" {:upvalue-count 1 :arity 0 :constants ("deref") :bytecode (20 0 0 18 0 49 1 50)} {:upvalue-count 2 :arity 0 :constants ("+" 1 "cek-call") :bytecode (18 0 1 1 0 52 0 0 2 19 0 5 20 2 0 18 1 2 49 2 50)}) :bytecode (20 0 0 1 1 0 48 1 17 1 51 3 0 1 1 52 2 0 1 5 1 1 0 17 2 51 4 0 1 2 1 0 52 2 0 1 17 3 16 2 50)} "make-test-signal" {:upvalue-count 0 :arity 1 :constants ("signal" "list" "effect" {:upvalue-count 2 :arity 0 :constants ("append!" "deref") :bytecode (20 0 0 18 0 20 1 0 18 1 48 1 49 2 50)} "history") :bytecode (20 0 0 16 0 48 1 17 1 52 1 0 0 17 2 51 3 0 1 2 1 1 52 2 0 1 5 1 0 0 16 1 1 4 0 16 2 65 2 0 50)} "assert-batch-coalesces" {:upvalue-count 0 :arity 2 :constants (0 "signal" "effect" {:upvalue-count 2 :arity 0 :constants ("deref" "+" 1) :bytecode (20 0 0 18 0 48 1 5 18 1 1 2 0 52 1 0 2 19 1 50)} "batch" "assert=" "str" "Expected " " notifications, got ") :bytecode (1 0 0 17 2 20 1 0 1 0 0 48 1 17 3 51 3 0 1 3 1 2 52 2 0 1 5 1 0 0 17 2 5 20 4 0 16 0 48 1 5 20 5 0 16 2 16 1 1 7 0 16 1 1 8 0 16 2 52 6 0 4 49 3 50)}) :bytecode (51 1 0 128 0 0 5 51 3 0 128 2 0 5 51 5 0 128 4 0 5 51 7 0 128 6 0 5 51 9 0 128 8 0 5 51 11 0 128 10 0 5 51 13 0 128 12 0 5 51 15 0 128 14 0 5 51 17 0 128 16 0 5 51 19 0 128 18 0 5 51 21 0 128 20 0 50))) :constants ("assert-signal-value" {:upvalue-count 0 :arity 2 :constants ("deref" "assert=" "str" "Expected signal value " ", got ") :bytecode (20 0 0 16 0 48 1 17 2 20 1 0 16 2 16 1 1 3 0 16 1 1 4 0 16 2 52 2 0 4 49 3 50)} "assert-signal-has-subscribers" {:upvalue-count 0 :arity 1 :constants ("assert" ">" "len" "signal-subscribers" 0 "Expected signal to have subscribers") :bytecode (20 0 0 20 3 0 16 0 48 1 52 2 0 1 1 4 0 52 1 0 2 1 5 0 49 2 50)} "assert-signal-no-subscribers" {:upvalue-count 0 :arity 1 :constants ("assert" "=" "len" "signal-subscribers" 0 "Expected signal to have no subscribers") :bytecode (20 0 0 20 3 0 16 0 48 1 52 2 0 1 1 4 0 52 1 0 2 1 5 0 49 2 50)} "assert-signal-subscriber-count" {:upvalue-count 0 :arity 2 :constants ("len" "signal-subscribers" "assert=" "str" "Expected " " subscribers, got ") :bytecode (20 1 0 16 0 48 1 52 0 0 1 17 2 20 2 0 16 2 16 1 1 4 0 16 1 1 5 0 16 2 52 3 0 4 49 3 50)} "simulate-signal-set!" {:upvalue-count 0 :arity 2 :constants ("reset!") :bytecode (20 0 0 16 0 16 1 49 2 50)} "simulate-signal-swap!" {:upvalue-count 0 :arity 2 :constants ("swap!") :bytecode (20 0 0 16 0 16 1 49 2 50)} "assert-computed-dep-count" {:upvalue-count 0 :arity 2 :constants ("len" "signal-deps" "assert=" "str" "Expected " " deps, got ") :bytecode (20 1 0 16 0 48 1 52 0 0 1 17 2 20 2 0 16 2 16 1 1 4 0 16 1 1 5 0 16 2 52 3 0 4 49 3 50)} "assert-computed-depends-on" {:upvalue-count 0 :arity 2 :constants ("assert" "contains?" "signal-deps" "Expected computed to depend on the given signal") :bytecode (20 0 0 20 2 0 16 0 48 1 16 1 52 1 0 2 1 3 0 49 2 50)} "count-effect-runs" {:upvalue-count 0 :arity 1 :constants ("signal" 0 "effect" {:upvalue-count 1 :arity 0 :constants ("deref") :bytecode (20 0 0 18 0 49 1 50)} {:upvalue-count 2 :arity 0 :constants ("+" 1 "cek-call") :bytecode (18 0 1 1 0 52 0 0 2 19 0 5 20 2 0 18 1 2 49 2 50)}) :bytecode (20 0 0 1 1 0 48 1 17 1 20 2 0 51 3 0 1 1 48 1 5 1 1 0 17 2 20 2 0 51 4 0 1 2 1 0 48 1 17 3 16 2 50)} "make-test-signal" {:upvalue-count 0 :arity 1 :constants ("signal" "list" "effect" {:upvalue-count 2 :arity 0 :constants ("append!" "deref") :bytecode (20 0 0 18 0 20 1 0 18 1 48 1 49 2 50)} "history") :bytecode (20 0 0 16 0 48 1 17 1 52 1 0 0 17 2 20 2 0 51 3 0 1 2 1 1 48 1 5 1 0 0 16 1 1 4 0 16 2 65 2 0 50)} "assert-batch-coalesces" {:upvalue-count 0 :arity 2 :constants (0 "signal" "effect" {:upvalue-count 2 :arity 0 :constants ("deref" "+" 1) :bytecode (20 0 0 18 0 48 1 5 18 1 1 2 0 52 1 0 2 19 1 50)} "batch" "assert=" "str" "Expected " " notifications, got ") :bytecode (1 0 0 17 2 20 1 0 1 0 0 48 1 17 3 20 2 0 51 3 0 1 3 1 2 48 1 5 1 0 0 17 2 5 20 4 0 16 0 48 1 5 20 5 0 16 2 16 1 1 7 0 16 1 1 8 0 16 2 52 6 0 4 49 3 50)}) :bytecode (51 1 0 128 0 0 5 51 3 0 128 2 0 5 51 5 0 128 4 0 5 51 7 0 128 6 0 5 51 9 0 128 8 0 5 51 11 0 128 10 0 5 51 13 0 128 12 0 5 51 15 0 128 14 0 5 51 17 0 128 16 0 5 51 19 0 128 18 0 5 51 21 0 128 20 0 50)))

View File

@@ -256,25 +256,6 @@
"sx:afterSwap" "sx:afterSwap"
(dict "target" target-el "swap" swap-style))))))) (dict "target" target-el "swap" swap-style)))))))
(define
flush-cssx!
:effects (mutation io)
(fn
()
(let
((rules (collected "cssx")))
(clear-collected! "cssx")
(when
(not (empty? rules))
(let
((style (dom-query "#sx-css")))
(when
style
(dom-set-prop
style
"textContent"
(str (dom-get-prop style "textContent") (join "" rules)))))))))
(define (define
handle-sx-response handle-sx-response
:effects (mutation io) :effects (mutation io)
@@ -527,8 +508,7 @@
(sx-hydrate root) (sx-hydrate root)
(sx-hydrate-islands root) (sx-hydrate-islands root)
(run-post-render-hooks) (run-post-render-hooks)
(process-elements root) (process-elements root)))
(flush-cssx!)))
(define (define
process-settle-hooks process-settle-hooks

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,3 @@
(sxbc 1 "7e4a727b2f55684e" (sxbc 1 "7e4a727b2f55684e"
(code (code
:constants ("with-marsh-scope" {:upvalue-count 0 :arity 2 :constants ("list" "with-island-scope" {:upvalue-count 1 :arity 1 :constants ("append!") :bytecode (20 0 0 18 0 16 0 49 2 50)} "dom-set-data" "sx-marsh-disposers") :bytecode (52 0 0 0 17 2 20 1 0 51 2 0 1 2 16 1 48 2 5 20 3 0 16 0 1 4 0 16 2 49 3 50)} "dispose-marsh-scope" {:upvalue-count 0 :arity 1 :constants ("dom-get-data" "sx-marsh-disposers" "for-each" {:upvalue-count 0 :arity 1 :constants ("cek-call") :bytecode (20 0 0 16 0 2 49 2 50)} "dom-set-data") :bytecode (20 0 0 16 0 1 1 0 48 2 17 1 16 1 33 24 0 51 3 0 16 1 52 2 0 2 5 20 4 0 16 0 1 1 0 2 49 3 32 1 0 2 50)} "emit-event" {:upvalue-count 0 :arity 3 :constants ("dom-dispatch") :bytecode (20 0 0 16 0 16 1 16 2 49 3 50)} "on-event" {:upvalue-count 0 :arity 3 :constants ("dom-on") :bytecode (20 0 0 16 0 16 1 16 2 49 3 50)} "bridge-event" {:upvalue-count 0 :arity 4 :constants ("effect" {:upvalue-count 4 :arity 0 :constants ("dom-on" {:upvalue-count 2 :arity 1 :constants ("event-detail" "cek-call" "list" "reset!") :bytecode (20 0 0 16 0 48 1 17 1 18 0 33 16 0 20 1 0 18 0 16 1 52 2 0 1 48 2 32 2 0 16 1 17 2 20 3 0 18 1 16 2 49 2 50)}) :bytecode (20 0 0 18 0 18 1 51 1 0 0 2 0 3 48 3 17 0 16 0 50)}) :bytecode (51 1 0 1 0 1 1 1 3 1 2 52 0 0 1 50)} "resource" {:upvalue-count 0 :arity 1 :constants ("signal" "dict" "loading" "data" "error" "promise-then" "cek-call" {:upvalue-count 1 :arity 1 :constants ("reset!" "dict" "loading" "data" "error") :bytecode (20 0 0 18 0 1 2 0 4 1 3 0 16 0 1 4 0 2 52 1 0 6 49 2 50)} {:upvalue-count 1 :arity 1 :constants ("reset!" "dict" "loading" "data" "error") :bytecode (20 0 0 18 0 1 2 0 4 1 3 0 2 1 4 0 16 0 52 1 0 6 49 2 50)}) :bytecode (20 0 0 1 2 0 3 1 3 0 2 1 4 0 2 52 1 0 6 48 1 17 1 20 5 0 20 6 0 16 0 2 48 2 51 7 0 1 1 51 8 0 1 1 48 3 5 16 1 50)}) :bytecode (51 1 0 128 0 0 5 51 3 0 128 2 0 5 51 5 0 128 4 0 5 51 7 0 128 6 0 5 51 9 0 128 8 0 5 51 11 0 128 10 0 50))) :constants ("with-marsh-scope" {:upvalue-count 0 :arity 2 :constants ("list" "with-island-scope" {:upvalue-count 1 :arity 1 :constants ("append!") :bytecode (20 0 0 18 0 16 0 49 2 50)} "dom-set-data" "sx-marsh-disposers") :bytecode (52 0 0 0 17 2 20 1 0 51 2 0 1 2 16 1 48 2 5 20 3 0 16 0 1 4 0 16 2 49 3 50)} "dispose-marsh-scope" {:upvalue-count 0 :arity 1 :constants ("dom-get-data" "sx-marsh-disposers" "for-each" {:upvalue-count 0 :arity 1 :constants ("cek-call") :bytecode (20 0 0 16 0 2 49 2 50)} "dom-set-data") :bytecode (20 0 0 16 0 1 1 0 48 2 17 1 16 1 33 24 0 51 3 0 16 1 52 2 0 2 5 20 4 0 16 0 1 1 0 2 49 3 32 1 0 2 50)} "emit-event" {:upvalue-count 0 :arity 3 :constants ("dom-dispatch") :bytecode (20 0 0 16 0 16 1 16 2 49 3 50)} "on-event" {:upvalue-count 0 :arity 3 :constants ("dom-on") :bytecode (20 0 0 16 0 16 1 16 2 49 3 50)} "bridge-event" {:upvalue-count 0 :arity 4 :constants ("effect" {:upvalue-count 4 :arity 0 :constants ("dom-on" {:upvalue-count 2 :arity 1 :constants ("event-detail" "cek-call" "list" "reset!") :bytecode (20 0 0 16 0 48 1 17 1 18 0 33 16 0 20 1 0 18 0 16 1 52 2 0 1 48 2 32 2 0 16 1 17 2 20 3 0 18 1 16 2 49 2 50)}) :bytecode (20 0 0 18 0 18 1 51 1 0 0 2 0 3 48 3 17 0 16 0 50)}) :bytecode (20 0 0 51 1 0 1 0 1 1 1 3 1 2 49 1 50)} "resource" {:upvalue-count 0 :arity 1 :constants ("signal" "dict" "loading" "data" "error" "promise-then" "cek-call" {:upvalue-count 1 :arity 1 :constants ("reset!" "dict" "loading" "data" "error") :bytecode (20 0 0 18 0 1 2 0 4 1 3 0 16 0 1 4 0 2 52 1 0 6 49 2 50)} {:upvalue-count 1 :arity 1 :constants ("reset!" "dict" "loading" "data" "error") :bytecode (20 0 0 18 0 1 2 0 4 1 3 0 2 1 4 0 16 0 52 1 0 6 49 2 50)}) :bytecode (20 0 0 1 2 0 3 1 3 0 2 1 4 0 2 52 1 0 6 48 1 17 1 20 5 0 20 6 0 16 0 2 48 2 51 7 0 1 1 51 8 0 1 1 48 3 5 16 1 50)}) :bytecode (51 1 0 128 0 0 5 51 3 0 128 2 0 5 51 5 0 128 4 0 5 51 7 0 128 6 0 5 51 9 0 128 8 0 5 51 11 0 128 10 0 50)))

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1792,7 +1792,7 @@
blake2_js_for_wasm_create: blake2_js_for_wasm_create}; blake2_js_for_wasm_create: blake2_js_for_wasm_create};
} }
(globalThis)) (globalThis))
({"link":[["runtime-0db9b496",0],["prelude-d7e4b000",0],["stdlib-23ce0836",[]],["sx-a0c22109",[2]],["jsoo_runtime-f96b44a8",[2]],["js_of_ocaml-651f6707",[2,4]],["dune__exe__Sx_browser-8ae21d0a",[2,3,5]],["std_exit-10fb8830",[2]],["start-80fdb768",0]],"generated":(b=>{var ({"link":[["runtime-0db9b496",0],["prelude-d7e4b000",0],["stdlib-23ce0836",[]],["sx-86ee6606",[2]],["jsoo_runtime-f96b44a8",[2]],["js_of_ocaml-651f6707",[2,4]],["dune__exe__Sx_browser-8ae21d0a",[2,3,5]],["std_exit-10fb8830",[2]],["start-80fdb768",0]],"generated":(b=>{var
c=b,a=b?.module?.export||b;return{"env":{"caml_ba_kind_of_typed_array":()=>{throw new c=b,a=b?.module?.export||b;return{"env":{"caml_ba_kind_of_typed_array":()=>{throw new
Error("caml_ba_kind_of_typed_array not implemented")},"caml_exn_with_js_backtrace":()=>{throw new Error("caml_ba_kind_of_typed_array not implemented")},"caml_exn_with_js_backtrace":()=>{throw new
Error("caml_exn_with_js_backtrace not implemented")},"caml_int64_create_lo_mi_hi":()=>{throw new Error("caml_exn_with_js_backtrace not implemented")},"caml_int64_create_lo_mi_hi":()=>{throw new