Skip to content

Add typed renderer adapters for Jinja2, htpy, Jx, and tdom #9

Description

@yhay81

Outcome

Make hayate-htmx an engine-neutral, statically typed hypermedia layer with
first-party Jinja2, htpy, Jx, and experimental tdom rendering paths. This
implements the direction recorded in the maintainer-owned DESIGN.md without
making the Hayate core depend on a template engine.

Why now

  • The competitive capability matrix still gives Django and Hono stronger
    framework-native HTML/component ergonomics in important profiles.
  • htpy supplies typed Python components and async rendering.
  • Jx supplies Jinja-backed components, typed props, slots, and component
    assets.
  • tdom supplies Python 3.14 t-string components with default escaping.
  • The existing page/fragment selection and Vary behavior are already
    renderer-independent; the remaining public type assumed string template
    names.

Phase 1 — public renderer boundary

  • Introduce Renderer[ViewT] with one view type shared by page and
    fragment targets.
  • Make HtmxTemplates[ViewT] generic without changing request selection,
    response, status, headers, or cache variation.
  • Preserve the existing TemplateRenderer import as a compatible
    string-view protocol for the 0.x transition.
  • Keep Jinja2 as the installed and documented default.
  • Add strict typing tests proving that page and fragment targets cannot
    silently use incompatible view types.

Phase 2 — first-party adapters

  • Add hayate-htmx[htpy] using htpy 26.x, including async component
    rendering and default escaping.
  • Add hayate-htmx[jx] using Jx 0.11.x, including catalog reuse, props,
    slots, assets, default escaping, and normalized missing-component identity.
  • Add hayate-htmx[tdom] using tdom 0.1.x only on Python 3.14+, with an
    actionable Python/extra error and no tdom import from the base package on
    Python 3.12/3.13.
  • Add hayate-htmx[all] with environment markers that preserve the base
    package's Python 3.12 floor.
  • Exercise the same page, fragment, history restore, htmx 4, escaping,
    async, missing-view, Vary, content-type, and response contract for every
    applicable adapter.

Phase 3 — runtime and scaffold evidence

  • Prove every adapter currently claimed as Workers-compatible through real
    workerd/Pyodide: Jinja2 is covered by the golden app and htpy by a dedicated
    gate. Jx and tdom remain explicitly unclaimed.
  • Add a renderer axis to create-hayate while keeping Jinja2 as the
    compatibility default and tdom experimental/Python-3.14-only.
  • Keep generated routing, handlers, security, htmx behavior, and tests
    structurally equivalent across renderers.
  • Publish package, compatibility, dependency, payload, and browser
    evidence before changing the competitive matrix.

Landed evidence

Remaining publication gate

The implementation and generated-scaffold evidence are complete. The package
is not yet on PyPI because its one-time pending trusted publisher has not been
configured. Until that external setting is complete, create-hayate remains
unreleased with the renderer axis and the competitive matrix must not claim
public-package availability.

Sources reviewed

Non-goals

  • Moving rendering into hayate core.
  • Claiming tdom stability while it remains pre-alpha.
  • Claiming Workers compatibility from CPython-only tests.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions