Skip to main content

Frontage

documentation · PyPI

A fine-grained reactive UI framework for Python in the browser. Signals, memos and effects; templates that clone once and bind only their holes; a keyed For; a nested router; running on MicroPython compiled to WebAssembly, with the framework delivered as precompiled bytecode. No JavaScript, no Node, no bundler: you write Python and the browser runs it.

Status: 0.8.3, alpha. The rewrite planned in DESIGN.md is complete through its M5 milestone: reactive core, store, templates (h and html(t"…")), control flow and boundaries, Resource/Action, a nested router, widgets, State, timers, the playground; 0.3.0 added the command line (export, tailwind, check); 0.4.0 added prerendering with hydration (M6): pages that show before Python loads; 0.5.0 adds transitions (transition, is_pending, Optimistic), async memos, the debug warnings, the frontage console script and prerender --crawl (M7); 0.6.0 builds the new state off screen during a transition and lets the router navigate inside one (M8); 0.7.0 makes async memos the router's data primitive: they count toward is_routing, and prerender settles and hydrates them (M9); 0.8.0 adds frontage serve, a dev server that reloads the page on save; 0.9.0 replaces PyScript with a direct WebAssembly boot (M11): four requests instead of twenty-nine, 52 ms instead of 88, the framework precompiled, and a dev server that swaps a module into the running page without reloading it. The API is young and will move; the browser suite runs every example on Chromium each push and on Firefox and WebKit nightly.

from frontage import Signal, component, html, mount


@component
def counter(initial=0):
    count = Signal(initial)

    def inc(ev):
        count.update(lambda n: n + 1)

    def dec(ev):
        count.update(lambda n: n - 1)

    return html(t"""
        <div class="counter">
            <button on:click={dec}>-</button>
            <span>Value: {count}</span>
            <button on:click={inc}>+</button>
        </div>
    """)


mount(lambda: counter(initial=0), "#app")

Signals hold state; anything callable in a template is a hole that updates in place when what it read changes; a component body runs once. Name the functions you put in holes: MicroPython does not accept a lambda inside a template's braces.

Try it at frontage.optersoft.com/playground, which runs your code on MicroPython and keeps it in the link. Learn it at academy.optersoft.com/python/frontage, ten chapters with exercises, nine of them with an app published on GitLab Pages. Install it with pip, and frontage build writes a directory that runs anywhere:

uvx frontage build myapp        # index.html, your .py, and _frontage/ beside them
The counter, cold cache 0.9.0 0.8.3 (PyScript)
requests 6 29
transferred 0.64 MB 0.91 MB
compressed 0.27 MB 0.33 MB
to first paint 52 ms 88 ms

Most of that is the interpreter: the framework is 82 KB of precompiled bytecode, and none of it is parsed in the browser. Medians of five, this laptop's Chromium; DESIGN.md §12 has the method.

The same package is a small command line on your machine, stdlib only:

uvx frontage serve              # a dev server that reloads the page whenever a file changes
uvx frontage check app.py       # the rules MicroPython enforces and CPython does not
uvx frontage tailwind           # Tailwind CSS: the standalone CLI, fetched once, no Node
uvx frontage export . --out build              # a self-contained static folder
uvx frontage prerender . --out build --crawl   # every route the pages link to, as finished HTML

(uvx runs the frontage script straight from PyPI; pip install frontage puts the same frontage command on PATH, and python -m frontage is the same thing.)

prerender runs the app on your machine, waits for its resources and async memos, and writes each route as finished HTML with the values embedded. In the browser mount hydrates: it adopts the HTML already on screen instead of building it, skips the fetches the page already holds, and replays the clicks made before Python was ready. Static hosting only, no server: Leptos's async rendering mode as a build step.

Tailwind with no build at all: the playground loads Tailwind's browser build, so utility classes work as you type. The Style, Ship and Prerender chapters cover all of it.

Why

Python in the browser exists (MicroPython and CPython both compile to WebAssembly) and the frameworks that use it either carry a server into the browser (Streamlit's stlite, Shiny's Shinylive: tens of seconds to start) or rebuild and diff the page on every change. Frontage is browser-first: no session, no transport, no DSL, and a state change touches only the DOM nodes that read it. The whole reasoning, with the frameworks it learned from, is in DESIGN.md; the behaviours it must have, one line each, are in SPEC.md.

Develop

The repo uses uv and mkrun (mk).

mk sync                 # .venv with every dependency group
mk check                # lint, types, unit tests: the gate
mk runtime.fetch        # the pinned micropython.mjs + .wasm into frontage/_runtime/
mk serve                # examples and playground at http://127.0.0.1:8000/, package read live, reload on save
mk test --browser       # every example in Chromium, on MicroPython in WebAssembly
mk build examples/todo  # a static directory that boots from WebAssembly
mk site.deploy          # publish frontage.optersoft.com by hand (Cloudflare Pages): landing page, gallery, playground, wheels

Without mk: uv sync --all-groups, uv run pytest, uv run ruff check, uv run ty check.

Contributing

Contributions are welcome and are accepted under the Apache License 2.0, the same terms the project is published under. By opening a pull request you agree that your contribution may be distributed under that license, including its patent grant (section 3). There is no separate contributor agreement. The rewrite is clean-room: code is written from SPEC.md, not from any reference framework's source, and a pull request says so.

License

Apache License 2.0, copyright Optersoft, S.L. See LICENSE and NOTICE.

Frontage and the Frontage logo are trademarks of Optersoft, S.L. The license grants no rights to the name or the logo (Apache License section 6). You may say that your work uses or is built with Frontage; a fork or a derivative must ship under another name.

Frontage's reactive model follows Solid and Leptos.

Metadata

Release files for frontage 0.9.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for frontage 0.9.0
File Size Uploaded
frontage-0.9.0.tar.gz 535.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for frontage 0.9.0
File Interpreter ABI Platform
frontage-0.9.0-py3-none-any.whl Python 3 none any Details

Total release size: 940.4 kB

Release files / frontage-0.9.0.tar.gz

Download URL frontage-0.9.0.tar.gz
Size 535.9 kB
Tags Source
SHA-256 checksum
How to use checksums
5c7cbb54c53d3ccc94152cdef97451872ac98bd53d1d9dc441c147636167d972
BLAKE2b-256 checksum
How to use checksums
21c057aad2b5d23c20af7239a099bad0f5db87ba839ee0ce4abdfddb006232b8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / frontage-0.9.0-py3-none-any.whl

Download URL frontage-0.9.0-py3-none-any.whl
Size 404.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0b8fa567723a65a88fcb1f279f765e308dc2bb1cc2ad0169cbd1e02c0a36f2de
BLAKE2b-256 checksum
How to use checksums
59635506a3586eb10eddb980c28c042921d20eb98de70915627a504aa87479a2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page