Add on-demand CSS: registry, pre-computed component classes, header compression
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 42s

- Parse tw.css into per-class lookup registry at startup
- Pre-scan component CSS classes at registration time (avoid per-request regex)
- Compress SX-Css header: 8-char hash replaces full class list (LRU cache)
- Add ;@css comment annotation for dynamically constructed class names
- Safelist bg-sky-{100..400} in Tailwind config for menu-row-sx dynamic shades
- Client sends/receives hash, falls back gracefully on cache miss

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 21:39:57 +00:00
parent ab45e21c7c
commit 1447122a0c
12 changed files with 603 additions and 31 deletions

View File

@@ -113,11 +113,25 @@ def register_components(sx_source: str) -> None:
"""
from .evaluator import _eval
from .parser import parse_all
from .css_registry import scan_classes_from_sx
# Snapshot existing component names before eval
existing = set(_COMPONENT_ENV.keys())
exprs = parse_all(sx_source)
for expr in exprs:
_eval(expr, _COMPONENT_ENV)
# Pre-scan CSS classes for newly registered components.
# Scan the full source once — components from the same file share the set.
# Slightly over-counts per component but safe and avoids re-scanning at request time.
all_classes: set[str] | None = None
for key, val in _COMPONENT_ENV.items():
if key not in existing and isinstance(val, Component):
if all_classes is None:
all_classes = scan_classes_from_sx(sx_source)
val.css_classes = set(all_classes)
# ---------------------------------------------------------------------------
# sx() — render s-expression from Jinja template
@@ -232,6 +246,12 @@ def client_components_tag(*names: str) -> str:
return f'<script type="text/sx" data-components>{source}</script>'
def sx_css_all() -> str:
"""Return all CSS rules (preamble + utilities) for Jinja fallback pages."""
from .css_registry import get_all_css
return get_all_css()
def setup_sx_bridge(app: Any) -> None:
"""Register s-expression helpers with a Quart app's Jinja environment.
@@ -243,7 +263,9 @@ def setup_sx_bridge(app: Any) -> None:
This registers:
- ``sx(source, **kwargs)`` — sync render (components, pure HTML)
- ``sx_async(source, **kwargs)`` — async render (with I/O resolution)
- ``sx_css_all()`` — full CSS dump for non-sx pages
"""
app.jinja_env.globals["sx"] = sx
app.jinja_env.globals["render"] = render
app.jinja_env.globals["sx_async"] = sx_async
app.jinja_env.globals["sx_css_all"] = sx_css_all