Frontage
frontage.optersoft.com · 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 PyScript over WebAssembly, on Pyodide or
MicroPython. No JavaScript, no Node, no bundler: you write Python and the browser runs it.
Status: 0.4.0, alpha. The rewrite planned in DESIGN.md is complete through its M5 milestone: reactive core, store, templates (
handhtml(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 adds prerendering with hydration (M6): pages that show before Python loads. The API is young and will move; the browser suite runs every example under MicroPython and Pyodide 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, eight
chapters with exercises. Install it with a pyscript.json:
{ "packages": ["https://frontage.optersoft.com/dist/frontage-0.3.0-py3-none-any.whl"] }
| The counter above, as downloaded | MicroPython | Pyodide |
|---|---|---|
| transferred | 0.84 MB | 13.8 MB |
| compressed | 0.32 MB | 6.4 MB |
Frontage itself is 131 KB (39 KB compressed); the rest is the interpreter.
The same package is a small command line on your machine, stdlib only:
uv run --with frontage python -m frontage check app.py # the rules MicroPython enforces and CPython does not
uv run --with frontage python -m frontage tailwind # Tailwind CSS: the standalone CLI, fetched once, no Node
uv run --with frontage python -m frontage export . --out build # a self-contained static folder
uv run --with frontage python -m frontage prerender . --out build --route / --route /about
prerender runs the app on your machine, waits for its resources, 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 and Export chapters cover both.
Why
Python in the browser exists (PyScript, Pyodide, MicroPython) 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 pyscript.fetch # PyScript's offline bundle (core + both interpreters) into tools/pyscript/
mk serve # examples and playground at http://127.0.0.1:8000/, package read live
mk test --browser # every example in Chromium, under MicroPython and Pyodide
mk export examples/todo # python -m frontage export, with the local PyScript bundle
mk site.deploy # publish frontage.optersoft.com (Cloudflare Pages)
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; the project began as a fork of PuePy.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file frontage-0.4.0.tar.gz.
File metadata
- Download URL: frontage-0.4.0.tar.gz
- Upload date:
- Size: 109.5 kB
- Tags: Source
- Uploaded using 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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
035eba4eec39e1c38ead31654fcf29baf86db4759c25f0db637df97058308e82
|
|
| MD5 |
83d25e9ae750acabdb91e7d2323cbe80
|
|
| BLAKE2b-256 |
858b6cca0cbc3a2b688dcd7e7628965d84af9910098d24fb5256a88e256a4780
|
File details
Details for the file frontage-0.4.0-py3-none-any.whl.
File metadata
- Download URL: frontage-0.4.0-py3-none-any.whl
- Upload date:
- Size: 72.2 kB
- Tags: Python 3
- Uploaded using 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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de207be80f3e93e2d03e5b7d713de9e4a1acc5ec4e12b746e1295ac1f0406b71
|
|
| MD5 |
9b31aa02716b6d5ef66a8bd3be65f14e
|
|
| BLAKE2b-256 |
55c46b038bb9b49423751e6c0b7a1d2216382a77cf71bfc623791461435eae25
|