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:
@@ -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
|
||||||
|
|||||||
@@ -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)"
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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)))
|
||||||
|
|||||||
@@ -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
@@ -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
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user