Fix register_sx_layout: use async_eval_slot_to_sx to expand component bodies
async_eval_to_sx serializes component calls without expanding their bodies, so free variables from _ctx_to_env were passed through as unresolved symbols to the client. Switch to async_eval_slot_to_sx which expands the top-level component body server-side, resolving free variables during expansion. Also inline ~root-header/~root-mobile into layout defcomps rather than using wrapper defcomps (nested ~component calls in _aser are serialized without expansion, so wrapper defcomps would still leave free vars unresolved). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -427,15 +427,20 @@ async def render_to_sx_with_env(__name: str, extra_env: dict, **kwargs: Any) ->
|
|||||||
"""Like ``render_to_sx`` but merges *extra_env* into the evaluation
|
"""Like ``render_to_sx`` but merges *extra_env* into the evaluation
|
||||||
environment before eval. Used by ``register_sx_layout`` so .sx
|
environment before eval. Used by ``register_sx_layout`` so .sx
|
||||||
defcomps can read ctx values as free variables.
|
defcomps can read ctx values as free variables.
|
||||||
|
|
||||||
|
Uses ``async_eval_slot_to_sx`` (not ``async_eval_to_sx``) so the
|
||||||
|
top-level component body is expanded server-side — free variables
|
||||||
|
from *extra_env* are resolved during expansion rather than being
|
||||||
|
serialized as unresolved symbols for the client.
|
||||||
"""
|
"""
|
||||||
from .jinja_bridge import get_component_env, _get_request_context
|
from .jinja_bridge import get_component_env, _get_request_context
|
||||||
from .async_eval import async_eval_to_sx
|
from .async_eval import async_eval_slot_to_sx
|
||||||
|
|
||||||
ast = _build_component_ast(__name, **kwargs)
|
ast = _build_component_ast(__name, **kwargs)
|
||||||
env = dict(get_component_env())
|
env = dict(get_component_env())
|
||||||
env.update(extra_env)
|
env.update(extra_env)
|
||||||
ctx = _get_request_context()
|
ctx = _get_request_context()
|
||||||
return await async_eval_to_sx(ast, env, ctx)
|
return await async_eval_slot_to_sx(ast, env, ctx)
|
||||||
|
|
||||||
|
|
||||||
async def render_to_sx(__name: str, **kwargs: Any) -> str:
|
async def render_to_sx(__name: str, **kwargs: Any) -> str:
|
||||||
|
|||||||
@@ -146,32 +146,24 @@
|
|||||||
(when auth-menu
|
(when auth-menu
|
||||||
(div :class "p-3 border-t border-stone-200" auth-menu))))
|
(div :class "p-3 border-t border-stone-200" auth-menu))))
|
||||||
|
|
||||||
;; ---------------------------------------------------------------------------
|
|
||||||
;; Root header/mobile wrappers — read ctx values from env free variables
|
|
||||||
;; Used by register_sx_layout so .sx defcomps compose without Python
|
|
||||||
;; ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
(defcomp ~root-header (&key oob)
|
|
||||||
(~header-row-sx :cart-mini cart-mini :blog-url blog-url :site-title site-title
|
|
||||||
:app-label app-label :nav-tree nav-tree :auth-menu auth-menu
|
|
||||||
:nav-panel nav-panel :settings-url settings-url :is-admin is-admin
|
|
||||||
:oob oob))
|
|
||||||
|
|
||||||
(defcomp ~root-mobile ()
|
|
||||||
(~mobile-root-nav :nav-tree nav-tree :auth-menu auth-menu))
|
|
||||||
|
|
||||||
;; ---------------------------------------------------------------------------
|
;; ---------------------------------------------------------------------------
|
||||||
;; Built-in layout defcomps — used by register_sx_layout("root", ...)
|
;; Built-in layout defcomps — used by register_sx_layout("root", ...)
|
||||||
|
;; Free variables (cart-mini, blog-url, etc.) come from _ctx_to_env().
|
||||||
;; ---------------------------------------------------------------------------
|
;; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
(defcomp ~layout-root-full ()
|
(defcomp ~layout-root-full ()
|
||||||
(~root-header))
|
(~header-row-sx :cart-mini cart-mini :blog-url blog-url :site-title site-title
|
||||||
|
:app-label app-label :nav-tree nav-tree :auth-menu auth-menu
|
||||||
|
:nav-panel nav-panel :settings-url settings-url :is-admin is-admin))
|
||||||
|
|
||||||
(defcomp ~layout-root-oob ()
|
(defcomp ~layout-root-oob ()
|
||||||
(~oob-header-sx :parent-id "root-header-child" :row (~root-header)))
|
(~oob-header-sx :parent-id "root-header-child"
|
||||||
|
:row (~header-row-sx :cart-mini cart-mini :blog-url blog-url :site-title site-title
|
||||||
|
:app-label app-label :nav-tree nav-tree :auth-menu auth-menu
|
||||||
|
:nav-panel nav-panel :settings-url settings-url :is-admin is-admin)))
|
||||||
|
|
||||||
(defcomp ~layout-root-mobile ()
|
(defcomp ~layout-root-mobile ()
|
||||||
(~root-mobile))
|
(~mobile-root-nav :nav-tree nav-tree :auth-menu auth-menu))
|
||||||
|
|
||||||
(defcomp ~error-content (&key errnum message image)
|
(defcomp ~error-content (&key errnum message image)
|
||||||
(div :class "text-center p-8 max-w-lg mx-auto"
|
(div :class "text-center p-8 max-w-lg mx-auto"
|
||||||
|
|||||||
Reference in New Issue
Block a user