Files
mizan/docs/SSR_ARCHITECTURE.md

2.4 KiB

SSR Architecture

Decided 2026-04-07.

Mizan's SSR adapter is a Django template backend. It plugs into Django's existing TEMPLATES setting, replacing the template rendering engine.

TEMPLATES = [
    {
        'BACKEND': 'mizan.ssr.MizanTemplates',
        'DIRS': [BASE_DIR / 'frontend'],
        'OPTIONS': {
            'worker': 'path/to/mizan-ssr/src/worker.tsx',
            'timeout': 5,
        },
    }
]

Then render(request, 'components/Hello.tsx', context) calls the Bun subprocess bridge instead of rendering a Django/Jinja2 template. The template name IS a .tsx/.jsx file path, resolved against DIRS; get_template returns a MizanTemplate wrapping the absolute file path. The context dict becomes the component's props (request and csrf_token stripped). Rendered output is wrapped in <div id="mizan-root">…</div> plus a <script>window.__MIZAN_SSR_DATA__=…</script> hydration payload.

AFI boundary

Side Responsibility
Backend adapter (SSRBridge) Manages the Bun subprocess lifecycle; gathers props
Bun worker (worker.tsx) import()s the file path, renderToString(createElement(Component, props))
stdin/stdout JSON-RPC Newline-delimited; {id, method:"render", params:{file, props}}{id, html} / {id, error}; ping{id, pong:true}

Why template backend

  • Django's template system is swappable by design (batteries included, but replaceable).
  • Django developers already use render(request, template, context) — no new API to learn.
  • URL routing, views, middleware, auth — all unchanged.

A templatetags/ package exists for a future {% mizan_render %} convenience tag (base.html shell with Mizan components inside), but it is currently empty — no tag is implemented yet.

Implementation surface

The SSR backend (mizan/ssr/backend.py) implements Django's template backend interface:

  • MizanTemplates(BaseEngine) — requires OPTIONS['worker'] (path to worker.tsx); get_template(name) resolves a file under DIRS
  • MizanTemplate with .render(context, request) → calls the bridge
  • SSRBridge (bridge.py) — spawns bun run <worker>, holds the persistent subprocess, correlates requests by message id, thread-safe, auto-restarts on crash, waits for the worker's ready signal

Everything Django expects from a template backend, but the actual rendering routes to Bun.